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