1/*
2 * Copyright (c) 2002, 2013, 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
25package sun.jvm.hotspot.asm;
26
27import java.io.PrintStream;
28import java.util.Observer;
29import java.util.Observable;
30import sun.jvm.hotspot.code.CodeBlob;
31import sun.jvm.hotspot.code.NMethod;
32import sun.jvm.hotspot.debugger.Address;
33import sun.jvm.hotspot.runtime.VM;
34
35public class Disassembler {
36   private static String options = "";
37   private static long decode_function;
38
39   protected long startPc;
40   protected byte[] code;
41   private CodeBlob blob;
42   private NMethod nmethod;
43
44   public static void decode(InstructionVisitor visitor, CodeBlob blob) {
45      decode(visitor, blob, blob.codeBegin(), blob.codeEnd());
46   }
47
48   public static void decode(InstructionVisitor visitor, CodeBlob blob, Address begin, Address end) {
49      int codeSize = (int)end.minus(begin);
50      long startPc = VM.getAddressValue(begin);
51      byte[] code = new byte[codeSize];
52      for (int i = 0; i < code.length; i++)
53         code[i] = begin.getJByteAt(i);
54      Disassembler dis = new Disassembler(startPc, code);
55      dis.decode(visitor);
56   }
57
58   private Disassembler(long startPc, byte[] code) {
59      this.startPc = startPc;
60      this.code = code;
61
62      // Lazily load hsdis
63      if (decode_function == 0) {
64         StringBuilder path = new StringBuilder(System.getProperty("java.home"));
65         String sep = System.getProperty("file.separator");
66         String os = System.getProperty("os.name");
67         String libname = "hsdis";
68         String arch = System.getProperty("os.arch");
69         if (os.lastIndexOf("Windows", 0) != -1) {
70            if (arch.equals("x86")) {
71               libname +=  "-i386";
72            } else if (arch.equals("amd64")) {
73               libname +=  "-amd64";
74            } else {
75               libname +=  "-" + arch;
76            }
77            path.append(sep + "bin" + sep);
78            libname += ".dll";
79         } else if (os.lastIndexOf("SunOS", 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")) {
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("Linux", 0) != -1) {
91            if (arch.equals("x86") || arch.equals("i386")) {
92               path.append(sep + "lib" + sep + "i386" + sep);
93               libname += "-i386.so";
94            } else if (arch.equals("amd64") || arch.equals("x86_64")) {
95               path.append(sep + "lib" + sep + "amd64" + sep);
96               libname +=  "-amd64.so";
97            } else {
98               path.append(sep + "lib" + sep + arch + sep);
99               libname +=  "-" + arch + ".so";
100            }
101         } else if (os.lastIndexOf("Mac OS X", 0) != -1) {
102            path.append(sep + "lib" + sep);
103            libname += "-amd64" + ".dylib";       // x86_64 => amd64
104         } else {
105            path.append(sep + "lib" + sep + "arch" + sep);
106            libname +=  "-" + arch + ".so";
107         }
108         decode_function = load_library(path.toString(), libname);
109      }
110   }
111
112   private static native long load_library(String installed_jrepath, String hsdis_library_name);
113
114   private native void decode(InstructionVisitor visitor, long pc, byte[] code,
115                              String options, long decode_function);
116
117   private void decode(InstructionVisitor visitor) {
118      visitor.prologue();
119      decode(visitor, startPc, code, options, decode_function);
120      visitor.epilogue();
121   }
122
123   private boolean match(String event, String tag) {
124      if (!event.startsWith(tag))
125         return false;
126      int taglen = tag.length();
127      if (taglen == event.length()) return true;
128      char delim = event.charAt(taglen);
129      return delim == ' ' || delim == '/' || delim == '=';
130   }
131
132   // This is called from the native code to process various markers
133   // in the dissassembly.
134   private long handleEvent(InstructionVisitor visitor, String event, long arg) {
135      if (match(event, "insn")) {
136         try {
137            visitor.beginInstruction(arg);
138         } catch (Throwable e) {
139            e.printStackTrace();
140         }
141      } else if (match(event, "/insn")) {
142         try {
143            visitor.endInstruction(arg);
144         } catch (Throwable e) {
145            e.printStackTrace();
146         }
147      } else if (match(event, "addr")) {
148         if (arg != 0) {
149            visitor.printAddress(arg);
150         }
151         return arg;
152      } else if (match(event, "mach")) {
153         // output().printf("[Disassembling for mach='%s']\n", arg);
154      } else {
155         // ignore unrecognized markup
156      }
157      return 0;
158   }
159
160   // This called from the native code to perform printing
161   private  void rawPrint(InstructionVisitor visitor, String s) {
162      visitor.print(s);
163   }
164}
165