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