1 /* 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 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 with null classloader 553 // will go in boot.jar and everything else will go in 554 // app.jar. boot.jar usually not needed, unless changed by jvmti. 555 public void doit(Tokens t) { 556 int tcount = t.countTokens(); 557 if (tcount > 2) { 558 usage(); 559 return; 560 } 561 try { 562 String prefix = ""; 563 String option = "all"; // default 564 switch(tcount) { 565 case 0: 566 break; 567 case 1: 568 option = t.nextToken(); 569 if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") && 570 !option.equalsIgnoreCase("root")) { 571 prefix = option; 572 option = "all"; 573 } 574 break; 575 case 2: 576 option = t.nextToken(); 577 prefix = t.nextToken(); 578 break; 579 default: 580 usage(); 581 return; 582 } 583 if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") && 584 !option.equalsIgnoreCase("boot")) { 585 usage(); 586 return; 587 } 588 ClassDump cd = new ClassDump(); 589 if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) { 590 cd.setClassFilter(new BootFilter()); 591 cd.setJarOutput(prefix + "boot.jar"); 592 cd.run(); 593 } 594 if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) { 595 cd.setClassFilter(new NonBootFilter()); 596 cd.setJarOutput(prefix + "app.jar"); 597 cd.run(); 598 } 599 } catch (IOException ioe) { 600 ioe.printStackTrace(); 601 } 602 } 603 }, 604 new Command("findpc", "findpc address", false) { 605 public void doit(Tokens t) { 606 if (t.countTokens() != 1) { 607 usage(); 608 } else { 609 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 610 PointerLocation loc = PointerFinder.find(a); 611 loc.printOn(out); 612 } 613 } 614 }, 615 new Command("symbol", "symbol address", false) { 616 public void doit(Tokens t) { 617 if (t.countTokens() != 1) { 618 usage(); 619 } else { 620 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 621 Symbol.create(a).printValueOn(out); 622 out.println(); 623 } 624 } 625 }, 626 new Command("symboltable", "symboltable name", false) { 627 public void doit(Tokens t) { 628 if (t.countTokens() != 1) { 629 usage(); 630 } else { 631 out.println(SymbolTable.getTheTable().probe(t.nextToken())); 632 } 633 } 634 }, 635 new Command("symboldump", "symboldump", false) { 636 public void doit(Tokens t) { 637 SymbolTable.getTheTable().symbolsDo(new SymbolTable.SymbolVisitor() { 638 public void visit(Symbol sym) { 639 sym.printValueOn(out); 640 out.println(); 641 } 642 }); 643 } 644 }, 645 new Command("flags", "flags [ flag | -nd ]", false) { 646 public void doit(Tokens t) { 647 int tokens = t.countTokens(); 648 if (tokens != 0 && tokens != 1) { 649 usage(); 650 } else { 651 String name = tokens > 0 ? t.nextToken() : null; 652 boolean nonDefault = false; 653 if (name != null && name.equals("-nd")) { 654 name = null; 655 nonDefault = true; 656 } 657 658 VM.Flag[] flags = VM.getVM().getCommandLineFlags(); 659 if (flags == null) { 660 out.println("Command Flag info not available (use 1.4.1_03 or later)!"); 661 } else { 662 boolean printed = false; 663 for (int f = 0; f < flags.length; f++) { 664 VM.Flag flag = flags[f]; 665 if (name == null || flag.getName().equals(name)) { 666 667 if (nonDefault && flag.getOrigin() == 0) { 668 // only print flags which aren't their defaults 669 continue; 670 } 671 out.println(flag.getName() + " = " + flag.getValue() + " " + flag.getOrigin()); 672 printed = true; 673 } 674 } 675 if (name != null && !printed) { 676 out.println("Couldn't find flag: " + name); 677 } 678 } 679 } 680 } 681 }, 682 new Command("help", "help [ command ]", true) { 683 public void doit(Tokens t) { 684 int tokens = t.countTokens(); 685 Command cmd = null; 686 if (tokens == 1) { 687 cmd = findCommand(t.nextToken()); 688 } 689 690 if (cmd != null) { 691 cmd.usage(); 692 } else if (tokens == 0) { 693 out.println("Available commands:"); 694 Object[] keys = commands.keySet().toArray(); 695 Arrays.sort(keys, new Comparator() { 696 public int compare(Object o1, Object o2) { 697 return o1.toString().compareTo(o2.toString()); 698 } 699 }); 700 for (int i = 0; i < keys.length; i++) { 701 out.print(" "); 702 out.println(((Command)commands.get(keys[i])).usage); 703 } 704 } 705 } 706 }, 707 new Command("history", "history", true) { 708 public void doit(Tokens t) { 709 int tokens = t.countTokens(); 710 if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) { 711 usage(); 712 return; 713 } 714 boolean printIndex = tokens == 0; 715 for (int i = 0; i < history.size(); i++) { 716 if (printIndex) out.print(i + " "); 717 out.println(history.get(i)); 718 } 719 } 720 }, 721 // decode raw address 722 new Command("dis", "dis address [length]", false) { 723 public void doit(Tokens t) { 724 int tokens = t.countTokens(); 725 if (tokens != 1 && tokens != 2) { 726 usage(); 727 return; 728 } 729 String name = t.nextToken(); 730 Address addr = null; 731 int len = 0x10; // default length 732 try { 733 addr = VM.getVM().getDebugger().parseAddress(name); 734 } catch (NumberFormatException e) { 735 out.println(e); 736 return; 737 } 738 if (tokens == 2) { 739 try { 740 len = Integer.parseInt(t.nextToken()); 741 } catch (NumberFormatException e) { 742 out.println(e); 743 return; 744 } 745 } 746 HTMLGenerator generator = new HTMLGenerator(false); 747 out.println(generator.genHTMLForRawDisassembly(addr, len)); 748 } 749 750 }, 751 // decode codeblob or nmethod 752 new Command("disassemble", "disassemble address", false) { 753 public void doit(Tokens t) { 754 int tokens = t.countTokens(); 755 if (tokens != 1) { 756 usage(); 757 return; 758 } 759 String name = t.nextToken(); 760 Address addr = null; 761 try { 762 addr = VM.getVM().getDebugger().parseAddress(name); 763 } catch (NumberFormatException e) { 764 out.println(e); 765 return; 766 } 767 768 HTMLGenerator generator = new HTMLGenerator(false); 769 out.println(generator.genHTML(addr)); 770 } 771 }, 772 // print Java bytecode disassembly 773 new Command("jdis", "jdis address", false) { 774 public void doit(Tokens t) { 775 int tokens = t.countTokens(); 776 if (tokens != 1) { 777 usage(); 778 return; 779 } 780 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 781 Method m = (Method)Metadata.instantiateWrapperFor(a); 782 HTMLGenerator html = new HTMLGenerator(false); 783 out.println(html.genHTML(m)); 784 } 785 }, 786 new Command("revptrs", "revptrs address", false) { 787 public void doit(Tokens t) { 788 int tokens = t.countTokens(); 789 if (tokens != 1 && (tokens != 2 || !t.nextToken().equals("-c"))) { 790 usage(); 791 return; 792 } 793 boolean chase = tokens == 2; 794 ReversePtrs revptrs = VM.getVM().getRevPtrs(); 795 if (revptrs == null) { 796 out.println("Computing reverse pointers..."); 797 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); 798 final boolean[] complete = new boolean[1]; 799 HeapProgressThunk thunk = new HeapProgressThunk() { 800 public void heapIterationFractionUpdate(double d) {} 801 public synchronized void heapIterationComplete() { 802 complete[0] = true; 803 notify(); 804 } 805 }; 806 analysis.setHeapProgressThunk(thunk); 807 analysis.run(); 808 while (!complete[0]) { 809 synchronized (thunk) { 810 try { 811 thunk.wait(); 812 } catch (Exception e) { 813 } 814 } 815 } 816 revptrs = VM.getVM().getRevPtrs(); 817 out.println("Done."); 818 } 819 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 820 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 821 OopHandle handle = a.addOffsetToAsOopHandle(0); 822 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 823 ArrayList ptrs = revptrs.get(oop); 824 if (ptrs == null) { 825 out.println("no live references to " + a); 826 } else { 827 if (chase) { 828 while (ptrs.size() == 1) { 829 LivenessPathElement e = (LivenessPathElement)ptrs.get(0); 830 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 831 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 832 out.println(bos.toString()); 833 ptrs = revptrs.get(e.getObj()); 834 } 835 } else { 836 for (int i = 0; i < ptrs.size(); i++) { 837 LivenessPathElement e = (LivenessPathElement)ptrs.get(i); 838 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 839 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 840 out.println(bos.toString()); 841 oop = e.getObj(); 842 } 843 } 844 } 845 } 846 } 847 }, 848 new Command("printmdo", "printmdo [ -a | expression ]", false) { 849 // Print every MDO in the heap or the one referenced by expression. 850 public void doit(Tokens t) { 851 if (t.countTokens() != 1) { 852 usage(); 853 } else { 854 String s = t.nextToken(); 855 if (s.equals("-a")) { 856 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 857 sysDict.allClassesDo(new SystemDictionary.ClassVisitor() { 858 public void visit(Klass k) { 859 if (k instanceof InstanceKlass) { 860 MethodArray methods = ((InstanceKlass)k).getMethods(); 861 for (int i = 0; i < methods.length(); i++) { 862 Method m = methods.at(i); 863 MethodData mdo = m.getMethodData(); 864 if (mdo != null) { 865 out.println("MethodData " + mdo.getAddress() + " for " + 866 "method " + m.getMethodHolder().getName().asString() + "." + 867 m.getName().asString() + 868 m.getSignature().asString() + "@" + m.getAddress()); 869 mdo.printDataOn(out); 870 } 871 } 872 } 873 } 874 } 875 ); 876 } else { 877 Address a = VM.getVM().getDebugger().parseAddress(s); 878 MethodData mdo = (MethodData) Metadata.instantiateWrapperFor(a); 879 mdo.printDataOn(out); 880 } 881 } 882 } 883 }, 884 new Command("printall", "printall", false) { 885 // Print every MDO in the heap or the one referenced by expression. 886 public void doit(Tokens t) { 887 if (t.countTokens() != 0) { 888 usage(); 889 } else { 890 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 891 sysDict.allClassesDo(new SystemDictionary.ClassVisitor() { 892 public void visit(Klass k) { 893 if (k instanceof InstanceKlass && ((InstanceKlass)k).getConstants().getCache() != null) { 894 MethodArray methods = ((InstanceKlass)k).getMethods(); 895 for (int i = 0; i < methods.length(); i++) { 896 Method m = methods.at(i); 897 HTMLGenerator gen = new HTMLGenerator(false); 898 out.println(gen.genHTML(m)); 899 } 900 } 901 } 902 } 903 ); 904 } 905 } 906 }, 907 new Command("dumpideal", "dumpideal { -a | id }", false) { 908 // Do a full dump of the nodes reachabile from root in each compiler thread. 909 public void doit(Tokens t) { 910 if (t.countTokens() != 1) { 911 usage(); 912 } else { 913 String name = t.nextToken(); 914 boolean all = name.equals("-a"); 915 Threads threads = VM.getVM().getThreads(); 916 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 917 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 918 thread.printThreadIDOn(new PrintStream(bos)); 919 if (all || bos.toString().equals(name)) { 920 if (thread instanceof CompilerThread) { 921 CompilerThread ct = (CompilerThread)thread; 922 out.println(ct); 923 ciEnv env = ct.env(); 924 if (env != null) { 925 Compile c = env.compilerData(); 926 c.root().dump(9999, out); 927 } else { 928 out.println(" not compiling"); 929 } 930 } 931 } 932 } 933 } 934 } 935 }, 936 new Command("dumpcfg", "dumpcfg { -a | id }", false) { 937 // Dump the PhaseCFG for every compiler thread that has one live. 938 public void doit(Tokens t) { 939 if (t.countTokens() != 1) { 940 usage(); 941 } else { 942 String name = t.nextToken(); 943 boolean all = name.equals("-a"); 944 Threads threads = VM.getVM().getThreads(); 945 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 946 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 947 thread.printThreadIDOn(new PrintStream(bos)); 948 if (all || bos.toString().equals(name)) { 949 if (thread instanceof CompilerThread) { 950 CompilerThread ct = (CompilerThread)thread; 951 out.println(ct); 952 ciEnv env = ct.env(); 953 if (env != null) { 954 Compile c = env.compilerData(); 955 c.cfg().dump(out); 956 } 957 } 958 } 959 } 960 } 961 } 962 }, 963 new Command("dumpilt", "dumpilt { -a | id }", false) { 964 // dumps the InlineTree of a C2 compile 965 public void doit(Tokens t) { 966 if (t.countTokens() != 1) { 967 usage(); 968 } else { 969 String name = t.nextToken(); 970 boolean all = name.equals("-a"); 971 Threads threads = VM.getVM().getThreads(); 972 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 973 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 974 thread.printThreadIDOn(new PrintStream(bos)); 975 if (all || bos.toString().equals(name)) { 976 if (thread instanceof CompilerThread) { 977 CompilerThread ct = (CompilerThread)thread; 978 ciEnv env = ct.env(); 979 if (env != null) { 980 Compile c = env.compilerData(); 981 InlineTree ilt = c.ilt(); 982 if (ilt != null) { 983 ilt.print(out); 984 } 985 } 986 } 987 } 988 } 989 } 990 } 991 }, 992 new Command("vmstructsdump", "vmstructsdump", false) { 993 public void doit(Tokens t) { 994 if (t.countTokens() != 0) { 995 usage(); 996 return; 997 } 998 999 // Dump a copy of the type database in a form that can 1000 // be read back. 1001 Iterator i = agent.getTypeDataBase().getTypes(); 1002 // Make sure the types are emitted in an order than can be read back in 1003 HashSet emitted = new HashSet(); 1004 Stack pending = new Stack(); 1005 while (i.hasNext()) { 1006 Type n = (Type)i.next(); 1007 if (emitted.contains(n.getName())) { 1008 continue; 1009 } 1010 1011 while (n != null && !emitted.contains(n.getName())) { 1012 pending.push(n); 1013 n = n.getSuperclass(); 1014 } 1015 while (!pending.empty()) { 1016 n = (Type)pending.pop(); 1017 dumpType(n); 1018 emitted.add(n.getName()); 1019 } 1020 } 1021 i = agent.getTypeDataBase().getTypes(); 1022 while (i.hasNext()) { 1023 dumpFields((Type)i.next(), false); 1024 } 1025 } 1026 }, 1027 1028 new Command("inspect", "inspect expression", false) { 1029 public void doit(Tokens t) { 1030 if (t.countTokens() != 1) { 1031 usage(); 1032 } else { 1033 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1034 SimpleTreeNode node = null; 1035 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 1036 OopHandle handle = a.addOffsetToAsOopHandle(0); 1037 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1038 node = new OopTreeNodeAdapter(oop, null); 1039 1040 out.println("instance of " + node.getValue() + " @ " + a + 1041 " (size = " + oop.getObjectSize() + ")"); 1042 } else if (VM.getVM().getCodeCache().contains(a)) { 1043 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a); 1044 a = blob.headerBegin(); 1045 } 1046 if (node == null) { 1047 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a); 1048 if (type != null) { 1049 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")"); 1050 node = new CTypeTreeNodeAdapter(a, type, null); 1051 } 1052 } 1053 if (node != null) { 1054 printNode(node); 1055 } 1056 } 1057 } 1058 }, 1059 new Command("jhisto", "jhisto", false) { 1060 public void doit(Tokens t) { 1061 ObjectHistogram histo = new ObjectHistogram(); 1062 histo.run(out, err); 1063 } 1064 }, 1065 new Command("jstack", "jstack [-v]", false) { 1066 public void doit(Tokens t) { 1067 boolean verbose = false; 1068 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1069 verbose = true; 1070 } 1071 StackTrace jstack = new StackTrace(verbose, true); 1072 jstack.run(out); 1073 } 1074 }, 1075 new Command("print", "print expression", false) { 1076 public void doit(Tokens t) { 1077 if (t.countTokens() != 1) { 1078 usage(); 1079 } else { 1080 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1081 HTMLGenerator gen = new HTMLGenerator(false); 1082 out.println(gen.genHTML(a)); 1083 } 1084 } 1085 }, 1086 new Command("printas", "printas type expression", false) { 1087 public void doit(Tokens t) { 1088 if (t.countTokens() != 2) { 1089 usage(); 1090 } else { 1091 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1092 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1093 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null); 1094 1095 out.println("pointer to " + type + " @ " + a + 1096 " (size = " + type.getSize() + ")"); 1097 printNode(node); 1098 } 1099 } 1100 }, 1101 new Command("printstatics", "printstatics [ type ]", false) { 1102 public void doit(Tokens t) { 1103 if (t.countTokens() > 1) { 1104 usage(); 1105 } else { 1106 if (t.countTokens() == 0) { 1107 out.println("All known static fields"); 1108 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes())); 1109 } else { 1110 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1111 out.println("Static fields of " + type.getName()); 1112 printNode(new CTypeTreeNodeAdapter(type)); 1113 } 1114 } 1115 } 1116 }, 1117 new Command("pmap", "pmap", false) { 1118 public void doit(Tokens t) { 1119 PMap pmap = new PMap(); 1120 pmap.run(out, debugger.getAgent().getDebugger()); 1121 } 1122 }, 1123 new Command("pstack", "pstack [-v]", false) { 1124 public void doit(Tokens t) { 1125 boolean verbose = false; 1126 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1127 verbose = true; 1128 } 1129 PStack pstack = new PStack(verbose, true); 1130 pstack.run(out, debugger.getAgent().getDebugger()); 1131 } 1132 }, 1133 new Command("quit", true) { 1134 public void doit(Tokens t) { 1135 if (t.countTokens() != 0) { 1136 usage(); 1137 } else { 1138 debugger.detach(); 1139 quit = true; 1140 } 1141 } 1142 }, 1143 new Command("echo", "echo [ true | false ]", true) { 1144 public void doit(Tokens t) { 1145 if (t.countTokens() == 0) { 1146 out.println("echo is " + doEcho); 1147 } else if (t.countTokens() == 1) { 1148 doEcho = Boolean.valueOf(t.nextToken()).booleanValue(); 1149 } else { 1150 usage(); 1151 } 1152 } 1153 }, 1154 new Command("versioncheck", "versioncheck [ true | false ]", true) { 1155 public void doit(Tokens t) { 1156 if (t.countTokens() == 0) { 1157 out.println("versioncheck is " + 1158 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); 1159 } else if (t.countTokens() == 1) { 1160 if (Boolean.valueOf(t.nextToken()).booleanValue()) { 1161 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null); 1162 } else { 1163 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true"); 1164 } 1165 } else { 1166 usage(); 1167 } 1168 } 1169 }, 1170 new Command("scanoops", "scanoops start end [ type ]", false) { 1171 public void doit(Tokens t) { 1172 if (t.countTokens() != 2 && t.countTokens() != 3) { 1173 usage(); 1174 } else { 1175 long stride = VM.getVM().getAddressSize(); 1176 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1177 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1178 Klass klass = null; 1179 if (t.countTokens() == 1) { 1180 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); 1181 if (klass == null) { 1182 out.println("No such type."); 1183 return; 1184 } 1185 } 1186 while (base != null && base.lessThan(end)) { 1187 long step = stride; 1188 OopHandle handle = base.addOffsetToAsOopHandle(0); 1189 if (RobustOopDeterminator.oopLooksValid(handle)) { 1190 try { 1191 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1192 if (klass == null || oop.getKlass().isSubtypeOf(klass)) 1193 out.println(handle.toString() + " " + oop.getKlass().getName().asString()); 1194 step = oop.getObjectSize(); 1195 } catch (UnknownOopException ex) { 1196 // ok 1197 } catch (RuntimeException ex) { 1198 ex.printStackTrace(); 1199 } 1200 } 1201 base = base.addOffsetTo(step); 1202 } 1203 } 1204 } 1205 }, 1206 new Command("intConstant", "intConstant [ name [ value ] ]", true) { 1207 public void doit(Tokens t) { 1208 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1209 usage(); 1210 return; 1211 } 1212 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1213 if (t.countTokens() == 1) { 1214 String name = t.nextToken(); 1215 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1216 } else if (t.countTokens() == 0) { 1217 Iterator i = db.getIntConstants(); 1218 while (i.hasNext()) { 1219 String name = (String)i.next(); 1220 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1221 } 1222 } else if (t.countTokens() == 2) { 1223 String name = t.nextToken(); 1224 Integer value = Integer.valueOf(t.nextToken()); 1225 db.addIntConstant(name, value); 1226 } 1227 } 1228 }, 1229 new Command("longConstant", "longConstant [ name [ value ] ]", true) { 1230 public void doit(Tokens t) { 1231 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1232 usage(); 1233 return; 1234 } 1235 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1236 if (t.countTokens() == 1) { 1237 String name = t.nextToken(); 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.getStackBase(); 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 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1460 thread.printThreadIDOn(new PrintStream(bos)); 1461 out.println("found on the stack of thread " + bos.toString() + " at " + base); 1462 } 1463 base = base.addOffsetTo(stride); 1464 } 1465 } 1466 } else if (type.equals("rawheap")) { 1467 RawHeapVisitor iterator = new RawHeapVisitor() { 1468 public void prologue(long used) { 1469 } 1470 1471 public void visitAddress(Address addr) { 1472 Address val = addr.getAddressAt(0); 1473 if (AddressOps.equal(val, value)) { 1474 out.println("found at " + addr); 1475 } 1476 } 1477 public void visitCompOopAddress(Address addr) { 1478 Address val = addr.getCompOopAddressAt(0); 1479 if (AddressOps.equal(val, value)) { 1480 out.println("found at " + addr); 1481 } 1482 } 1483 public void epilogue() { 1484 } 1485 }; 1486 VM.getVM().getObjectHeap().iterateRaw(iterator); 1487 } else if (type.equals("heap")) { 1488 HeapVisitor iterator = new DefaultHeapVisitor() { 1489 public boolean doObj(Oop obj) { 1490 int index = 0; 1491 Address start = obj.getHandle(); 1492 long end = obj.getObjectSize(); 1493 while (index < end) { 1494 Address val = start.getAddressAt(index); 1495 if (AddressOps.equal(val, value)) { 1496 out.println("found in " + obj.getHandle()); 1497 break; 1498 } 1499 index += 4; 1500 } 1501 return false; 1502 } 1503 }; 1504 VM.getVM().getObjectHeap().iterate(iterator); 1505 } else if (type.equals("codecache")) { 1506 CodeCacheVisitor v = new CodeCacheVisitor() { 1507 public void prologue(Address start, Address end) { 1508 } 1509 public void visit(CodeBlob blob) { 1510 boolean printed = false; 1511 Address base = blob.getAddress(); 1512 Address end = base.addOffsetTo(blob.getSize()); 1513 while (base != null && base.lessThan(end)) { 1514 Address val = base.getAddressAt(0); 1515 if (AddressOps.equal(val, value)) { 1516 if (!printed) { 1517 printed = true; 1518 try { 1519 blob.printOn(out); 1520 } catch (Exception e) { 1521 out.println("Exception printing blob at " + base); 1522 e.printStackTrace(); 1523 } 1524 } 1525 out.println("found at " + base + "\n"); 1526 } 1527 base = base.addOffsetTo(stride); 1528 } 1529 } 1530 public void epilogue() { 1531 } 1532 1533 1534 }; 1535 VM.getVM().getCodeCache().iterate(v); 1536 1537 } 1538 } 1539 }, 1540 new Command("dumpcodecache", "dumpcodecache", false) { 1541 public void doit(Tokens t) { 1542 if (t.countTokens() != 0) { 1543 usage(); 1544 } else { 1545 final PrintStream fout = out; 1546 final HTMLGenerator gen = new HTMLGenerator(false); 1547 CodeCacheVisitor v = new CodeCacheVisitor() { 1548 public void prologue(Address start, Address end) { 1549 } 1550 public void visit(CodeBlob blob) { 1551 fout.println(gen.genHTML(blob.contentBegin())); 1552 } 1553 public void epilogue() { 1554 } 1555 1556 1557 }; 1558 VM.getVM().getCodeCache().iterate(v); 1559 } 1560 } 1561 }, 1562 new Command("where", "where { -a | id }", false) { 1563 public void doit(Tokens t) { 1564 if (t.countTokens() != 1) { 1565 usage(); 1566 } else { 1567 String name = t.nextToken(); 1568 Threads threads = VM.getVM().getThreads(); 1569 boolean all = name.equals("-a"); 1570 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 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 (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 1600 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1601 thread.printThreadIDOn(new PrintStream(bos)); 1602 if (all || bos.toString().equals(name)) { 1603 out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); 1604 thread.printInfoOn(out); 1605 out.println(" "); 1606 if (!all) return; 1607 } 1608 } 1609 out.println("Couldn't find thread " + name); 1610 } 1611 } 1612 }, 1613 1614 new Command("threads", false) { 1615 public void doit(Tokens t) { 1616 if (t.countTokens() != 0) { 1617 usage(); 1618 } else { 1619 Threads threads = VM.getVM().getThreads(); 1620 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 1621 thread.printThreadIDOn(out); 1622 out.println(" " + thread.getThreadName()); 1623 thread.printInfoOn(out); 1624 out.println("\n..."); 1625 } 1626 } 1627 } 1628 }, 1629 1630 new Command("livenmethods", false) { 1631 public void doit(Tokens t) { 1632 if (t.countTokens() != 0) { 1633 usage(); 1634 } else { 1635 ArrayList nmethods = new ArrayList(); 1636 Threads threads = VM.getVM().getThreads(); 1637 HTMLGenerator gen = new HTMLGenerator(false); 1638 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 1639 try { 1640 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 1641 if (vf instanceof CompiledVFrame) { 1642 NMethod c = ((CompiledVFrame)vf).getCode(); 1643 if (!nmethods.contains(c)) { 1644 nmethods.add(c); 1645 out.println(gen.genHTML(c)); 1646 } 1647 } 1648 } 1649 } catch (Exception e) { 1650 e.printStackTrace(); 1651 } 1652 } 1653 } 1654 } 1655 }, 1656 new Command("universe", false) { 1657 public void doit(Tokens t) { 1658 if (t.countTokens() != 0) { 1659 usage(); 1660 } else { 1661 Universe u = VM.getVM().getUniverse(); 1662 out.println("Heap Parameters:"); 1663 u.heap().printOn(out); 1664 } 1665 } 1666 }, 1667 new Command("verbose", "verbose true | false", true) { 1668 public void doit(Tokens t) { 1669 if (t.countTokens() != 1) { 1670 usage(); 1671 } else { 1672 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); 1673 } 1674 } 1675 }, 1676 new Command("assert", "assert true | false", true) { 1677 public void doit(Tokens t) { 1678 if (t.countTokens() != 1) { 1679 usage(); 1680 } else { 1681 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); 1682 } 1683 } 1684 }, 1685 }; 1686 1687 private boolean verboseExceptions = false; 1688 private ArrayList history = new ArrayList(); 1689 private HashMap commands = new HashMap(); 1690 private boolean doEcho = false; 1691 1692 private Command findCommand(String key) { 1693 return (Command)commands.get(key); 1694 } 1695 1696 public void printPrompt() { 1697 out.print("hsdb> "); 1698 } 1699 1700 private DebuggerInterface debugger; 1701 private HotSpotAgent agent; 1702 private JSJavaScriptEngine jsengine; 1703 private BufferedReader in; 1704 private PrintStream out; 1705 private PrintStream err; 1706 1707 // called before debuggee attach 1708 private void preAttach() { 1709 // nothing for now.. 1710 } 1711 1712 // called after debuggee attach 1713 private void postAttach() { 1714 // create JavaScript engine and start it 1715 try { 1716 jsengine = new JSJavaScriptEngine() { 1717 private ObjectReader reader = new ObjectReader(); 1718 private JSJavaFactory factory = new JSJavaFactoryImpl(); 1719 public ObjectReader getObjectReader() { 1720 return reader; 1721 } 1722 public JSJavaFactory getJSJavaFactory() { 1723 return factory; 1724 } 1725 protected void quit() { 1726 debugger.detach(); 1727 quit = true; 1728 } 1729 protected BufferedReader getInputReader() { 1730 return in; 1731 } 1732 protected PrintStream getOutputStream() { 1733 return out; 1734 } 1735 protected PrintStream getErrorStream() { 1736 return err; 1737 } 1738 }; 1739 try { 1740 jsengine.defineFunction(this, 1741 this.getClass().getMethod("registerCommand", 1742 new Class[] { 1743 String.class, String.class, String.class 1744 })); 1745 } catch (NoSuchMethodException exp) { 1746 // should not happen, see below...!! 1747 exp.printStackTrace(); 1748 } 1749 jsengine.start(); 1750 } 1751 catch (Exception ex) { 1752 System.out.println("Warning! JS Engine can't start, some commands will not be available."); 1753 if (verboseExceptions) { 1754 ex.printStackTrace(out); 1755 } 1756 } 1757 } 1758 1759 public void registerCommand(String cmd, String usage, final String func) { 1760 commands.put(cmd, new Command(cmd, usage, false) { 1761 public void doit(Tokens t) { 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 setOutput(PrintStream o) { 1773 out = o; 1774 } 1775 1776 public void setErr(PrintStream e) { 1777 err = e; 1778 } 1779 1780 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { 1781 this.debugger = debugger; 1782 this.agent = debugger.getAgent(); 1783 this.in = in; 1784 this.out = out; 1785 this.err = err; 1786 for (int i = 0; i < commandList.length; i++) { 1787 Command c = commandList[i]; 1788 if (commands.get(c.name) != null) { 1789 throw new InternalError(c.name + " has multiple definitions"); 1790 } 1791 commands.put(c.name, c); 1792 } 1793 if (debugger.isAttached()) { 1794 postAttach(); 1795 } 1796 } 1797 1798 1799 public void run(boolean prompt) { 1800 // Process interactive commands. 1801 while (!quit) { 1802 if (prompt) printPrompt(); 1803 String ln = null; 1804 try { 1805 ln = in.readLine(); 1806 } catch (IOException e) { 1807 } 1808 if (ln == null) { 1809 if (prompt) err.println("Input stream closed."); 1810 return; 1811 } 1812 1813 executeCommand(ln, prompt); 1814 } 1815 } 1816 1817 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*)|(![a-zA-Z][^ ]*))"); 1818 1819 public void executeCommand(String ln, boolean putInHistory) { 1820 if (ln.indexOf('!') != -1) { 1821 int size = history.size(); 1822 if (size == 0) { 1823 ln = ""; 1824 err.println("History is empty"); 1825 } else { 1826 StringBuffer result = new StringBuffer(); 1827 Matcher m = historyPattern.matcher(ln); 1828 int start = 0; 1829 while (m.find()) { 1830 if (m.start() > start) { 1831 result.append(ln.substring(start, m.start() - start)); 1832 } 1833 start = m.end(); 1834 1835 String cmd = m.group(); 1836 if (cmd.equals("!!")) { 1837 result.append((String)history.get(history.size() - 1)); 1838 } else if (cmd.equals("!!-")) { 1839 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1840 item.trim(1); 1841 result.append(item.join(" ")); 1842 } else if (cmd.equals("!*")) { 1843 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1844 item.nextToken(); 1845 result.append(item.join(" ")); 1846 } else if (cmd.equals("!$")) { 1847 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1848 result.append(item.at(item.countTokens() - 1)); 1849 } else { 1850 String tail = cmd.substring(1); 1851 switch (tail.charAt(0)) { 1852 case '0': 1853 case '1': 1854 case '2': 1855 case '3': 1856 case '4': 1857 case '5': 1858 case '6': 1859 case '7': 1860 case '8': 1861 case '9': 1862 case '-': { 1863 int index = Integer.parseInt(tail); 1864 if (index < 0) { 1865 index = history.size() + index; 1866 } 1867 if (index > size) { 1868 err.println("No such history item"); 1869 } else { 1870 result.append((String)history.get(index)); 1871 } 1872 break; 1873 } 1874 default: { 1875 for (int i = history.size() - 1; i >= 0; i--) { 1876 String s = (String)history.get(i); 1877 if (s.startsWith(tail)) { 1878 result.append(s); 1879 } 1880 } 1881 } 1882 } 1883 } 1884 } 1885 if (result.length() == 0) { 1886 err.println("malformed history reference"); 1887 ln = ""; 1888 } else { 1889 if (start < ln.length()) { 1890 result.append(ln.substring(start)); 1891 } 1892 ln = result.toString(); 1893 if (!doEcho) { 1894 out.println(ln); 1895 } 1896 } 1897 } 1898 } 1899 1900 if (doEcho) { 1901 out.println("+ " + ln); 1902 } 1903 1904 PrintStream redirect = null; 1905 Tokens t = new Tokens(ln); 1906 if (t.hasMoreTokens()) { 1907 boolean error = false; 1908 if (putInHistory) history.add(ln); 1909 int len = t.countTokens(); 1910 if (len > 2) { 1911 String r = t.at(len - 2); 1912 if (r.equals(">") || r.equals(">>")) { 1913 boolean append = r.length() == 2; 1914 String file = t.at(len - 1); 1915 try { 1916 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append))); 1917 t.trim(2); 1918 } catch (Exception e) { 1919 out.println("Error: " + e); 1920 if (verboseExceptions) { 1921 e.printStackTrace(out); 1922 } 1923 error = true; 1924 } 1925 } 1926 } 1927 if (!error) { 1928 PrintStream savedout = out; 1929 if (redirect != null) { 1930 out = redirect; 1931 } 1932 try { 1933 executeCommand(t); 1934 } catch (Exception e) { 1935 err.println("Error: " + e); 1936 if (verboseExceptions) { 1937 e.printStackTrace(err); 1938 } 1939 } finally { 1940 if (redirect != null) { 1941 out = savedout; 1942 redirect.close(); 1943 } 1944 } 1945 } 1946 } 1947 } 1948 1949 void executeCommand(Tokens args) { 1950 String cmd = args.nextToken(); 1951 1952 Command doit = findCommand(cmd); 1953 1954 /* 1955 * Check for an unknown command 1956 */ 1957 if (doit == null) { 1958 out.println("Unrecognized command. Try help..."); 1959 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { 1960 out.println("Command not valid until attached to a VM"); 1961 } else { 1962 try { 1963 doit.doit(args); 1964 } catch (Exception e) { 1965 out.println("Error: " + e); 1966 if (verboseExceptions) { 1967 e.printStackTrace(out); 1968 } 1969 } 1970 } 1971 } 1972 }