< 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 >