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