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; 26 27 import java.io.BufferedOutputStream; 28 import java.io.BufferedReader; 29 import java.io.ByteArrayOutputStream; 30 import java.io.FileInputStream; 31 import java.io.FileOutputStream; 32 import java.io.IOException; 33 import java.io.InputStreamReader; 34 import java.io.PrintStream; 35 import java.util.ArrayList; 36 import java.util.Arrays; 37 import java.util.Comparator; 38 import java.util.HashMap; 39 import java.util.HashSet; 40 import java.util.Iterator; 41 import java.util.Stack; 42 import java.util.regex.Matcher; 43 import java.util.regex.Pattern; 44 45 import sun.jvm.hotspot.ci.ciEnv; 46 import sun.jvm.hotspot.code.CodeBlob; 47 import sun.jvm.hotspot.code.CodeCacheVisitor; 48 import sun.jvm.hotspot.code.NMethod; 49 import sun.jvm.hotspot.debugger.Address; 50 import sun.jvm.hotspot.debugger.OopHandle; 51 import sun.jvm.hotspot.classfile.ClassLoaderDataGraph; 52 import sun.jvm.hotspot.memory.FileMapInfo; 53 import sun.jvm.hotspot.memory.SystemDictionary; 54 import sun.jvm.hotspot.memory.Universe; 55 import sun.jvm.hotspot.gc.shared.CollectedHeap; 56 import sun.jvm.hotspot.gc.g1.G1CollectedHeap; 57 import sun.jvm.hotspot.oops.DefaultHeapVisitor; 58 import sun.jvm.hotspot.oops.HeapVisitor; 59 import sun.jvm.hotspot.oops.InstanceKlass; 60 import sun.jvm.hotspot.oops.Klass; 61 import sun.jvm.hotspot.oops.Metadata; 62 import sun.jvm.hotspot.oops.Method; 63 import sun.jvm.hotspot.oops.MethodData; 64 import sun.jvm.hotspot.oops.Oop; 121 public boolean canInclude(InstanceKlass kls) { 122 return kls.getClassLoader() == null; 123 } 124 } 125 126 public static class NonBootFilter implements ClassFilter { 127 private HashMap emitted = new HashMap(); 128 public boolean canInclude(InstanceKlass kls) { 129 if (kls.getClassLoader() == null) return false; 130 if (emitted.get(kls.getName()) != null) { 131 // Since multiple class loaders are being shoved 132 // together duplicate classes are a possibilty. For 133 // now just ignore them. 134 return false; 135 } 136 emitted.put(kls.getName(), kls); 137 return true; 138 } 139 } 140 141 static class Tokens { 142 final String input; 143 int i; 144 String[] tokens; 145 int length; 146 147 String[] splitWhitespace(String cmd) { 148 String[] t = cmd.split("\\s"); 149 if (t.length == 1 && t[0].length() == 0) { 150 return new String[0]; 151 } 152 return t; 153 } 154 155 void add(String s, ArrayList t) { 156 if (s.length() > 0) { 157 t.add(s); 158 } 159 } 160 161 Tokens(String cmd) { 162 input = cmd; 163 164 // check for quoting 165 int quote = cmd.indexOf('"'); 166 ArrayList t = new ArrayList(); 167 if (quote != -1) { 168 while (cmd.length() > 0) { 169 if (quote != -1) { 170 int endquote = cmd.indexOf('"', quote + 1); 171 if (endquote == -1) { 172 throw new RuntimeException("mismatched quotes: " + input); 173 } 174 175 String before = cmd.substring(0, quote).trim(); 176 String quoted = cmd.substring(quote + 1, endquote); 177 cmd = cmd.substring(endquote + 1).trim(); 178 if (before.length() > 0) { 179 String[] w = splitWhitespace(before); 180 for (int i = 0; i < w.length; i++) { 181 add(w[i], t); 182 } 183 } 184 add(quoted, t); 185 quote = cmd.indexOf('"'); 186 } else { 187 String[] w = splitWhitespace(cmd); 188 for (int i = 0; i < w.length; i++) { 189 add(w[i], t); 190 } 191 cmd = ""; 192 193 } 194 } 195 } else { 196 String[] w = splitWhitespace(cmd); 197 for (int i = 0; i < w.length; i++) { 198 add(w[i], t); 199 } 200 } 201 tokens = (String[])t.toArray(new String[0]); 202 i = 0; 203 length = tokens.length; 204 205 //for (int i = 0; i < tokens.length; i++) { 206 // System.out.println("\"" + tokens[i] + "\""); 207 //} 208 } 209 210 String nextToken() { 211 return tokens[i++]; 212 } 213 boolean hasMoreTokens() { 214 return i < length; 215 } 216 int countTokens() { 217 return length - i; 218 } 219 void trim(int n) { 220 if (length >= n) { 221 length -= n; 222 } else { 223 throw new IndexOutOfBoundsException(String.valueOf(n)); 224 } 225 } 226 String join(String sep) { 227 StringBuffer result = new StringBuffer(); 228 for (int w = i; w < length; w++) { 229 result.append(tokens[w]); 230 if (w + 1 < length) { 231 result.append(sep); 232 } 233 } 234 return result.toString(); 235 } 236 237 String at(int i) { 238 if (i < 0 || i >= length) { 239 throw new IndexOutOfBoundsException(String.valueOf(i)); 240 } 241 return tokens[i]; 242 } 243 } 244 245 246 abstract class Command { 247 Command(String n, String u, boolean ok) { 248 name = n; 249 usage = u; 250 okIfDisconnected = ok; 251 } 252 253 Command(String n, boolean ok) { 254 name = n; 255 usage = n; 256 okIfDisconnected = ok; 257 } 258 259 final String name; 260 final String usage; 261 final boolean okIfDisconnected; 262 abstract void doit(Tokens t); 263 void usage() { 264 out.println("Usage: " + usage); 265 } 266 267 void printOopValue(Oop oop) { 268 if (oop != null) { 269 Klass k = oop.getKlass(); 270 Symbol s = k.getName(); 271 if (s != null) { 272 out.print("Oop for " + s.asString() + " @ "); 273 } else { 274 out.print("Oop @ "); 275 } 276 Oop.printOopAddressOn(oop, out); 277 } else { 278 out.print("null"); 279 } 280 } 281 282 void printNode(SimpleTreeNode node) { 283 int count = node.getChildCount(); 284 for (int i = 0; i < count; i++) { 285 try { 286 SimpleTreeNode field = node.getChild(i); 373 for (int i = 0; i < parts.length; i++) { 374 int len = parts[i].length(); 375 if (len >= 26) { 376 mangled.append((char)('a' + (len / 26))); 377 len = len % 26; 378 } 379 mangled.append((char)('A' + len)); 380 mangled.append(parts[i]); 381 } 382 mangled.append("_"); 383 symbol = mangled.toString(); 384 } 385 return VM.getVM().getDebugger().lookup(null, symbol); 386 } 387 388 Address parseAddress(String addr) { 389 return VM.getVM().getDebugger().parseAddress(addr); 390 } 391 392 private final Command[] commandList = { 393 new Command("reattach", true) { 394 public void doit(Tokens t) { 395 int tokens = t.countTokens(); 396 if (tokens != 0) { 397 usage(); 398 return; 399 } 400 preAttach(); 401 debugger.reattach(); 402 postAttach(); 403 } 404 }, 405 new Command("attach", "attach pid | exec core", true) { 406 public void doit(Tokens t) { 407 int tokens = t.countTokens(); 408 if (tokens == 1) { 409 preAttach(); 410 debugger.attach(t.nextToken()); 411 postAttach(); 412 } else if (tokens == 2) { 413 preAttach(); 414 debugger.attach(t.nextToken(), t.nextToken()); 415 postAttach(); 416 } else { 417 usage(); 418 } 419 } 420 }, 421 new Command("detach", false) { 422 public void doit(Tokens t) { 423 if (t.countTokens() != 0) { 424 usage(); 425 } else { 426 debugger.detach(); 427 } 428 } 429 }, 430 new Command("examine", "examine [ address/count ] | [ address,address]", false) { 431 Pattern args1 = Pattern.compile("^(0x[0-9a-f]+)(/([0-9]*)([a-z]*))?$"); 432 Pattern args2 = Pattern.compile("^(0x[0-9a-f]+),(0x[0-9a-f]+)(/[a-z]*)?$"); 433 434 String fill(Address a, int width) { 435 String s = "0x0"; 436 if (a != null) { 437 s = a.toString(); 438 } 439 if (s.length() != width) { 440 return s.substring(0, 2) + "000000000000000000000".substring(0, width - s.length()) + s.substring(2); 441 } 442 return s; 443 } 444 445 public void doit(Tokens t) { 446 if (t.countTokens() != 1) { 447 usage(); 448 } else { 449 String arg = t.nextToken(); 450 Matcher m1 = args1.matcher(arg); 451 Matcher m2 = args2.matcher(arg); 452 Address start = null; 453 Address end = null; 454 String format = ""; 455 int formatSize = (int)VM.getVM().getAddressSize(); 456 457 if (m1.matches()) { 458 start = VM.getVM().getDebugger().parseAddress(m1.group(1)); 459 int count = 1; 460 if (m1.group(2) != null) { 461 count = Integer.parseInt(m1.group(3)); 462 } 463 end = start.addOffsetTo(count * formatSize); 464 } else if (m2.matches()) { 465 start = VM.getVM().getDebugger().parseAddress(m2.group(1)); 484 start = start.addOffsetTo(formatSize); 485 if (width <= formatWidth) { 486 out.println(); 487 needsPrintln = false; 488 if (start.lessThan(end)) { 489 out.print(fill(start, formatWidth)); 490 out.print(": "); 491 width = line - formatWidth - 2; 492 } 493 } else { 494 out.print(" "); 495 width -= 1; 496 } 497 } 498 if (needsPrintln) { 499 out.println(); 500 } 501 } 502 } 503 }, 504 new Command("dumpreplaydata", "dumpreplaydata { <address > | -a | <thread_id> }", false) { 505 // This is used to dump replay data from ciInstanceKlass, ciMethodData etc 506 // default file name is replay.txt, also if java crashes in compiler 507 // thread, this file will be dumped in error processing. 508 public void doit(Tokens t) { 509 if (t.countTokens() != 1) { 510 usage(); 511 return; 512 } 513 String name = t.nextToken(); 514 Address a = null; 515 try { 516 a = VM.getVM().getDebugger().parseAddress(name); 517 } catch (NumberFormatException e) { } 518 if (a != null) { 519 // only nmethod, Method, MethodData and InstanceKlass needed to 520 // dump replay data 521 522 CodeBlob cb = VM.getVM().getCodeCache().findBlob(a); 523 if (cb != null && (cb instanceof NMethod)) { 524 ((NMethod)cb).dumpReplayData(out); 525 return; 526 } 527 // assume it is Metadata 528 Metadata meta = Metadata.instantiateWrapperFor(a); 535 } 536 // Not an address 537 boolean all = name.equals("-a"); 538 Threads threads = VM.getVM().getThreads(); 539 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 540 JavaThread thread = threads.getJavaThreadAt(i); 541 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 542 thread.printThreadIDOn(new PrintStream(bos)); 543 if (all || bos.toString().equals(name)) { 544 if (thread instanceof CompilerThread) { 545 CompilerThread ct = (CompilerThread)thread; 546 ciEnv env = ct.env(); 547 if (env != null) { 548 env.dumpReplayData(out); 549 } 550 } 551 } 552 } 553 } 554 }, 555 new Command("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) { 556 // This is used to dump jar files of all the classes 557 // loaded in the core. Everything with null classloader 558 // will go in boot.jar and everything else will go in 559 // app.jar. boot.jar usually not needed, unless changed by jvmti. 560 public void doit(Tokens t) { 561 int tcount = t.countTokens(); 562 if (tcount > 2) { 563 usage(); 564 return; 565 } 566 try { 567 String prefix = ""; 568 String option = "all"; // default 569 switch(tcount) { 570 case 0: 571 break; 572 case 1: 573 option = t.nextToken(); 574 if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") && 575 !option.equalsIgnoreCase("root")) { 576 prefix = option; 577 option = "all"; 578 } 579 break; 580 case 2: 589 !option.equalsIgnoreCase("boot")) { 590 usage(); 591 return; 592 } 593 ClassDump cd = new ClassDump(); 594 if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) { 595 cd.setClassFilter(new BootFilter()); 596 cd.setJarOutput(prefix + "boot.jar"); 597 cd.run(); 598 } 599 if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) { 600 cd.setClassFilter(new NonBootFilter()); 601 cd.setJarOutput(prefix + "app.jar"); 602 cd.run(); 603 } 604 } catch (IOException ioe) { 605 ioe.printStackTrace(); 606 } 607 } 608 }, 609 new Command("findpc", "findpc address", false) { 610 public void doit(Tokens t) { 611 if (t.countTokens() != 1) { 612 usage(); 613 } else { 614 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 615 PointerLocation loc = PointerFinder.find(a); 616 loc.printOn(out); 617 } 618 } 619 }, 620 new Command("symbol", "symbol address", false) { 621 public void doit(Tokens t) { 622 if (t.countTokens() != 1) { 623 usage(); 624 } else { 625 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 626 Symbol.create(a).printValueOn(out); 627 out.println(); 628 } 629 } 630 }, 631 new Command("flags", "flags [ flag | -nd ]", false) { 632 public void doit(Tokens t) { 633 int tokens = t.countTokens(); 634 if (tokens != 0 && tokens != 1) { 635 usage(); 636 } else { 637 String name = tokens > 0 ? t.nextToken() : null; 638 boolean nonDefault = false; 639 if (name != null && name.equals("-nd")) { 640 name = null; 641 nonDefault = true; 642 } 643 644 VM.Flag[] flags = VM.getVM().getCommandLineFlags(); 645 if (flags == null) { 646 out.println("Command Flag info not available (use 1.4.1_03 or later)!"); 647 } else { 648 boolean printed = false; 649 for (int f = 0; f < flags.length; f++) { 650 VM.Flag flag = flags[f]; 651 if (name == null || flag.getName().equals(name)) { 652 653 if (nonDefault && (flag.getOrigin() == VM.Flags_DEFAULT)) { 654 // only print flags which aren't their defaults 655 continue; 656 } 657 out.println(flag.getName() + " = " + flag.getValue() + " " + flag.getOriginString()); 658 printed = true; 659 } 660 } 661 if (name != null && !printed) { 662 out.println("Couldn't find flag: " + name); 663 } 664 } 665 } 666 } 667 }, 668 new Command("help", "help [ command ]", true) { 669 public void doit(Tokens t) { 670 int tokens = t.countTokens(); 671 Command cmd = null; 672 if (tokens == 1) { 673 cmd = findCommand(t.nextToken()); 674 } 675 676 if (cmd != null) { 677 cmd.usage(); 678 } else if (tokens == 0) { 679 out.println("Available commands:"); 680 Object[] keys = commands.keySet().toArray(); 681 Arrays.sort(keys, new Comparator() { 682 public int compare(Object o1, Object o2) { 683 return o1.toString().compareTo(o2.toString()); 684 } 685 }); 686 for (int i = 0; i < keys.length; i++) { 687 out.print(" "); 688 out.println(((Command)commands.get(keys[i])).usage); 689 } 690 } 691 } 692 }, 693 new Command("history", "history", true) { 694 public void doit(Tokens t) { 695 int tokens = t.countTokens(); 696 if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) { 697 usage(); 698 return; 699 } 700 boolean printIndex = tokens == 0; 701 for (int i = 0; i < history.size(); i++) { 702 if (printIndex) out.print(i + " "); 703 out.println(history.get(i)); 704 } 705 } 706 }, 707 // decode raw address 708 new Command("dis", "dis address [length]", false) { 709 public void doit(Tokens t) { 710 int tokens = t.countTokens(); 711 if (tokens != 1 && tokens != 2) { 712 usage(); 713 return; 714 } 715 String name = t.nextToken(); 716 Address addr = null; 717 int len = 0x10; // default length 718 try { 719 addr = VM.getVM().getDebugger().parseAddress(name); 720 } catch (NumberFormatException e) { 721 out.println(e); 722 return; 723 } 724 if (tokens == 2) { 725 try { 726 len = Integer.parseInt(t.nextToken()); 727 } catch (NumberFormatException e) { 728 out.println(e); 729 return; 730 } 731 } 732 HTMLGenerator generator = new HTMLGenerator(false); 733 out.println(generator.genHTMLForRawDisassembly(addr, len)); 734 } 735 736 }, 737 // decode codeblob or nmethod 738 new Command("disassemble", "disassemble address", false) { 739 public void doit(Tokens t) { 740 int tokens = t.countTokens(); 741 if (tokens != 1) { 742 usage(); 743 return; 744 } 745 String name = t.nextToken(); 746 Address addr = null; 747 try { 748 addr = VM.getVM().getDebugger().parseAddress(name); 749 } catch (NumberFormatException e) { 750 out.println(e); 751 return; 752 } 753 754 HTMLGenerator generator = new HTMLGenerator(false); 755 out.println(generator.genHTML(addr)); 756 } 757 }, 758 // print Java bytecode disassembly 759 new Command("jdis", "jdis address", false) { 760 public void doit(Tokens t) { 761 int tokens = t.countTokens(); 762 if (tokens != 1) { 763 usage(); 764 return; 765 } 766 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 767 Method m = (Method)Metadata.instantiateWrapperFor(a); 768 HTMLGenerator html = new HTMLGenerator(false); 769 out.println(html.genHTML(m)); 770 } 771 }, 772 new Command("revptrs", "revptrs address", false) { 773 public void doit(Tokens t) { 774 int tokens = t.countTokens(); 775 if (tokens != 1 && (tokens != 2 || !t.nextToken().equals("-c"))) { 776 usage(); 777 return; 778 } 779 boolean chase = tokens == 2; 780 ReversePtrs revptrs = VM.getVM().getRevPtrs(); 781 if (revptrs == null) { 782 out.println("Computing reverse pointers..."); 783 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); 784 final boolean[] complete = new boolean[1]; 785 HeapProgressThunk thunk = new HeapProgressThunk() { 786 public void heapIterationFractionUpdate(double d) {} 787 public synchronized void heapIterationComplete() { 788 complete[0] = true; 789 notify(); 790 } 791 }; 792 analysis.setHeapProgressThunk(thunk); 793 analysis.run(); 814 while (ptrs.size() == 1) { 815 LivenessPathElement e = (LivenessPathElement)ptrs.get(0); 816 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 817 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 818 out.println(bos.toString()); 819 ptrs = revptrs.get(e.getObj()); 820 } 821 } else { 822 for (int i = 0; i < ptrs.size(); i++) { 823 LivenessPathElement e = (LivenessPathElement)ptrs.get(i); 824 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 825 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 826 out.println(bos.toString()); 827 oop = e.getObj(); 828 } 829 } 830 } 831 } 832 } 833 }, 834 new Command("printmdo", "printmdo [ -a | expression ]", false) { 835 // Print every MDO in the heap or the one referenced by expression. 836 public void doit(Tokens t) { 837 if (t.countTokens() != 1) { 838 usage(); 839 } else { 840 String s = t.nextToken(); 841 if (s.equals("-a")) { 842 ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph(); 843 cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() { 844 public void visit(Klass k) { 845 if (k instanceof InstanceKlass) { 846 MethodArray methods = ((InstanceKlass)k).getMethods(); 847 for (int i = 0; i < methods.length(); i++) { 848 Method m = methods.at(i); 849 MethodData mdo = m.getMethodData(); 850 if (mdo != null) { 851 out.println("MethodData " + mdo.getAddress() + " for " + 852 "method " + m.getMethodHolder().getName().asString() + "." + 853 m.getName().asString() + 854 m.getSignature().asString() + "@" + m.getAddress()); 855 mdo.printDataOn(out); 856 } 857 } 858 } 859 } 860 } 861 ); 862 } else { 863 Address a = VM.getVM().getDebugger().parseAddress(s); 864 MethodData mdo = (MethodData) Metadata.instantiateWrapperFor(a); 865 mdo.printDataOn(out); 866 } 867 } 868 } 869 }, 870 new Command("printall", "printall", false) { 871 // Print every MDO in the heap or the one referenced by expression. 872 public void doit(Tokens t) { 873 if (t.countTokens() != 0) { 874 usage(); 875 } else { 876 ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph(); 877 cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() { 878 public void visit(Klass k) { 879 if (k instanceof InstanceKlass && ((InstanceKlass)k).getConstants().getCache() != null) { 880 MethodArray methods = ((InstanceKlass)k).getMethods(); 881 for (int i = 0; i < methods.length(); i++) { 882 Method m = methods.at(i); 883 HTMLGenerator gen = new HTMLGenerator(false); 884 out.println(gen.genHTML(m)); 885 } 886 } 887 } 888 } 889 ); 890 } 891 } 892 }, 893 new Command("dumpideal", "dumpideal { -a | id }", false) { 894 // Do a full dump of the nodes reachabile from root in each compiler thread. 895 public void doit(Tokens t) { 896 if (t.countTokens() != 1) { 897 usage(); 898 } else { 899 String name = t.nextToken(); 900 boolean all = name.equals("-a"); 901 Threads threads = VM.getVM().getThreads(); 902 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 903 JavaThread thread = threads.getJavaThreadAt(i); 904 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 905 thread.printThreadIDOn(new PrintStream(bos)); 906 if (all || bos.toString().equals(name)) { 907 if (thread instanceof CompilerThread) { 908 CompilerThread ct = (CompilerThread)thread; 909 out.println(ct); 910 ciEnv env = ct.env(); 911 if (env != null) { 912 Compile c = env.compilerData(); 913 c.root().dump(9999, out); 914 } else { 915 out.println(" not compiling"); 916 } 917 } 918 } 919 } 920 } 921 } 922 }, 923 new Command("dumpcfg", "dumpcfg { -a | id }", false) { 924 // Dump the PhaseCFG for every compiler thread that has one live. 925 public void doit(Tokens t) { 926 if (t.countTokens() != 1) { 927 usage(); 928 } else { 929 String name = t.nextToken(); 930 boolean all = name.equals("-a"); 931 Threads threads = VM.getVM().getThreads(); 932 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 933 JavaThread thread = threads.getJavaThreadAt(i); 934 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 935 thread.printThreadIDOn(new PrintStream(bos)); 936 if (all || bos.toString().equals(name)) { 937 if (thread instanceof CompilerThread) { 938 CompilerThread ct = (CompilerThread)thread; 939 out.println(ct); 940 ciEnv env = ct.env(); 941 if (env != null) { 942 Compile c = env.compilerData(); 943 c.cfg().dump(out); 944 } 945 } 946 } 947 } 948 } 949 } 950 }, 951 new Command("dumpilt", "dumpilt { -a | id }", false) { 952 // dumps the InlineTree of a C2 compile 953 public void doit(Tokens t) { 954 if (t.countTokens() != 1) { 955 usage(); 956 } else { 957 String name = t.nextToken(); 958 boolean all = name.equals("-a"); 959 Threads threads = VM.getVM().getThreads(); 960 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 961 JavaThread thread = threads.getJavaThreadAt(i); 962 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 963 thread.printThreadIDOn(new PrintStream(bos)); 964 if (all || bos.toString().equals(name)) { 965 if (thread instanceof CompilerThread) { 966 CompilerThread ct = (CompilerThread)thread; 967 ciEnv env = ct.env(); 968 if (env != null) { 969 Compile c = env.compilerData(); 970 InlineTree ilt = c.ilt(); 971 if (ilt != null) { 972 ilt.print(out); 973 } 974 } 975 } 976 } 977 } 978 } 979 } 980 }, 981 new Command("vmstructsdump", "vmstructsdump", false) { 982 public void doit(Tokens t) { 983 if (t.countTokens() != 0) { 984 usage(); 985 return; 986 } 987 988 // Dump a copy of the type database in a form that can 989 // be read back. 990 Iterator i = agent.getTypeDataBase().getTypes(); 991 // Make sure the types are emitted in an order than can be read back in 992 HashSet emitted = new HashSet(); 993 Stack pending = new Stack(); 994 while (i.hasNext()) { 995 Type n = (Type)i.next(); 996 if (emitted.contains(n.getName())) { 997 continue; 998 } 999 1000 while (n != null && !emitted.contains(n.getName())) { 1001 pending.push(n); 1002 n = n.getSuperclass(); 1003 } 1004 while (!pending.empty()) { 1005 n = (Type)pending.pop(); 1006 dumpType(n); 1007 emitted.add(n.getName()); 1008 } 1009 } 1010 i = agent.getTypeDataBase().getTypes(); 1011 while (i.hasNext()) { 1012 dumpFields((Type)i.next(), false); 1013 } 1014 } 1015 }, 1016 1017 new Command("inspect", "inspect expression", false) { 1018 public void doit(Tokens t) { 1019 if (t.countTokens() != 1) { 1020 usage(); 1021 } else { 1022 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1023 SimpleTreeNode node = null; 1024 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 1025 OopHandle handle = a.addOffsetToAsOopHandle(0); 1026 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1027 node = new OopTreeNodeAdapter(oop, null); 1028 1029 out.println("instance of " + node.getValue() + " @ " + a + 1030 " (size = " + oop.getObjectSize() + ")"); 1031 } else if (VM.getVM().getCodeCache().contains(a)) { 1032 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a); 1033 a = blob.headerBegin(); 1034 } 1035 if (node == null) { 1036 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a); 1037 if (type == null && VM.getVM().isSharingEnabled()) { 1038 // Check if the value falls in the _md_region 1039 Address loc1 = a.getAddressAt(0); 1040 FileMapInfo cdsFileMapInfo = VM.getVM().getFileMapInfo(); 1041 if (cdsFileMapInfo.inCopiedVtableSpace(loc1)) { 1042 type = cdsFileMapInfo.getTypeForVptrAddress(loc1); 1043 } 1044 1045 } 1046 if (type != null) { 1047 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")"); 1048 node = new CTypeTreeNodeAdapter(a, type, null); 1049 } 1050 } 1051 if (node != null) { 1052 printNode(node); 1053 } 1054 } 1055 } 1056 }, 1057 new Command("jhisto", "jhisto", false) { 1058 public void doit(Tokens t) { 1059 ObjectHistogram histo = new ObjectHistogram(); 1060 histo.run(out, err); 1061 } 1062 }, 1063 new Command("jstack", "jstack [-v]", false) { 1064 public void doit(Tokens t) { 1065 boolean verbose = false; 1066 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1067 verbose = true; 1068 } 1069 StackTrace jstack = new StackTrace(verbose, true); 1070 jstack.run(out); 1071 } 1072 }, 1073 new Command("print", "print expression", false) { 1074 public void doit(Tokens t) { 1075 if (t.countTokens() != 1) { 1076 usage(); 1077 } else { 1078 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1079 HTMLGenerator gen = new HTMLGenerator(false); 1080 out.println(gen.genHTML(a)); 1081 } 1082 } 1083 }, 1084 new Command("printas", "printas type expression", false) { 1085 public void doit(Tokens t) { 1086 if (t.countTokens() != 2) { 1087 usage(); 1088 } else { 1089 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1090 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1091 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null); 1092 1093 out.println("pointer to " + type + " @ " + a + 1094 " (size = " + type.getSize() + ")"); 1095 printNode(node); 1096 } 1097 } 1098 }, 1099 new Command("printstatics", "printstatics [ type ]", false) { 1100 public void doit(Tokens t) { 1101 if (t.countTokens() > 1) { 1102 usage(); 1103 } else { 1104 if (t.countTokens() == 0) { 1105 out.println("All known static fields"); 1106 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes())); 1107 } else { 1108 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1109 out.println("Static fields of " + type.getName()); 1110 printNode(new CTypeTreeNodeAdapter(type)); 1111 } 1112 } 1113 } 1114 }, 1115 new Command("pmap", "pmap", false) { 1116 public void doit(Tokens t) { 1117 PMap pmap = new PMap(); 1118 pmap.run(out, debugger.getAgent().getDebugger()); 1119 } 1120 }, 1121 new Command("pstack", "pstack [-v]", false) { 1122 public void doit(Tokens t) { 1123 boolean verbose = false; 1124 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1125 verbose = true; 1126 } 1127 PStack pstack = new PStack(verbose, true); 1128 pstack.run(out, debugger.getAgent().getDebugger()); 1129 } 1130 }, 1131 new Command("quit", true) { 1132 public void doit(Tokens t) { 1133 if (t.countTokens() != 0) { 1134 usage(); 1135 } else { 1136 debugger.detach(); 1137 quit = true; 1138 } 1139 } 1140 }, 1141 new Command("echo", "echo [ true | false ]", true) { 1142 public void doit(Tokens t) { 1143 if (t.countTokens() == 0) { 1144 out.println("echo is " + doEcho); 1145 } else if (t.countTokens() == 1) { 1146 doEcho = Boolean.valueOf(t.nextToken()).booleanValue(); 1147 } else { 1148 usage(); 1149 } 1150 } 1151 }, 1152 new Command("versioncheck", "versioncheck [ true | false ]", true) { 1153 public void doit(Tokens t) { 1154 if (t.countTokens() == 0) { 1155 out.println("versioncheck is " + 1156 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); 1157 } else if (t.countTokens() == 1) { 1158 if (Boolean.valueOf(t.nextToken()).booleanValue()) { 1159 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null); 1160 } else { 1161 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true"); 1162 } 1163 } else { 1164 usage(); 1165 } 1166 } 1167 }, 1168 new Command("scanoops", "scanoops start end [ type ]", false) { 1169 public void doit(Tokens t) { 1170 if (t.countTokens() != 2 && t.countTokens() != 3) { 1171 usage(); 1172 } else { 1173 long stride = VM.getVM().getAddressSize(); 1174 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1175 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1176 Klass klass = null; 1177 if (t.countTokens() == 1) { 1178 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); 1179 if (klass == null) { 1180 out.println("No such type."); 1181 return; 1182 } 1183 } 1184 while (base != null && base.lessThan(end)) { 1185 long step = stride; 1186 OopHandle handle = base.addOffsetToAsOopHandle(0); 1187 if (RobustOopDeterminator.oopLooksValid(handle)) { 1188 try { 1189 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1190 if (klass == null || oop.getKlass().isSubtypeOf(klass)) 1191 out.println(handle.toString() + " " + oop.getKlass().getName().asString()); 1192 step = oop.getObjectSize(); 1193 } catch (UnknownOopException ex) { 1194 // ok 1195 } catch (RuntimeException ex) { 1196 ex.printStackTrace(); 1197 } 1198 } 1199 base = base.addOffsetTo(step); 1200 } 1201 } 1202 } 1203 }, 1204 new Command("intConstant", "intConstant [ name [ value ] ]", true) { 1205 public void doit(Tokens t) { 1206 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1207 usage(); 1208 return; 1209 } 1210 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1211 if (t.countTokens() == 1) { 1212 String name = t.nextToken(); 1213 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1214 } else if (t.countTokens() == 0) { 1215 Iterator i = db.getIntConstants(); 1216 while (i.hasNext()) { 1217 String name = (String)i.next(); 1218 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1219 } 1220 } else if (t.countTokens() == 2) { 1221 String name = t.nextToken(); 1222 Integer value = Integer.valueOf(t.nextToken()); 1223 db.addIntConstant(name, value); 1224 } 1225 } 1226 }, 1227 new Command("longConstant", "longConstant [ name [ value ] ]", true) { 1228 public void doit(Tokens t) { 1229 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1230 usage(); 1231 return; 1232 } 1233 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1234 if (t.countTokens() == 1) { 1235 String name = t.nextToken(); 1236 out.println("longConstant " + name + " " + db.lookupLongConstant(name)); 1237 } else if (t.countTokens() == 0) { 1238 Iterator i = db.getLongConstants(); 1239 while (i.hasNext()) { 1240 String name = (String)i.next(); 1241 out.println("longConstant " + name + " " + db.lookupLongConstant(name)); 1242 } 1243 } else if (t.countTokens() == 2) { 1244 String name = t.nextToken(); 1245 Long value = Long.valueOf(t.nextToken()); 1246 db.addLongConstant(name, value); 1247 } 1248 } 1249 }, 1250 new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { 1251 public void doit(Tokens t) { 1252 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 1253 usage(); 1254 return; 1255 } 1256 if (t.countTokens() == 1) { 1257 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1258 dumpFields(type); 1259 } else if (t.countTokens() == 0) { 1260 Iterator i = agent.getTypeDataBase().getTypes(); 1261 while (i.hasNext()) { 1262 dumpFields((Type)i.next()); 1263 } 1264 } else { 1265 BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken()); 1266 1267 String fieldName = t.nextToken(); 1268 1269 // The field's Type must already be in the database -- no exceptions 1270 Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken()); 1271 1272 boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue(); 1273 long offset = Long.parseLong(t.nextToken()); 1274 Address staticAddress = parseAddress(t.nextToken()); 1275 if (isStatic && staticAddress == null) { 1276 staticAddress = lookup(containingType.getName() + "::" + fieldName); 1277 } 1278 1279 // check to see if the field already exists 1280 Iterator i = containingType.getFields(); 1281 while (i.hasNext()) { 1282 Field f = (Field) i.next(); 1283 if (f.getName().equals(fieldName)) { 1284 if (f.isStatic() != isStatic) { 1285 throw new RuntimeException("static/nonstatic mismatch: " + t.input); 1286 } 1287 if (!isStatic) { 1288 if (f.getOffset() != offset) { 1289 throw new RuntimeException("bad redefinition of field offset: " + t.input); 1290 } 1291 } else { 1292 if (!f.getStaticFieldAddress().equals(staticAddress)) { 1293 throw new RuntimeException("bad redefinition of field location: " + t.input); 1294 } 1295 } 1296 if (f.getType() != fieldType) { 1297 throw new RuntimeException("bad redefinition of field type: " + t.input); 1298 } 1299 return; 1300 } 1301 } 1302 1303 // Create field by type 1304 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1305 db.createField(containingType, 1306 fieldName, fieldType, 1307 isStatic, 1308 offset, 1309 staticAddress); 1310 1311 } 1312 } 1313 1314 }, 1315 new Command("tokenize", "tokenize ...", true) { 1316 public void doit(Tokens t) { 1317 while (t.hasMoreTokens()) { 1318 out.println("\"" + t.nextToken() + "\""); 1319 } 1320 } 1321 }, 1322 new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { 1323 public void doit(Tokens t) { 1324 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 1325 usage(); 1326 return; 1327 } 1328 if (t.countTokens() == 6) { 1329 String typeName = t.nextToken(); 1330 String superclassName = t.nextToken(); 1331 if (superclassName.equals("null")) { 1332 superclassName = null; 1333 } 1334 boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue(); 1335 boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue(); 1336 boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue(); 1337 long size = Long.parseLong(t.nextToken()); 1338 1339 BasicType type = null; 1340 try { 1341 type = (BasicType)agent.getTypeDataBase().lookupType(typeName); 1342 } catch (RuntimeException e) { 1343 } 1344 if (type != null) { 1345 if (type.isOopType() != isOop) { 1346 throw new RuntimeException("oop mismatch in type definition: " + t.input); 1347 } 1348 if (type.isCIntegerType() != isInteger) { 1349 throw new RuntimeException("integer type mismatch in type definition: " + t.input); 1350 } 1351 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { 1352 throw new RuntimeException("unsigned mismatch in type definition: " + t.input); 1353 } 1354 if (type.getSuperclass() == null) { 1355 if (superclassName != null) { 1356 if (type.getSize() == -1) { 1357 type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName)); 1358 } else { 1359 throw new RuntimeException("unexpected superclass in type definition: " + t.input); 1360 } 1361 } 1362 } else { 1363 if (superclassName == null) { 1364 throw new RuntimeException("missing superclass in type definition: " + t.input); 1365 } 1366 if (!type.getSuperclass().getName().equals(superclassName)) { 1367 throw new RuntimeException("incorrect superclass in type definition: " + t.input); 1368 } 1369 } 1370 if (type.getSize() != size) { 1371 if (type.getSize() == -1) { 1372 type.setSize(size); 1373 } 1374 throw new RuntimeException("size mismatch in type definition: " + t.input); 1375 } 1376 return; 1377 } 1378 1379 // Create type 1380 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1381 db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size); 1382 } else if (t.countTokens() == 1) { 1383 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1384 dumpType(type); 1385 } else { 1386 Iterator i = agent.getTypeDataBase().getTypes(); 1387 // Make sure the types are emitted in an order than can be read back in 1388 HashSet emitted = new HashSet(); 1389 Stack pending = new Stack(); 1390 while (i.hasNext()) { 1391 Type n = (Type)i.next(); 1392 if (emitted.contains(n.getName())) { 1393 continue; 1394 } 1395 1396 while (n != null && !emitted.contains(n.getName())) { 1397 pending.push(n); 1398 n = n.getSuperclass(); 1399 } 1400 while (!pending.empty()) { 1401 n = (Type)pending.pop(); 1402 dumpType(n); 1403 emitted.add(n.getName()); 1404 } 1405 } 1406 } 1407 } 1408 1409 }, 1410 new Command("source", "source filename", true) { 1411 public void doit(Tokens t) { 1412 if (t.countTokens() != 1) { 1413 usage(); 1414 return; 1415 } 1416 String file = t.nextToken(); 1417 BufferedReader savedInput = in; 1418 try { 1419 BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 1420 in = input; 1421 run(false); 1422 } catch (Exception e) { 1423 out.println("Error: " + e); 1424 if (verboseExceptions) { 1425 e.printStackTrace(out); 1426 } 1427 } finally { 1428 in = savedInput; 1429 } 1430 1431 } 1432 }, 1433 new Command("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) { 1434 public void doit(Tokens t) { 1435 if (t.countTokens() != 2) { 1436 usage(); 1437 return; 1438 } 1439 String type = t.nextToken(); 1440 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1441 final long stride = VM.getVM().getAddressSize(); 1442 if (type.equals("threads")) { 1443 Threads threads = VM.getVM().getThreads(); 1444 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1445 JavaThread thread = threads.getJavaThreadAt(i); 1446 Address base = thread.getStackBase(); 1447 Address end = thread.getLastJavaSP(); 1448 if (end == null) continue; 1449 if (end.lessThan(base)) { 1450 Address tmp = base; 1451 base = end; 1452 end = tmp; 1453 } 1454 //out.println("Searching " + base + " " + end); 1519 } catch (Exception e) { 1520 out.println("Exception printing blob at " + base); 1521 e.printStackTrace(); 1522 } 1523 } 1524 out.println("found at " + base + "\n"); 1525 } 1526 base = base.addOffsetTo(stride); 1527 } 1528 } 1529 public void epilogue() { 1530 } 1531 1532 1533 }; 1534 VM.getVM().getCodeCache().iterate(v); 1535 1536 } 1537 } 1538 }, 1539 new Command("dumpcodecache", "dumpcodecache", false) { 1540 public void doit(Tokens t) { 1541 if (t.countTokens() != 0) { 1542 usage(); 1543 } else { 1544 final PrintStream fout = out; 1545 final HTMLGenerator gen = new HTMLGenerator(false); 1546 CodeCacheVisitor v = new CodeCacheVisitor() { 1547 public void prologue(Address start, Address end) { 1548 } 1549 public void visit(CodeBlob blob) { 1550 fout.println(gen.genHTML(blob.contentBegin())); 1551 } 1552 public void epilogue() { 1553 } 1554 1555 1556 }; 1557 VM.getVM().getCodeCache().iterate(v); 1558 } 1559 } 1560 }, 1561 new Command("where", "where { -a | id }", false) { 1562 public void doit(Tokens t) { 1563 if (t.countTokens() != 1) { 1564 usage(); 1565 } else { 1566 String name = t.nextToken(); 1567 Threads threads = VM.getVM().getThreads(); 1568 boolean all = name.equals("-a"); 1569 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1570 JavaThread thread = threads.getJavaThreadAt(i); 1571 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1572 thread.printThreadIDOn(new PrintStream(bos)); 1573 if (all || bos.toString().equals(name)) { 1574 out.println("Thread " + bos.toString() + " Address: " + thread.getAddress()); 1575 HTMLGenerator gen = new HTMLGenerator(false); 1576 try { 1577 out.println(gen.genHTMLForJavaStackTrace(thread)); 1578 } catch (Exception e) { 1579 err.println("Error: " + e); 1580 if (verboseExceptions) { 1581 e.printStackTrace(err); 1582 } 1583 } 1584 if (!all) return; 1585 } 1586 } 1587 if (!all) out.println("Couldn't find thread " + name); 1588 } 1589 } 1590 }, 1591 new Command("thread", "thread { -a | id }", false) { 1592 public void doit(Tokens t) { 1593 if (t.countTokens() != 1) { 1594 usage(); 1595 } else { 1596 String name = t.nextToken(); 1597 Threads threads = VM.getVM().getThreads(); 1598 boolean all = name.equals("-a"); 1599 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1600 JavaThread thread = threads.getJavaThreadAt(i); 1601 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1602 thread.printThreadIDOn(new PrintStream(bos)); 1603 if (all || bos.toString().equals(name)) { 1604 out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); 1605 thread.printInfoOn(out); 1606 out.println(" "); 1607 if (!all) return; 1608 } 1609 } 1610 if (!all) { 1611 out.println("Couldn't find thread " + name); 1612 } 1613 } 1614 } 1615 }, 1616 1617 new Command("threads", false) { 1618 public void doit(Tokens t) { 1619 if (t.countTokens() != 0) { 1620 usage(); 1621 } else { 1622 Threads threads = VM.getVM().getThreads(); 1623 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1624 JavaThread thread = threads.getJavaThreadAt(i); 1625 thread.printThreadIDOn(out); 1626 out.println(" " + thread.getThreadName()); 1627 thread.printInfoOn(out); 1628 out.println("\n..."); 1629 } 1630 } 1631 } 1632 }, 1633 1634 new Command("livenmethods", false) { 1635 public void doit(Tokens t) { 1636 if (t.countTokens() != 0) { 1637 usage(); 1638 } else { 1639 ArrayList nmethods = new ArrayList(); 1640 Threads threads = VM.getVM().getThreads(); 1641 HTMLGenerator gen = new HTMLGenerator(false); 1642 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1643 JavaThread thread = threads.getJavaThreadAt(i); 1644 try { 1645 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 1646 if (vf instanceof CompiledVFrame) { 1647 NMethod c = ((CompiledVFrame)vf).getCode(); 1648 if (!nmethods.contains(c)) { 1649 nmethods.add(c); 1650 out.println(gen.genHTML(c)); 1651 } 1652 } 1653 } 1654 } catch (Exception e) { 1655 e.printStackTrace(); 1656 } 1657 } 1658 } 1659 } 1660 }, 1661 new Command("g1regiondetails", false) { 1662 public void doit(Tokens t) { 1663 if (t.countTokens() != 0) { 1664 usage(); 1665 } else { 1666 CollectedHeap heap = VM.getVM().getUniverse().heap(); 1667 if (!(heap instanceof G1CollectedHeap)) { 1668 out.println("This command is valid only for G1GC."); 1669 return; 1670 } 1671 out.println("Region Details:"); 1672 ((G1CollectedHeap)heap).printRegionDetails(out); 1673 } 1674 } 1675 }, 1676 new Command("universe", false) { 1677 public void doit(Tokens t) { 1678 if (t.countTokens() != 0) { 1679 usage(); 1680 } else { 1681 Universe u = VM.getVM().getUniverse(); 1682 out.println("Heap Parameters:"); 1683 u.heap().printOn(out); 1684 } 1685 } 1686 }, 1687 new Command("verbose", "verbose true | false", true) { 1688 public void doit(Tokens t) { 1689 if (t.countTokens() != 1) { 1690 usage(); 1691 } else { 1692 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); 1693 } 1694 } 1695 }, 1696 new Command("assert", "assert true | false", true) { 1697 public void doit(Tokens t) { 1698 if (t.countTokens() != 1) { 1699 usage(); 1700 } else { 1701 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); 1702 } 1703 } 1704 }, 1705 }; 1706 1707 private boolean verboseExceptions = false; 1708 private ArrayList history = new ArrayList(); 1709 private HashMap commands = new HashMap(); 1710 private boolean doEcho = false; 1711 1712 private Command findCommand(String key) { 1713 return (Command)commands.get(key); 1714 } 1715 1716 public void printPrompt() { 1717 out.print("hsdb> "); 1718 } 1719 1720 private DebuggerInterface debugger; 1721 private HotSpotAgent agent; 1722 private JSJavaScriptEngine jsengine; 1723 private BufferedReader in; 1724 private PrintStream out; 1763 this.getClass().getMethod("registerCommand", 1764 new Class[] { 1765 String.class, String.class, String.class 1766 })); 1767 } catch (NoSuchMethodException exp) { 1768 // should not happen, see below...!! 1769 exp.printStackTrace(); 1770 } 1771 jsengine.start(); 1772 } 1773 catch (Exception ex) { 1774 System.out.println("Warning! JS Engine can't start, some commands will not be available."); 1775 if (verboseExceptions) { 1776 ex.printStackTrace(out); 1777 } 1778 } 1779 */ 1780 } 1781 1782 public void registerCommand(String cmd, String usage, final String func) { 1783 commands.put(cmd, new Command(cmd, usage, false) { 1784 public void doit(Tokens t) { 1785 final int len = t.countTokens(); 1786 Object[] args = new Object[len]; 1787 for (int i = 0; i < len; i++) { 1788 args[i] = t.nextToken(); 1789 } 1790 jsengine.call(func, args); 1791 } 1792 }); 1793 } 1794 1795 public void setOutput(PrintStream o) { 1796 out = o; 1797 } 1798 1799 public void setErr(PrintStream e) { 1800 err = e; 1801 } 1802 1803 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { 1804 this.debugger = debugger; 1805 this.agent = debugger.getAgent(); 1806 this.in = in; 1807 this.out = out; 1808 this.err = err; 1809 for (int i = 0; i < commandList.length; i++) { 1810 Command c = commandList[i]; 1811 if (commands.get(c.name) != null) { 1812 throw new InternalError(c.name + " has multiple definitions"); 1813 } 1814 commands.put(c.name, c); 1815 } 1816 if (debugger.isAttached()) { 1817 postAttach(); 1818 } 1819 } 1820 1821 1822 public void run(boolean prompt) { 1823 // Process interactive commands. 1824 while (!quit) { 1825 if (prompt) printPrompt(); 1826 String ln = null; 1827 try { 1828 ln = in.readLine(); 1829 } catch (IOException e) { 1830 } 1831 if (ln == null) { 1832 if (prompt) err.println("Input stream closed."); 1833 return; 1834 } 1962 } finally { 1963 if (redirect != null) { 1964 out = savedout; 1965 redirect.close(); 1966 } 1967 } 1968 } 1969 } 1970 } 1971 1972 void executeCommand(Tokens args) { 1973 String cmd = args.nextToken(); 1974 1975 Command doit = findCommand(cmd); 1976 1977 /* 1978 * Check for an unknown command 1979 */ 1980 if (doit == null) { 1981 out.println("Unrecognized command. Try help..."); 1982 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { 1983 out.println("Command not valid until attached to a VM"); 1984 } else { 1985 try { 1986 doit.doit(args); 1987 } catch (Exception e) { 1988 out.println("Error: " + e); 1989 if (verboseExceptions) { 1990 e.printStackTrace(out); 1991 } 1992 } 1993 } 1994 } 1995 } | 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; 26 27 import java.lang.module.Configuration; 28 import java.lang.module.ModuleFinder; 29 import java.nio.file.Path; 30 import java.io.BufferedOutputStream; 31 import java.io.BufferedReader; 32 import java.io.ByteArrayOutputStream; 33 import java.io.FileInputStream; 34 import java.io.FileOutputStream; 35 import java.io.IOException; 36 import java.io.InputStreamReader; 37 import java.io.PrintStream; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.Collections; 41 import java.util.Comparator; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.Iterator; 45 import java.util.ServiceLoader; 46 import java.util.Set; 47 import java.util.Stack; 48 import java.util.stream.Collectors; 49 import java.util.regex.Matcher; 50 import java.util.regex.Pattern; 51 52 import sun.jvm.hotspot.api.Command; 53 import sun.jvm.hotspot.api.Tokens; 54 import sun.jvm.hotspot.ci.ciEnv; 55 import sun.jvm.hotspot.code.CodeBlob; 56 import sun.jvm.hotspot.code.CodeCacheVisitor; 57 import sun.jvm.hotspot.code.NMethod; 58 import sun.jvm.hotspot.debugger.Address; 59 import sun.jvm.hotspot.debugger.OopHandle; 60 import sun.jvm.hotspot.classfile.ClassLoaderDataGraph; 61 import sun.jvm.hotspot.memory.FileMapInfo; 62 import sun.jvm.hotspot.memory.SystemDictionary; 63 import sun.jvm.hotspot.memory.Universe; 64 import sun.jvm.hotspot.gc.shared.CollectedHeap; 65 import sun.jvm.hotspot.gc.g1.G1CollectedHeap; 66 import sun.jvm.hotspot.oops.DefaultHeapVisitor; 67 import sun.jvm.hotspot.oops.HeapVisitor; 68 import sun.jvm.hotspot.oops.InstanceKlass; 69 import sun.jvm.hotspot.oops.Klass; 70 import sun.jvm.hotspot.oops.Metadata; 71 import sun.jvm.hotspot.oops.Method; 72 import sun.jvm.hotspot.oops.MethodData; 73 import sun.jvm.hotspot.oops.Oop; 130 public boolean canInclude(InstanceKlass kls) { 131 return kls.getClassLoader() == null; 132 } 133 } 134 135 public static class NonBootFilter implements ClassFilter { 136 private HashMap emitted = new HashMap(); 137 public boolean canInclude(InstanceKlass kls) { 138 if (kls.getClassLoader() == null) return false; 139 if (emitted.get(kls.getName()) != null) { 140 // Since multiple class loaders are being shoved 141 // together duplicate classes are a possibilty. For 142 // now just ignore them. 143 return false; 144 } 145 emitted.put(kls.getName(), kls); 146 return true; 147 } 148 } 149 150 abstract class ClhsdbCommand implements Command { 151 ClhsdbCommand(String n, String u, boolean ok) { 152 name = n; 153 usage = u; 154 okIfDisconnected = ok; 155 } 156 157 ClhsdbCommand(String n, boolean ok) { 158 name = n; 159 usage = n; 160 okIfDisconnected = ok; 161 } 162 163 private final String name; 164 private final String usage; 165 private final boolean okIfDisconnected; 166 167 @Override 168 public String name() { 169 return name; 170 } 171 172 @Override 173 public String usage() { 174 return "Usage: " + usage; 175 } 176 177 @Override 178 public boolean okIfDisconnected() { 179 return okIfDisconnected; 180 } 181 182 @Override 183 public abstract void doit(Tokens t, PrintStream out); 184 185 void printOopValue(Oop oop) { 186 if (oop != null) { 187 Klass k = oop.getKlass(); 188 Symbol s = k.getName(); 189 if (s != null) { 190 out.print("Oop for " + s.asString() + " @ "); 191 } else { 192 out.print("Oop @ "); 193 } 194 Oop.printOopAddressOn(oop, out); 195 } else { 196 out.print("null"); 197 } 198 } 199 200 void printNode(SimpleTreeNode node) { 201 int count = node.getChildCount(); 202 for (int i = 0; i < count; i++) { 203 try { 204 SimpleTreeNode field = node.getChild(i); 291 for (int i = 0; i < parts.length; i++) { 292 int len = parts[i].length(); 293 if (len >= 26) { 294 mangled.append((char)('a' + (len / 26))); 295 len = len % 26; 296 } 297 mangled.append((char)('A' + len)); 298 mangled.append(parts[i]); 299 } 300 mangled.append("_"); 301 symbol = mangled.toString(); 302 } 303 return VM.getVM().getDebugger().lookup(null, symbol); 304 } 305 306 Address parseAddress(String addr) { 307 return VM.getVM().getDebugger().parseAddress(addr); 308 } 309 310 private final Command[] commandList = { 311 new ClhsdbCommand("reattach", true) { 312 @Override 313 public void doit(Tokens t, PrintStream out) { 314 int tokens = t.countTokens(); 315 if (tokens != 0) { 316 usage(); 317 return; 318 } 319 preAttach(); 320 debugger.reattach(); 321 postAttach(); 322 } 323 }, 324 new ClhsdbCommand("attach", "attach pid | exec core", true) { 325 @Override 326 public void doit(Tokens t, PrintStream out) { 327 int tokens = t.countTokens(); 328 if (tokens == 1) { 329 preAttach(); 330 debugger.attach(t.nextToken()); 331 postAttach(); 332 } else if (tokens == 2) { 333 preAttach(); 334 debugger.attach(t.nextToken(), t.nextToken()); 335 postAttach(); 336 } else { 337 usage(); 338 } 339 } 340 }, 341 new ClhsdbCommand("detach", false) { 342 @Override 343 public void doit(Tokens t, PrintStream out) { 344 if (t.countTokens() != 0) { 345 usage(); 346 } else { 347 debugger.detach(); 348 } 349 } 350 }, 351 new ClhsdbCommand("examine", "examine [ address/count ] | [ address,address]", false) { 352 Pattern args1 = Pattern.compile("^(0x[0-9a-f]+)(/([0-9]*)([a-z]*))?$"); 353 Pattern args2 = Pattern.compile("^(0x[0-9a-f]+),(0x[0-9a-f]+)(/[a-z]*)?$"); 354 355 String fill(Address a, int width) { 356 String s = "0x0"; 357 if (a != null) { 358 s = a.toString(); 359 } 360 if (s.length() != width) { 361 return s.substring(0, 2) + "000000000000000000000".substring(0, width - s.length()) + s.substring(2); 362 } 363 return s; 364 } 365 366 @Override 367 public void doit(Tokens t, PrintStream out) { 368 if (t.countTokens() != 1) { 369 usage(); 370 } else { 371 String arg = t.nextToken(); 372 Matcher m1 = args1.matcher(arg); 373 Matcher m2 = args2.matcher(arg); 374 Address start = null; 375 Address end = null; 376 String format = ""; 377 int formatSize = (int)VM.getVM().getAddressSize(); 378 379 if (m1.matches()) { 380 start = VM.getVM().getDebugger().parseAddress(m1.group(1)); 381 int count = 1; 382 if (m1.group(2) != null) { 383 count = Integer.parseInt(m1.group(3)); 384 } 385 end = start.addOffsetTo(count * formatSize); 386 } else if (m2.matches()) { 387 start = VM.getVM().getDebugger().parseAddress(m2.group(1)); 406 start = start.addOffsetTo(formatSize); 407 if (width <= formatWidth) { 408 out.println(); 409 needsPrintln = false; 410 if (start.lessThan(end)) { 411 out.print(fill(start, formatWidth)); 412 out.print(": "); 413 width = line - formatWidth - 2; 414 } 415 } else { 416 out.print(" "); 417 width -= 1; 418 } 419 } 420 if (needsPrintln) { 421 out.println(); 422 } 423 } 424 } 425 }, 426 new ClhsdbCommand("dumpreplaydata", "dumpreplaydata { <address > | -a | <thread_id> }", false) { 427 // This is used to dump replay data from ciInstanceKlass, ciMethodData etc 428 // default file name is replay.txt, also if java crashes in compiler 429 // thread, this file will be dumped in error processing. 430 @Override 431 public void doit(Tokens t, PrintStream out) { 432 if (t.countTokens() != 1) { 433 usage(); 434 return; 435 } 436 String name = t.nextToken(); 437 Address a = null; 438 try { 439 a = VM.getVM().getDebugger().parseAddress(name); 440 } catch (NumberFormatException e) { } 441 if (a != null) { 442 // only nmethod, Method, MethodData and InstanceKlass needed to 443 // dump replay data 444 445 CodeBlob cb = VM.getVM().getCodeCache().findBlob(a); 446 if (cb != null && (cb instanceof NMethod)) { 447 ((NMethod)cb).dumpReplayData(out); 448 return; 449 } 450 // assume it is Metadata 451 Metadata meta = Metadata.instantiateWrapperFor(a); 458 } 459 // Not an address 460 boolean all = name.equals("-a"); 461 Threads threads = VM.getVM().getThreads(); 462 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 463 JavaThread thread = threads.getJavaThreadAt(i); 464 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 465 thread.printThreadIDOn(new PrintStream(bos)); 466 if (all || bos.toString().equals(name)) { 467 if (thread instanceof CompilerThread) { 468 CompilerThread ct = (CompilerThread)thread; 469 ciEnv env = ct.env(); 470 if (env != null) { 471 env.dumpReplayData(out); 472 } 473 } 474 } 475 } 476 } 477 }, 478 new ClhsdbCommand("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) { 479 // This is used to dump jar files of all the classes 480 // loaded in the core. Everything with null classloader 481 // will go in boot.jar and everything else will go in 482 // app.jar. boot.jar usually not needed, unless changed by jvmti. 483 @Override 484 public void doit(Tokens t, PrintStream out) { 485 int tcount = t.countTokens(); 486 if (tcount > 2) { 487 usage(); 488 return; 489 } 490 try { 491 String prefix = ""; 492 String option = "all"; // default 493 switch(tcount) { 494 case 0: 495 break; 496 case 1: 497 option = t.nextToken(); 498 if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") && 499 !option.equalsIgnoreCase("root")) { 500 prefix = option; 501 option = "all"; 502 } 503 break; 504 case 2: 513 !option.equalsIgnoreCase("boot")) { 514 usage(); 515 return; 516 } 517 ClassDump cd = new ClassDump(); 518 if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) { 519 cd.setClassFilter(new BootFilter()); 520 cd.setJarOutput(prefix + "boot.jar"); 521 cd.run(); 522 } 523 if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) { 524 cd.setClassFilter(new NonBootFilter()); 525 cd.setJarOutput(prefix + "app.jar"); 526 cd.run(); 527 } 528 } catch (IOException ioe) { 529 ioe.printStackTrace(); 530 } 531 } 532 }, 533 new ClhsdbCommand("findpc", "findpc address", false) { 534 @Override 535 public void doit(Tokens t, PrintStream out) { 536 if (t.countTokens() != 1) { 537 usage(); 538 } else { 539 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 540 PointerLocation loc = PointerFinder.find(a); 541 loc.printOn(out); 542 } 543 } 544 }, 545 new ClhsdbCommand("symbol", "symbol address", false) { 546 @Override 547 public void doit(Tokens t, PrintStream out) { 548 if (t.countTokens() != 1) { 549 usage(); 550 } else { 551 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 552 Symbol.create(a).printValueOn(out); 553 out.println(); 554 } 555 } 556 }, 557 new ClhsdbCommand("flags", "flags [ flag | -nd ]", false) { 558 @Override 559 public void doit(Tokens t, PrintStream out) { 560 int tokens = t.countTokens(); 561 if (tokens != 0 && tokens != 1) { 562 usage(); 563 } else { 564 String name = tokens > 0 ? t.nextToken() : null; 565 boolean nonDefault = false; 566 if (name != null && name.equals("-nd")) { 567 name = null; 568 nonDefault = true; 569 } 570 571 VM.Flag[] flags = VM.getVM().getCommandLineFlags(); 572 if (flags == null) { 573 out.println("Command Flag info not available (use 1.4.1_03 or later)!"); 574 } else { 575 boolean printed = false; 576 for (int f = 0; f < flags.length; f++) { 577 VM.Flag flag = flags[f]; 578 if (name == null || flag.getName().equals(name)) { 579 580 if (nonDefault && (flag.getOrigin() == VM.Flags_DEFAULT)) { 581 // only print flags which aren't their defaults 582 continue; 583 } 584 out.println(flag.getName() + " = " + flag.getValue() + " " + flag.getOriginString()); 585 printed = true; 586 } 587 } 588 if (name != null && !printed) { 589 out.println("Couldn't find flag: " + name); 590 } 591 } 592 } 593 } 594 }, 595 new ClhsdbCommand("help", "help [ command ]", true) { 596 @Override 597 public void doit(Tokens t, PrintStream out) { 598 int tokens = t.countTokens(); 599 Command cmd = null; 600 if (tokens == 1) { 601 cmd = findCommand(t.nextToken()); 602 } 603 604 if (cmd != null) { 605 cmd.usage(); 606 } else if (tokens == 0) { 607 out.println("Available commands:"); 608 Object[] keys = commands.keySet().toArray(); 609 Arrays.sort(keys, new Comparator() { 610 public int compare(Object o1, Object o2) { 611 return o1.toString().compareTo(o2.toString()); 612 } 613 }); 614 for (int i = 0; i < keys.length; i++) { 615 out.print(" "); 616 out.println(((Command)commands.get(keys[i])).usage()); 617 } 618 } 619 } 620 }, 621 new ClhsdbCommand("history", "history", true) { 622 @Override 623 public void doit(Tokens t, PrintStream out) { 624 int tokens = t.countTokens(); 625 if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) { 626 usage(); 627 return; 628 } 629 boolean printIndex = tokens == 0; 630 for (int i = 0; i < history.size(); i++) { 631 if (printIndex) out.print(i + " "); 632 out.println(history.get(i)); 633 } 634 } 635 }, 636 // decode raw address 637 new ClhsdbCommand("dis", "dis address [length]", false) { 638 @Override 639 public void doit(Tokens t, PrintStream out) { 640 int tokens = t.countTokens(); 641 if (tokens != 1 && tokens != 2) { 642 usage(); 643 return; 644 } 645 String name = t.nextToken(); 646 Address addr = null; 647 int len = 0x10; // default length 648 try { 649 addr = VM.getVM().getDebugger().parseAddress(name); 650 } catch (NumberFormatException e) { 651 out.println(e); 652 return; 653 } 654 if (tokens == 2) { 655 try { 656 len = Integer.parseInt(t.nextToken()); 657 } catch (NumberFormatException e) { 658 out.println(e); 659 return; 660 } 661 } 662 HTMLGenerator generator = new HTMLGenerator(false); 663 out.println(generator.genHTMLForRawDisassembly(addr, len)); 664 } 665 666 }, 667 // decode codeblob or nmethod 668 new ClhsdbCommand("disassemble", "disassemble address", false) { 669 @Override 670 public void doit(Tokens t, PrintStream out) { 671 int tokens = t.countTokens(); 672 if (tokens != 1) { 673 usage(); 674 return; 675 } 676 String name = t.nextToken(); 677 Address addr = null; 678 try { 679 addr = VM.getVM().getDebugger().parseAddress(name); 680 } catch (NumberFormatException e) { 681 out.println(e); 682 return; 683 } 684 685 HTMLGenerator generator = new HTMLGenerator(false); 686 out.println(generator.genHTML(addr)); 687 } 688 }, 689 // print Java bytecode disassembly 690 new ClhsdbCommand("jdis", "jdis address", false) { 691 @Override 692 public void doit(Tokens t, PrintStream out) { 693 int tokens = t.countTokens(); 694 if (tokens != 1) { 695 usage(); 696 return; 697 } 698 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 699 Method m = (Method)Metadata.instantiateWrapperFor(a); 700 HTMLGenerator html = new HTMLGenerator(false); 701 out.println(html.genHTML(m)); 702 } 703 }, 704 new ClhsdbCommand("revptrs", "revptrs address", false) { 705 @Override 706 public void doit(Tokens t, PrintStream out) { 707 int tokens = t.countTokens(); 708 if (tokens != 1 && (tokens != 2 || !t.nextToken().equals("-c"))) { 709 usage(); 710 return; 711 } 712 boolean chase = tokens == 2; 713 ReversePtrs revptrs = VM.getVM().getRevPtrs(); 714 if (revptrs == null) { 715 out.println("Computing reverse pointers..."); 716 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); 717 final boolean[] complete = new boolean[1]; 718 HeapProgressThunk thunk = new HeapProgressThunk() { 719 public void heapIterationFractionUpdate(double d) {} 720 public synchronized void heapIterationComplete() { 721 complete[0] = true; 722 notify(); 723 } 724 }; 725 analysis.setHeapProgressThunk(thunk); 726 analysis.run(); 747 while (ptrs.size() == 1) { 748 LivenessPathElement e = (LivenessPathElement)ptrs.get(0); 749 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 750 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 751 out.println(bos.toString()); 752 ptrs = revptrs.get(e.getObj()); 753 } 754 } else { 755 for (int i = 0; i < ptrs.size(); i++) { 756 LivenessPathElement e = (LivenessPathElement)ptrs.get(i); 757 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 758 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 759 out.println(bos.toString()); 760 oop = e.getObj(); 761 } 762 } 763 } 764 } 765 } 766 }, 767 new ClhsdbCommand("printmdo", "printmdo [ -a | expression ]", false) { 768 // Print every MDO in the heap or the one referenced by expression. 769 @Override 770 public void doit(Tokens t, PrintStream out) { 771 if (t.countTokens() != 1) { 772 usage(); 773 } else { 774 String s = t.nextToken(); 775 if (s.equals("-a")) { 776 ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph(); 777 cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() { 778 public void visit(Klass k) { 779 if (k instanceof InstanceKlass) { 780 MethodArray methods = ((InstanceKlass)k).getMethods(); 781 for (int i = 0; i < methods.length(); i++) { 782 Method m = methods.at(i); 783 MethodData mdo = m.getMethodData(); 784 if (mdo != null) { 785 out.println("MethodData " + mdo.getAddress() + " for " + 786 "method " + m.getMethodHolder().getName().asString() + "." + 787 m.getName().asString() + 788 m.getSignature().asString() + "@" + m.getAddress()); 789 mdo.printDataOn(out); 790 } 791 } 792 } 793 } 794 } 795 ); 796 } else { 797 Address a = VM.getVM().getDebugger().parseAddress(s); 798 MethodData mdo = (MethodData) Metadata.instantiateWrapperFor(a); 799 mdo.printDataOn(out); 800 } 801 } 802 } 803 }, 804 new ClhsdbCommand("printall", "printall", false) { 805 // Print every MDO in the heap or the one referenced by expression. 806 @Override 807 public void doit(Tokens t, PrintStream out) { 808 if (t.countTokens() != 0) { 809 usage(); 810 } else { 811 ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph(); 812 cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() { 813 public void visit(Klass k) { 814 if (k instanceof InstanceKlass && ((InstanceKlass)k).getConstants().getCache() != null) { 815 MethodArray methods = ((InstanceKlass)k).getMethods(); 816 for (int i = 0; i < methods.length(); i++) { 817 Method m = methods.at(i); 818 HTMLGenerator gen = new HTMLGenerator(false); 819 out.println(gen.genHTML(m)); 820 } 821 } 822 } 823 } 824 ); 825 } 826 } 827 }, 828 new ClhsdbCommand("dumpideal", "dumpideal { -a | id }", false) { 829 // Do a full dump of the nodes reachabile from root in each compiler thread. 830 @Override 831 public void doit(Tokens t, PrintStream out) { 832 if (t.countTokens() != 1) { 833 usage(); 834 } else { 835 String name = t.nextToken(); 836 boolean all = name.equals("-a"); 837 Threads threads = VM.getVM().getThreads(); 838 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 839 JavaThread thread = threads.getJavaThreadAt(i); 840 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 841 thread.printThreadIDOn(new PrintStream(bos)); 842 if (all || bos.toString().equals(name)) { 843 if (thread instanceof CompilerThread) { 844 CompilerThread ct = (CompilerThread)thread; 845 out.println(ct); 846 ciEnv env = ct.env(); 847 if (env != null) { 848 Compile c = env.compilerData(); 849 c.root().dump(9999, out); 850 } else { 851 out.println(" not compiling"); 852 } 853 } 854 } 855 } 856 } 857 } 858 }, 859 new ClhsdbCommand("dumpcfg", "dumpcfg { -a | id }", false) { 860 // Dump the PhaseCFG for every compiler thread that has one live. 861 @Override 862 public void doit(Tokens t, PrintStream out) { 863 if (t.countTokens() != 1) { 864 usage(); 865 } else { 866 String name = t.nextToken(); 867 boolean all = name.equals("-a"); 868 Threads threads = VM.getVM().getThreads(); 869 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 870 JavaThread thread = threads.getJavaThreadAt(i); 871 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 872 thread.printThreadIDOn(new PrintStream(bos)); 873 if (all || bos.toString().equals(name)) { 874 if (thread instanceof CompilerThread) { 875 CompilerThread ct = (CompilerThread)thread; 876 out.println(ct); 877 ciEnv env = ct.env(); 878 if (env != null) { 879 Compile c = env.compilerData(); 880 c.cfg().dump(out); 881 } 882 } 883 } 884 } 885 } 886 } 887 }, 888 new ClhsdbCommand("dumpilt", "dumpilt { -a | id }", false) { 889 // dumps the InlineTree of a C2 compile 890 @Override 891 public void doit(Tokens t, PrintStream out) { 892 if (t.countTokens() != 1) { 893 usage(); 894 } else { 895 String name = t.nextToken(); 896 boolean all = name.equals("-a"); 897 Threads threads = VM.getVM().getThreads(); 898 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 899 JavaThread thread = threads.getJavaThreadAt(i); 900 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 901 thread.printThreadIDOn(new PrintStream(bos)); 902 if (all || bos.toString().equals(name)) { 903 if (thread instanceof CompilerThread) { 904 CompilerThread ct = (CompilerThread)thread; 905 ciEnv env = ct.env(); 906 if (env != null) { 907 Compile c = env.compilerData(); 908 InlineTree ilt = c.ilt(); 909 if (ilt != null) { 910 ilt.print(out); 911 } 912 } 913 } 914 } 915 } 916 } 917 } 918 }, 919 new ClhsdbCommand("vmstructsdump", "vmstructsdump", false) { 920 @Override 921 public void doit(Tokens t, PrintStream out) { 922 if (t.countTokens() != 0) { 923 usage(); 924 return; 925 } 926 927 // Dump a copy of the type database in a form that can 928 // be read back. 929 Iterator i = agent.getTypeDataBase().getTypes(); 930 // Make sure the types are emitted in an order than can be read back in 931 HashSet emitted = new HashSet(); 932 Stack pending = new Stack(); 933 while (i.hasNext()) { 934 Type n = (Type)i.next(); 935 if (emitted.contains(n.getName())) { 936 continue; 937 } 938 939 while (n != null && !emitted.contains(n.getName())) { 940 pending.push(n); 941 n = n.getSuperclass(); 942 } 943 while (!pending.empty()) { 944 n = (Type)pending.pop(); 945 dumpType(n); 946 emitted.add(n.getName()); 947 } 948 } 949 i = agent.getTypeDataBase().getTypes(); 950 while (i.hasNext()) { 951 dumpFields((Type)i.next(), false); 952 } 953 } 954 }, 955 956 new ClhsdbCommand("inspect", "inspect expression", false) { 957 @Override 958 public void doit(Tokens t, PrintStream out) { 959 if (t.countTokens() != 1) { 960 usage(); 961 } else { 962 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 963 SimpleTreeNode node = null; 964 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 965 OopHandle handle = a.addOffsetToAsOopHandle(0); 966 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 967 node = new OopTreeNodeAdapter(oop, null); 968 969 out.println("instance of " + node.getValue() + " @ " + a + 970 " (size = " + oop.getObjectSize() + ")"); 971 } else if (VM.getVM().getCodeCache().contains(a)) { 972 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a); 973 a = blob.headerBegin(); 974 } 975 if (node == null) { 976 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a); 977 if (type == null && VM.getVM().isSharingEnabled()) { 978 // Check if the value falls in the _md_region 979 Address loc1 = a.getAddressAt(0); 980 FileMapInfo cdsFileMapInfo = VM.getVM().getFileMapInfo(); 981 if (cdsFileMapInfo.inCopiedVtableSpace(loc1)) { 982 type = cdsFileMapInfo.getTypeForVptrAddress(loc1); 983 } 984 985 } 986 if (type != null) { 987 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")"); 988 node = new CTypeTreeNodeAdapter(a, type, null); 989 } 990 } 991 if (node != null) { 992 printNode(node); 993 } 994 } 995 } 996 }, 997 new ClhsdbCommand("jhisto", "jhisto", false) { 998 @Override 999 public void doit(Tokens t, PrintStream out) { 1000 ObjectHistogram histo = new ObjectHistogram(); 1001 histo.run(out, err); 1002 } 1003 }, 1004 new ClhsdbCommand("jstack", "jstack [-v]", false) { 1005 @Override 1006 public void doit(Tokens t, PrintStream out) { 1007 boolean verbose = false; 1008 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1009 verbose = true; 1010 } 1011 StackTrace jstack = new StackTrace(verbose, true); 1012 jstack.run(out); 1013 } 1014 }, 1015 new ClhsdbCommand("print", "print expression", false) { 1016 @Override 1017 public void doit(Tokens t, PrintStream out) { 1018 if (t.countTokens() != 1) { 1019 usage(); 1020 } else { 1021 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1022 HTMLGenerator gen = new HTMLGenerator(false); 1023 out.println(gen.genHTML(a)); 1024 } 1025 } 1026 }, 1027 new ClhsdbCommand("printas", "printas type expression", false) { 1028 @Override 1029 public void doit(Tokens t, PrintStream out) { 1030 if (t.countTokens() != 2) { 1031 usage(); 1032 } else { 1033 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1034 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1035 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null); 1036 1037 out.println("pointer to " + type + " @ " + a + 1038 " (size = " + type.getSize() + ")"); 1039 printNode(node); 1040 } 1041 } 1042 }, 1043 new ClhsdbCommand("printstatics", "printstatics [ type ]", false) { 1044 @Override 1045 public void doit(Tokens t, PrintStream out) { 1046 if (t.countTokens() > 1) { 1047 usage(); 1048 } else { 1049 if (t.countTokens() == 0) { 1050 out.println("All known static fields"); 1051 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes())); 1052 } else { 1053 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1054 out.println("Static fields of " + type.getName()); 1055 printNode(new CTypeTreeNodeAdapter(type)); 1056 } 1057 } 1058 } 1059 }, 1060 new ClhsdbCommand("pmap", "pmap", false) { 1061 @Override 1062 public void doit(Tokens t, PrintStream out) { 1063 PMap pmap = new PMap(); 1064 pmap.run(out, debugger.getAgent().getDebugger()); 1065 } 1066 }, 1067 new ClhsdbCommand("pstack", "pstack [-v]", false) { 1068 @Override 1069 public void doit(Tokens t, PrintStream out) { 1070 boolean verbose = false; 1071 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1072 verbose = true; 1073 } 1074 PStack pstack = new PStack(verbose, true); 1075 pstack.run(out, debugger.getAgent().getDebugger()); 1076 } 1077 }, 1078 new ClhsdbCommand("quit", true) { 1079 @Override 1080 public void doit(Tokens t, PrintStream out) { 1081 if (t.countTokens() != 0) { 1082 usage(); 1083 } else { 1084 debugger.detach(); 1085 quit = true; 1086 } 1087 } 1088 }, 1089 new ClhsdbCommand("echo", "echo [ true | false ]", true) { 1090 @Override 1091 public void doit(Tokens t, PrintStream out) { 1092 if (t.countTokens() == 0) { 1093 out.println("echo is " + doEcho); 1094 } else if (t.countTokens() == 1) { 1095 doEcho = Boolean.valueOf(t.nextToken()).booleanValue(); 1096 } else { 1097 usage(); 1098 } 1099 } 1100 }, 1101 new ClhsdbCommand("versioncheck", "versioncheck [ true | false ]", true) { 1102 @Override 1103 public void doit(Tokens t, PrintStream out) { 1104 if (t.countTokens() == 0) { 1105 out.println("versioncheck is " + 1106 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); 1107 } else if (t.countTokens() == 1) { 1108 if (Boolean.valueOf(t.nextToken()).booleanValue()) { 1109 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null); 1110 } else { 1111 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true"); 1112 } 1113 } else { 1114 usage(); 1115 } 1116 } 1117 }, 1118 new ClhsdbCommand("scanoops", "scanoops start end [ type ]", false) { 1119 @Override 1120 public void doit(Tokens t, PrintStream out) { 1121 if (t.countTokens() != 2 && t.countTokens() != 3) { 1122 usage(); 1123 } else { 1124 long stride = VM.getVM().getAddressSize(); 1125 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1126 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1127 Klass klass = null; 1128 if (t.countTokens() == 1) { 1129 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); 1130 if (klass == null) { 1131 out.println("No such type."); 1132 return; 1133 } 1134 } 1135 while (base != null && base.lessThan(end)) { 1136 long step = stride; 1137 OopHandle handle = base.addOffsetToAsOopHandle(0); 1138 if (RobustOopDeterminator.oopLooksValid(handle)) { 1139 try { 1140 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1141 if (klass == null || oop.getKlass().isSubtypeOf(klass)) 1142 out.println(handle.toString() + " " + oop.getKlass().getName().asString()); 1143 step = oop.getObjectSize(); 1144 } catch (UnknownOopException ex) { 1145 // ok 1146 } catch (RuntimeException ex) { 1147 ex.printStackTrace(); 1148 } 1149 } 1150 base = base.addOffsetTo(step); 1151 } 1152 } 1153 } 1154 }, 1155 new ClhsdbCommand("intConstant", "intConstant [ name [ value ] ]", true) { 1156 @Override 1157 public void doit(Tokens t, PrintStream out) { 1158 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1159 usage(); 1160 return; 1161 } 1162 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1163 if (t.countTokens() == 1) { 1164 String name = t.nextToken(); 1165 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1166 } else if (t.countTokens() == 0) { 1167 Iterator i = db.getIntConstants(); 1168 while (i.hasNext()) { 1169 String name = (String)i.next(); 1170 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1171 } 1172 } else if (t.countTokens() == 2) { 1173 String name = t.nextToken(); 1174 Integer value = Integer.valueOf(t.nextToken()); 1175 db.addIntConstant(name, value); 1176 } 1177 } 1178 }, 1179 new ClhsdbCommand("longConstant", "longConstant [ name [ value ] ]", true) { 1180 @Override 1181 public void doit(Tokens t, PrintStream out) { 1182 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1183 usage(); 1184 return; 1185 } 1186 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1187 if (t.countTokens() == 1) { 1188 String name = t.nextToken(); 1189 out.println("longConstant " + name + " " + db.lookupLongConstant(name)); 1190 } else if (t.countTokens() == 0) { 1191 Iterator i = db.getLongConstants(); 1192 while (i.hasNext()) { 1193 String name = (String)i.next(); 1194 out.println("longConstant " + name + " " + db.lookupLongConstant(name)); 1195 } 1196 } else if (t.countTokens() == 2) { 1197 String name = t.nextToken(); 1198 Long value = Long.valueOf(t.nextToken()); 1199 db.addLongConstant(name, value); 1200 } 1201 } 1202 }, 1203 new ClhsdbCommand("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { 1204 @Override 1205 public void doit(Tokens t, PrintStream out) { 1206 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 1207 usage(); 1208 return; 1209 } 1210 if (t.countTokens() == 1) { 1211 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1212 dumpFields(type); 1213 } else if (t.countTokens() == 0) { 1214 Iterator i = agent.getTypeDataBase().getTypes(); 1215 while (i.hasNext()) { 1216 dumpFields((Type)i.next()); 1217 } 1218 } else { 1219 BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken()); 1220 1221 String fieldName = t.nextToken(); 1222 1223 // The field's Type must already be in the database -- no exceptions 1224 Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken()); 1225 1226 boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue(); 1227 long offset = Long.parseLong(t.nextToken()); 1228 Address staticAddress = parseAddress(t.nextToken()); 1229 if (isStatic && staticAddress == null) { 1230 staticAddress = lookup(containingType.getName() + "::" + fieldName); 1231 } 1232 1233 // check to see if the field already exists 1234 Iterator i = containingType.getFields(); 1235 while (i.hasNext()) { 1236 Field f = (Field) i.next(); 1237 if (f.getName().equals(fieldName)) { 1238 if (f.isStatic() != isStatic) { 1239 throw new RuntimeException("static/nonstatic mismatch: " + t.getInput()); 1240 } 1241 if (!isStatic) { 1242 if (f.getOffset() != offset) { 1243 throw new RuntimeException("bad redefinition of field offset: " + t.getInput()); 1244 } 1245 } else { 1246 if (!f.getStaticFieldAddress().equals(staticAddress)) { 1247 throw new RuntimeException("bad redefinition of field location: " + t.getInput()); 1248 } 1249 } 1250 if (f.getType() != fieldType) { 1251 throw new RuntimeException("bad redefinition of field type: " + t.getInput()); 1252 } 1253 return; 1254 } 1255 } 1256 1257 // Create field by type 1258 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1259 db.createField(containingType, 1260 fieldName, fieldType, 1261 isStatic, 1262 offset, 1263 staticAddress); 1264 1265 } 1266 } 1267 1268 }, 1269 new ClhsdbCommand("tokenize", "tokenize ...", true) { 1270 @Override 1271 public void doit(Tokens t, PrintStream out) { 1272 while (t.hasMoreTokens()) { 1273 out.println("\"" + t.nextToken() + "\""); 1274 } 1275 } 1276 }, 1277 new ClhsdbCommand("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { 1278 @Override 1279 public void doit(Tokens t, PrintStream out) { 1280 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 1281 usage(); 1282 return; 1283 } 1284 if (t.countTokens() == 6) { 1285 String typeName = t.nextToken(); 1286 String superclassName = t.nextToken(); 1287 if (superclassName.equals("null")) { 1288 superclassName = null; 1289 } 1290 boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue(); 1291 boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue(); 1292 boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue(); 1293 long size = Long.parseLong(t.nextToken()); 1294 1295 BasicType type = null; 1296 try { 1297 type = (BasicType)agent.getTypeDataBase().lookupType(typeName); 1298 } catch (RuntimeException e) { 1299 } 1300 if (type != null) { 1301 if (type.isOopType() != isOop) { 1302 throw new RuntimeException("oop mismatch in type definition: " + t.getInput()); 1303 } 1304 if (type.isCIntegerType() != isInteger) { 1305 throw new RuntimeException("integer type mismatch in type definition: " + t.getInput()); 1306 } 1307 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { 1308 throw new RuntimeException("unsigned mismatch in type definition: " + t.getInput()); 1309 } 1310 if (type.getSuperclass() == null) { 1311 if (superclassName != null) { 1312 if (type.getSize() == -1) { 1313 type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName)); 1314 } else { 1315 throw new RuntimeException("unexpected superclass in type definition: " + t.getInput()); 1316 } 1317 } 1318 } else { 1319 if (superclassName == null) { 1320 throw new RuntimeException("missing superclass in type definition: " + t.getInput()); 1321 } 1322 if (!type.getSuperclass().getName().equals(superclassName)) { 1323 throw new RuntimeException("incorrect superclass in type definition: " + t.getInput()); 1324 } 1325 } 1326 if (type.getSize() != size) { 1327 if (type.getSize() == -1) { 1328 type.setSize(size); 1329 } 1330 throw new RuntimeException("size mismatch in type definition: " + t.getInput()); 1331 } 1332 return; 1333 } 1334 1335 // Create type 1336 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1337 db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size); 1338 } else if (t.countTokens() == 1) { 1339 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1340 dumpType(type); 1341 } else { 1342 Iterator i = agent.getTypeDataBase().getTypes(); 1343 // Make sure the types are emitted in an order than can be read back in 1344 HashSet emitted = new HashSet(); 1345 Stack pending = new Stack(); 1346 while (i.hasNext()) { 1347 Type n = (Type)i.next(); 1348 if (emitted.contains(n.getName())) { 1349 continue; 1350 } 1351 1352 while (n != null && !emitted.contains(n.getName())) { 1353 pending.push(n); 1354 n = n.getSuperclass(); 1355 } 1356 while (!pending.empty()) { 1357 n = (Type)pending.pop(); 1358 dumpType(n); 1359 emitted.add(n.getName()); 1360 } 1361 } 1362 } 1363 } 1364 1365 }, 1366 new ClhsdbCommand("source", "source filename", true) { 1367 @Override 1368 public void doit(Tokens t, PrintStream out) { 1369 if (t.countTokens() != 1) { 1370 usage(); 1371 return; 1372 } 1373 String file = t.nextToken(); 1374 BufferedReader savedInput = in; 1375 try { 1376 BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 1377 in = input; 1378 run(false); 1379 } catch (Exception e) { 1380 out.println("Error: " + e); 1381 if (verboseExceptions) { 1382 e.printStackTrace(out); 1383 } 1384 } finally { 1385 in = savedInput; 1386 } 1387 1388 } 1389 }, 1390 new ClhsdbCommand("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) { 1391 @Override 1392 public void doit(Tokens t, PrintStream out) { 1393 if (t.countTokens() != 2) { 1394 usage(); 1395 return; 1396 } 1397 String type = t.nextToken(); 1398 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1399 final long stride = VM.getVM().getAddressSize(); 1400 if (type.equals("threads")) { 1401 Threads threads = VM.getVM().getThreads(); 1402 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1403 JavaThread thread = threads.getJavaThreadAt(i); 1404 Address base = thread.getStackBase(); 1405 Address end = thread.getLastJavaSP(); 1406 if (end == null) continue; 1407 if (end.lessThan(base)) { 1408 Address tmp = base; 1409 base = end; 1410 end = tmp; 1411 } 1412 //out.println("Searching " + base + " " + end); 1477 } catch (Exception e) { 1478 out.println("Exception printing blob at " + base); 1479 e.printStackTrace(); 1480 } 1481 } 1482 out.println("found at " + base + "\n"); 1483 } 1484 base = base.addOffsetTo(stride); 1485 } 1486 } 1487 public void epilogue() { 1488 } 1489 1490 1491 }; 1492 VM.getVM().getCodeCache().iterate(v); 1493 1494 } 1495 } 1496 }, 1497 new ClhsdbCommand("dumpcodecache", "dumpcodecache", false) { 1498 @Override 1499 public void doit(Tokens t, PrintStream out) { 1500 if (t.countTokens() != 0) { 1501 usage(); 1502 } else { 1503 final PrintStream fout = out; 1504 final HTMLGenerator gen = new HTMLGenerator(false); 1505 CodeCacheVisitor v = new CodeCacheVisitor() { 1506 public void prologue(Address start, Address end) { 1507 } 1508 public void visit(CodeBlob blob) { 1509 fout.println(gen.genHTML(blob.contentBegin())); 1510 } 1511 public void epilogue() { 1512 } 1513 1514 1515 }; 1516 VM.getVM().getCodeCache().iterate(v); 1517 } 1518 } 1519 }, 1520 new ClhsdbCommand("where", "where { -a | id }", false) { 1521 @Override 1522 public void doit(Tokens t, PrintStream out) { 1523 if (t.countTokens() != 1) { 1524 usage(); 1525 } else { 1526 String name = t.nextToken(); 1527 Threads threads = VM.getVM().getThreads(); 1528 boolean all = name.equals("-a"); 1529 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1530 JavaThread thread = threads.getJavaThreadAt(i); 1531 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1532 thread.printThreadIDOn(new PrintStream(bos)); 1533 if (all || bos.toString().equals(name)) { 1534 out.println("Thread " + bos.toString() + " Address: " + thread.getAddress()); 1535 HTMLGenerator gen = new HTMLGenerator(false); 1536 try { 1537 out.println(gen.genHTMLForJavaStackTrace(thread)); 1538 } catch (Exception e) { 1539 err.println("Error: " + e); 1540 if (verboseExceptions) { 1541 e.printStackTrace(err); 1542 } 1543 } 1544 if (!all) return; 1545 } 1546 } 1547 if (!all) out.println("Couldn't find thread " + name); 1548 } 1549 } 1550 }, 1551 new ClhsdbCommand("thread", "thread { -a | id }", false) { 1552 @Override 1553 public void doit(Tokens t, PrintStream out) { 1554 if (t.countTokens() != 1) { 1555 usage(); 1556 } else { 1557 String name = t.nextToken(); 1558 Threads threads = VM.getVM().getThreads(); 1559 boolean all = name.equals("-a"); 1560 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1561 JavaThread thread = threads.getJavaThreadAt(i); 1562 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1563 thread.printThreadIDOn(new PrintStream(bos)); 1564 if (all || bos.toString().equals(name)) { 1565 out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); 1566 thread.printInfoOn(out); 1567 out.println(" "); 1568 if (!all) return; 1569 } 1570 } 1571 if (!all) { 1572 out.println("Couldn't find thread " + name); 1573 } 1574 } 1575 } 1576 }, 1577 1578 new ClhsdbCommand("threads", false) { 1579 public void doit(Tokens t, PrintStream out) { 1580 if (t.countTokens() != 0) { 1581 usage(); 1582 } else { 1583 Threads threads = VM.getVM().getThreads(); 1584 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1585 JavaThread thread = threads.getJavaThreadAt(i); 1586 thread.printThreadIDOn(out); 1587 out.println(" " + thread.getThreadName()); 1588 thread.printInfoOn(out); 1589 out.println("\n..."); 1590 } 1591 } 1592 } 1593 }, 1594 1595 new ClhsdbCommand("livenmethods", false) { 1596 @Override 1597 public void doit(Tokens t, PrintStream out) { 1598 if (t.countTokens() != 0) { 1599 usage(); 1600 } else { 1601 ArrayList nmethods = new ArrayList(); 1602 Threads threads = VM.getVM().getThreads(); 1603 HTMLGenerator gen = new HTMLGenerator(false); 1604 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 1605 JavaThread thread = threads.getJavaThreadAt(i); 1606 try { 1607 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 1608 if (vf instanceof CompiledVFrame) { 1609 NMethod c = ((CompiledVFrame)vf).getCode(); 1610 if (!nmethods.contains(c)) { 1611 nmethods.add(c); 1612 out.println(gen.genHTML(c)); 1613 } 1614 } 1615 } 1616 } catch (Exception e) { 1617 e.printStackTrace(); 1618 } 1619 } 1620 } 1621 } 1622 }, 1623 new ClhsdbCommand("g1regiondetails", false) { 1624 @Override 1625 public void doit(Tokens t, PrintStream out) { 1626 if (t.countTokens() != 0) { 1627 usage(); 1628 } else { 1629 CollectedHeap heap = VM.getVM().getUniverse().heap(); 1630 if (!(heap instanceof G1CollectedHeap)) { 1631 out.println("This command is valid only for G1GC."); 1632 return; 1633 } 1634 out.println("Region Details:"); 1635 ((G1CollectedHeap)heap).printRegionDetails(out); 1636 } 1637 } 1638 }, 1639 new ClhsdbCommand("universe", false) { 1640 @Override 1641 public void doit(Tokens t, PrintStream out) { 1642 if (t.countTokens() != 0) { 1643 usage(); 1644 } else { 1645 Universe u = VM.getVM().getUniverse(); 1646 out.println("Heap Parameters:"); 1647 u.heap().printOn(out); 1648 } 1649 } 1650 }, 1651 new ClhsdbCommand("verbose", "verbose true | false", true) { 1652 @Override 1653 public void doit(Tokens t, PrintStream out) { 1654 if (t.countTokens() != 1) { 1655 usage(); 1656 } else { 1657 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); 1658 } 1659 } 1660 }, 1661 new ClhsdbCommand("assert", "assert true | false", true) { 1662 @Override 1663 public void doit(Tokens t, PrintStream out) { 1664 if (t.countTokens() != 1) { 1665 usage(); 1666 } else { 1667 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); 1668 } 1669 } 1670 }, 1671 new ClhsdbCommand("load_plugin", "load_plugin [path]", true) { 1672 @Override 1673 public void doit(Tokens t, PrintStream out) { 1674 if (t.countTokens() != 1) { 1675 usage(); 1676 } else { 1677 registerCommand(Path.of(t.nextToken())); 1678 } 1679 } 1680 }, 1681 }; 1682 1683 private boolean verboseExceptions = false; 1684 private ArrayList history = new ArrayList(); 1685 private HashMap commands = new HashMap(); 1686 private boolean doEcho = false; 1687 1688 private Command findCommand(String key) { 1689 return (Command)commands.get(key); 1690 } 1691 1692 public void printPrompt() { 1693 out.print("hsdb> "); 1694 } 1695 1696 private DebuggerInterface debugger; 1697 private HotSpotAgent agent; 1698 private JSJavaScriptEngine jsengine; 1699 private BufferedReader in; 1700 private PrintStream out; 1739 this.getClass().getMethod("registerCommand", 1740 new Class[] { 1741 String.class, String.class, String.class 1742 })); 1743 } catch (NoSuchMethodException exp) { 1744 // should not happen, see below...!! 1745 exp.printStackTrace(); 1746 } 1747 jsengine.start(); 1748 } 1749 catch (Exception ex) { 1750 System.out.println("Warning! JS Engine can't start, some commands will not be available."); 1751 if (verboseExceptions) { 1752 ex.printStackTrace(out); 1753 } 1754 } 1755 */ 1756 } 1757 1758 public void registerCommand(String cmd, String usage, final String func) { 1759 commands.put(cmd, new ClhsdbCommand(cmd, usage, false) { 1760 @Override 1761 public void doit(Tokens t, PrintStream out) { 1762 final int len = t.countTokens(); 1763 Object[] args = new Object[len]; 1764 for (int i = 0; i < len; i++) { 1765 args[i] = t.nextToken(); 1766 } 1767 jsengine.call(func, args); 1768 } 1769 }); 1770 } 1771 1772 public void registerCommand(Path path) { 1773 Module saModule = this.getClass().getModule(); 1774 ModuleLayer saLayer = saModule.getLayer(); 1775 1776 // Create new module for the path 1777 ModuleFinder finder = ModuleFinder.of(path); 1778 Set<String> moduleNames = finder.findAll() 1779 .stream() 1780 .map(r -> r.descriptor().name()) 1781 .peek(m -> System.out.println("Module found: " + m)) 1782 .collect(Collectors.toSet()); 1783 1784 Configuration conf = saLayer.configuration() 1785 .resolveAndBind(finder, ModuleFinder.of(), moduleNames); 1786 ModuleLayer layer = saLayer.defineModulesWithOneLoader(conf, saModule.getClassLoader()); 1787 1788 // Export all SA packages to the new module 1789 layer.modules() 1790 .stream() 1791 .forEach(m -> saModule.getPackages() 1792 .stream() 1793 .forEach(p -> saModule.addExports(p, m))); 1794 1795 // Register command in the new module 1796 ServiceLoader.load(layer, Command.class) 1797 .stream() 1798 .map(ServiceLoader.Provider::get) 1799 .peek(s -> System.out.println("Installing: " + s.name())) 1800 .forEach(s -> commands.put(s.name(), s)); 1801 } 1802 1803 public void setOutput(PrintStream o) { 1804 out = o; 1805 } 1806 1807 public void setErr(PrintStream e) { 1808 err = e; 1809 } 1810 1811 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { 1812 this.debugger = debugger; 1813 this.agent = debugger.getAgent(); 1814 this.in = in; 1815 this.out = out; 1816 this.err = err; 1817 for (int i = 0; i < commandList.length; i++) { 1818 Command c = commandList[i]; 1819 if (commands.get(c.name()) != null) { 1820 throw new InternalError(c.name() + " has multiple definitions"); 1821 } 1822 commands.put(c.name(), c); 1823 } 1824 if (debugger.isAttached()) { 1825 postAttach(); 1826 } 1827 } 1828 1829 1830 public void run(boolean prompt) { 1831 // Process interactive commands. 1832 while (!quit) { 1833 if (prompt) printPrompt(); 1834 String ln = null; 1835 try { 1836 ln = in.readLine(); 1837 } catch (IOException e) { 1838 } 1839 if (ln == null) { 1840 if (prompt) err.println("Input stream closed."); 1841 return; 1842 } 1970 } finally { 1971 if (redirect != null) { 1972 out = savedout; 1973 redirect.close(); 1974 } 1975 } 1976 } 1977 } 1978 } 1979 1980 void executeCommand(Tokens args) { 1981 String cmd = args.nextToken(); 1982 1983 Command doit = findCommand(cmd); 1984 1985 /* 1986 * Check for an unknown command 1987 */ 1988 if (doit == null) { 1989 out.println("Unrecognized command. Try help..."); 1990 } else if (!debugger.isAttached() && !doit.okIfDisconnected()) { 1991 out.println("Command not valid until attached to a VM"); 1992 } else { 1993 try { 1994 doit.doit(args, out); 1995 } catch (Exception e) { 1996 out.println("Error: " + e); 1997 if (verboseExceptions) { 1998 e.printStackTrace(out); 1999 } 2000 } 2001 } 2002 } 2003 } |