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