1 /* 2 * Copyright 2005 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 889 public void epilogue() { 890 } 891 }; 892 VM.getVM().getObjectHeap().iterateRaw(iterator); 893 } else if (type.equals("codecache")) { 894 CodeCacheVisitor v = new CodeCacheVisitor() { 895 public void prologue(Address start, Address end) { 896 } 897 public void visit(CodeBlob blob) { 898 boolean printed = false; 899 Address base = blob.getAddress(); 900 Address end = base.addOffsetTo(blob.getSize()); 901 while (base != null && base.lessThan(end)) { 902 Address val = base.getAddressAt(0); 903 if (AddressOps.equal(val, value)) { 904 if (!printed) { 905 printed = true; 906 blob.printOn(out); 907 } 908 out.println("found at " + base + "\n"); 909 } 910 base = base.addOffsetTo(stride); 911 } 912 } 913 public void epilogue() { 914 } 915 916 917 }; 918 VM.getVM().getCodeCache().iterate(v); 919 920 } 921 } 922 } 923 }, 924 new Command("where", "where { -a | id }", false) { 925 public void doit(Tokens t) { 926 if (t.countTokens() != 1) { 927 usage(); 928 } else { 929 String name = t.nextToken(); 930 Threads threads = VM.getVM().getThreads(); 931 boolean all = name.equals("-a"); 932 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 933 StringWriter sw = new StringWriter(); 934 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 935 thread.printThreadIDOn(new PrintStream(bos)); 936 if (all || bos.toString().equals(name)) { 937 HTMLGenerator gen = new HTMLGenerator(false); 938 out.println(gen.genHTMLForJavaStackTrace(thread)); 939 if (!all) return; 940 } 941 } 942 if (!all) out.println("Couldn't find thread " + name); 943 } 944 } 945 }, 946 947 new Command("threads", false) { 948 public void doit(Tokens t) { 949 if (t.countTokens() != 0) { 950 usage(); 951 } else { 952 Threads threads = VM.getVM().getThreads(); 953 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 954 thread.printThreadIDOn(out); 955 out.println(" " + thread.getThreadName()); 956 } 957 } 958 } 959 }, 960 961 new Command("livenmethods", false) { 962 public void doit(Tokens t) { 963 if (t.countTokens() != 0) { 964 usage(); 965 } else { 966 ArrayList nmethods = new ArrayList(); 967 Threads threads = VM.getVM().getThreads(); 968 HTMLGenerator gen = new HTMLGenerator(false); 969 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 970 try { 971 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 972 if (vf instanceof CompiledVFrame) { 973 NMethod c = ((CompiledVFrame)vf).getCode(); 974 if (!nmethods.contains(c)) { 975 nmethods.add(c); 976 out.println(gen.genHTML(c)); 977 } 978 } 979 } 980 } catch (Exception e) { 981 e.printStackTrace(); 982 } 983 } 984 } 985 } 986 }, 987 new Command("universe", false) { 988 public void doit(Tokens t) { 989 if (t.countTokens() != 0) { 990 usage(); 991 } else { 992 Universe u = VM.getVM().getUniverse(); 993 out.println("Heap Parameters:"); 994 u.heap().printOn(out); 995 } 996 } 997 }, 998 new Command("verbose", "verbose true | false", true) { 999 public void doit(Tokens t) { 1000 if (t.countTokens() != 1) { 1001 usage(); 1002 } else { 1003 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); 1004 } 1005 } 1006 }, 1007 new Command("assert", "assert true | false", true) { 1008 public void doit(Tokens t) { 1009 if (t.countTokens() != 1) { 1010 usage(); 1011 } else { 1012 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); 1013 } 1014 } 1015 }, 1016 }; 1017 1018 private boolean verboseExceptions = false; 1019 private ArrayList history = new ArrayList(); 1020 private HashMap commands = new HashMap(); 1021 private boolean doEcho = false; 1022 1023 private Command findCommand(String key) { 1024 return (Command)commands.get(key); 1025 } 1026 1027 public void printPrompt() { 1028 out.print("hsdb> "); 1029 } 1030 1031 private DebuggerInterface debugger; 1032 private HotSpotAgent agent; 1033 private JSJavaScriptEngine jsengine; 1034 private BufferedReader in; 1035 private PrintStream out; 1036 private PrintStream err; 1037 1038 // called before debuggee attach 1039 private void preAttach() { 1040 // nothing for now.. 1041 } 1042 1043 // called after debuggee attach 1044 private void postAttach() { 1045 // create JavaScript engine and start it 1046 jsengine = new JSJavaScriptEngine() { 1047 private ObjectReader reader = new ObjectReader(); 1048 private JSJavaFactory factory = new JSJavaFactoryImpl(); 1049 public ObjectReader getObjectReader() { 1050 return reader; 1051 } 1052 public JSJavaFactory getJSJavaFactory() { 1053 return factory; 1054 } 1055 protected void quit() { 1056 debugger.detach(); 1057 System.exit(0); 1058 } 1059 protected BufferedReader getInputReader() { 1060 return in; 1061 } 1062 protected PrintStream getOutputStream() { 1063 return out; 1064 } 1065 protected PrintStream getErrorStream() { 1066 return err; 1067 } 1068 }; 1069 try { 1070 jsengine.defineFunction(this, 1071 this.getClass().getMethod("registerCommand", 1072 new Class[] { 1073 String.class, String.class, String.class 1074 })); 1075 } catch (NoSuchMethodException exp) { 1076 // should not happen, see below...!! 1077 exp.printStackTrace(); 1078 } 1079 jsengine.start(); 1080 } 1081 1082 public void registerCommand(String cmd, String usage, final String func) { 1083 commands.put(cmd, new Command(cmd, usage, false) { 1084 public void doit(Tokens t) { 1085 final int len = t.countTokens(); 1086 Object[] args = new Object[len]; 1087 for (int i = 0; i < len; i++) { 1088 args[i] = t.nextToken(); 1089 } 1090 jsengine.call(func, args); 1091 } 1092 }); 1093 } 1094 1095 public void setOutput(PrintStream o) { 1096 out = o; 1097 } 1098 1099 public void setErr(PrintStream e) { 1100 err = e; 1101 } 1102 1103 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { 1104 this.debugger = debugger; 1105 this.agent = debugger.getAgent(); 1106 this.in = in; 1107 this.out = out; 1108 this.err = err; 1109 for (int i = 0; i < commandList.length; i++) { 1110 Command c = commandList[i]; 1111 commands.put(c.name, c); 1112 } 1113 if (debugger.isAttached()) { 1114 postAttach(); 1115 } 1116 } 1117 1118 1119 public void run(boolean prompt) { 1120 // Process interactive commands. 1121 while (true) { 1122 if (prompt) printPrompt(); 1123 String ln = null; 1124 try { 1125 ln = in.readLine(); 1126 } catch (IOException e) { 1127 } 1128 if (ln == null) { 1129 if (prompt) err.println("Input stream closed."); 1130 return; 1131 } 1132 1133 executeCommand(ln); 1134 } 1135 } 1136 1137 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*))"); 1138 1139 public void executeCommand(String ln) { 1140 if (ln.indexOf('!') != -1) { 1141 int size = history.size(); 1142 if (size == 0) { 1143 ln = ""; 1144 err.println("History is empty"); 1145 } else { 1146 StringBuffer result = new StringBuffer(); 1147 Matcher m = historyPattern.matcher(ln); 1148 int start = 0; 1149 while (m.find()) { 1150 if (m.start() > start) { 1151 result.append(ln.substring(start, m.start() - start)); 1152 } 1153 start = m.end(); 1154 1155 String cmd = m.group(); 1156 if (cmd.equals("!!")) { 1157 result.append((String)history.get(history.size() - 1)); 1158 } else if (cmd.equals("!!-")) { 1159 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1160 item.trim(1); 1161 result.append(item.join(" ")); 1162 } else if (cmd.equals("!*")) { 1163 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1164 item.nextToken(); 1165 result.append(item.join(" ")); 1166 } else if (cmd.equals("!$")) { 1167 Tokens item = new Tokens((String)history.get(history.size() - 1)); 1168 result.append(item.at(item.countTokens() - 1)); 1169 } else { 1170 String tail = cmd.substring(1); 1171 int index = Integer.parseInt(tail); 1172 if (index < 0) { 1173 index = history.size() + index; 1174 } 1175 if (index > size) { 1176 err.println("No such history item"); 1177 } else { 1178 result.append((String)history.get(index)); 1179 } 1180 } 1181 } 1182 if (result.length() == 0) { 1183 err.println("malformed history reference"); 1184 ln = ""; 1185 } else { 1186 if (start < ln.length()) { 1187 result.append(ln.substring(start)); 1188 } 1189 ln = result.toString(); 1190 if (!doEcho) { 1191 out.println(ln); 1192 } 1193 } 1194 } 1195 } 1196 1197 if (doEcho) { 1198 out.println("+ " + ln); 1199 } 1200 1201 PrintStream redirect = null; 1202 Tokens t = new Tokens(ln); 1203 if (t.hasMoreTokens()) { 1204 boolean error = false; 1205 history.add(ln); 1206 int len = t.countTokens(); 1207 if (len > 2) { 1208 String r = t.at(len - 2); 1209 if (r.equals(">") || r.equals(">>")) { 1210 boolean append = r.length() == 2; 1211 String file = t.at(len - 1); 1212 try { 1213 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append))); 1214 t.trim(2); 1215 } catch (Exception e) { 1216 out.println("Error: " + e); 1217 if (verboseExceptions) { 1218 e.printStackTrace(out); 1219 } 1220 error = true; 1221 } 1222 } 1223 } 1224 if (!error) { 1225 PrintStream savedout = out; 1226 if (redirect != null) { 1227 out = redirect; 1228 } 1229 try { 1230 executeCommand(t); 1231 } catch (Exception e) { 1232 err.println("Error: " + e); 1233 if (verboseExceptions) { 1234 e.printStackTrace(err); 1235 } 1236 } finally { 1237 if (redirect != null) { 1238 out = savedout; 1239 redirect.close(); 1240 } 1241 } 1242 } 1243 } 1244 } 1245 1246 void executeCommand(Tokens args) { 1247 String cmd = args.nextToken(); 1248 1249 Command doit = findCommand(cmd); 1250 1251 /* 1252 * Check for an unknown command 1253 */ 1254 if (doit == null) { 1255 out.println("Unrecognized command. Try help..."); 1256 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { 1257 out.println("Command not valid until the attached to a VM"); 1258 } else { 1259 try { 1260 doit.doit(args); 1261 } catch (Exception e) { 1262 out.println("Error: " + e); 1263 if (verboseExceptions) { 1264 e.printStackTrace(out); 1265 } 1266 } 1267 } 1268 } 1269 }