< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotObjdumpDisassemblerProvider.java

Print this page

        

*** 37,46 **** --- 37,47 ---- import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; import org.graalvm.compiler.code.DisassemblerProvider; import org.graalvm.compiler.serviceprovider.ServiceProvider; + import org.graalvm.util.CollectionsUtil; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.CodeUtil.DefaultRefMapFormatter; import jdk.vm.ci.code.CodeUtil.RefMapFormatter;
*** 54,85 **** import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.services.Services; /** ! * This disassembles the code immediatly with objdump. */ @ServiceProvider(DisassemblerProvider.class) public class HotSpotObjdumpDisassemblerProvider extends HotSpotDisassemblerProvider { ! /** ! * Uses objdump to disassemble the compiled code. ! */ @Override public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { File tmp = null; try { tmp = File.createTempFile("compiledBinary", ".bin"); try (FileOutputStream fos = new FileOutputStream(tmp)) { fos.write(compResult.getTargetCode()); } String[] cmdline; String arch = Services.getSavedProperties().get("os.arch"); ! if (arch.equals("amd64")) { ! cmdline = new String[]{"objdump", "-D", "-b", "binary", "-M", "x86-64", "-m", "i386", tmp.getAbsolutePath()}; } else if (arch.equals("aarch64")) { ! cmdline = new String[]{"objdump", "-D", "-b", "binary", "-m", "aarch64", tmp.getAbsolutePath()}; } else { return null; } Pattern p = Pattern.compile(" *(([0-9a-fA-F]+):\t.*)"); --- 55,89 ---- import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.services.Services; /** ! * A provider that uses the {@code GNU objdump} utility to disassemble code. */ @ServiceProvider(DisassemblerProvider.class) public class HotSpotObjdumpDisassemblerProvider extends HotSpotDisassemblerProvider { ! private final String objdump = getObjdump(); ! @Override public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { + if (objdump == null) { + return null; + } File tmp = null; try { tmp = File.createTempFile("compiledBinary", ".bin"); try (FileOutputStream fos = new FileOutputStream(tmp)) { fos.write(compResult.getTargetCode()); } + String[] cmdline; String arch = Services.getSavedProperties().get("os.arch"); ! if (arch.equals("amd64") || arch.equals("x86_64")) { ! cmdline = new String[]{objdump, "-D", "-b", "binary", "-M", "x86-64", "-m", "i386", tmp.getAbsolutePath()}; } else if (arch.equals("aarch64")) { ! cmdline = new String[]{objdump, "-D", "-b", "binary", "-m", "aarch64", tmp.getAbsolutePath()}; } else { return null; } Pattern p = Pattern.compile(" *(([0-9a-fA-F]+):\t.*)");
*** 114,160 **** } } Process proc = Runtime.getRuntime().exec(cmdline); InputStream is = proc.getInputStream(); InputStreamReader isr = new InputStreamReader(is); ! BufferedReader br = new BufferedReader(isr); ! String line; ! ! StringBuilder sb = new StringBuilder(); ! while ((line = br.readLine()) != null) { ! Matcher m = p.matcher(line); ! if (m.find()) { ! int address = Integer.parseInt(m.group(2), 16); ! String annotation = annotations.get(address); ! if (annotation != null) { ! annotation = annotation.replace("\n", "\n; "); ! sb.append("; ").append(annotation).append('\n'); } ! line = m.replaceAll("0x$1"); } - sb.append(line).append("\n"); } ! BufferedReader ebr = new BufferedReader(new InputStreamReader(proc.getErrorStream())); ! while ((line = ebr.readLine()) != null) { ! System.err.println(line); } - ebr.close(); return sb.toString(); } catch (IOException e) { if (tmp != null) { tmp.delete(); } - e.printStackTrace(); - return null; } } private static void putAnnotation(Map<Integer, String> annotations, int idx, String txt) { ! String newAnnoation = annotations.getOrDefault(idx, "") + "\n" + txt; ! annotations.put(idx, newAnnoation); } @Override public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode code) { return ((HotSpotCodeCacheProvider) codeCache).disassemble(code); --- 118,220 ---- } } Process proc = Runtime.getRuntime().exec(cmdline); InputStream is = proc.getInputStream(); + StringBuilder sb = new StringBuilder(); InputStreamReader isr = new InputStreamReader(is); ! try (BufferedReader br = new BufferedReader(isr)) { ! String line; ! while ((line = br.readLine()) != null) { ! Matcher m = p.matcher(line); ! if (m.find()) { ! int address = Integer.parseInt(m.group(2), 16); ! String annotation = annotations.get(address); ! if (annotation != null) { ! annotation = annotation.replace("\n", "\n; "); ! sb.append("; ").append(annotation).append('\n'); ! } ! line = m.replaceAll("0x$1"); } ! sb.append(line).append("\n"); } } ! try (BufferedReader ebr = new BufferedReader(new InputStreamReader(proc.getErrorStream()))) { ! String errLine = ebr.readLine(); ! if (errLine != null) { ! System.err.println("Error output from executing: " + CollectionsUtil.mapAndJoin(cmdline, e -> quoteShellArg(String.valueOf(e)), " ")); ! System.err.println(errLine); ! while ((errLine = ebr.readLine()) != null) { ! System.err.println(errLine); ! } ! } } return sb.toString(); } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { if (tmp != null) { tmp.delete(); } } } + /** + * Pattern for a single shell command argument that does not need to quoted. + */ + private static final Pattern SAFE_SHELL_ARG = Pattern.compile("[A-Za-z0-9@%_\\-\\+=:,\\./]+"); + + /** + * Reliably quote a string as a single shell command argument. + */ + public static String quoteShellArg(String arg) { + if (arg.isEmpty()) { + return "\"\""; + } + Matcher m = SAFE_SHELL_ARG.matcher(arg); + if (m.matches()) { + return arg; + } + // See http://stackoverflow.com/a/1250279 + return "'" + arg.replace("'", "'\"'\"'") + "'"; + } + + /** + * Searches for a valid GNU objdump executable. + */ + private static String getObjdump() { + // On macOS, `brew install binutils` will provide + // an executable named gobjdump + for (String candidate : new String[]{"objdump", "gobjdump"}) { + try { + String[] cmd = {candidate, "--version"}; + Process proc = Runtime.getRuntime().exec(cmd); + InputStream is = proc.getInputStream(); + int exitValue = proc.waitFor(); + if (exitValue == 0) { + byte[] buf = new byte[is.available()]; + int pos = 0; + while (pos < buf.length) { + int read = is.read(buf, pos, buf.length - pos); + pos += read; + } + String output = new String(buf); + if (output.contains("GNU objdump")) { + return candidate; + } + } + } catch (IOException | InterruptedException e) { + } + } + return null; + } + private static void putAnnotation(Map<Integer, String> annotations, int idx, String txt) { ! String newAnnotation = annotations.getOrDefault(idx, "") + "\n" + txt; ! annotations.put(idx, newAnnotation); } @Override public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode code) { return ((HotSpotCodeCacheProvider) codeCache).disassemble(code);
< prev index next >