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