1 /* 2 * Copyright 2005-2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any 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("flags", "flags [ flag ]", false) { 432 public void doit(Tokens t) { 433 int tokens = t.countTokens(); 434 if (tokens != 0 && tokens != 1) { 435 usage(); 436 } else { 437 String name = tokens > 0 ? t.nextToken() : null; 438 439 VM.Flag[] flags = VM.getVM().getCommandLineFlags(); 440 if (flags == null) { 441 out.println("Command Flag info not available (use 1.4.1_03 or later)!"); 442 } else { 443 boolean printed = false; 444 for (int f = 0; f < flags.length; f++) { 445 VM.Flag flag = flags[f]; 446 if (name == null || flag.getName().equals(name)) { 447 out.println(flag.getName() + " = " + flag.getValue()); 448 printed = true; 449 } 450 } 451 if (name != null && !printed) { 452 out.println("Couldn't find flag: " + name); 453 } 454 } 455 } 456 } 457 }, 458 new Command("help", "help [ command ]", true) { 459 public void doit(Tokens t) { 460 int tokens = t.countTokens(); 461 Command cmd = null; 462 if (tokens == 1) { 463 cmd = findCommand(t.nextToken()); 464 } 465 466 if (cmd != null) { 467 cmd.usage(); 468 } else if (tokens == 0) { 469 out.println("Available commands:"); 470 Object[] keys = commands.keySet().toArray(); 471 Arrays.sort(keys, new Comparator() { 472 public int compare(Object o1, Object o2) { 473 return o1.toString().compareTo(o2.toString()); 474 } 475 }); 476 for (int i = 0; i < keys.length; i++) { 477 out.print(" "); 478 out.println(((Command)commands.get(keys[i])).usage); 479 } 480 } 481 } 482 }, 483 new Command("history", "history", true) { 484 public void doit(Tokens t) { 485 int tokens = t.countTokens(); 486 if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) { 487 usage(); 488 return; 489 } 490 boolean printIndex = tokens == 0; 491 for (int i = 0; i < history.size(); i++) { 492 if (printIndex) out.print(i + " "); 493 out.println(history.get(i)); 494 } 495 } 496 }, 497 new Command("inspect", "inspect expression", false) { 498 public void doit(Tokens t) { 499 if (t.countTokens() != 1) { 500 usage(); 501 } else { 502 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 503 SimpleTreeNode node = null; 504 if (VM.getVM().getUniverse().heap().isInReserved(a)) { 505 OopHandle handle = a.addOffsetToAsOopHandle(0); 506 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 507 node = new OopTreeNodeAdapter(oop, null); 508 509 out.println("instance of " + node.getValue() + " @ " + a + 510 " (size = " + oop.getObjectSize() + ")"); 511 } else if (VM.getVM().getCodeCache().contains(a)) { 512 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a); 513 a = blob.headerBegin(); 514 } 515 if (node == null) { 516 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a); 517 if (type != null) { 518 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")"); 519 node = new CTypeTreeNodeAdapter(a, type, null); 520 } 521 } 522 if (node != null) { 523 printNode(node); 524 } 525 } 526 } 527 }, 528 new Command("jhisto", "jhisto", false) { 529 public void doit(Tokens t) { 530 ObjectHistogram histo = new ObjectHistogram(); 531 histo.run(out, err); 532 } 533 }, 534 new Command("jstack", "jstack [-v]", false) { 535 public void doit(Tokens t) { 536 boolean verbose = false; 537 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 538 verbose = true; 539 } 540 StackTrace jstack = new StackTrace(verbose, true); 541 jstack.run(out); 542 } 543 }, 544 new Command("print", "print expression", false) { 545 public void doit(Tokens t) { 546 if (t.countTokens() != 1) { 547 usage(); 548 } else { 549 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 550 HTMLGenerator gen = new HTMLGenerator(false); 551 out.println(gen.genHTML(a)); 552 } 553 } 554 }, 555 new Command("printas", "printas type expression", false) { 556 public void doit(Tokens t) { 557 if (t.countTokens() != 2) { 558 usage(); 559 } else { 560 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 561 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); 562 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null); 563 564 out.println("pointer to " + type + " @ " + a + 565 " (size = " + type.getSize() + ")"); 566 printNode(node); 567 } 568 } 569 }, 570 new Command("symbol", "symbol name", false) { 571 public void doit(Tokens t) { 572 if (t.countTokens() != 1) { 573 usage(); 574 } else { 575 String symbol = t.nextToken(); 576 Address a = lookup(symbol); 577 out.println(symbol + " = " + a); 578 } 579 } 580 }, 581 new Command("printstatics", "printstatics [ type ]", false) { 582 public void doit(Tokens t) { 583 if (t.countTokens() > 1) { 584 usage(); 585 } else { 586 if (t.countTokens() == 0) { 587 out.println("All known static fields"); 588 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes())); 589 } else { 590 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 591 out.println("Static fields of " + type.getName()); 592 printNode(new CTypeTreeNodeAdapter(type)); 593 } 594 } 595 } 596 }, 597 new Command("pmap", "pmap", false) { 598 public void doit(Tokens t) { 599 PMap pmap = new PMap(); 600 pmap.run(out, debugger.getAgent().getDebugger()); 601 } 602 }, 603 new Command("pstack", "pstack [-v]", false) { 604 public void doit(Tokens t) { 605 boolean verbose = false; 606 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { 607 verbose = true; 608 } 609 PStack pstack = new PStack(verbose, true); 610 pstack.run(out, debugger.getAgent().getDebugger()); 611 } 612 }, 613 new Command("quit", true) { 614 public void doit(Tokens t) { 615 if (t.countTokens() != 0) { 616 usage(); 617 } else { 618 debugger.detach(); 619 System.exit(0); 620 } 621 } 622 }, 623 new Command("echo", "echo [ true | false ]", true) { 624 public void doit(Tokens t) { 625 if (t.countTokens() == 0) { 626 out.println("echo is " + doEcho); 627 } else if (t.countTokens() == 1) { 628 doEcho = Boolean.valueOf(t.nextToken()).booleanValue(); 629 } else { 630 usage(); 631 } 632 } 633 }, 634 new Command("versioncheck", "versioncheck [ true | false ]", true) { 635 public void doit(Tokens t) { 636 if (t.countTokens() == 0) { 637 out.println("versioncheck is " + 638 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); 639 } else if (t.countTokens() == 1) { 640 if (Boolean.valueOf(t.nextToken()).booleanValue()) { 641 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null); 642 } else { 643 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true"); 644 } 645 } else { 646 usage(); 647 } 648 } 649 }, 650 new Command("scanoops", "scanoops start end [ type ]", false) { 651 public void doit(Tokens t) { 652 if (t.countTokens() != 2 && t.countTokens() != 3) { 653 usage(); 654 } else { 655 long stride = VM.getVM().getAddressSize(); 656 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken()); 657 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken()); 658 Klass klass = null; 659 if (t.countTokens() == 1) { 660 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); 661 } 662 while (base != null && base.lessThan(end)) { 663 long step = stride; 664 OopHandle handle = base.addOffsetToAsOopHandle(0); 665 if (RobustOopDeterminator.oopLooksValid(handle)) { 666 try { 667 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 668 if (klass == null || oop.getKlass().isSubtypeOf(klass)) 669 out.println(handle.toString() + " " + oop.getKlass().getName().asString()); 670 step = oop.getObjectSize(); 671 } catch (UnknownOopException ex) { 672 // ok 673 } catch (RuntimeException ex) { 674 ex.printStackTrace(); 675 } 676 } 677 base = base.addOffsetTo(step); 678 } 679 } 680 } 681 }, 682 new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { 683 public void doit(Tokens t) { 684 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 685 usage(); 686 return; 687 } 688 if (t.countTokens() == 1) { 689 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 690 dumpFields(type); 691 } else if (t.countTokens() == 0) { 692 Iterator i = agent.getTypeDataBase().getTypes(); 693 while (i.hasNext()) { 694 dumpFields((Type)i.next()); 695 } 696 } else { 697 BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken()); 698 699 String fieldName = t.nextToken(); 700 701 // The field's Type must already be in the database -- no exceptions 702 Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken()); 703 704 boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue(); 705 long offset = Long.parseLong(t.nextToken()); 706 Address staticAddress = parseAddress(t.nextToken()); 707 if (isStatic && staticAddress == null) { 708 staticAddress = lookup(containingType.getName() + "::" + fieldName); 709 } 710 711 // check to see if the field already exists 712 Iterator i = containingType.getFields(); 713 while (i.hasNext()) { 714 Field f = (Field) i.next(); 715 if (f.getName().equals(fieldName)) { 716 if (f.isStatic() != isStatic) { 717 throw new RuntimeException("static/nonstatic mismatch: " + t.input); 718 } 719 if (!isStatic) { 720 if (f.getOffset() != offset) { 721 throw new RuntimeException("bad redefinition of field offset: " + t.input); 722 } 723 } else { 724 if (!f.getStaticFieldAddress().equals(staticAddress)) { 725 throw new RuntimeException("bad redefinition of field location: " + t.input); 726 } 727 } 728 if (f.getType() != fieldType) { 729 throw new RuntimeException("bad redefinition of field type: " + t.input); 730 } 731 return; 732 } 733 } 734 735 // Create field by type 736 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 737 db.createField(containingType, 738 fieldName, fieldType, 739 isStatic, 740 offset, 741 staticAddress); 742 743 } 744 } 745 746 }, 747 new Command("tokenize", "tokenize ...", true) { 748 public void doit(Tokens t) { 749 while (t.hasMoreTokens()) { 750 out.println("\"" + t.nextToken() + "\""); 751 } 752 } 753 }, 754 new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { 755 public void doit(Tokens t) { 756 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { 757 usage(); 758 return; 759 } 760 if (t.countTokens() == 6) { 761 String typeName = t.nextToken(); 762 String superclassName = t.nextToken(); 763 if (superclassName.equals("null")) { 764 superclassName = null; 765 } 766 boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue(); 767 boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue(); 768 boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue(); 769 long size = Long.parseLong(t.nextToken()); 770 771 BasicType type = null; 772 try { 773 type = (BasicType)agent.getTypeDataBase().lookupType(typeName); 774 } catch (RuntimeException e) { 775 } 776 if (type != null) { 777 if (type.isOopType() != isOop) { 778 throw new RuntimeException("oop mismatch in type definition: " + t.input); 779 } 780 if (type.isCIntegerType() != isInteger) { 781 throw new RuntimeException("integer type mismatch in type definition: " + t.input); 782 } 783 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { 784 throw new RuntimeException("unsigned mismatch in type definition: " + t.input); 785 } 786 if (type.getSuperclass() == null) { 787 if (superclassName != null) { 788 if (type.getSize() == -1) { 789 type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName)); 790 } else { 791 throw new RuntimeException("unexpected superclass in type definition: " + t.input); 792 } 793 } 794 } else { 795 if (superclassName == null) { 796 throw new RuntimeException("missing superclass in type definition: " + t.input); 797 } 798 if (!type.getSuperclass().getName().equals(superclassName)) { 799 throw new RuntimeException("incorrect superclass in type definition: " + t.input); 800 } 801 } 802 if (type.getSize() != size) { 803 if (type.getSize() == -1) { 804 type.setSize(size); 805 } 806 throw new RuntimeException("size mismatch in type definition: " + t.input); 807 } 808 return; 809 } 810 811 // Create type 812 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); 813 db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size); 814 } else if (t.countTokens() == 1) { 815 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); 816 dumpType(type); 817 } else { 818 Iterator i = agent.getTypeDataBase().getTypes(); 819 while (i.hasNext()) { 820 dumpType((Type)i.next()); 821 } 822 } 823 } 824 825 }, 826 new Command("source", "source filename", true) { 827 public void doit(Tokens t) { 828 if (t.countTokens() != 1) { 829 usage(); 830 return; 831 } 832 String file = t.nextToken(); 833 BufferedReader savedInput = in; 834 try { 835 BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 836 in = input; 837 run(false); 838 } catch (Exception e) { 839 out.println("Error: " + e); 840 if (verboseExceptions) { 841 e.printStackTrace(out); 842 } 843 } finally { 844 in = savedInput; 845 } 846 847 } 848 }, 849 new Command("search", "search [ heap | codecache | threads ] value", false) { 850 public void doit(Tokens t) { 851 if (t.countTokens() != 2) { 852 usage(); 853 } else { 854 String type = t.nextToken(); 855 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken()); 856 final long stride = VM.getVM().getAddressSize(); 857 if (type.equals("threads")) { 858 Threads threads = VM.getVM().getThreads(); 859 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 860 Address base = thread.getBaseOfStackPointer(); 861 Address end = thread.getLastJavaSP(); 862 if (end == null) continue; 863 if (end.lessThan(base)) { 864 Address tmp = base; 865 base = end; 866 end = tmp; 867 } 868 out.println("Searching " + base + " " + end); 869 while (base != null && base.lessThan(end)) { 870 Address val = base.getAddressAt(0); 871 if (AddressOps.equal(val, value)) { 872 out.println(base); 873 } 874 base = base.addOffsetTo(stride); 875 } 876 } 877 } else if (type.equals("heap")) { 878 RawHeapVisitor iterator = new RawHeapVisitor() { 879 public void prologue(long used) { 880 } 881 882 public void visitAddress(Address addr) { 883 Address val = addr.getAddressAt(0); 884 if (AddressOps.equal(val, value)) { 885 out.println("found at " + addr); 886 } 887 } 888 public void visitCompOopAddress(Address addr) { 889 Address val = addr.getCompOopAddressAt(0); 890 if (AddressOps.equal(val, value)) { 891 out.println("found at " + addr); 892 } 893 } 894 public void epilogue() { 895 } 896 }; 897 VM.getVM().getObjectHeap().iterateRaw(iterator); 898 } else if (type.equals("codecache")) { 899 CodeCacheVisitor v = new CodeCacheVisitor() { 900 public void prologue(Address start, Address end) { 901 } 902 public void visit(CodeBlob blob) { 903 boolean printed = false; 904 Address base = blob.getAddress(); 905 Address end = base.addOffsetTo(blob.getSize()); 906 while (base != null && base.lessThan(end)) { 907 Address val = base.getAddressAt(0); 908 if (AddressOps.equal(val, value)) { 909 if (!printed) { 910 printed = true; 911 blob.printOn(out); 912 } 913 out.println("found at " + base + "\n"); 914 } 915 base = base.addOffsetTo(stride); 916 } 917 } 918 public void epilogue() { 919 } 920 921 922 }; 923 VM.getVM().getCodeCache().iterate(v); 924 925 } 926 } 927 } 928 }, 929 new Command("where", "where { -a | id }", false) { 930 public void doit(Tokens t) { 931 if (t.countTokens() != 1) { 932 usage(); 933 } else { 934 String name = t.nextToken(); 935 Threads threads = VM.getVM().getThreads(); 936 boolean all = name.equals("-a"); 937 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 938 StringWriter sw = new StringWriter(); 939 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 940 thread.printThreadIDOn(new PrintStream(bos)); 941 if (all || bos.toString().equals(name)) { 942 HTMLGenerator gen = new HTMLGenerator(false); 943 out.println(gen.genHTMLForJavaStackTrace(thread)); 944 if (!all) return; 945 } 946 } 947 if (!all) out.println("Couldn't find thread " + name); 948 } 949 } 950 }, 951 952 new Command("threads", false) { 953 public void doit(Tokens t) { 954 if (t.countTokens() != 0) { 955 usage(); 956 } else { 957 Threads threads = VM.getVM().getThreads(); 958 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 959 thread.printThreadIDOn(out); 960 out.println(" " + thread.getThreadName()); 961 } 962 } 963 } 964 }, 965 966 new Command("livenmethods", false) { 967 public void doit(Tokens t) { 968 if (t.countTokens() != 0) { 969 usage(); 970 } else { 971 ArrayList nmethods = new ArrayList(); 972 Threads threads = VM.getVM().getThreads(); 973 HTMLGenerator gen = new HTMLGenerator(false); 974 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 975 try { 976 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 977 if (vf instanceof CompiledVFrame) { 978 NMethod c = ((CompiledVFrame)vf).getCode(); 979 if (!nmethods.contains(c)) { 980 nmethods.add(c); 981 out.println(gen.genHTML(c)); 982 } 983 } 984 } 985 } catch (Exception e) { 986 e.printStackTrace(); 987 } 988 } 989 } 990 } 991 }, 992 new Command("universe", false) { 993 public void doit(Tokens t) { 994 if (t.countTokens() != 0) { 995 usage(); 996 } else { 997 Universe u = VM.getVM().getUniverse(); 998 out.println("Heap Parameters:"); 999 u.heap().printOn(out); 1000 } 1001 } 1002 }, 1003 new Command("verbose", "verbose true | false", true) { 1004 public void doit(Tokens t) { 1005 if (t.countTokens() != 1) { 1006 usage(); 1007 } else { 1008 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); 1009 } 1010 } 1011 }, 1012 new Command("assert", "assert true | false", true) { 1013 public void doit(Tokens t) { 1014 if (t.countTokens() != 1) { 1015 usage(); 1016 } else { 1017 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); 1018 } 1019 } 1020 }, 1021 }; 1022 1023 private boolean verboseExceptions = false; 1024 private ArrayList history = new ArrayList(); 1025 private HashMap commands = new HashMap(); 1026 private boolean doEcho = false; 1027 1028 private Command findCommand(String key) { 1029 return (Command)commands.get(key); 1030 } 1031 1032 public void printPrompt() { 1033 out.print("hsdb> "); 1034 } 1035 1036 private DebuggerInterface debugger; 1037 private HotSpotAgent agent; 1038 private JSJavaScriptEngine jsengine; 1039 private BufferedReader in; 1040 private PrintStream out; 1041 private PrintStream err; 1042 1043 // called before debuggee attach 1044 private void preAttach() { 1045 // nothing for now.. 1046 } 1047 1048 // called after debuggee attach 1049 private void postAttach() { 1050 // create JavaScript engine and start it 1051 jsengine = new JSJavaScriptEngine() { 1052 private ObjectReader reader = new ObjectReader(); 1053 private JSJavaFactory factory = new JSJavaFactoryImpl(); 1054 public ObjectReader getObjectReader() { 1055 return reader; 1056 } 1057 public JSJavaFactory getJSJavaFactory() { 1058 return factory; 1059 } 1060 protected void quit() { 1061 debugger.detach(); 1062 System.exit(0); 1063 } 1064 protected BufferedReader getInputReader() { 1065 return in; 1066 } 1067 protected PrintStream getOutputStream() { 1068 return out; 1069 } 1070 protected PrintStream getErrorStream() { 1071 return err; 1072 } 1073 }; 1074 try { 1075 jsengine.defineFunction(this, 1076 this.getClass().getMethod("registerCommand", 1077 new Class[] { 1078 String.class, String.class, String.class 1079 })); 1080 } catch (NoSuchMethodException exp) { 1081 // should not happen, see below...!! 1082 exp.printStackTrace(); 1083 } 1084 jsengine.start(); 1085 } 1086 1087 public void registerCommand(String cmd, String usage, final String func) { 1088 commands.put(cmd, new Command(cmd, usage, false) { 1089 public void doit(Tokens t) { 1090 final int len = t.countTokens(); 1091 Object[] args = new Object[len]; 1092 for (int i = 0; i < len; i++) { 1093 args[i] = t.nextToken(); 1094 } 1095 jsengine.call(func, args); 1096 } 1097 }); 1098 } 1099 1100 public void setOutput(PrintStream o) { 1101 out = o; 1102 } 1103 1104 public void setErr(PrintStream e) { 1105 err = e; 1106 } 1107 1108 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { 1109 this.debugger = debugger; 1110 this.agent = debugger.getAgent(); 1111 this.in = in; 1112 this.out = out; 1113 this.err = err; 1114 for (int i = 0; i < commandList.length; i++) { 1115 Command c = commandList[i]; 1116 commands.put(c.name, c); 1117 } 1118 if (debugger.isAttached()) { 1119 postAttach(); 1120 } 1121 } 1122 1123 1124 public void run(boolean prompt) { 1125 // Process interactive commands. 1126 while (true) { 1127 if (prompt) printPrompt(); 1128 String ln = null; 1129 try { 1130 ln = in.readLine(); 1131 } catch (IOException e) { 1132 } 1133 if (ln == null) { 1134 if (prompt) err.println("Input stream closed."); 1135 return; 1136 } 1137 1138 executeCommand(ln); 1139 } 1140 } 1141 1142 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*))"); 1143 1144 public void executeCommand(String ln) { 1145 if (ln.indexOf('!') != -1) { 1146 int size = history.size(); 1147 if (size == 0) { 1148 ln = ""; 1149 err.println("History is empty"); 1150 } else { 1151 StringBuffer result = new StringBuffer(); 1152 Matcher m = historyPattern.matcher(ln); 1153 int start = 0; 1154 while (m.find()) { 1155 if (m.start() > start) { 1156 result.append(ln.substring(start, m.start() - start)); 1157 } 1158 start = m.end(); 1159 1160 String cmd = m.group(); 1161 if (cmd.equals("!!")) { 1162 result.append((String)history.get(history.size() - 1)); 1163 } else if (cmd.equals("!!-")) { 1164 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1165 item.trim(1); 1166 result.append(item.join(" ")); 1167 } else if (cmd.equals("!*")) { 1168 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1169 item.nextToken(); 1170 result.append(item.join(" ")); 1171 } else if (cmd.equals("!$")) { 1172 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1173 result.append(item.at(item.countTokens() - 1)); 1174 } else { 1175 String tail = cmd.substring(1); 1176 int index = Integer.parseInt(tail); 1177 if (index < 0) { 1178 index = history.size() + index; 1179 } 1180 if (index > size) { 1181 err.println("No such history item"); 1182 } else { 1183 result.append((String)history.get(index)); 1184 } 1185 } 1186 } 1187 if (result.length() == 0) { 1188 err.println("malformed history reference"); 1189 ln = ""; 1190 } else { 1191 if (start < ln.length()) { 1192 result.append(ln.substring(start)); 1193 } 1194 ln = result.toString(); 1195 if (!doEcho) { 1196 out.println(ln); 1197 } 1198 } 1199 } 1200 } 1201 1202 if (doEcho) { 1203 out.println("+ " + ln); 1204 } 1205 1206 PrintStream redirect = null; 1207 Tokens t = new Tokens(ln); 1208 if (t.hasMoreTokens()) { 1209 boolean error = false; 1210 history.add(ln); 1211 int len = t.countTokens(); 1212 if (len > 2) { 1213 String r = t.at(len - 2); 1214 if (r.equals(">") || r.equals(">>")) { 1215 boolean append = r.length() == 2; 1216 String file = t.at(len - 1); 1217 try { 1218 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append))); 1219 t.trim(2); 1220 } catch (Exception e) { 1221 out.println("Error: " + e); 1222 if (verboseExceptions) { 1223 e.printStackTrace(out); 1224 } 1225 error = true; 1226 } 1227 } 1228 } 1229 if (!error) { 1230 PrintStream savedout = out; 1231 if (redirect != null) { 1232 out = redirect; 1233 } 1234 try { 1235 executeCommand(t); 1236 } catch (Exception e) { 1237 err.println("Error: " + e); 1238 if (verboseExceptions) { 1239 e.printStackTrace(err); 1240 } 1241 } finally { 1242 if (redirect != null) { 1243 out = savedout; 1244 redirect.close(); 1245 } 1246 } 1247 } 1248 } 1249 } 1250 1251 void executeCommand(Tokens args) { 1252 String cmd = args.nextToken(); 1253 1254 Command doit = findCommand(cmd); 1255 1256 /* 1257 * Check for an unknown command 1258 */ 1259 if (doit == null) { 1260 out.println("Unrecognized command. Try help..."); 1261 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { 1262 out.println("Command not valid until the attached to a VM"); 1263 } else { 1264 try { 1265 doit.doit(args); 1266 } catch (Exception e) { 1267 out.println("Error: " + e); 1268 if (verboseExceptions) { 1269 e.printStackTrace(out); 1270 } 1271 } 1272 } 1273 } 1274 }