1 /* 2 * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.asm; 26 27 import java.io.PrintStream; 28 import sun.jvm.hotspot.code.CodeBlob; 29 import sun.jvm.hotspot.code.NMethod; 30 import sun.jvm.hotspot.debugger.Address; 31 import sun.jvm.hotspot.runtime.VM; 32 33 public class Disassembler { 34 private static String options = ""; 35 private static long decode_function; 36 37 protected long startPc; 38 protected byte[] code; 39 private CodeBlob blob; 40 private NMethod nmethod; 41 42 public static void decode(InstructionVisitor visitor, CodeBlob blob) { 43 decode(visitor, blob, blob.codeBegin(), blob.codeEnd()); 44 } 45 46 public static void decode(InstructionVisitor visitor, CodeBlob blob, Address begin, Address end) { 47 int codeSize = (int)end.minus(begin); 48 long startPc = VM.getAddressValue(begin); 49 byte[] code = new byte[codeSize]; 50 for (int i = 0; i < code.length; i++) 51 code[i] = begin.getJByteAt(i); 52 Disassembler dis = new Disassembler(startPc, code); 53 dis.decode(visitor); 54 } 55 56 private Disassembler(long startPc, byte[] code) { 57 this.startPc = startPc; 58 this.code = code; 59 60 // Lazily load hsdis 61 if (decode_function == 0) { 62 StringBuilder path = new StringBuilder(System.getProperty("java.home")); 63 String sep = System.getProperty("file.separator"); 64 String os = System.getProperty("os.name"); 65 String libname = "hsdis"; 66 String arch = System.getProperty("os.arch"); 67 if (os.lastIndexOf("Windows", 0) != -1) { 68 if (arch.equals("x86")) { 69 libname += "-i386"; 70 } else if (arch.equals("amd64")) { 71 libname += "-amd64"; 72 } else if (arch.equals("aarch64")) { 73 libname += "-arm64"; 74 } else { 75 libname += "-" + arch; 76 } 77 path.append(sep + "bin" + sep); 78 libname += ".dll"; 79 } else if (os.lastIndexOf("Linux", 0) != -1) { 80 if (arch.equals("x86") || arch.equals("i386")) { 81 path.append(sep + "lib" + sep + "i386" + sep); 82 libname += "-i386.so"; 83 } else if (arch.equals("amd64") || arch.equals("x86_64")) { 84 path.append(sep + "lib" + sep + "amd64" + sep); 85 libname += "-amd64.so"; 86 } else { 87 path.append(sep + "lib" + sep + arch + sep); 88 libname += "-" + arch + ".so"; 89 } 90 } else if (os.lastIndexOf("Mac OS X", 0) != -1) { 91 path.append(sep + "lib" + sep); 92 libname += "-amd64" + ".dylib"; // x86_64 => amd64 93 } else { 94 path.append(sep + "lib" + sep + "arch" + sep); 95 libname += "-" + arch + ".so"; 96 } 97 decode_function = load_library(path.toString(), libname); 98 } 99 } 100 101 private static native long load_library(String installed_jrepath, String hsdis_library_name); 102 103 private native void decode(InstructionVisitor visitor, long pc, byte[] code, 104 String options, long decode_function); 105 106 private void decode(InstructionVisitor visitor) { 107 visitor.prologue(); 108 decode(visitor, startPc, code, options, decode_function); 109 visitor.epilogue(); 110 } 111 112 private boolean match(String event, String tag) { 113 if (!event.startsWith(tag)) 114 return false; 115 int taglen = tag.length(); 116 if (taglen == event.length()) return true; 117 char delim = event.charAt(taglen); 118 return delim == ' ' || delim == '/' || delim == '='; 119 } 120 121 // This is called from the native code to process various markers 122 // in the dissassembly. 123 private long handleEvent(InstructionVisitor visitor, String event, long arg) { 124 if (match(event, "insn")) { 125 try { 126 visitor.beginInstruction(arg); 127 } catch (Throwable e) { 128 e.printStackTrace(); 129 } 130 } else if (match(event, "/insn")) { 131 try { 132 visitor.endInstruction(arg); 133 } catch (Throwable e) { 134 e.printStackTrace(); 135 } 136 } else if (match(event, "addr")) { 137 if (arg != 0) { 138 visitor.printAddress(arg); 139 } 140 return arg; 141 } else if (match(event, "mach")) { 142 // output().printf("[Disassembling for mach='%s']\n", arg); 143 } else { 144 // ignore unrecognized markup 145 } 146 return 0; 147 } 148 149 // This called from the native code to perform printing 150 private void rawPrint(InstructionVisitor visitor, String s) { 151 visitor.print(s); 152 } 153 }