1 /*
   2  * Copyright 2002 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.asm;
  26 
  27 import java.io.PrintStream;
  28 import java.util.Observer;
  29 import java.util.Observable;
  30 import sun.jvm.hotspot.code.CodeBlob;
  31 import sun.jvm.hotspot.code.NMethod;
  32 import sun.jvm.hotspot.debugger.Address;
  33 import sun.jvm.hotspot.runtime.VM;
  34 
  35 public class Disassembler {
  36    static final int COMMENT_COLUMN = 40;
  37    static final String BYTES_COMMENT =  ";...";  /* funky byte display comment */
  38 
  39    private static String libname;
  40    private static String options;
  41    private static long decode_function;
  42    private static int instructionAlignment;
  43 
  44    static {
  45       VM.registerVMInitializedObserver(new Observer() {
  46          public void update(Observable o, Object data) {
  47             options = "";
  48             instructionAlignment = 1;
  49             libname = null;
  50             String cpu = VM.getVM().getCPU();
  51             if (cpu.equals("sparc")) {
  52                libname = "hsdis-sparc";
  53                instructionAlignment = 4;
  54                if (VM.getVM().isLP64()) {
  55                   options = "v9only";
  56                }
  57             } else if (cpu.equals("x86")) {
  58                libname = "hsdis-i386";
  59             } else if (cpu.equals("amd64")) {
  60                libname = "hsdis-amd64";
  61             } else if (cpu.equals("ia64")) {
  62                libname = "hsdis-ia64";
  63             }
  64          }
  65       });
  66    }
  67 
  68    protected long   startPc;
  69    protected byte[] code;
  70    private String        _option_buf = "";
  71    private boolean       _print_pc;
  72    private long          _cur_insn;
  73    private int           _bytes_per_line; // arch-specific formatting option
  74    private CodeBlob blob;
  75    private NMethod nmethod;
  76    private int instruction_alignment;
  77 
  78    public static void decode(InstructionVisitor visitor, CodeBlob blob) {
  79       decode(visitor, blob, blob.instructionsBegin(), blob.instructionsEnd());
  80    }
  81 
  82    public static void decode(InstructionVisitor visitor, CodeBlob blob, Address begin, Address end) {
  83       int codeSize = (int)end.minus(begin);
  84       long startPc = addressToLong(begin);
  85       byte[] code = new byte[codeSize];
  86       for (int i = 0; i < code.length; i++)
  87          code[i] = begin.getJByteAt(i);
  88       Disassembler dis = new Disassembler(startPc, code);
  89       dis.decode(visitor);
  90    }
  91 
  92    private Disassembler(long startPc, byte[] code) {
  93       this.startPc = startPc;
  94       this.code = code;
  95 
  96       // Lazily load hsdis
  97       if (decode_function == 0) {
  98          decode_function = load_library(libname);
  99          if (decode_function == 0) {
 100             throw new InternalError("Can't open " + libname);
 101          }
 102       }
 103    }
 104 
 105    public long getStartPC() {
 106       return startPc;
 107    }
 108 
 109    public byte[] getCode() {
 110       return code;
 111    }
 112 
 113    private static native long load_library(String hsdis_library_name);
 114 
 115    private native void decode(InstructionVisitor visitor, long pc, byte[] code,
 116                               String options, long decode_function);
 117 
 118    private void decode(InstructionVisitor visitor) {
 119       visitor.prologue();
 120       decode(visitor, startPc, code, options, decode_function);
 121       visitor.epilogue();
 122    }
 123 
 124    private boolean match(String event, String tag) {
 125       if (!event.startsWith(tag))
 126          return false;
 127       int taglen = tag.length();
 128       if (taglen == event.length()) return true;
 129       char delim = event.charAt(taglen);
 130       return delim == ' ' || delim == '/' || delim == '=';
 131    }
 132 
 133    private long handle_event(InstructionVisitor visitor, String event, long arg) {
 134       if (match(event, "insn")) {
 135          start_insn(visitor, arg);
 136       } else if (match(event, "/insn")) {
 137          end_insn(visitor, arg);
 138       } else if (match(event, "addr")) {
 139          if (arg != 0) {
 140             print_address(visitor, arg);
 141             return arg;
 142          }
 143       } else if (match(event, "mach")) {
 144          // output().printf("[Disassembling for mach='%s']\n", arg);
 145       } else if (match(event, "format bytes-per-line")) {
 146          _bytes_per_line = (int)arg;
 147       } else {
 148          // ignore unrecognized markup
 149       }
 150       return 0;
 151    }
 152 
 153    void start_insn(InstructionVisitor visitor, long pc) {
 154       _cur_insn = pc;
 155       print_insn_labels(visitor);
 156       visitor.beginInstruction(pc);
 157    }
 158 
 159    void end_insn(InstructionVisitor visitor, long pc) {
 160       long pc0 = _cur_insn;
 161       if (nmethod != null)
 162          print_code_comment_on(visitor, COMMENT_COLUMN, pc0, pc);
 163       visitor.endInstruction(pc);
 164    }
 165 
 166    long cur_insn() { return _cur_insn; }
 167 
 168    protected static long addressToLong(sun.jvm.hotspot.debugger.Address addr) {
 169       return VM.getVM().getDebugger().getAddressValue(addr);
 170    }
 171 
 172    void print_insn_labels(InstructionVisitor visitor) {
 173       long p = cur_insn();
 174       if (nmethod != null) {
 175          if (p == addressToLong(nmethod.getEntryPoint()))             visitor.print("[Entry Point]\n");
 176          if (p == addressToLong(nmethod.getVerifiedEntryPoint()))     visitor.print("[Verified Entry Point]\n");
 177          if (p == addressToLong(nmethod.exceptionBegin()))         visitor.print("[Exception Handler]\n");
 178          if (p == addressToLong(nmethod.stubBegin()))              visitor.print("[Stub Code]\n");
 179          // if (p == addressToLong(nmethod.getConstsBegin()))            visitor.print("[Constants]\n");
 180       }
 181       CodeBlob cb = blob;
 182       //       if (cb != null) {
 183       //          cb.print_block_comment(st, (long)(p - addressToLong(cb.instructionsBegin())));
 184       //       }
 185       if (_print_pc) {
 186          visitor.print("  " + p + ": ");
 187       }
 188    }
 189 
 190    public void raw_print(InstructionVisitor visitor, String s) {
 191       visitor.print(s);
 192    }
 193 
 194    public void print_address(InstructionVisitor visitor, long adr) {
 195       if (adr == 0) {
 196          visitor.print("NULL");
 197          return;
 198       }
 199       
 200       int small_num = (int)adr;
 201       if (adr == small_num && -1 <= small_num && small_num <= 9) {
 202          visitor.print(Integer.toString(small_num));
 203          return;
 204       }
 205 
 206 
 207       //     if (StubRoutines::contains(adr)) {
 208       //       StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
 209       //       if (desc == null)
 210       //         desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
 211       //       if (desc != null) {
 212       //         visitor.print("Stub::%s", desc.name());
 213       //         if (desc.begin() != adr)
 214       //           visitor.print("%+d 0x%p",adr - desc.begin(), adr);
 215       //         else if (WizardMode) visitor.print(" " INTPTR_FORMAT, adr);
 216       //         return;
 217       //       }
 218       //       visitor.print("Stub::<unknown> " INTPTR_FORMAT, adr);
 219       //       return;
 220       //     }
 221       // 
 222       //     BarrierSet* bs = Universe::heap().barrier_set();
 223       //     if (bs.kind() == BarrierSet::CardTableModRef &&
 224       //         adr == (address)((CardTableModRefBS*)(bs)).byte_map_base) {
 225       //       visitor.print("word_map_base");
 226       //       if (WizardMode) visitor.print(" " INTPTR_FORMAT, (long)adr);
 227       //       return;
 228       //     }
 229       // 
 230       //       Oop obj;
 231       //       if (nmethod != null &&
 232       //           (obj = nmethod.embeddedOop_at(cur_insn())) != null &&
 233       //           addresstoLong(obj) == adr) {
 234       //          obj.printValueOn(st);
 235       //          return;
 236       //       }
 237       
 238       // Fall through to a simple numeral.
 239       visitor.printAddress(adr);
 240    }
 241 
 242    void print_code_comment_on(InstructionVisitor visitor, int column, long begin, long end) {
 243 //       // First, find an oopmap in (begin, end].
 244 //       // We use the odd half-closed interval so that oop maps and scope descs
 245 //       // which are tied to the byte after a call are printed with the call itself.
 246 //       Address base = nm.instructionsBegin();
 247 //       OopMapSet oms = nm.oop_maps();
 248 //       if (oms != null) {
 249 //          for (int i = 0, imax = oms.size(); i < imax; i++) {
 250 //             OopMap* om = oms.at(i);
 251 //             address pc = base + om.offset();
 252 //             if (pc > begin) {
 253 //                if (pc <= end) {
 254 //                   st.move_to(column);
 255 //                   st.print("; ");
 256 //                   om.print_on(st);
 257 //                }
 258 //                break;
 259 //             }
 260 //          }
 261 //       }
 262 
 263 //       // Print any debug info present at this pc.
 264 //       ScopeDesc* sd  = scope_desc_in(begin, end);
 265 //       if (sd != null) {
 266 //          st.move_to(column);
 267 //          if (sd.bci() == SynchronizationEntryBCI) {
 268 //             st.print(";*synchronization entry");
 269 //          } else {
 270 //             if (sd.method().is_null()) {
 271 //                st.print("method is null");
 272 //             } else if (sd.method().is_native()) {
 273 //                st.print("method is native");
 274 //             } else {
 275 //                address bcp  = sd.method().bcp_from(sd.bci());
 276 //                Bytecodes::Code bc = Bytecodes::java_code_at(bcp);
 277 //                st.print(";*%s", Bytecodes::name(bc));
 278 //                switch (bc) {
 279 //                case Bytecodes::_invokevirtual:
 280 //                case Bytecodes::_invokespecial:
 281 //                case Bytecodes::_invokestatic:
 282 //                case Bytecodes::_invokeinterface:
 283 //                   {
 284 //                      Bytecode_invoke* invoke = Bytecode_invoke_at(sd.method(), sd.bci());
 285 //                      st.print(" ");
 286 //                      if (invoke.name() != null)
 287 //                         invoke.name().print_symbol_on(st);
 288 //                      else
 289 //                         st.print("<UNKNOWN>");
 290 //                      break;
 291 //                   }
 292 //                case Bytecodes::_getfield:
 293 //                case Bytecodes::_putfield:
 294 //                case Bytecodes::_getstatic:
 295 //                case Bytecodes::_putstatic:
 296 //                   {
 297 //                      methodHandle sdm = sd.method();
 298 //                      Bytecode_field* field = Bytecode_field_at(sdm(), sdm.bcp_from(sd.bci()));
 299 //                      constantPoolOop sdmc = sdm.constants();
 300 //                      symbolOop name = sdmc.name_ref_at(field.index());
 301 //                      st.print(" ");
 302 //                      if (name != null)
 303 //                         name.print_symbol_on(st);
 304 //                      else
 305 //                         st.print("<UNKNOWN>");
 306 //                   }
 307 //                }
 308 //             }
 309 //          }
 310 
 311 //          // Print all scopes
 312 //          for (;sd != null; sd = sd.sender()) {
 313 //             st.move_to(column);
 314 //             st.print("; -");
 315 //             if (sd.method().is_null()) {
 316 //                st.print("method is null");
 317 //             } else {
 318 //                sd.method().print_short_name(st);
 319 //             }
 320 //             int lineno = sd.method().line_number_from_bci(sd.bci());
 321 //             if (lineno != -1) {
 322 //                st.print("@%d (line %d)", sd.bci(), lineno);
 323 //             } else {
 324 //                st.print("@%d", sd.bci());
 325 //             }
 326 //             st.println();
 327 //          }
 328 //       }
 329 
 330 //       // Print relocation information
 331 //       const char* str = reloc_string_for(begin, end);
 332 //       if (str != null) {
 333 //          if (sd != null) st.println();
 334 //          st.move_to(column);
 335 //          st.print(";   {%s}", str);
 336 //       }
 337 //       int cont_offset = ImplicitExceptionTable(this).at(begin - instructions_begin());
 338 //       if (cont_offset != 0) {
 339 //          st.move_to(column);
 340 //          st.print("; implicit exception: dispatches to " INTPTR_FORMAT, instructions_begin() + cont_offset);
 341 //       }
 342 
 343    }
 344 
 345 }