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 { 73 libname += "-" + arch; 74 } 75 path.append(sep + "bin" + sep); 76 libname += ".dll"; 77 } else if (os.lastIndexOf("SunOS", 0) != -1) { 78 if (arch.equals("x86") || arch.equals("i386")) { 79 path.append(sep + "lib" + sep + "i386" + sep); 80 libname += "-i386" + ".so"; 81 } else if (arch.equals("amd64")) { 82 path.append(sep + "lib" + sep + "amd64" + sep); 83 libname += "-amd64" + ".so"; 84 } else { 85 path.append(sep + "lib" + sep + arch + sep); 86 libname += "-" + arch + ".so"; 87 } 88 } else if (os.lastIndexOf("Linux", 0) != -1) { 89 if (arch.equals("x86") || arch.equals("i386")) { 90 path.append(sep + "lib" + sep + "i386" + sep); 91 libname += "-i386.so"; 92 } else if (arch.equals("amd64") || arch.equals("x86_64")) { 93 path.append(sep + "lib" + sep + "amd64" + sep); 94 libname += "-amd64.so"; 95 } else { 96 path.append(sep + "lib" + sep + arch + sep); 97 libname += "-" + arch + ".so"; 98 } 99 } else if (os.lastIndexOf("Mac OS X", 0) != -1) { 100 path.append(sep + "lib" + sep); 101 libname += "-amd64" + ".dylib"; // x86_64 => amd64 102 } else { 103 path.append(sep + "lib" + sep + "arch" + sep); 104 libname += "-" + arch + ".so"; 105 } 106 decode_function = load_library(path.toString(), libname); 107 } 108 } 109 110 private static native long load_library(String installed_jrepath, String hsdis_library_name); 111 112 private native void decode(InstructionVisitor visitor, long pc, byte[] code, 113 String options, long decode_function); 114 115 private void decode(InstructionVisitor visitor) { 116 visitor.prologue(); 117 decode(visitor, startPc, code, options, decode_function); 118 visitor.epilogue(); 119 } 120 121 private boolean match(String event, String tag) { 122 if (!event.startsWith(tag)) 123 return false; 124 int taglen = tag.length(); 125 if (taglen == event.length()) return true; 126 char delim = event.charAt(taglen); 127 return delim == ' ' || delim == '/' || delim == '='; 128 } 129 130 // This is called from the native code to process various markers 131 // in the dissassembly. 132 private long handleEvent(InstructionVisitor visitor, String event, long arg) { 133 if (match(event, "insn")) { 134 try { 135 visitor.beginInstruction(arg); 136 } catch (Throwable e) { 137 e.printStackTrace(); 138 } 139 } else if (match(event, "/insn")) { 140 try { 141 visitor.endInstruction(arg); 142 } catch (Throwable e) { 143 e.printStackTrace(); 144 } 145 } else if (match(event, "addr")) { 146 if (arg != 0) { 147 visitor.printAddress(arg); 148 } 149 return arg; 150 } else if (match(event, "mach")) { 151 // output().printf("[Disassembling for mach='%s']\n", arg); 152 } else { 153 // ignore unrecognized markup 154 } 155 return 0; 156 } 157 158 // This called from the native code to perform printing 159 private void rawPrint(InstructionVisitor visitor, String s) { 160 visitor.print(s); 161 } 162 }