1 /* 2 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot; 26 27 import java.io.*; 28 import java.math.*; 29 import java.util.*; 30 import java.util.regex.*; 31 32 import sun.jvm.hotspot.types.Type; 33 import sun.jvm.hotspot.types.Field; 34 import sun.jvm.hotspot.HotSpotTypeDataBase; 35 import sun.jvm.hotspot.types.basic.BasicType; 36 import sun.jvm.hotspot.types.CIntegerType; 37 import sun.jvm.hotspot.code.*; 38 import sun.jvm.hotspot.compiler.*; 39 import sun.jvm.hotspot.debugger.*; 40 import sun.jvm.hotspot.interpreter.*; 41 import sun.jvm.hotspot.memory.*; 42 import sun.jvm.hotspot.oops.*; 43 import sun.jvm.hotspot.runtime.*; 44 import sun.jvm.hotspot.utilities.*; 45 import sun.jvm.hotspot.utilities.soql.*; 46 import sun.jvm.hotspot.ui.classbrowser.*; 47 import sun.jvm.hotspot.ui.tree.*; 48 import sun.jvm.hotspot.tools.*; 49 import sun.jvm.hotspot.tools.ObjectHistogram; 50 import sun.jvm.hotspot.tools.StackTrace; 51 52 public class CommandProcessor { 53 public abstract static class DebuggerInterface { 54 public abstract HotSpotAgent getAgent(); 55 public abstract boolean isAttached(); 56 public abstract void attach(String pid); 57 public abstract void attach(String java, String core); 58 public abstract void detach(); 59 public abstract void reattach(); 60 } 61 62 static class Tokens { 63 final String input; 64 int i; 65 String[] tokens; 66 int length; 67 68 String[] splitWhitespace(String cmd) { 69 String[] t = cmd.split("\\s"); 70 if (t.length == 1 && t[0].length() == 0) { 71 return new String[0]; 72 } 73 return t; 74 } 75 76 void add(String s, ArrayList t) { 77 if (s.length() > 0) { 78 t.add(s); 79 } 80 } 81 82 Tokens(String cmd) { 83 input = cmd; 84 85 // check for quoting 86 int quote = cmd.indexOf('"'); 87 ArrayList t = new ArrayList(); 88 if (quote != -1) { 89 while (cmd.length() > 0) { 90 if (quote != -1) { 91 int endquote = cmd.indexOf('"', quote + 1); 92 if (endquote == -1) { 93 throw new RuntimeException("mismatched quotes: " + input); 94 } 95 96 String before = cmd.substring(0, quote).trim(); 97 String quoted = cmd.substring(quote + 1, endquote); 98 cmd = cmd.substring(endquote + 1).trim(); 99 if (before.length() > 0) { 100 String[] w = splitWhitespace(before); 101 for (int i = 0; i < w.length; i++) { 102 add(w[i], t); 103 } 104 } 105 add(quoted, t); 106 quote = cmd.indexOf('"'); 107 } else { 108 String[] w = splitWhitespace(cmd); 109 for (int i = 0; i < w.length; i++) { 110 add(w[i], t); 111 } 112 cmd = ""; 113 114 } 115 } 116 } else { 117 String[] w = splitWhitespace(cmd); 118 for (int i = 0; i < w.length; i++) { 119 add(w[i], t); 120 } 121 } 122 tokens = (String[])t.toArray(new String[0]); 123 i = 0; 124 length = tokens.length; 125 126 //for (int i = 0; i < tokens.length; i++) { 127 // System.out.println("\"" + tokens[i] + "\""); 128 //} 129 } 130 131 String nextToken() { 132 return tokens[i++]; 133 } 134 boolean hasMoreTokens() { 135 return i < length; 136 } 137 int countTokens() { 138 return length - i; 139 } 140 void trim(int n) { 141 if (length >= n) { 142 length -= n; 143 } else { 144 throw new IndexOutOfBoundsException(String.valueOf(n)); 145 } 146 } 147 String join(String sep) { 148 StringBuffer result = new StringBuffer(); 149 for (int w = i; w < length; w++) { 150 result.append(tokens[w]); 151 if (w + 1 < length) { 152 result.append(sep); 153 } 154 } 155 return result.toString(); 156 } 157 158 String at(int i) { 159 if (i < 0 || i >= length) { 160 throw new IndexOutOfBoundsException(String.valueOf(i)); 161 } 162 return tokens[i]; 163 } 164 } 165 166 167 abstract class Command { 168 Command(String n, String u, boolean ok) { 169 name = n; 170 usage = u; 171 okIfDisconnected = ok; 172 } 173 174 Command(String n, boolean ok) { 175 name = n; 176 usage = n; 177 okIfDisconnected = ok; 178 } 179 180 final String name; 181 final String usage; 182 final boolean okIfDisconnected; 183 abstract void doit(Tokens t); 184 void usage() { 185 out.println("Usage: " + usage); 186 } 187 188 void printOopValue(Oop oop) { 189 if (oop != null) { 190 Klass k = oop.getKlass(); 191 Symbol s = k.getName(); 192 if (s != null) { 193 out.print("Oop for " + s.asString() + " @ "); 194 } else { 195 out.print("Oop @ "); 196 } 197 Oop.printOopAddressOn(oop, out); 198 } else { 199 out.print("null"); 200 } 201 } 202 203 void printNode(SimpleTreeNode node) { 204 int count = node.getChildCount(); 205 for (int i = 0; i < count; i++) { 206 try { 207 SimpleTreeNode field = node.getChild(i); 208 if (field instanceof OopTreeNodeAdapter) { 209 out.print(field); 210 out.print(" "); 211 printOopValue(((OopTreeNodeAdapter)field).getOop()); 212 out.println(); 213 } else { 214 out.println(field); 215 } 216 } catch (Exception e) { 217 out.println(); 218 out.println("Error: " + e); 219 if (verboseExceptions) { 220 e.printStackTrace(out); 221 } 222 } 223 } 224 } 225 } 226 227 void quote(String s) { 228 if (s.indexOf(" ") == -1) { 229 out.print(s); 230 } else { 231 out.print("\""); 232 out.print(s); 233 out.print("\""); 234 } 235 } 236 237 void dumpType(Type type) { 238 out.print("type "); 239 quote(type.getName()); 240 out.print(" "); 241 if (type.getSuperclass() != null) { 242 quote(type.getSuperclass().getName()); 243 out.print(" "); 244 } else { 245 out.print("null "); 246 } 247 out.print(type.isOopType()); 248 out.print(" "); 249 if (type.isCIntegerType()) { 250 out.print("true "); 251 out.print(((CIntegerType)type).isUnsigned()); 252 out.print(" "); 253 } else { 254 out.print("false false "); 255 } 256 out.print(type.getSize()); 257 out.println(); 258 } 259 260 void dumpFields(Type type) { 261 Iterator i = type.getFields(); 262 while (i.hasNext()) { 263 Field f = (Field) i.next(); 264 out.print("field "); 265 quote(type.getName()); 266 out.print(" "); 267 out.print(f.getName()); 268 out.print(" "); 269 quote(f.getType().getName()); 270 out.print(" "); 271 out.print(f.isStatic()); 272 out.print(" "); 273 if (f.isStatic()) { 274 out.print("0 "); 275 out.print(f.getStaticFieldAddress()); 276 } else { 277 out.print(f.getOffset()); 278 out.print(" 0x0"); 279 } 280 out.println(); 281 } 282 } 283 284 285 Address lookup(String symbol) { 286 if (symbol.indexOf("::") != -1) { 287 String[] parts = symbol.split("::"); 288 StringBuffer mangled = new StringBuffer("__1c"); 289 for (int i = 0; i < parts.length; i++) { 290 int len = parts[i].length(); 291 if (len >= 26) { 292 mangled.append((char)('a' + (len / 26))); 293 len = len % 26; 294 } 295 mangled.append((char)('A' + len)); 296 mangled.append(parts[i]); 297 } 298 mangled.append("_"); 299 symbol = mangled.toString(); 300 } 301 return VM.getVM().getDebugger().lookup(null, symbol); 302 } 303 304 Address parseAddress(String addr) { 305 return VM.getVM().getDebugger().parseAddress(addr); 306 } 307 308 private final Command[] commandList = { 309 new Command("reattach", true) { 310 public void doit(Tokens t) { 311 int tokens = t.countTokens(); 312 if (tokens != 0) { 313 usage(); 314 return; 315 } 316 preAttach(); 317 debugger.reattach(); 318 postAttach(); 319 } 320 }, 321 new Command("attach", "attach pid | exec core", true) { 322 public void doit(Tokens t) { 323 int tokens = t.countTokens(); 324 if (tokens == 1) { 325 preAttach(); 326 debugger.attach(t.nextToken()); 327 postAttach(); 328 } else if (tokens == 2) { 329 preAttach(); 330 debugger.attach(t.nextToken(), t.nextToken()); 331 postAttach(); 332 } else { 333 usage(); 334 } 335 } 336 }, 337 new Command("detach", false) { 338 public void doit(Tokens t) { 339 if (t.countTokens() != 0) { 340 usage(); 341 } else { 342 debugger.detach(); 343 } 344 } 345 }, 346 new Command("examine", "examine [ address/count ] | [ address,address]", false) { 347 Pattern args1 = Pattern.compile("^(0x[0-9a-f]+)(/([0-9]*)([a-z]*))?$"); 348 Pattern args2 = Pattern.compile("^(0x[0-9a-f]+),(0x[0-9a-f]+)(/[a-z]*)?$"); 349 350 String fill(Address a, int width) { 351 String s = "0x0"; 352 if (a != null) { 353 s = a.toString(); 354 } 355 if (s.length() != width) { 356 return s.substring(0, 2) + "000000000000000000000".substring(0, width - s.length()) + s.substring(2); 357 } 358 return s; 359 } 360 361 public void doit(Tokens t) { 362 if (t.countTokens() != 1) { 363 usage(); 364 } else { 365 String arg = t.nextToken(); 366 Matcher m1 = args1.matcher(arg); 367 Matcher m2 = args2.matcher(arg); 368 Address start = null; 369 Address end = null; 370 String format = ""; 371 int formatSize = (int)VM.getVM().getAddressSize(); 372 373 if (m1.matches()) { 374 start = VM.getVM().getDebugger().parseAddress(m1.group(1)); 375 int count = 1; 376 if (m1.group(2) != null) { 377 count = Integer.parseInt(m1.group(3)); 378 } 379 end = start.addOffsetTo(count * formatSize); 380 } else if (m2.matches()) { 381 start = VM.getVM().getDebugger().parseAddress(m2.group(1)); 382 end = VM.getVM().getDebugger().parseAddress(m2.group(2)); 383 } else { 384 usage(); 385 return; 386 } 387 int line = 80; 388 int formatWidth = formatSize * 8 / 4 + 2; 389 390 out.print(fill(start, formatWidth)); 391 out.print(": "); 392 int width = line - formatWidth - 2; 393 394 boolean needsPrintln = true; 395 while (start != null && start.lessThan(end)) { 396 Address val = start.getAddressAt(0); 397 out.print(fill(val, formatWidth)); 398 needsPrintln = true; 399 width -= formatWidth; 400 start = start.addOffsetTo(formatSize); 401 if (width <= formatWidth) { 402 out.println(); 403 needsPrintln = false; 404 if (start.lessThan(end)) { 405 out.print(fill(start, formatWidth)); 406 out.print(": "); 407 width = line - formatWidth - 2; 408 } 409 } else { 410 out.print(" "); 411 width -= 1; 412 } 413 } 414 if (needsPrintln) { 415 out.println(); 416 } 417 } 418 } 419 }, 420 new Command("findpc", "findpc address", false) { 421 public void doit(Tokens t) { 422 if (t.countTokens() != 1) { 423 usage(); 424 } else { 425 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 426 PointerLocation loc = PointerFinder.find(a); 427 loc.printOn(out); 428 } 429 } 430 }, 431 new Command("symbol", "symbol address", false) { 432 public void doit(Tokens t) { 433 if (t.countTokens() != 1) { 434 usage(); 435 } else { 436 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 437 Symbol.create(a).printValueOn(out); 438 out.println(); 439 } 440 } 441 }, 442 new Command("symboltable", "symboltable name", false) { 443 public void doit(Tokens t) { 444 if (t.countTokens() != 1) { 445 usage(); 446 } else { 447 out.println(SymbolTable.getTheTable().probe(t.nextToken())); 448 } 449 } 450 }, 451 new Command("symboldump", "symboldump", false) { 452 public void doit(Tokens t) { 453 SymbolTable.getTheTable().symbolsDo(new SymbolTable.SymbolVisitor() { 454 public void visit(Symbol sym) { 455 sym.printValueOn(out); 456 out.println(); 457 } 458 }); 459 } 460 }, 461 new Command("flags", "flags [ flag ]", false) { 462 public void doit(Tokens t) { 463 int tokens = t.countTokens(); 464 if (tokens != 0 && tokens != 1) { 465 usage(); 466 } else { 467 String name = tokens > 0 ? t.nextToken() : null; 468 469 VM.Flag[] flags = VM.getVM().getCommandLineFlags(); 470 if (flags == null) { 471 out.println("Command Flag info not available (use 1.4.1_03 or later)!"); 472 } else { 473 boolean printed = false; 474 for (int f = 0; f < flags.length; f++) { 475 VM.Flag flag = flags[f]; 476 if (name == null || flag.getName().equals(name)) { 477 out.println(flag.getName() + " = " + flag.getValue()); 478 printed = true; 479 } 480 } 481 if (name != null && !printed) { 482 out.println("Couldn't find flag: " + name); 483 } 484 } 485 } 486 } 487 }, 488 new Command("help", "help [ command ]", true) { 489 public void doit(Tokens t) { 490 int tokens = t.countTokens(); 491 Command cmd = null; 492 if (tokens == 1) { 493 cmd = findCommand(t.nextToken()); 494 } 495 496 if (cmd != null) { 497 cmd.usage(); 498 } else if (tokens == 0) { 499 out.println("Available commands:"); 500 Object[] keys = commands.keySet().toArray(); 501 Arrays.sort(keys, new Comparator() { 502 public int compare(Object o1, Object o2) { 503 return o1.toString().compareTo(o2.toString()); 504 } 505 }); 506 for (int i = 0; i < keys.length; i++) { 507 out.print(" "); 508 out.println(((Command)commands.get(keys[i])).usage); 509 } 510 } 511 } 512 }, 513 new Command("history", "history", true) { 514 public void doit(Tokens t) { 515 int tokens = t.countTokens(); 516 if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) { 517 usage(); 518 return; 519 } 520 boolean printIndex = tokens == 0; 521 for (int i = 0; i < history.size(); i++) { 522 if (printIndex) out.print(i + " "); 523 out.println(history.get(i)); 524 } 525 } 526 }, 527 new Command("revptrs", "revptrs address", false) { 528 public void doit(Tokens t) { 529 int tokens = t.countTokens(); 530 if (tokens != 1 && (tokens != 2 || !t.nextToken().equals("-c"))) { 531 usage(); 532 return; 533 } 534 boolean chase = tokens == 2; 535 ReversePtrs revptrs = VM.getVM().getRevPtrs(); 536 if (revptrs == null) { 537 out.println("Computing reverse pointers..."); 538 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); 539 final boolean[] complete = new boolean[1]; 540 HeapProgressThunk thunk = new HeapProgressThunk() { 541 public void heapIterationFractionUpdate(double d) {} 542 public synchronized void heapIterationComplete() { 543 complete[0] = true; 544 notify(); 545 } 546 }; 547 analysis.setHeapProgressThunk(thunk); 548 analysis.run(); 549 while (!complete[0]) { 550 synchronized (thunk) { 551 try { 552 thunk.wait(); 553 } catch (Exception e) { 554 } 555 } 556 } 557 revptrs = VM.getVM().getRevPtrs(); 558 out.println("Done."); 559 } 560 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 561 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 562 OopHandle handle = a.addOffsetToAsOopHandle(0); 563 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 564 ArrayList ptrs = revptrs.get(oop); 565 if (ptrs == null) { 566 out.println("no live references to " + a); 567 } else { 568 if (chase) { 569 while (ptrs.size() == 1) { 570 LivenessPathElement e = (LivenessPathElement)ptrs.get(0); 571 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 572 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 573 out.println(bos.toString()); 574 ptrs = revptrs.get(e.getObj()); 575 } 576 } else { 577 for (int i = 0; i < ptrs.size(); i++) { 578 LivenessPathElement e = (LivenessPathElement)ptrs.get(i); 579 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 580 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); 581 out.println(bos.toString()); 582 oop = e.getObj(); 583 } 584 } 585 } 586 } 587 } 588 }, 589 new Command("inspect", "inspect expression", false) { 590 public void doit(Tokens t) { 591 if (t.countTokens() != 1) { 592 usage(); 593 } else { 594 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 595 SimpleTreeNode node = null; 596 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 597 OopHandle handle = a.addOffsetToAsOopHandle(0); 598 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 599 node = new OopTreeNodeAdapter(oop, null); 600 601 out.println("instance of " + node.getValue() + " @ " + a + 602 " (size = " + oop.getObjectSize() + ")"); 603 } else if (VM.getVM().getCodeCache().contains(a)) { 604 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a); 605 a = blob.headerBegin(); 606 } 607 if (node == null) { 608 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a); 609 if (type != null) { 610 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")"); 611 node = new CTypeTreeNodeAdapter(a, type, null); 612 } 613 } 614 if (node != null) { 615 printNode(node); 616 } 617 } 618 } 619 }, 620 new Command("jhisto", "jhisto", false) { 621 public void doit(Tokens t) { 622 ObjectHistogram histo = new ObjectHistogram(); 623 histo.run(out, err); 624 } 625 }, 626 new Command("jstack", "jstack [-v]", false) { 627 public void doit(Tokens t) { 628 boolean verbose = false; 629 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 630 verbose = true; 631 } 632 StackTrace jstack = new StackTrace(verbose, true); 633 jstack.run(out); 634 } 635 }, 636 new Command("print", "print expression", false) { 637 public void doit(Tokens t) { 638 if (t.countTokens() != 1) { 639 usage(); 640 } else { 641 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 642 HTMLGenerator gen = new HTMLGenerator(false); 643 out.println(gen.genHTML(a)); 644 } 645 } 646 }, 647 new Command("printas", "printas type expression", false) { 648 public void doit(Tokens t) { 649 if (t.countTokens() != 2) { 650 usage(); 651 } else { 652 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 653 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 654 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null); 655 656 out.println("pointer to " + type + " @ " + a + 657 " (size = " + type.getSize() + ")"); 658 printNode(node); 659 } 660 } 661 }, 662 new Command("printstatics", "printstatics [ type ]", false) { 663 public void doit(Tokens t) { 664 if (t.countTokens() > 1) { 665 usage(); 666 } else { 667 if (t.countTokens() == 0) { 668 out.println("All known static fields"); 669 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes())); 670 } else { 671 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 672 out.println("Static fields of " + type.getName()); 673 printNode(new CTypeTreeNodeAdapter(type)); 674 } 675 } 676 } 677 }, 678 new Command("pmap", "pmap", false) { 679 public void doit(Tokens t) { 680 PMap pmap = new PMap(); 681 pmap.run(out, debugger.getAgent().getDebugger()); 682 } 683 }, 684 new Command("pstack", "pstack [-v]", false) { 685 public void doit(Tokens t) { 686 boolean verbose = false; 687 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 688 verbose = true; 689 } 690 PStack pstack = new PStack(verbose, true); 691 pstack.run(out, debugger.getAgent().getDebugger()); 692 } 693 }, 694 new Command("quit", true) { 695 public void doit(Tokens t) { 696 if (t.countTokens() != 0) { 697 usage(); 698 } else { 699 debugger.detach(); 700 System.exit(0); 701 } 702 } 703 }, 704 new Command("echo", "echo [ true | false ]", true) { 705 public void doit(Tokens t) { 706 if (t.countTokens() == 0) { 707 out.println("echo is " + doEcho); 708 } else if (t.countTokens() == 1) { 709 doEcho = Boolean.valueOf(t.nextToken()).booleanValue(); 710 } else { 711 usage(); 712 } 713 } 714 }, 715 new Command("versioncheck", "versioncheck [ true | false ]", true) { 716 public void doit(Tokens t) { 717 if (t.countTokens() == 0) { 718 out.println("versioncheck is " + 719 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); 720 } else if (t.countTokens() == 1) { 721 if (Boolean.valueOf(t.nextToken()).booleanValue()) { 722 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null); 723 } else { 724 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true"); 725 } 726 } else { 727 usage(); 728 } 729 } 730 }, 731 new Command("scanoops", "scanoops start end [ type ]", false) { 732 public void doit(Tokens t) { 733 if (t.countTokens() != 2 && t.countTokens() != 3) { 734 usage(); 735 } else { 736 long stride = VM.getVM().getAddressSize(); 737 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken()); 738 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken()); 739 Klass klass = null; 740 if (t.countTokens() == 1) { 741 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); 742 } 743 while (base != null && base.lessThan(end)) { 744 long step = stride; 745 OopHandle handle = base.addOffsetToAsOopHandle(0); 746 if (RobustOopDeterminator.oopLooksValid(handle)) { 747 try { 748 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 749 if (klass == null || oop.getKlass().isSubtypeOf(klass)) 750 out.println(handle.toString() + " " + oop.getKlass().getName().asString()); 751 step = oop.getObjectSize(); 752 } catch (UnknownOopException ex) { 753 // ok 754 } catch (RuntimeException ex) { 755 ex.printStackTrace(); 756 } 757 } 758 base = base.addOffsetTo(step); 759 } 760 } 761 } 762 }, 763 new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { 764 public void doit(Tokens t) { 765 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 766 usage(); 767 return; 768 } 769 if (t.countTokens() == 1) { 770 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 771 dumpFields(type); 772 } else if (t.countTokens() == 0) { 773 Iterator i = agent.getTypeDataBase().getTypes(); 774 while (i.hasNext()) { 775 dumpFields((Type)i.next()); 776 } 777 } else { 778 BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken()); 779 780 String fieldName = t.nextToken(); 781 782 // The field's Type must already be in the database -- no exceptions 783 Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken()); 784 785 boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue(); 786 long offset = Long.parseLong(t.nextToken()); 787 Address staticAddress = parseAddress(t.nextToken()); 788 if (isStatic && staticAddress == null) { 789 staticAddress = lookup(containingType.getName() + "::" + fieldName); 790 } 791 792 // check to see if the field already exists 793 Iterator i = containingType.getFields(); 794 while (i.hasNext()) { 795 Field f = (Field) i.next(); 796 if (f.getName().equals(fieldName)) { 797 if (f.isStatic() != isStatic) { 798 throw new RuntimeException("static/nonstatic mismatch: " + t.input); 799 } 800 if (!isStatic) { 801 if (f.getOffset() != offset) { 802 throw new RuntimeException("bad redefinition of field offset: " + t.input); 803 } 804 } else { 805 if (!f.getStaticFieldAddress().equals(staticAddress)) { 806 throw new RuntimeException("bad redefinition of field location: " + t.input); 807 } 808 } 809 if (f.getType() != fieldType) { 810 throw new RuntimeException("bad redefinition of field type: " + t.input); 811 } 812 return; 813 } 814 } 815 816 // Create field by type 817 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 818 db.createField(containingType, 819 fieldName, fieldType, 820 isStatic, 821 offset, 822 staticAddress); 823 824 } 825 } 826 827 }, 828 new Command("tokenize", "tokenize ...", true) { 829 public void doit(Tokens t) { 830 while (t.hasMoreTokens()) { 831 out.println("\"" + t.nextToken() + "\""); 832 } 833 } 834 }, 835 new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { 836 public void doit(Tokens t) { 837 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 838 usage(); 839 return; 840 } 841 if (t.countTokens() == 6) { 842 String typeName = t.nextToken(); 843 String superclassName = t.nextToken(); 844 if (superclassName.equals("null")) { 845 superclassName = null; 846 } 847 boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue(); 848 boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue(); 849 boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue(); 850 long size = Long.parseLong(t.nextToken()); 851 852 BasicType type = null; 853 try { 854 type = (BasicType)agent.getTypeDataBase().lookupType(typeName); 855 } catch (RuntimeException e) { 856 } 857 if (type != null) { 858 if (type.isOopType() != isOop) { 859 throw new RuntimeException("oop mismatch in type definition: " + t.input); 860 } 861 if (type.isCIntegerType() != isInteger) { 862 throw new RuntimeException("integer type mismatch in type definition: " + t.input); 863 } 864 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { 865 throw new RuntimeException("unsigned mismatch in type definition: " + t.input); 866 } 867 if (type.getSuperclass() == null) { 868 if (superclassName != null) { 869 if (type.getSize() == -1) { 870 type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName)); 871 } else { 872 throw new RuntimeException("unexpected superclass in type definition: " + t.input); 873 } 874 } 875 } else { 876 if (superclassName == null) { 877 throw new RuntimeException("missing superclass in type definition: " + t.input); 878 } 879 if (!type.getSuperclass().getName().equals(superclassName)) { 880 throw new RuntimeException("incorrect superclass in type definition: " + t.input); 881 } 882 } 883 if (type.getSize() != size) { 884 if (type.getSize() == -1) { 885 type.setSize(size); 886 } 887 throw new RuntimeException("size mismatch in type definition: " + t.input); 888 } 889 return; 890 } 891 892 // Create type 893 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 894 db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size); 895 } else if (t.countTokens() == 1) { 896 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 897 dumpType(type); 898 } else { 899 Iterator i = agent.getTypeDataBase().getTypes(); 900 // Make sure the types are emitted in an order than can be read back in 901 HashSet emitted = new HashSet(); 902 Stack pending = new Stack(); 903 while (i.hasNext()) { 904 Type n = (Type)i.next(); 905 if (emitted.contains(n.getName())) { 906 continue; 907 } 908 909 while (n != null && !emitted.contains(n.getName())) { 910 pending.push(n); 911 n = n.getSuperclass(); 912 } 913 while (!pending.empty()) { 914 n = (Type)pending.pop(); 915 dumpType(n); 916 emitted.add(n.getName()); 917 } 918 } 919 } 920 } 921 922 }, 923 new Command("source", "source filename", true) { 924 public void doit(Tokens t) { 925 if (t.countTokens() != 1) { 926 usage(); 927 return; 928 } 929 String file = t.nextToken(); 930 BufferedReader savedInput = in; 931 try { 932 BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 933 in = input; 934 run(false); 935 } catch (Exception e) { 936 out.println("Error: " + e); 937 if (verboseExceptions) { 938 e.printStackTrace(out); 939 } 940 } finally { 941 in = savedInput; 942 } 943 944 } 945 }, 946 new Command("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) { 947 public void doit(Tokens t) { 948 if (t.countTokens() != 2) { 949 usage(); 950 return; 951 } 952 String type = t.nextToken(); 953 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken()); 954 final long stride = VM.getVM().getAddressSize(); 955 if (type.equals("threads")) { 956 Threads threads = VM.getVM().getThreads(); 957 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 958 Address base = thread.getBaseOfStackPointer(); 959 Address end = thread.getLastJavaSP(); 960 if (end == null) continue; 961 if (end.lessThan(base)) { 962 Address tmp = base; 963 base = end; 964 end = tmp; 965 } 966 out.println("Searching " + base + " " + end); 967 while (base != null && base.lessThan(end)) { 968 Address val = base.getAddressAt(0); 969 if (AddressOps.equal(val, value)) { 970 out.println(base); 971 } 972 base = base.addOffsetTo(stride); 973 } 974 } 975 } else if (type.equals("rawheap")) { 976 RawHeapVisitor iterator = new RawHeapVisitor() { 977 public void prologue(long used) { 978 } 979 980 public void visitAddress(Address addr) { 981 Address val = addr.getAddressAt(0); 982 if (AddressOps.equal(val, value)) { 983 out.println("found at " + addr); 984 } 985 } 986 public void visitCompOopAddress(Address addr) { 987 Address val = addr.getCompOopAddressAt(0); 988 if (AddressOps.equal(val, value)) { 989 out.println("found at " + addr); 990 } 991 } 992 public void epilogue() { 993 } 994 }; 995 VM.getVM().getObjectHeap().iterateRaw(iterator); 996 } else if (type.equals("heap") || type.equals("perm")) { 997 HeapVisitor iterator = new DefaultHeapVisitor() { 998 public boolean doObj(Oop obj) { 999 int index = 0; 1000 Address start = obj.getHandle(); 1001 long end = obj.getObjectSize(); 1002 while (index < end) { 1003 Address val = start.getAddressAt(index); 1004 if (AddressOps.equal(val, value)) { 1005 out.println("found in " + obj.getHandle()); 1006 break; 1007 } 1008 index += 4; 1009 } 1010 return false; 1011 } 1012 }; 1013 if (type.equals("heap")) { 1014 VM.getVM().getObjectHeap().iterate(iterator); 1015 } else { 1016 VM.getVM().getObjectHeap().iteratePerm(iterator); 1017 } 1018 } else if (type.equals("codecache")) { 1019 CodeCacheVisitor v = new CodeCacheVisitor() { 1020 public void prologue(Address start, Address end) { 1021 } 1022 public void visit(CodeBlob blob) { 1023 boolean printed = false; 1024 Address base = blob.getAddress(); 1025 Address end = base.addOffsetTo(blob.getSize()); 1026 while (base != null && base.lessThan(end)) { 1027 Address val = base.getAddressAt(0); 1028 if (AddressOps.equal(val, value)) { 1029 if (!printed) { 1030 printed = true; 1031 try { 1032 blob.printOn(out); 1033 } catch (Exception e) { 1034 out.println("Exception printing blob at " + base); 1035 e.printStackTrace(); 1036 } 1037 } 1038 out.println("found at " + base + "\n"); 1039 } 1040 base = base.addOffsetTo(stride); 1041 } 1042 } 1043 public void epilogue() { 1044 } 1045 1046 1047 }; 1048 VM.getVM().getCodeCache().iterate(v); 1049 1050 } 1051 } 1052 }, 1053 new Command("dumpcodecache", "dumpcodecache", false) { 1054 public void doit(Tokens t) { 1055 if (t.countTokens() != 0) { 1056 usage(); 1057 } else { 1058 final PrintStream fout = out; 1059 final HTMLGenerator gen = new HTMLGenerator(false); 1060 CodeCacheVisitor v = new CodeCacheVisitor() { 1061 public void prologue(Address start, Address end) { 1062 } 1063 public void visit(CodeBlob blob) { 1064 fout.println(gen.genHTML(blob.contentBegin())); 1065 } 1066 public void epilogue() { 1067 } 1068 1069 1070 }; 1071 VM.getVM().getCodeCache().iterate(v); 1072 } 1073 } 1074 }, 1075 new Command("where", "where { -a | id }", false) { 1076 public void doit(Tokens t) { 1077 if (t.countTokens() != 1) { 1078 usage(); 1079 } else { 1080 String name = t.nextToken(); 1081 Threads threads = VM.getVM().getThreads(); 1082 boolean all = name.equals("-a"); 1083 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 1084 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1085 thread.printThreadIDOn(new PrintStream(bos)); 1086 if (all || bos.toString().equals(name)) { 1087 out.println(bos.toString() + " = " + thread.getAddress()); 1088 HTMLGenerator gen = new HTMLGenerator(false); 1089 try { 1090 out.println(gen.genHTMLForJavaStackTrace(thread)); 1091 } catch (Exception e) { 1092 err.println("Error: " + e); 1093 if (verboseExceptions) { 1094 e.printStackTrace(err); 1095 } 1096 } 1097 if (!all) return; 1098 } 1099 } 1100 if (!all) out.println("Couldn't find thread " + name); 1101 } 1102 } 1103 }, 1104 new Command("thread", "thread { -a | id }", false) { 1105 public void doit(Tokens t) { 1106 if (t.countTokens() != 1) { 1107 usage(); 1108 } else { 1109 String name = t.nextToken(); 1110 Threads threads = VM.getVM().getThreads(); 1111 boolean all = name.equals("-a"); 1112 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 1113 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1114 thread.printThreadIDOn(new PrintStream(bos)); 1115 if (all || bos.toString().equals(name)) { 1116 out.println(bos.toString() + " = " + thread.getAddress()); 1117 if (!all) return; 1118 } 1119 } 1120 out.println("Couldn't find thread " + name); 1121 } 1122 } 1123 }, 1124 1125 new Command("threads", false) { 1126 public void doit(Tokens t) { 1127 if (t.countTokens() != 0) { 1128 usage(); 1129 } else { 1130 Threads threads = VM.getVM().getThreads(); 1131 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 1132 thread.printThreadIDOn(out); 1133 out.println(" " + thread.getThreadName()); 1134 } 1135 } 1136 } 1137 }, 1138 1139 new Command("livenmethods", false) { 1140 public void doit(Tokens t) { 1141 if (t.countTokens() != 0) { 1142 usage(); 1143 } else { 1144 ArrayList nmethods = new ArrayList(); 1145 Threads threads = VM.getVM().getThreads(); 1146 HTMLGenerator gen = new HTMLGenerator(false); 1147 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 1148 try { 1149 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 1150 if (vf instanceof CompiledVFrame) { 1151 NMethod c = ((CompiledVFrame)vf).getCode(); 1152 if (!nmethods.contains(c)) { 1153 nmethods.add(c); 1154 out.println(gen.genHTML(c)); 1155 } 1156 } 1157 } 1158 } catch (Exception e) { 1159 e.printStackTrace(); 1160 } 1161 } 1162 } 1163 } 1164 }, 1165 new Command("universe", false) { 1166 public void doit(Tokens t) { 1167 if (t.countTokens() != 0) { 1168 usage(); 1169 } else { 1170 Universe u = VM.getVM().getUniverse(); 1171 out.println("Heap Parameters:"); 1172 u.heap().printOn(out); 1173 } 1174 } 1175 }, 1176 new Command("verbose", "verbose true | false", true) { 1177 public void doit(Tokens t) { 1178 if (t.countTokens() != 1) { 1179 usage(); 1180 } else { 1181 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); 1182 } 1183 } 1184 }, 1185 new Command("assert", "assert true | false", true) { 1186 public void doit(Tokens t) { 1187 if (t.countTokens() != 1) { 1188 usage(); 1189 } else { 1190 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); 1191 } 1192 } 1193 }, 1194 }; 1195 1196 private boolean verboseExceptions = false; 1197 private ArrayList history = new ArrayList(); 1198 private HashMap commands = new HashMap(); 1199 private boolean doEcho = false; 1200 1201 private Command findCommand(String key) { 1202 return (Command)commands.get(key); 1203 } 1204 1205 public void printPrompt() { 1206 out.print("hsdb> "); 1207 } 1208 1209 private DebuggerInterface debugger; 1210 private HotSpotAgent agent; 1211 private JSJavaScriptEngine jsengine; 1212 private BufferedReader in; 1213 private PrintStream out; 1214 private PrintStream err; 1215 1216 // called before debuggee attach 1217 private void preAttach() { 1218 // nothing for now.. 1219 } 1220 1221 // called after debuggee attach 1222 private void postAttach() { 1223 // create JavaScript engine and start it 1224 jsengine = new JSJavaScriptEngine() { 1225 private ObjectReader reader = new ObjectReader(); 1226 private JSJavaFactory factory = new JSJavaFactoryImpl(); 1227 public ObjectReader getObjectReader() { 1228 return reader; 1229 } 1230 public JSJavaFactory getJSJavaFactory() { 1231 return factory; 1232 } 1233 protected void quit() { 1234 debugger.detach(); 1235 System.exit(0); 1236 } 1237 protected BufferedReader getInputReader() { 1238 return in; 1239 } 1240 protected PrintStream getOutputStream() { 1241 return out; 1242 } 1243 protected PrintStream getErrorStream() { 1244 return err; 1245 } 1246 }; 1247 try { 1248 jsengine.defineFunction(this, 1249 this.getClass().getMethod("registerCommand", 1250 new Class[] { 1251 String.class, String.class, String.class 1252 })); 1253 } catch (NoSuchMethodException exp) { 1254 // should not happen, see below...!! 1255 exp.printStackTrace(); 1256 } 1257 jsengine.start(); 1258 } 1259 1260 public void registerCommand(String cmd, String usage, final String func) { 1261 commands.put(cmd, new Command(cmd, usage, false) { 1262 public void doit(Tokens t) { 1263 final int len = t.countTokens(); 1264 Object[] args = new Object[len]; 1265 for (int i = 0; i < len; i++) { 1266 args[i] = t.nextToken(); 1267 } 1268 jsengine.call(func, args); 1269 } 1270 }); 1271 } 1272 1273 public void setOutput(PrintStream o) { 1274 out = o; 1275 } 1276 1277 public void setErr(PrintStream e) { 1278 err = e; 1279 } 1280 1281 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { 1282 this.debugger = debugger; 1283 this.agent = debugger.getAgent(); 1284 this.in = in; 1285 this.out = out; 1286 this.err = err; 1287 for (int i = 0; i < commandList.length; i++) { 1288 Command c = commandList[i]; 1289 if (commands.get(c.name) != null) { 1290 throw new InternalError(c.name + " has multiple definitions"); 1291 } 1292 commands.put(c.name, c); 1293 } 1294 if (debugger.isAttached()) { 1295 postAttach(); 1296 } 1297 } 1298 1299 1300 public void run(boolean prompt) { 1301 // Process interactive commands. 1302 while (true) { 1303 if (prompt) printPrompt(); 1304 String ln = null; 1305 try { 1306 ln = in.readLine(); 1307 } catch (IOException e) { 1308 } 1309 if (ln == null) { 1310 if (prompt) err.println("Input stream closed."); 1311 return; 1312 } 1313 1314 executeCommand(ln); 1315 } 1316 } 1317 1318 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*)|(![a-zA-Z][^ ]*))"); 1319 1320 public void executeCommand(String ln) { 1321 if (ln.indexOf('!') != -1) { 1322 int size = history.size(); 1323 if (size == 0) { 1324 ln = ""; 1325 err.println("History is empty"); 1326 } else { 1327 StringBuffer result = new StringBuffer(); 1328 Matcher m = historyPattern.matcher(ln); 1329 int start = 0; 1330 while (m.find()) { 1331 if (m.start() > start) { 1332 result.append(ln.substring(start, m.start() - start)); 1333 } 1334 start = m.end(); 1335 1336 String cmd = m.group(); 1337 if (cmd.equals("!!")) { 1338 result.append((String)history.get(history.size() - 1)); 1339 } else if (cmd.equals("!!-")) { 1340 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1341 item.trim(1); 1342 result.append(item.join(" ")); 1343 } else if (cmd.equals("!*")) { 1344 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1345 item.nextToken(); 1346 result.append(item.join(" ")); 1347 } else if (cmd.equals("!$")) { 1348 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1349 result.append(item.at(item.countTokens() - 1)); 1350 } else { 1351 String tail = cmd.substring(1); 1352 switch (tail.charAt(0)) { 1353 case '0': 1354 case '1': 1355 case '2': 1356 case '3': 1357 case '4': 1358 case '5': 1359 case '6': 1360 case '7': 1361 case '8': 1362 case '9': 1363 case '-': { 1364 int index = Integer.parseInt(tail); 1365 if (index < 0) { 1366 index = history.size() + index; 1367 } 1368 if (index > size) { 1369 err.println("No such history item"); 1370 } else { 1371 result.append((String)history.get(index)); 1372 } 1373 break; 1374 } 1375 default: { 1376 for (int i = history.size() - 1; i >= 0; i--) { 1377 String s = (String)history.get(i); 1378 if (s.startsWith(tail)) { 1379 result.append(s); 1380 } 1381 } 1382 } 1383 } 1384 } 1385 } 1386 if (result.length() == 0) { 1387 err.println("malformed history reference"); 1388 ln = ""; 1389 } else { 1390 if (start < ln.length()) { 1391 result.append(ln.substring(start)); 1392 } 1393 ln = result.toString(); 1394 if (!doEcho) { 1395 out.println(ln); 1396 } 1397 } 1398 } 1399 } 1400 1401 if (doEcho) { 1402 out.println("+ " + ln); 1403 } 1404 1405 PrintStream redirect = null; 1406 Tokens t = new Tokens(ln); 1407 if (t.hasMoreTokens()) { 1408 boolean error = false; 1409 history.add(ln); 1410 int len = t.countTokens(); 1411 if (len > 2) { 1412 String r = t.at(len - 2); 1413 if (r.equals(">") || r.equals(">>")) { 1414 boolean append = r.length() == 2; 1415 String file = t.at(len - 1); 1416 try { 1417 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append))); 1418 t.trim(2); 1419 } catch (Exception e) { 1420 out.println("Error: " + e); 1421 if (verboseExceptions) { 1422 e.printStackTrace(out); 1423 } 1424 error = true; 1425 } 1426 } 1427 } 1428 if (!error) { 1429 PrintStream savedout = out; 1430 if (redirect != null) { 1431 out = redirect; 1432 } 1433 try { 1434 executeCommand(t); 1435 } catch (Exception e) { 1436 err.println("Error: " + e); 1437 if (verboseExceptions) { 1438 e.printStackTrace(err); 1439 } 1440 } finally { 1441 if (redirect != null) { 1442 out = savedout; 1443 redirect.close(); 1444 } 1445 } 1446 } 1447 } 1448 } 1449 1450 void executeCommand(Tokens args) { 1451 String cmd = args.nextToken(); 1452 1453 Command doit = findCommand(cmd); 1454 1455 /* 1456 * Check for an unknown command 1457 */ 1458 if (doit == null) { 1459 out.println("Unrecognized command. Try help..."); 1460 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { 1461 out.println("Command not valid until the attached to a VM"); 1462 } else { 1463 try { 1464 doit.doit(args); 1465 } catch (Exception e) { 1466 out.println("Error: " + e); 1467 if (verboseExceptions) { 1468 e.printStackTrace(out); 1469 } 1470 } 1471 } 1472 } 1473 }