1 /* 2 * Copyright (c) 2005, 2019, 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 boolean allThreads = false; 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 allThreads = name.equals("-a"); 539 VM.getVM().getThreads().doJavaThreads((thread) -> { 540 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 541 thread.printThreadIDOn(new PrintStream(bos)); 542 if (allThreads || 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() == VM.Flags_DEFAULT)) { 653 // only print flags which aren't their defaults 654 continue; 655 } 656 out.println(flag.getName() + " = " + flag.getValue() + " " + flag.getOriginString()); 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 boolean allThreads = false; 895 public void doit(Tokens t) { 896 if (t.countTokens() != 1) { 897 usage(); 898 } else { 899 String name = t.nextToken(); 900 allThreads = name.equals("-a"); 901 VM.getVM().getThreads().doJavaThreads((thread) -> { 902 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 903 thread.printThreadIDOn(new PrintStream(bos)); 904 if (allThreads || 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 VM.getVM().getThreads().doJavaThreads((thread) -> { 930 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 931 thread.printThreadIDOn(new PrintStream(bos)); 932 if (all || bos.toString().equals(name)) { 933 if (thread instanceof CompilerThread) { 934 CompilerThread ct = (CompilerThread)thread; 935 out.println(ct); 936 ciEnv env = ct.env(); 937 if (env != null) { 938 Compile c = env.compilerData(); 939 c.cfg().dump(out); 940 } 941 } 942 } 943 }); 944 } 945 } 946 }, 947 new Command("dumpilt", "dumpilt { -a | id }", false) { 948 // dumps the InlineTree of a C2 compile 949 public void doit(Tokens t) { 950 if (t.countTokens() != 1) { 951 usage(); 952 } else { 953 String name = t.nextToken(); 954 boolean all = name.equals("-a"); 955 VM.getVM().getThreads().doJavaThreads((thread) -> { 956 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 957 thread.printThreadIDOn(new PrintStream(bos)); 958 if (all || bos.toString().equals(name)) { 959 if (thread instanceof CompilerThread) { 960 CompilerThread ct = (CompilerThread)thread; 961 ciEnv env = ct.env(); 962 if (env != null) { 963 Compile c = env.compilerData(); 964 InlineTree ilt = c.ilt(); 965 if (ilt != null) { 966 ilt.print(out); 967 } 968 } 969 } 970 } 971 }); 972 } 973 } 974 }, 975 new Command("vmstructsdump", "vmstructsdump", false) { 976 public void doit(Tokens t) { 977 if (t.countTokens() != 0) { 978 usage(); 979 return; 980 } 981 982 // Dump a copy of the type database in a form that can 983 // be read back. 984 Iterator i = agent.getTypeDataBase().getTypes(); 985 // Make sure the types are emitted in an order than can be read back in 986 HashSet emitted = new HashSet(); 987 Stack pending = new Stack(); 988 while (i.hasNext()) { 989 Type n = (Type)i.next(); 990 if (emitted.contains(n.getName())) { 991 continue; 992 } 993 994 while (n != null && !emitted.contains(n.getName())) { 995 pending.push(n); 996 n = n.getSuperclass(); 997 } 998 while (!pending.empty()) { 999 n = (Type)pending.pop(); 1000 dumpType(n); 1001 emitted.add(n.getName()); 1002 } 1003 } 1004 i = agent.getTypeDataBase().getTypes(); 1005 while (i.hasNext()) { 1006 dumpFields((Type)i.next(), false); 1007 } 1008 } 1009 }, 1010 1011 new Command("inspect", "inspect expression", false) { 1012 public void doit(Tokens t) { 1013 if (t.countTokens() != 1) { 1014 usage(); 1015 } else { 1016 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1017 SimpleTreeNode node = null; 1018 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 1019 OopHandle handle = a.addOffsetToAsOopHandle(0); 1020 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1021 node = new OopTreeNodeAdapter(oop, null); 1022 1023 out.println("instance of " + node.getValue() + " @ " + a + 1024 " (size = " + oop.getObjectSize() + ")"); 1025 } else if (VM.getVM().getCodeCache().contains(a)) { 1026 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a); 1027 a = blob.headerBegin(); 1028 } 1029 if (node == null) { 1030 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a); 1031 if (type == null && VM.getVM().isSharingEnabled()) { 1032 // Check if the value falls in the _md_region 1033 Address loc1 = a.getAddressAt(0); 1034 FileMapInfo cdsFileMapInfo = VM.getVM().getFileMapInfo(); 1035 if (cdsFileMapInfo.inCopiedVtableSpace(loc1)) { 1036 type = cdsFileMapInfo.getTypeForVptrAddress(loc1); 1037 } 1038 1039 } 1040 if (type != null) { 1041 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")"); 1042 node = new CTypeTreeNodeAdapter(a, type, null); 1043 } 1044 } 1045 if (node != null) { 1046 printNode(node); 1047 } 1048 } 1049 } 1050 }, 1051 new Command("jhisto", "jhisto", false) { 1052 public void doit(Tokens t) { 1053 ObjectHistogram histo = new ObjectHistogram(); 1054 histo.run(out, err); 1055 } 1056 }, 1057 new Command("jstack", "jstack [-v]", false) { 1058 public void doit(Tokens t) { 1059 boolean verbose = false; 1060 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1061 verbose = true; 1062 } 1063 StackTrace jstack = new StackTrace(verbose, true); 1064 jstack.run(out); 1065 } 1066 }, 1067 new Command("print", "print expression", false) { 1068 public void doit(Tokens t) { 1069 if (t.countTokens() != 1) { 1070 usage(); 1071 } else { 1072 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1073 HTMLGenerator gen = new HTMLGenerator(false); 1074 out.println(gen.genHTML(a)); 1075 } 1076 } 1077 }, 1078 new Command("printas", "printas type expression", false) { 1079 public void doit(Tokens t) { 1080 if (t.countTokens() != 2) { 1081 usage(); 1082 } else { 1083 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1084 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1085 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null); 1086 1087 out.println("pointer to " + type + " @ " + a + 1088 " (size = " + type.getSize() + ")"); 1089 printNode(node); 1090 } 1091 } 1092 }, 1093 new Command("printstatics", "printstatics [ type ]", false) { 1094 public void doit(Tokens t) { 1095 if (t.countTokens() > 1) { 1096 usage(); 1097 } else { 1098 if (t.countTokens() == 0) { 1099 out.println("All known static fields"); 1100 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes())); 1101 } else { 1102 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1103 out.println("Static fields of " + type.getName()); 1104 printNode(new CTypeTreeNodeAdapter(type)); 1105 } 1106 } 1107 } 1108 }, 1109 new Command("pmap", "pmap", false) { 1110 public void doit(Tokens t) { 1111 PMap pmap = new PMap(); 1112 pmap.run(out, debugger.getAgent().getDebugger()); 1113 } 1114 }, 1115 new Command("pstack", "pstack [-v]", false) { 1116 public void doit(Tokens t) { 1117 boolean verbose = false; 1118 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 1119 verbose = true; 1120 } 1121 PStack pstack = new PStack(verbose, true); 1122 pstack.run(out, debugger.getAgent().getDebugger()); 1123 } 1124 }, 1125 new Command("quit", true) { 1126 public void doit(Tokens t) { 1127 if (t.countTokens() != 0) { 1128 usage(); 1129 } else { 1130 debugger.detach(); 1131 quit = true; 1132 } 1133 } 1134 }, 1135 new Command("echo", "echo [ true | false ]", true) { 1136 public void doit(Tokens t) { 1137 if (t.countTokens() == 0) { 1138 out.println("echo is " + doEcho); 1139 } else if (t.countTokens() == 1) { 1140 doEcho = Boolean.valueOf(t.nextToken()).booleanValue(); 1141 } else { 1142 usage(); 1143 } 1144 } 1145 }, 1146 new Command("versioncheck", "versioncheck [ true | false ]", true) { 1147 public void doit(Tokens t) { 1148 if (t.countTokens() == 0) { 1149 out.println("versioncheck is " + 1150 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); 1151 } else if (t.countTokens() == 1) { 1152 if (Boolean.valueOf(t.nextToken()).booleanValue()) { 1153 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null); 1154 } else { 1155 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true"); 1156 } 1157 } else { 1158 usage(); 1159 } 1160 } 1161 }, 1162 new Command("scanoops", "scanoops start end [ type ]", false) { 1163 public void doit(Tokens t) { 1164 if (t.countTokens() != 2 && t.countTokens() != 3) { 1165 usage(); 1166 } else { 1167 long stride = VM.getVM().getAddressSize(); 1168 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1169 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1170 Klass klass = null; 1171 if (t.countTokens() == 1) { 1172 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); 1173 if (klass == null) { 1174 out.println("No such type."); 1175 return; 1176 } 1177 } 1178 while (base != null && base.lessThan(end)) { 1179 long step = stride; 1180 OopHandle handle = base.addOffsetToAsOopHandle(0); 1181 if (RobustOopDeterminator.oopLooksValid(handle)) { 1182 try { 1183 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1184 if (klass == null || oop.getKlass().isSubtypeOf(klass)) 1185 out.println(handle.toString() + " " + oop.getKlass().getName().asString()); 1186 step = oop.getObjectSize(); 1187 } catch (UnknownOopException ex) { 1188 // ok 1189 } catch (RuntimeException ex) { 1190 ex.printStackTrace(); 1191 } 1192 } 1193 base = base.addOffsetTo(step); 1194 } 1195 } 1196 } 1197 }, 1198 new Command("intConstant", "intConstant [ name [ value ] ]", true) { 1199 public void doit(Tokens t) { 1200 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1201 usage(); 1202 return; 1203 } 1204 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1205 if (t.countTokens() == 1) { 1206 String name = t.nextToken(); 1207 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1208 } else if (t.countTokens() == 0) { 1209 Iterator i = db.getIntConstants(); 1210 while (i.hasNext()) { 1211 String name = (String)i.next(); 1212 out.println("intConstant " + name + " " + db.lookupIntConstant(name)); 1213 } 1214 } else if (t.countTokens() == 2) { 1215 String name = t.nextToken(); 1216 Integer value = Integer.valueOf(t.nextToken()); 1217 db.addIntConstant(name, value); 1218 } 1219 } 1220 }, 1221 new Command("longConstant", "longConstant [ name [ value ] ]", true) { 1222 public void doit(Tokens t) { 1223 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { 1224 usage(); 1225 return; 1226 } 1227 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1228 if (t.countTokens() == 1) { 1229 String name = t.nextToken(); 1230 out.println("longConstant " + name + " " + db.lookupLongConstant(name)); 1231 } else if (t.countTokens() == 0) { 1232 Iterator i = db.getLongConstants(); 1233 while (i.hasNext()) { 1234 String name = (String)i.next(); 1235 out.println("longConstant " + name + " " + db.lookupLongConstant(name)); 1236 } 1237 } else if (t.countTokens() == 2) { 1238 String name = t.nextToken(); 1239 Long value = Long.valueOf(t.nextToken()); 1240 db.addLongConstant(name, value); 1241 } 1242 } 1243 }, 1244 new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { 1245 public void doit(Tokens t) { 1246 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 1247 usage(); 1248 return; 1249 } 1250 if (t.countTokens() == 1) { 1251 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1252 dumpFields(type); 1253 } else if (t.countTokens() == 0) { 1254 Iterator i = agent.getTypeDataBase().getTypes(); 1255 while (i.hasNext()) { 1256 dumpFields((Type)i.next()); 1257 } 1258 } else { 1259 BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken()); 1260 1261 String fieldName = t.nextToken(); 1262 1263 // The field's Type must already be in the database -- no exceptions 1264 Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken()); 1265 1266 boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue(); 1267 long offset = Long.parseLong(t.nextToken()); 1268 Address staticAddress = parseAddress(t.nextToken()); 1269 if (isStatic && staticAddress == null) { 1270 staticAddress = lookup(containingType.getName() + "::" + fieldName); 1271 } 1272 1273 // check to see if the field already exists 1274 Iterator i = containingType.getFields(); 1275 while (i.hasNext()) { 1276 Field f = (Field) i.next(); 1277 if (f.getName().equals(fieldName)) { 1278 if (f.isStatic() != isStatic) { 1279 throw new RuntimeException("static/nonstatic mismatch: " + t.input); 1280 } 1281 if (!isStatic) { 1282 if (f.getOffset() != offset) { 1283 throw new RuntimeException("bad redefinition of field offset: " + t.input); 1284 } 1285 } else { 1286 if (!f.getStaticFieldAddress().equals(staticAddress)) { 1287 throw new RuntimeException("bad redefinition of field location: " + t.input); 1288 } 1289 } 1290 if (f.getType() != fieldType) { 1291 throw new RuntimeException("bad redefinition of field type: " + t.input); 1292 } 1293 return; 1294 } 1295 } 1296 1297 // Create field by type 1298 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1299 db.createField(containingType, 1300 fieldName, fieldType, 1301 isStatic, 1302 offset, 1303 staticAddress); 1304 1305 } 1306 } 1307 1308 }, 1309 new Command("tokenize", "tokenize ...", true) { 1310 public void doit(Tokens t) { 1311 while (t.hasMoreTokens()) { 1312 out.println("\"" + t.nextToken() + "\""); 1313 } 1314 } 1315 }, 1316 new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { 1317 public void doit(Tokens t) { 1318 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 1319 usage(); 1320 return; 1321 } 1322 if (t.countTokens() == 6) { 1323 String typeName = t.nextToken(); 1324 String superclassName = t.nextToken(); 1325 if (superclassName.equals("null")) { 1326 superclassName = null; 1327 } 1328 boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue(); 1329 boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue(); 1330 boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue(); 1331 long size = Long.parseLong(t.nextToken()); 1332 1333 BasicType type = null; 1334 try { 1335 type = (BasicType)agent.getTypeDataBase().lookupType(typeName); 1336 } catch (RuntimeException e) { 1337 } 1338 if (type != null) { 1339 if (type.isOopType() != isOop) { 1340 throw new RuntimeException("oop mismatch in type definition: " + t.input); 1341 } 1342 if (type.isCIntegerType() != isInteger) { 1343 throw new RuntimeException("integer type mismatch in type definition: " + t.input); 1344 } 1345 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { 1346 throw new RuntimeException("unsigned mismatch in type definition: " + t.input); 1347 } 1348 if (type.getSuperclass() == null) { 1349 if (superclassName != null) { 1350 if (type.getSize() == -1) { 1351 type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName)); 1352 } else { 1353 throw new RuntimeException("unexpected superclass in type definition: " + t.input); 1354 } 1355 } 1356 } else { 1357 if (superclassName == null) { 1358 throw new RuntimeException("missing superclass in type definition: " + t.input); 1359 } 1360 if (!type.getSuperclass().getName().equals(superclassName)) { 1361 throw new RuntimeException("incorrect superclass in type definition: " + t.input); 1362 } 1363 } 1364 if (type.getSize() != size) { 1365 if (type.getSize() == -1) { 1366 type.setSize(size); 1367 } 1368 throw new RuntimeException("size mismatch in type definition: " + t.input); 1369 } 1370 return; 1371 } 1372 1373 // Create type 1374 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 1375 db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size); 1376 } else if (t.countTokens() == 1) { 1377 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 1378 dumpType(type); 1379 } else { 1380 Iterator i = agent.getTypeDataBase().getTypes(); 1381 // Make sure the types are emitted in an order than can be read back in 1382 HashSet emitted = new HashSet(); 1383 Stack pending = new Stack(); 1384 while (i.hasNext()) { 1385 Type n = (Type)i.next(); 1386 if (emitted.contains(n.getName())) { 1387 continue; 1388 } 1389 1390 while (n != null && !emitted.contains(n.getName())) { 1391 pending.push(n); 1392 n = n.getSuperclass(); 1393 } 1394 while (!pending.empty()) { 1395 n = (Type)pending.pop(); 1396 dumpType(n); 1397 emitted.add(n.getName()); 1398 } 1399 } 1400 } 1401 } 1402 1403 }, 1404 new Command("source", "source filename", true) { 1405 public void doit(Tokens t) { 1406 if (t.countTokens() != 1) { 1407 usage(); 1408 return; 1409 } 1410 String file = t.nextToken(); 1411 BufferedReader savedInput = in; 1412 try { 1413 BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 1414 in = input; 1415 run(false); 1416 } catch (Exception e) { 1417 out.println("Error: " + e); 1418 if (verboseExceptions) { 1419 e.printStackTrace(out); 1420 } 1421 } finally { 1422 in = savedInput; 1423 } 1424 1425 } 1426 }, 1427 new Command("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) { 1428 public void doit(Tokens t) { 1429 if (t.countTokens() != 2) { 1430 usage(); 1431 return; 1432 } 1433 String type = t.nextToken(); 1434 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken()); 1435 final long stride = VM.getVM().getAddressSize(); 1436 if (type.equals("threads")) { 1437 VM.getVM().getThreads().doJavaThreads((thread) -> { 1438 Address base = thread.getStackBase(); 1439 Address end = thread.getLastJavaSP(); 1440 if (end == null) return; 1441 if (end.lessThan(base)) { 1442 Address tmp = base; 1443 base = end; 1444 end = tmp; 1445 } 1446 //out.println("Searching " + base + " " + end); 1447 while (base != null && base.lessThan(end)) { 1448 Address val = base.getAddressAt(0); 1449 if (AddressOps.equal(val, value)) { 1450 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1451 thread.printThreadIDOn(new PrintStream(bos)); 1452 out.println("found on the stack of thread " + bos.toString() + " at " + base); 1453 } 1454 base = base.addOffsetTo(stride); 1455 } 1456 }); 1457 } else if (type.equals("rawheap")) { 1458 RawHeapVisitor iterator = new RawHeapVisitor() { 1459 public void prologue(long used) { 1460 } 1461 1462 public void visitAddress(Address addr) { 1463 Address val = addr.getAddressAt(0); 1464 if (AddressOps.equal(val, value)) { 1465 out.println("found at " + addr); 1466 } 1467 } 1468 public void visitCompOopAddress(Address addr) { 1469 Address val = addr.getCompOopAddressAt(0); 1470 if (AddressOps.equal(val, value)) { 1471 out.println("found at " + addr); 1472 } 1473 } 1474 public void epilogue() { 1475 } 1476 }; 1477 VM.getVM().getObjectHeap().iterateRaw(iterator); 1478 } else if (type.equals("heap")) { 1479 HeapVisitor iterator = new DefaultHeapVisitor() { 1480 public boolean doObj(Oop obj) { 1481 int index = 0; 1482 Address start = obj.getHandle(); 1483 long end = obj.getObjectSize(); 1484 while (index < end) { 1485 Address val = start.getAddressAt(index); 1486 if (AddressOps.equal(val, value)) { 1487 out.println("found in " + obj.getHandle()); 1488 break; 1489 } 1490 index += 4; 1491 } 1492 return false; 1493 } 1494 }; 1495 VM.getVM().getObjectHeap().iterate(iterator); 1496 } else if (type.equals("codecache")) { 1497 CodeCacheVisitor v = new CodeCacheVisitor() { 1498 public void prologue(Address start, Address end) { 1499 } 1500 public void visit(CodeBlob blob) { 1501 boolean printed = false; 1502 Address base = blob.getAddress(); 1503 Address end = base.addOffsetTo(blob.getSize()); 1504 while (base != null && base.lessThan(end)) { 1505 Address val = base.getAddressAt(0); 1506 if (AddressOps.equal(val, value)) { 1507 if (!printed) { 1508 printed = true; 1509 try { 1510 blob.printOn(out); 1511 } catch (Exception e) { 1512 out.println("Exception printing blob at " + base); 1513 e.printStackTrace(); 1514 } 1515 } 1516 out.println("found at " + base + "\n"); 1517 } 1518 base = base.addOffsetTo(stride); 1519 } 1520 } 1521 public void epilogue() { 1522 } 1523 1524 1525 }; 1526 VM.getVM().getCodeCache().iterate(v); 1527 1528 } 1529 } 1530 }, 1531 new Command("dumpcodecache", "dumpcodecache", false) { 1532 public void doit(Tokens t) { 1533 if (t.countTokens() != 0) { 1534 usage(); 1535 } else { 1536 final PrintStream fout = out; 1537 final HTMLGenerator gen = new HTMLGenerator(false); 1538 CodeCacheVisitor v = new CodeCacheVisitor() { 1539 public void prologue(Address start, Address end) { 1540 } 1541 public void visit(CodeBlob blob) { 1542 fout.println(gen.genHTML(blob.contentBegin())); 1543 } 1544 public void epilogue() { 1545 } 1546 1547 1548 }; 1549 VM.getVM().getCodeCache().iterate(v); 1550 } 1551 } 1552 }, 1553 new Command("where", "where { -a | id }", false) { 1554 boolean allThreads = false; 1555 public void doit(Tokens t) { 1556 if (t.countTokens() != 1) { 1557 usage(); 1558 } else { 1559 String name = t.nextToken(); 1560 allThreads = name.equals("-a"); 1561 VM.getVM().getThreads().doJavaThreads((thread) -> { 1562 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1563 thread.printThreadIDOn(new PrintStream(bos)); 1564 if (allThreads || bos.toString().equals(name)) { 1565 out.println("Thread " + bos.toString() + " Address: " + thread.getAddress()); 1566 HTMLGenerator gen = new HTMLGenerator(false); 1567 try { 1568 out.println(gen.genHTMLForJavaStackTrace(thread)); 1569 } catch (Exception e) { 1570 err.println("Error: " + e); 1571 if (verboseExceptions) { 1572 e.printStackTrace(err); 1573 } 1574 } 1575 if (!allThreads) return; 1576 } 1577 }); 1578 if (!allThreads) out.println("Couldn't find thread " + name); 1579 } 1580 } 1581 }, 1582 new Command("thread", "thread { -a | id }", false) { 1583 boolean allThreads = false; 1584 public void doit(Tokens t) { 1585 if (t.countTokens() != 1) { 1586 usage(); 1587 } else { 1588 String name = t.nextToken(); 1589 allThreads = name.equals("-a"); 1590 VM.getVM().getThreads().doJavaThreads((thread) -> { 1591 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1592 thread.printThreadIDOn(new PrintStream(bos)); 1593 if (allThreads || bos.toString().equals(name)) { 1594 out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); 1595 thread.printInfoOn(out); 1596 out.println(" "); 1597 if (!allThreads) return; 1598 } 1599 }); 1600 if (!allThreads) { 1601 out.println("Couldn't find thread " + name); 1602 } 1603 } 1604 } 1605 }, 1606 1607 new Command("threads", false) { 1608 public void doit(Tokens t) { 1609 if (t.countTokens() != 0) { 1610 usage(); 1611 } else { 1612 VM.getVM().getThreads().doJavaThreads((thread) -> { 1613 thread.printThreadIDOn(out); 1614 out.println(" " + thread.getThreadName()); 1615 thread.printInfoOn(out); 1616 out.println("\n..."); 1617 }); 1618 } 1619 } 1620 }, 1621 1622 new Command("livenmethods", false) { 1623 public void doit(Tokens t) { 1624 if (t.countTokens() != 0) { 1625 usage(); 1626 } else { 1627 ArrayList nmethods = new ArrayList(); 1628 HTMLGenerator gen = new HTMLGenerator(false); 1629 VM.getVM().getThreads().doJavaThreads((thread) -> { 1630 try { 1631 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 1632 if (vf instanceof CompiledVFrame) { 1633 NMethod c = ((CompiledVFrame)vf).getCode(); 1634 if (!nmethods.contains(c)) { 1635 nmethods.add(c); 1636 out.println(gen.genHTML(c)); 1637 } 1638 } 1639 } 1640 } catch (Exception e) { 1641 e.printStackTrace(); 1642 } 1643 }); 1644 } 1645 } 1646 }, 1647 new Command("g1regiondetails", false) { 1648 public void doit(Tokens t) { 1649 if (t.countTokens() != 0) { 1650 usage(); 1651 } else { 1652 CollectedHeap heap = VM.getVM().getUniverse().heap(); 1653 if (!(heap instanceof G1CollectedHeap)) { 1654 out.println("This command is valid only for G1GC."); 1655 return; 1656 } 1657 out.println("Region Details:"); 1658 ((G1CollectedHeap)heap).printRegionDetails(out); 1659 } 1660 } 1661 }, 1662 new Command("universe", false) { 1663 public void doit(Tokens t) { 1664 if (t.countTokens() != 0) { 1665 usage(); 1666 } else { 1667 Universe u = VM.getVM().getUniverse(); 1668 out.println("Heap Parameters:"); 1669 u.heap().printOn(out); 1670 } 1671 } 1672 }, 1673 new Command("verbose", "verbose true | false", true) { 1674 public void doit(Tokens t) { 1675 if (t.countTokens() != 1) { 1676 usage(); 1677 } else { 1678 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); 1679 } 1680 } 1681 }, 1682 new Command("assert", "assert true | false", true) { 1683 public void doit(Tokens t) { 1684 if (t.countTokens() != 1) { 1685 usage(); 1686 } else { 1687 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); 1688 } 1689 } 1690 }, 1691 }; 1692 1693 private boolean verboseExceptions = false; 1694 private ArrayList history = new ArrayList(); 1695 private HashMap commands = new HashMap(); 1696 private boolean doEcho = false; 1697 1698 private Command findCommand(String key) { 1699 return (Command)commands.get(key); 1700 } 1701 1702 public void printPrompt() { 1703 out.print("hsdb> "); 1704 } 1705 1706 private DebuggerInterface debugger; 1707 private HotSpotAgent agent; 1708 private JSJavaScriptEngine jsengine; 1709 private BufferedReader in; 1710 private PrintStream out; 1711 private PrintStream err; 1712 1713 // called before debuggee attach 1714 private void preAttach() { 1715 // nothing for now.. 1716 } 1717 1718 // called after debuggee attach 1719 private void postAttach() { 1720 // create JavaScript engine and start it 1721 try { 1722 jsengine = new JSJavaScriptEngine() { 1723 private ObjectReader reader = new ObjectReader(); 1724 private JSJavaFactory factory = new JSJavaFactoryImpl(); 1725 public ObjectReader getObjectReader() { 1726 return reader; 1727 } 1728 public JSJavaFactory getJSJavaFactory() { 1729 return factory; 1730 } 1731 protected void quit() { 1732 debugger.detach(); 1733 quit = true; 1734 } 1735 protected BufferedReader getInputReader() { 1736 return in; 1737 } 1738 protected PrintStream getOutputStream() { 1739 return out; 1740 } 1741 protected PrintStream getErrorStream() { 1742 return err; 1743 } 1744 }; 1745 try { 1746 jsengine.defineFunction(this, 1747 this.getClass().getMethod("registerCommand", 1748 new Class[] { 1749 String.class, String.class, String.class 1750 })); 1751 } catch (NoSuchMethodException exp) { 1752 // should not happen, see below...!! 1753 exp.printStackTrace(); 1754 } 1755 jsengine.start(); 1756 } 1757 catch (Exception ex) { 1758 System.out.println("Warning! JS Engine can't start, some commands will not be available."); 1759 if (verboseExceptions) { 1760 ex.printStackTrace(out); 1761 } 1762 } 1763 } 1764 1765 public void registerCommand(String cmd, String usage, final String func) { 1766 commands.put(cmd, new Command(cmd, usage, false) { 1767 public void doit(Tokens t) { 1768 final int len = t.countTokens(); 1769 Object[] args = new Object[len]; 1770 for (int i = 0; i < len; i++) { 1771 args[i] = t.nextToken(); 1772 } 1773 jsengine.call(func, args); 1774 } 1775 }); 1776 } 1777 1778 public void setOutput(PrintStream o) { 1779 out = o; 1780 } 1781 1782 public void setErr(PrintStream e) { 1783 err = e; 1784 } 1785 1786 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { 1787 this.debugger = debugger; 1788 this.agent = debugger.getAgent(); 1789 this.in = in; 1790 this.out = out; 1791 this.err = err; 1792 for (int i = 0; i < commandList.length; i++) { 1793 Command c = commandList[i]; 1794 if (commands.get(c.name) != null) { 1795 throw new InternalError(c.name + " has multiple definitions"); 1796 } 1797 commands.put(c.name, c); 1798 } 1799 if (debugger.isAttached()) { 1800 postAttach(); 1801 } 1802 } 1803 1804 1805 public void run(boolean prompt) { 1806 // Process interactive commands. 1807 while (!quit) { 1808 if (prompt) printPrompt(); 1809 String ln = null; 1810 try { 1811 ln = in.readLine(); 1812 } catch (IOException e) { 1813 } 1814 if (ln == null) { 1815 if (prompt) err.println("Input stream closed."); 1816 return; 1817 } 1818 1819 executeCommand(ln, prompt); 1820 } 1821 } 1822 1823 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*)|(![a-zA-Z][^ ]*))"); 1824 1825 public void executeCommand(String ln, boolean putInHistory) { 1826 if (ln.indexOf('!') != -1) { 1827 int size = history.size(); 1828 if (size == 0) { 1829 ln = ""; 1830 err.println("History is empty"); 1831 } else { 1832 StringBuffer result = new StringBuffer(); 1833 Matcher m = historyPattern.matcher(ln); 1834 int start = 0; 1835 while (m.find()) { 1836 if (m.start() > start) { 1837 result.append(ln.substring(start, m.start() - start)); 1838 } 1839 start = m.end(); 1840 1841 String cmd = m.group(); 1842 if (cmd.equals("!!")) { 1843 result.append((String)history.get(history.size() - 1)); 1844 } else if (cmd.equals("!!-")) { 1845 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1846 item.trim(1); 1847 result.append(item.join(" ")); 1848 } else if (cmd.equals("!*")) { 1849 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1850 item.nextToken(); 1851 result.append(item.join(" ")); 1852 } else if (cmd.equals("!$")) { 1853 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1854 result.append(item.at(item.countTokens() - 1)); 1855 } else { 1856 String tail = cmd.substring(1); 1857 switch (tail.charAt(0)) { 1858 case '0': 1859 case '1': 1860 case '2': 1861 case '3': 1862 case '4': 1863 case '5': 1864 case '6': 1865 case '7': 1866 case '8': 1867 case '9': 1868 case '-': { 1869 int index = Integer.parseInt(tail); 1870 if (index < 0) { 1871 index = history.size() + index; 1872 } 1873 if (index > size) { 1874 err.println("No such history item"); 1875 } else { 1876 result.append((String)history.get(index)); 1877 } 1878 break; 1879 } 1880 default: { 1881 for (int i = history.size() - 1; i >= 0; i--) { 1882 String s = (String)history.get(i); 1883 if (s.startsWith(tail)) { 1884 result.append(s); 1885 } 1886 } 1887 } 1888 } 1889 } 1890 } 1891 if (result.length() == 0) { 1892 err.println("malformed history reference"); 1893 ln = ""; 1894 } else { 1895 if (start < ln.length()) { 1896 result.append(ln.substring(start)); 1897 } 1898 ln = result.toString(); 1899 if (!doEcho) { 1900 out.println(ln); 1901 } 1902 } 1903 } 1904 } 1905 1906 if (doEcho) { 1907 out.println("+ " + ln); 1908 } 1909 1910 PrintStream redirect = null; 1911 Tokens t = new Tokens(ln); 1912 if (t.hasMoreTokens()) { 1913 boolean error = false; 1914 if (putInHistory) history.add(ln); 1915 int len = t.countTokens(); 1916 if (len > 2) { 1917 String r = t.at(len - 2); 1918 if (r.equals(">") || r.equals(">>")) { 1919 boolean append = r.length() == 2; 1920 String file = t.at(len - 1); 1921 try { 1922 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append))); 1923 t.trim(2); 1924 } catch (Exception e) { 1925 out.println("Error: " + e); 1926 if (verboseExceptions) { 1927 e.printStackTrace(out); 1928 } 1929 error = true; 1930 } 1931 } 1932 } 1933 if (!error) { 1934 PrintStream savedout = out; 1935 if (redirect != null) { 1936 out = redirect; 1937 } 1938 try { 1939 executeCommand(t); 1940 } catch (Exception e) { 1941 err.println("Error: " + e); 1942 if (verboseExceptions) { 1943 e.printStackTrace(err); 1944 } 1945 } finally { 1946 if (redirect != null) { 1947 out = savedout; 1948 redirect.close(); 1949 } 1950 } 1951 } 1952 } 1953 } 1954 1955 void executeCommand(Tokens args) { 1956 String cmd = args.nextToken(); 1957 1958 Command doit = findCommand(cmd); 1959 1960 /* 1961 * Check for an unknown command 1962 */ 1963 if (doit == null) { 1964 out.println("Unrecognized command. Try help..."); 1965 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { 1966 out.println("Command not valid until attached to a VM"); 1967 } else { 1968 try { 1969 doit.doit(args); 1970 } catch (Exception e) { 1971 out.println("Error: " + e); 1972 if (verboseExceptions) { 1973 e.printStackTrace(out); 1974 } 1975 } 1976 } 1977 } 1978 }