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