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