1 /* 2 * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * This source code is provided to illustrate the usage of a given feature 28 * or technique and has been deliberately simplified. Additional steps 29 * required for a production-quality application, such as security checks, 30 * input validation and proper error handling, might not be present in 31 * this sample code. 32 */ 33 34 35 package com.sun.tools.example.debug.tty; 36 37 import com.sun.jdi.*; 38 import com.sun.jdi.connect.Connector; 39 import com.sun.jdi.request.*; 40 import com.sun.tools.example.debug.expr.ExpressionParser; 41 import com.sun.tools.example.debug.expr.ParseException; 42 43 import java.text.*; 44 import java.util.*; 45 import java.io.*; 46 47 class Commands { 48 49 abstract class AsyncExecution { action()50 abstract void action(); 51 AsyncExecution()52 AsyncExecution() { 53 execute(); 54 } 55 execute()56 void execute() { 57 /* 58 * Save current thread and stack frame. (BugId 4296031) 59 */ 60 final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 61 final int stackFrame = threadInfo == null? 0 : threadInfo.getCurrentFrameIndex(); 62 Thread thread = new Thread("asynchronous jdb command") { 63 @Override 64 public void run() { 65 try { 66 action(); 67 } catch (UnsupportedOperationException uoe) { 68 //(BugId 4453329) 69 MessageOutput.println("Operation is not supported on the target VM"); 70 } catch (Exception e) { 71 MessageOutput.println("Internal exception during operation:", 72 e.getMessage()); 73 } finally { 74 /* 75 * This was an asynchronous command. Events may have been 76 * processed while it was running. Restore the thread and 77 * stack frame the user was looking at. (BugId 4296031) 78 */ 79 if (threadInfo != null) { 80 ThreadInfo.setCurrentThreadInfo(threadInfo); 81 try { 82 threadInfo.setCurrentFrameIndex(stackFrame); 83 } catch (IncompatibleThreadStateException e) { 84 MessageOutput.println("Current thread isnt suspended."); 85 } catch (ArrayIndexOutOfBoundsException e) { 86 MessageOutput.println("Requested stack frame is no longer active:", 87 new Object []{stackFrame}); 88 } 89 } 90 MessageOutput.printPrompt(); 91 } 92 } 93 }; 94 thread.start(); 95 } 96 } 97 Commands()98 Commands() { 99 } 100 evaluate(String expr)101 private Value evaluate(String expr) { 102 Value result = null; 103 ExpressionParser.GetFrame frameGetter = null; 104 try { 105 final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 106 if ((threadInfo != null) && (threadInfo.getCurrentFrame() != null)) { 107 frameGetter = new ExpressionParser.GetFrame() { 108 @Override 109 public StackFrame get() throws IncompatibleThreadStateException { 110 return threadInfo.getCurrentFrame(); 111 } 112 }; 113 } 114 result = ExpressionParser.evaluate(expr, Env.vm(), frameGetter); 115 } catch (InvocationException ie) { 116 MessageOutput.println("Exception in expression:", 117 ie.exception().referenceType().name()); 118 } catch (Exception ex) { 119 String exMessage = ex.getMessage(); 120 if (exMessage == null) { 121 MessageOutput.printException(exMessage, ex); 122 } else { 123 String s; 124 try { 125 s = MessageOutput.format(exMessage); 126 } catch (MissingResourceException mex) { 127 s = ex.toString(); 128 } 129 MessageOutput.printDirectln(s);// Special case: use printDirectln() 130 } 131 } 132 return result; 133 } 134 getStringValue()135 private String getStringValue() { 136 Value val = null; 137 String valStr = null; 138 try { 139 val = ExpressionParser.getMassagedValue(); 140 valStr = val.toString(); 141 } catch (ParseException e) { 142 String msg = e.getMessage(); 143 if (msg == null) { 144 MessageOutput.printException(msg, e); 145 } else { 146 String s; 147 try { 148 s = MessageOutput.format(msg); 149 } catch (MissingResourceException mex) { 150 s = e.toString(); 151 } 152 MessageOutput.printDirectln(s); 153 } 154 } 155 return valStr; 156 } 157 doGetThread(String idToken)158 private ThreadInfo doGetThread(String idToken) { 159 ThreadInfo threadInfo = ThreadInfo.getThreadInfo(idToken); 160 if (threadInfo == null) { 161 MessageOutput.println("is not a valid thread id", idToken); 162 } 163 return threadInfo; 164 } 165 typedName(Method method)166 String typedName(Method method) { 167 StringBuilder sb = new StringBuilder(); 168 sb.append(method.name()); 169 sb.append("("); 170 171 List<String> args = method.argumentTypeNames(); 172 int lastParam = args.size() - 1; 173 // output param types except for the last 174 for (int ii = 0; ii < lastParam; ii++) { 175 sb.append(args.get(ii)); 176 sb.append(", "); 177 } 178 if (lastParam >= 0) { 179 // output the last param 180 String lastStr = args.get(lastParam); 181 if (method.isVarArgs()) { 182 // lastParam is an array. Replace the [] with ... 183 sb.append(lastStr.substring(0, lastStr.length() - 2)); 184 sb.append("..."); 185 } else { 186 sb.append(lastStr); 187 } 188 } 189 sb.append(")"); 190 return sb.toString(); 191 } 192 commandConnectors(VirtualMachineManager vmm)193 void commandConnectors(VirtualMachineManager vmm) { 194 Collection<Connector> ccs = vmm.allConnectors(); 195 if (ccs.isEmpty()) { 196 MessageOutput.println("Connectors available"); 197 } 198 for (Connector cc : ccs) { 199 String transportName = 200 cc.transport() == null ? "null" : cc.transport().name(); 201 MessageOutput.println(); 202 MessageOutput.println("Connector and Transport name", 203 new Object [] {cc.name(), transportName}); 204 MessageOutput.println("Connector description", cc.description()); 205 206 for (Connector.Argument aa : cc.defaultArguments().values()) { 207 MessageOutput.println(); 208 209 boolean requiredArgument = aa.mustSpecify(); 210 if (aa.value() == null || aa.value() == "") { 211 //no current value and no default. 212 MessageOutput.println(requiredArgument ? 213 "Connector required argument nodefault" : 214 "Connector argument nodefault", aa.name()); 215 } else { 216 MessageOutput.println(requiredArgument ? 217 "Connector required argument default" : 218 "Connector argument default", 219 new Object [] {aa.name(), aa.value()}); 220 } 221 MessageOutput.println("Connector description", aa.description()); 222 223 } 224 } 225 226 } 227 commandClasses()228 void commandClasses() { 229 StringBuilder classList = new StringBuilder(); 230 for (ReferenceType refType : Env.vm().allClasses()) { 231 classList.append(refType.name()); 232 classList.append("\n"); 233 } 234 MessageOutput.print("** classes list **", classList.toString()); 235 } 236 commandClass(StringTokenizer t)237 void commandClass(StringTokenizer t) { 238 239 if (!t.hasMoreTokens()) { 240 MessageOutput.println("No class specified."); 241 return; 242 } 243 244 String idClass = t.nextToken(); 245 boolean showAll = false; 246 247 if (t.hasMoreTokens()) { 248 if (t.nextToken().toLowerCase().equals("all")) { 249 showAll = true; 250 } else { 251 MessageOutput.println("Invalid option on class command"); 252 return; 253 } 254 } 255 ReferenceType type = Env.getReferenceTypeFromToken(idClass); 256 if (type == null) { 257 MessageOutput.println("is not a valid id or class name", idClass); 258 return; 259 } 260 if (type instanceof ClassType) { 261 ClassType clazz = (ClassType)type; 262 MessageOutput.println("Class:", clazz.name()); 263 264 ClassType superclass = clazz.superclass(); 265 while (superclass != null) { 266 MessageOutput.println("extends:", superclass.name()); 267 superclass = showAll ? superclass.superclass() : null; 268 } 269 270 List<InterfaceType> interfaces = 271 showAll ? clazz.allInterfaces() : clazz.interfaces(); 272 for (InterfaceType interfaze : interfaces) { 273 MessageOutput.println("implements:", interfaze.name()); 274 } 275 276 for (ClassType sub : clazz.subclasses()) { 277 MessageOutput.println("subclass:", sub.name()); 278 } 279 for (ReferenceType nest : clazz.nestedTypes()) { 280 MessageOutput.println("nested:", nest.name()); 281 } 282 } else if (type instanceof InterfaceType) { 283 InterfaceType interfaze = (InterfaceType)type; 284 MessageOutput.println("Interface:", interfaze.name()); 285 for (InterfaceType superinterface : interfaze.superinterfaces()) { 286 MessageOutput.println("extends:", superinterface.name()); 287 } 288 for (InterfaceType sub : interfaze.subinterfaces()) { 289 MessageOutput.println("subinterface:", sub.name()); 290 } 291 for (ClassType implementor : interfaze.implementors()) { 292 MessageOutput.println("implementor:", implementor.name()); 293 } 294 for (ReferenceType nest : interfaze.nestedTypes()) { 295 MessageOutput.println("nested:", nest.name()); 296 } 297 } else { // array type 298 ArrayType array = (ArrayType)type; 299 MessageOutput.println("Array:", array.name()); 300 } 301 } 302 commandMethods(StringTokenizer t)303 void commandMethods(StringTokenizer t) { 304 if (!t.hasMoreTokens()) { 305 MessageOutput.println("No class specified."); 306 return; 307 } 308 309 String idClass = t.nextToken(); 310 ReferenceType cls = Env.getReferenceTypeFromToken(idClass); 311 if (cls != null) { 312 StringBuilder methodsList = new StringBuilder(); 313 for (Method method : cls.allMethods()) { 314 methodsList.append(method.declaringType().name()); 315 methodsList.append(" "); 316 methodsList.append(typedName(method)); 317 methodsList.append('\n'); 318 } 319 MessageOutput.print("** methods list **", methodsList.toString()); 320 } else { 321 MessageOutput.println("is not a valid id or class name", idClass); 322 } 323 } 324 commandFields(StringTokenizer t)325 void commandFields(StringTokenizer t) { 326 if (!t.hasMoreTokens()) { 327 MessageOutput.println("No class specified."); 328 return; 329 } 330 331 String idClass = t.nextToken(); 332 ReferenceType cls = Env.getReferenceTypeFromToken(idClass); 333 if (cls != null) { 334 List<Field> fields = cls.allFields(); 335 List<Field> visible = cls.visibleFields(); 336 StringBuilder fieldsList = new StringBuilder(); 337 for (Field field : fields) { 338 String s; 339 if (!visible.contains(field)) { 340 s = MessageOutput.format("list field typename and name hidden", 341 new Object [] {field.typeName(), 342 field.name()}); 343 } else if (!field.declaringType().equals(cls)) { 344 s = MessageOutput.format("list field typename and name inherited", 345 new Object [] {field.typeName(), 346 field.name(), 347 field.declaringType().name()}); 348 } else { 349 s = MessageOutput.format("list field typename and name", 350 new Object [] {field.typeName(), 351 field.name()}); 352 } 353 fieldsList.append(s); 354 } 355 MessageOutput.print("** fields list **", fieldsList.toString()); 356 } else { 357 MessageOutput.println("is not a valid id or class name", idClass); 358 } 359 } 360 printThreadGroup(ThreadGroupReference tg)361 private void printThreadGroup(ThreadGroupReference tg) { 362 ThreadIterator threadIter = new ThreadIterator(tg); 363 364 MessageOutput.println("Thread Group:", tg.name()); 365 int maxIdLength = 0; 366 int maxNameLength = 0; 367 while (threadIter.hasNext()) { 368 ThreadReference thr = threadIter.next(); 369 maxIdLength = Math.max(maxIdLength, 370 Env.description(thr).length()); 371 maxNameLength = Math.max(maxNameLength, 372 thr.name().length()); 373 } 374 375 threadIter = new ThreadIterator(tg); 376 while (threadIter.hasNext()) { 377 ThreadReference thr = threadIter.next(); 378 if (thr.threadGroup() == null) { 379 continue; 380 } 381 // Note any thread group changes 382 if (!thr.threadGroup().equals(tg)) { 383 tg = thr.threadGroup(); 384 MessageOutput.println("Thread Group:", tg.name()); 385 } 386 387 /* 388 * Do a bit of filling with whitespace to get thread ID 389 * and thread names to line up in the listing, and also 390 * allow for proper localization. This also works for 391 * very long thread names, at the possible cost of lines 392 * being wrapped by the display device. 393 */ 394 StringBuilder idBuffer = new StringBuilder(Env.description(thr)); 395 for (int i = idBuffer.length(); i < maxIdLength; i++) { 396 idBuffer.append(" "); 397 } 398 StringBuilder nameBuffer = new StringBuilder(thr.name()); 399 for (int i = nameBuffer.length(); i < maxNameLength; i++) { 400 nameBuffer.append(" "); 401 } 402 403 /* 404 * Select the output format to use based on thread status 405 * and breakpoint. 406 */ 407 String statusFormat; 408 switch (thr.status()) { 409 case ThreadReference.THREAD_STATUS_UNKNOWN: 410 if (thr.isAtBreakpoint()) { 411 statusFormat = "Thread description name unknownStatus BP"; 412 } else { 413 statusFormat = "Thread description name unknownStatus"; 414 } 415 break; 416 case ThreadReference.THREAD_STATUS_ZOMBIE: 417 if (thr.isAtBreakpoint()) { 418 statusFormat = "Thread description name zombieStatus BP"; 419 } else { 420 statusFormat = "Thread description name zombieStatus"; 421 } 422 break; 423 case ThreadReference.THREAD_STATUS_RUNNING: 424 if (thr.isAtBreakpoint()) { 425 statusFormat = "Thread description name runningStatus BP"; 426 } else { 427 statusFormat = "Thread description name runningStatus"; 428 } 429 break; 430 case ThreadReference.THREAD_STATUS_SLEEPING: 431 if (thr.isAtBreakpoint()) { 432 statusFormat = "Thread description name sleepingStatus BP"; 433 } else { 434 statusFormat = "Thread description name sleepingStatus"; 435 } 436 break; 437 case ThreadReference.THREAD_STATUS_MONITOR: 438 if (thr.isAtBreakpoint()) { 439 statusFormat = "Thread description name waitingStatus BP"; 440 } else { 441 statusFormat = "Thread description name waitingStatus"; 442 } 443 break; 444 case ThreadReference.THREAD_STATUS_WAIT: 445 if (thr.isAtBreakpoint()) { 446 statusFormat = "Thread description name condWaitstatus BP"; 447 } else { 448 statusFormat = "Thread description name condWaitstatus"; 449 } 450 break; 451 default: 452 throw new InternalError(MessageOutput.format("Invalid thread status.")); 453 } 454 MessageOutput.println(statusFormat, 455 new Object [] {idBuffer.toString(), 456 nameBuffer.toString()}); 457 } 458 } 459 commandThreads(StringTokenizer t)460 void commandThreads(StringTokenizer t) { 461 if (!t.hasMoreTokens()) { 462 printThreadGroup(ThreadInfo.group()); 463 return; 464 } 465 String name = t.nextToken(); 466 ThreadGroupReference tg = ThreadGroupIterator.find(name); 467 if (tg == null) { 468 MessageOutput.println("is not a valid threadgroup name", name); 469 } else { 470 printThreadGroup(tg); 471 } 472 } 473 commandThreadGroups()474 void commandThreadGroups() { 475 ThreadGroupIterator it = new ThreadGroupIterator(); 476 int cnt = 0; 477 while (it.hasNext()) { 478 ThreadGroupReference tg = it.nextThreadGroup(); 479 ++cnt; 480 MessageOutput.println("thread group number description name", 481 new Object [] { Integer.valueOf(cnt), 482 Env.description(tg), 483 tg.name()}); 484 } 485 } 486 commandThread(StringTokenizer t)487 void commandThread(StringTokenizer t) { 488 if (!t.hasMoreTokens()) { 489 MessageOutput.println("Thread number not specified."); 490 return; 491 } 492 ThreadInfo threadInfo = doGetThread(t.nextToken()); 493 if (threadInfo != null) { 494 ThreadInfo.setCurrentThreadInfo(threadInfo); 495 } 496 } 497 commandThreadGroup(StringTokenizer t)498 void commandThreadGroup(StringTokenizer t) { 499 if (!t.hasMoreTokens()) { 500 MessageOutput.println("Threadgroup name not specified."); 501 return; 502 } 503 String name = t.nextToken(); 504 ThreadGroupReference tg = ThreadGroupIterator.find(name); 505 if (tg == null) { 506 MessageOutput.println("is not a valid threadgroup name", name); 507 } else { 508 ThreadInfo.setThreadGroup(tg); 509 } 510 } 511 commandRun(StringTokenizer t)512 void commandRun(StringTokenizer t) { 513 /* 514 * The 'run' command makes little sense in a 515 * that doesn't support restarts or multiple VMs. However, 516 * this is an attempt to emulate the behavior of the old 517 * JDB as much as possible. For new users and implementations 518 * it is much more straightforward to launch immedidately 519 * with the -launch option. 520 */ 521 VMConnection connection = Env.connection(); 522 if (!connection.isLaunch()) { 523 if (!t.hasMoreTokens()) { 524 commandCont(); 525 } else { 526 MessageOutput.println("run <args> command is valid only with launched VMs"); 527 } 528 return; 529 } 530 if (connection.isOpen()) { 531 MessageOutput.println("VM already running. use cont to continue after events."); 532 return; 533 } 534 535 /* 536 * Set the main class and any arguments. Note that this will work 537 * only with the standard launcher, "com.sun.jdi.CommandLineLauncher" 538 */ 539 String args; 540 if (t.hasMoreTokens()) { 541 args = t.nextToken(""); 542 boolean argsSet = connection.setConnectorArg("main", args); 543 if (!argsSet) { 544 MessageOutput.println("Unable to set main class and arguments"); 545 return; 546 } 547 } else { 548 args = connection.connectorArg("main"); 549 if (args.length() == 0) { 550 MessageOutput.println("Main class and arguments must be specified"); 551 return; 552 } 553 } 554 MessageOutput.println("run", args); 555 556 /* 557 * Launch the VM. 558 */ 559 connection.open(); 560 561 } 562 commandLoad(StringTokenizer t)563 void commandLoad(StringTokenizer t) { 564 MessageOutput.println("The load command is no longer supported."); 565 } 566 allThreads(ThreadGroupReference group)567 private List<ThreadReference> allThreads(ThreadGroupReference group) { 568 List<ThreadReference> list = new ArrayList<ThreadReference>(); 569 list.addAll(group.threads()); 570 for (ThreadGroupReference child : group.threadGroups()) { 571 list.addAll(allThreads(child)); 572 } 573 return list; 574 } 575 commandSuspend(StringTokenizer t)576 void commandSuspend(StringTokenizer t) { 577 if (!t.hasMoreTokens()) { 578 Env.vm().suspend(); 579 MessageOutput.println("All threads suspended."); 580 } else { 581 while (t.hasMoreTokens()) { 582 ThreadInfo threadInfo = doGetThread(t.nextToken()); 583 if (threadInfo != null) { 584 threadInfo.getThread().suspend(); 585 } 586 } 587 } 588 } 589 commandResume(StringTokenizer t)590 void commandResume(StringTokenizer t) { 591 if (!t.hasMoreTokens()) { 592 ThreadInfo.invalidateAll(); 593 Env.vm().resume(); 594 MessageOutput.println("All threads resumed."); 595 } else { 596 while (t.hasMoreTokens()) { 597 ThreadInfo threadInfo = doGetThread(t.nextToken()); 598 if (threadInfo != null) { 599 threadInfo.invalidate(); 600 threadInfo.getThread().resume(); 601 } 602 } 603 } 604 } 605 commandCont()606 void commandCont() { 607 if (ThreadInfo.getCurrentThreadInfo() == null) { 608 MessageOutput.println("Nothing suspended."); 609 return; 610 } 611 ThreadInfo.invalidateAll(); 612 Env.vm().resume(); 613 } 614 clearPreviousStep(ThreadReference thread)615 void clearPreviousStep(ThreadReference thread) { 616 /* 617 * A previous step may not have completed on this thread; 618 * if so, it gets removed here. 619 */ 620 EventRequestManager mgr = Env.vm().eventRequestManager(); 621 for (StepRequest request : mgr.stepRequests()) { 622 if (request.thread().equals(thread)) { 623 mgr.deleteEventRequest(request); 624 break; 625 } 626 } 627 } 628 /* step 629 * 630 */ commandStep(StringTokenizer t)631 void commandStep(StringTokenizer t) { 632 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 633 if (threadInfo == null) { 634 MessageOutput.println("Nothing suspended."); 635 return; 636 } 637 int depth; 638 if (t.hasMoreTokens() && 639 t.nextToken().toLowerCase().equals("up")) { 640 depth = StepRequest.STEP_OUT; 641 } else { 642 depth = StepRequest.STEP_INTO; 643 } 644 645 clearPreviousStep(threadInfo.getThread()); 646 EventRequestManager reqMgr = Env.vm().eventRequestManager(); 647 StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(), 648 StepRequest.STEP_LINE, depth); 649 if (depth == StepRequest.STEP_INTO) { 650 Env.addExcludes(request); 651 } 652 // We want just the next step event and no others 653 request.addCountFilter(1); 654 request.enable(); 655 ThreadInfo.invalidateAll(); 656 Env.vm().resume(); 657 } 658 659 /* stepi 660 * step instruction. 661 */ commandStepi()662 void commandStepi() { 663 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 664 if (threadInfo == null) { 665 MessageOutput.println("Nothing suspended."); 666 return; 667 } 668 clearPreviousStep(threadInfo.getThread()); 669 EventRequestManager reqMgr = Env.vm().eventRequestManager(); 670 StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(), 671 StepRequest.STEP_MIN, 672 StepRequest.STEP_INTO); 673 Env.addExcludes(request); 674 // We want just the next step event and no others 675 request.addCountFilter(1); 676 request.enable(); 677 ThreadInfo.invalidateAll(); 678 Env.vm().resume(); 679 } 680 commandNext()681 void commandNext() { 682 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 683 if (threadInfo == null) { 684 MessageOutput.println("Nothing suspended."); 685 return; 686 } 687 clearPreviousStep(threadInfo.getThread()); 688 EventRequestManager reqMgr = Env.vm().eventRequestManager(); 689 StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(), 690 StepRequest.STEP_LINE, 691 StepRequest.STEP_OVER); 692 Env.addExcludes(request); 693 // We want just the next step event and no others 694 request.addCountFilter(1); 695 request.enable(); 696 ThreadInfo.invalidateAll(); 697 Env.vm().resume(); 698 } 699 doKill(ThreadReference thread, StringTokenizer t)700 void doKill(ThreadReference thread, StringTokenizer t) { 701 if (!t.hasMoreTokens()) { 702 MessageOutput.println("No exception object specified."); 703 return; 704 } 705 String expr = t.nextToken(""); 706 Value val = evaluate(expr); 707 if ((val != null) && (val instanceof ObjectReference)) { 708 try { 709 thread.stop((ObjectReference)val); 710 MessageOutput.println("killed", thread.toString()); 711 } catch (InvalidTypeException e) { 712 MessageOutput.println("Invalid exception object"); 713 } 714 } else { 715 MessageOutput.println("Expression must evaluate to an object"); 716 } 717 } 718 doKillThread(final ThreadReference threadToKill, final StringTokenizer tokenizer)719 void doKillThread(final ThreadReference threadToKill, 720 final StringTokenizer tokenizer) { 721 new AsyncExecution() { 722 @Override 723 void action() { 724 doKill(threadToKill, tokenizer); 725 } 726 }; 727 } 728 commandKill(StringTokenizer t)729 void commandKill(StringTokenizer t) { 730 if (!t.hasMoreTokens()) { 731 MessageOutput.println("Usage: kill <thread id> <throwable>"); 732 return; 733 } 734 ThreadInfo threadInfo = doGetThread(t.nextToken()); 735 if (threadInfo != null) { 736 MessageOutput.println("killing thread:", threadInfo.getThread().name()); 737 doKillThread(threadInfo.getThread(), t); 738 return; 739 } 740 } 741 listCaughtExceptions()742 void listCaughtExceptions() { 743 boolean noExceptions = true; 744 745 // Print a listing of the catch patterns currently in place 746 for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) { 747 if (spec instanceof ExceptionSpec) { 748 if (noExceptions) { 749 noExceptions = false; 750 MessageOutput.println("Exceptions caught:"); 751 } 752 MessageOutput.println("tab", spec.toString()); 753 } 754 } 755 if (noExceptions) { 756 MessageOutput.println("No exceptions caught."); 757 } 758 } 759 parseExceptionSpec(StringTokenizer t)760 private EventRequestSpec parseExceptionSpec(StringTokenizer t) { 761 String notification = t.nextToken(); 762 boolean notifyCaught = false; 763 boolean notifyUncaught = false; 764 EventRequestSpec spec = null; 765 String classPattern = null; 766 767 if (notification.equals("uncaught")) { 768 notifyCaught = false; 769 notifyUncaught = true; 770 } else if (notification.equals("caught")) { 771 notifyCaught = true; 772 notifyUncaught = false; 773 } else if (notification.equals("all")) { 774 notifyCaught = true; 775 notifyUncaught = true; 776 } else { 777 /* 778 * Handle the same as "all" for backward 779 * compatibility with existing .jdbrc files. 780 * 781 * Insert an "all" and take the current token as the 782 * intended classPattern 783 * 784 */ 785 notifyCaught = true; 786 notifyUncaught = true; 787 classPattern = notification; 788 } 789 if (classPattern == null && t.hasMoreTokens()) { 790 classPattern = t.nextToken(); 791 } 792 if ((classPattern != null) && (notifyCaught || notifyUncaught)) { 793 try { 794 spec = Env.specList.createExceptionCatch(classPattern, 795 notifyCaught, 796 notifyUncaught); 797 } catch (ClassNotFoundException exc) { 798 MessageOutput.println("is not a valid class name", classPattern); 799 } 800 } 801 return spec; 802 } 803 commandCatchException(StringTokenizer t)804 void commandCatchException(StringTokenizer t) { 805 if (!t.hasMoreTokens()) { 806 listCaughtExceptions(); 807 } else { 808 EventRequestSpec spec = parseExceptionSpec(t); 809 if (spec != null) { 810 resolveNow(spec); 811 } else { 812 MessageOutput.println("Usage: catch exception"); 813 } 814 } 815 } 816 commandIgnoreException(StringTokenizer t)817 void commandIgnoreException(StringTokenizer t) { 818 if (!t.hasMoreTokens()) { 819 listCaughtExceptions(); 820 } else { 821 EventRequestSpec spec = parseExceptionSpec(t); 822 if (Env.specList.delete(spec)) { 823 MessageOutput.println("Removed:", spec.toString()); 824 } else { 825 if (spec != null) { 826 MessageOutput.println("Not found:", spec.toString()); 827 } 828 MessageOutput.println("Usage: ignore exception"); 829 } 830 } 831 } 832 commandUp(StringTokenizer t)833 void commandUp(StringTokenizer t) { 834 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 835 if (threadInfo == null) { 836 MessageOutput.println("Current thread not set."); 837 return; 838 } 839 840 int nLevels = 1; 841 if (t.hasMoreTokens()) { 842 String idToken = t.nextToken(); 843 int i; 844 try { 845 NumberFormat nf = NumberFormat.getNumberInstance(); 846 nf.setParseIntegerOnly(true); 847 Number n = nf.parse(idToken); 848 i = n.intValue(); 849 } catch (java.text.ParseException jtpe) { 850 i = 0; 851 } 852 if (i <= 0) { 853 MessageOutput.println("Usage: up [n frames]"); 854 return; 855 } 856 nLevels = i; 857 } 858 859 try { 860 threadInfo.up(nLevels); 861 } catch (IncompatibleThreadStateException e) { 862 MessageOutput.println("Current thread isnt suspended."); 863 } catch (ArrayIndexOutOfBoundsException e) { 864 MessageOutput.println("End of stack."); 865 } 866 } 867 commandDown(StringTokenizer t)868 void commandDown(StringTokenizer t) { 869 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 870 if (threadInfo == null) { 871 MessageOutput.println("Current thread not set."); 872 return; 873 } 874 875 int nLevels = 1; 876 if (t.hasMoreTokens()) { 877 String idToken = t.nextToken(); 878 int i; 879 try { 880 NumberFormat nf = NumberFormat.getNumberInstance(); 881 nf.setParseIntegerOnly(true); 882 Number n = nf.parse(idToken); 883 i = n.intValue(); 884 } catch (java.text.ParseException jtpe) { 885 i = 0; 886 } 887 if (i <= 0) { 888 MessageOutput.println("Usage: down [n frames]"); 889 return; 890 } 891 nLevels = i; 892 } 893 894 try { 895 threadInfo.down(nLevels); 896 } catch (IncompatibleThreadStateException e) { 897 MessageOutput.println("Current thread isnt suspended."); 898 } catch (ArrayIndexOutOfBoundsException e) { 899 MessageOutput.println("End of stack."); 900 } 901 } 902 dumpStack(ThreadInfo threadInfo, boolean showPC)903 private void dumpStack(ThreadInfo threadInfo, boolean showPC) { 904 List<StackFrame> stack = null; 905 try { 906 stack = threadInfo.getStack(); 907 } catch (IncompatibleThreadStateException e) { 908 MessageOutput.println("Current thread isnt suspended."); 909 return; 910 } 911 if (stack == null) { 912 MessageOutput.println("Thread is not running (no stack)."); 913 } else { 914 int nFrames = stack.size(); 915 for (int i = threadInfo.getCurrentFrameIndex(); i < nFrames; i++) { 916 StackFrame frame = stack.get(i); 917 dumpFrame (i, showPC, frame); 918 } 919 } 920 } 921 dumpFrame(int frameNumber, boolean showPC, StackFrame frame)922 private void dumpFrame (int frameNumber, boolean showPC, StackFrame frame) { 923 Location loc = frame.location(); 924 long pc = -1; 925 if (showPC) { 926 pc = loc.codeIndex(); 927 } 928 Method meth = loc.method(); 929 930 long lineNumber = loc.lineNumber(); 931 String methodInfo = null; 932 if (meth.isNative()) { 933 methodInfo = MessageOutput.format("native method"); 934 } else if (lineNumber != -1) { 935 try { 936 methodInfo = loc.sourceName() + 937 MessageOutput.format("line number", 938 new Object [] {Long.valueOf(lineNumber)}); 939 } catch (AbsentInformationException e) { 940 methodInfo = MessageOutput.format("unknown"); 941 } 942 } 943 if (pc != -1) { 944 MessageOutput.println("stack frame dump with pc", 945 new Object [] {(frameNumber + 1), 946 meth.declaringType().name(), 947 meth.name(), 948 methodInfo, 949 Long.valueOf(pc)}); 950 } else { 951 MessageOutput.println("stack frame dump", 952 new Object [] {(frameNumber + 1), 953 meth.declaringType().name(), 954 meth.name(), 955 methodInfo}); 956 } 957 } 958 commandWhere(StringTokenizer t, boolean showPC)959 void commandWhere(StringTokenizer t, boolean showPC) { 960 if (!t.hasMoreTokens()) { 961 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 962 if (threadInfo == null) { 963 MessageOutput.println("No thread specified."); 964 return; 965 } 966 dumpStack(threadInfo, showPC); 967 } else { 968 String token = t.nextToken(); 969 if (token.toLowerCase().equals("all")) { 970 for (ThreadInfo threadInfo : ThreadInfo.threads()) { 971 MessageOutput.println("Thread:", 972 threadInfo.getThread().name()); 973 dumpStack(threadInfo, showPC); 974 } 975 } else { 976 ThreadInfo threadInfo = doGetThread(token); 977 if (threadInfo != null) { 978 ThreadInfo.setCurrentThreadInfo(threadInfo); 979 dumpStack(threadInfo, showPC); 980 } 981 } 982 } 983 } 984 commandInterrupt(StringTokenizer t)985 void commandInterrupt(StringTokenizer t) { 986 if (!t.hasMoreTokens()) { 987 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 988 if (threadInfo == null) { 989 MessageOutput.println("No thread specified."); 990 return; 991 } 992 threadInfo.getThread().interrupt(); 993 } else { 994 ThreadInfo threadInfo = doGetThread(t.nextToken()); 995 if (threadInfo != null) { 996 threadInfo.getThread().interrupt(); 997 } 998 } 999 } 1000 commandMemory()1001 void commandMemory() { 1002 MessageOutput.println("The memory command is no longer supported."); 1003 } 1004 commandGC()1005 void commandGC() { 1006 MessageOutput.println("The gc command is no longer necessary."); 1007 } 1008 1009 /* 1010 * The next two methods are used by this class and by EventHandler 1011 * to print consistent locations and error messages. 1012 */ locationString(Location loc)1013 static String locationString(Location loc) { 1014 return MessageOutput.format("locationString", 1015 new Object [] {loc.declaringType().name(), 1016 loc.method().name(), 1017 Integer.valueOf(loc.lineNumber()), 1018 Long.valueOf(loc.codeIndex())}); 1019 } 1020 listBreakpoints()1021 void listBreakpoints() { 1022 boolean noBreakpoints = true; 1023 1024 // Print set breakpoints 1025 for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) { 1026 if (spec instanceof BreakpointSpec) { 1027 if (noBreakpoints) { 1028 noBreakpoints = false; 1029 MessageOutput.println("Breakpoints set:"); 1030 } 1031 MessageOutput.println("tab", spec.toString()); 1032 } 1033 } 1034 if (noBreakpoints) { 1035 MessageOutput.println("No breakpoints set."); 1036 } 1037 } 1038 1039 printBreakpointCommandUsage(String usageMessage)1040 private void printBreakpointCommandUsage(String usageMessage) { 1041 MessageOutput.println(usageMessage); 1042 } 1043 parseBreakpointSpec(StringTokenizer t, String next_token, ThreadReference threadFilter, String usageMessage)1044 protected BreakpointSpec parseBreakpointSpec(StringTokenizer t, String next_token, 1045 ThreadReference threadFilter, 1046 String usageMessage) { 1047 BreakpointSpec breakpoint = null; 1048 try { 1049 String token = next_token; 1050 1051 // We can't use hasMoreTokens here because it will cause any leading 1052 // paren to be lost. 1053 String rest; 1054 try { 1055 rest = t.nextToken("").trim(); 1056 } catch (NoSuchElementException e) { 1057 rest = null; 1058 } 1059 1060 if ((rest != null) && rest.startsWith(":")) { 1061 t = new StringTokenizer(rest.substring(1)); 1062 String classId = token; 1063 String lineToken = t.nextToken(); 1064 1065 NumberFormat nf = NumberFormat.getNumberInstance(); 1066 nf.setParseIntegerOnly(true); 1067 Number n; 1068 try { 1069 n = nf.parse(lineToken); 1070 } catch (java.text.ParseException pe) { 1071 MessageOutput.println("Invalid line number specified"); 1072 printBreakpointCommandUsage(usageMessage); 1073 return null; 1074 } 1075 int lineNumber = n.intValue(); 1076 1077 if (t.hasMoreTokens()) { 1078 MessageOutput.println("Extra tokens after breakpoint location"); 1079 printBreakpointCommandUsage(usageMessage); 1080 return null; 1081 } 1082 try { 1083 breakpoint = Env.specList.createBreakpoint(classId, 1084 lineNumber, threadFilter); 1085 } catch (ClassNotFoundException exc) { 1086 MessageOutput.println("is not a valid class name", classId); 1087 } 1088 } else { 1089 // Try stripping method from class.method token. 1090 int idot = token.lastIndexOf('.'); 1091 if ( (idot <= 0) || /* No dot or dot in first char */ 1092 (idot >= token.length() - 1) ) { /* dot in last char */ 1093 MessageOutput.println("Invalid <class>.<method_name> specification"); 1094 printBreakpointCommandUsage(usageMessage); 1095 return null; 1096 } 1097 String methodName = token.substring(idot + 1); 1098 String classId = token.substring(0, idot); 1099 List<String> argumentList = null; 1100 if (rest != null) { 1101 if (!rest.startsWith("(") || !rest.endsWith(")")) { 1102 MessageOutput.println("Invalid <method_name> specification:", 1103 methodName + rest); 1104 printBreakpointCommandUsage(usageMessage); 1105 return null; 1106 } 1107 // Trim the parens 1108 rest = rest.substring(1, rest.length() - 1); 1109 1110 argumentList = new ArrayList<String>(); 1111 t = new StringTokenizer(rest, ","); 1112 while (t.hasMoreTokens()) { 1113 argumentList.add(t.nextToken()); 1114 } 1115 } 1116 try { 1117 breakpoint = Env.specList.createBreakpoint(classId, 1118 methodName, 1119 threadFilter, 1120 argumentList); 1121 } catch (MalformedMemberNameException exc) { 1122 MessageOutput.println("is not a valid method name", methodName); 1123 } catch (ClassNotFoundException exc) { 1124 MessageOutput.println("is not a valid class name", classId); 1125 } 1126 } 1127 } catch (Exception e) { 1128 printBreakpointCommandUsage(usageMessage); 1129 return null; 1130 } 1131 return breakpoint; 1132 } 1133 resolveNow(EventRequestSpec spec)1134 private void resolveNow(EventRequestSpec spec) { 1135 boolean success = Env.specList.addEagerlyResolve(spec); 1136 if (success && !spec.isResolved()) { 1137 MessageOutput.println("Deferring.", spec.toString()); 1138 } 1139 } 1140 commandDbgTrace(StringTokenizer t)1141 void commandDbgTrace(StringTokenizer t) { 1142 int traceFlags; 1143 if (t.hasMoreTokens()) { 1144 String flagStr = t.nextToken(); 1145 try { 1146 traceFlags = Integer.decode(flagStr).intValue(); 1147 } catch (NumberFormatException nfe) { 1148 MessageOutput.println("dbgtrace command value must be an integer:", flagStr); 1149 return; 1150 } 1151 } else { 1152 traceFlags = VirtualMachine.TRACE_ALL; 1153 } 1154 Env.setTraceFlags(traceFlags); 1155 } 1156 commandStop(StringTokenizer t)1157 void commandStop(StringTokenizer t) { 1158 byte suspendPolicy = EventRequest.SUSPEND_ALL; 1159 ThreadReference threadFilter = null; 1160 1161 /* 1162 * Allowed syntax: 1163 * stop [go|thread] [<thread_id>] <at|in> <location> 1164 * If no options are given, the current list of breakpoints is printed. 1165 * If "go" is specified, then immediately resume after stopping. No threads are suspended. 1166 * If "thread" is specified, then only suspend the thread we stop in. 1167 * If neither "go" nor "thread" are specified, then suspend all threads. 1168 * If an integer <thread_id> is specified, then only stop in the specified thread. 1169 * <location> can either be a line number or a method: 1170 * - <class id>:<line> 1171 * - <class id>.<method>[(argument_type,...)] 1172 */ 1173 1174 if (!t.hasMoreTokens()) { 1175 listBreakpoints(); 1176 return; 1177 } 1178 1179 String token = t.nextToken(); 1180 1181 /* Check for "go" or "thread" modifiers. */ 1182 if (token.equals("go") && t.hasMoreTokens()) { 1183 suspendPolicy = EventRequest.SUSPEND_NONE; 1184 token = t.nextToken(); 1185 } else if (token.equals("thread") && t.hasMoreTokens()) { 1186 suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; 1187 token = t.nextToken(); 1188 } 1189 1190 /* Handle <thread_id> modifier. */ 1191 if (!token.equals("at") && !token.equals("in")) { 1192 Long threadid; 1193 try { 1194 threadid = Long.decode(token); 1195 } catch (NumberFormatException nfe) { 1196 MessageOutput.println("Expected at, in, or an integer <thread_id>:", token); 1197 printBreakpointCommandUsage("printstopcommandusage"); 1198 return; 1199 } 1200 try { 1201 ThreadInfo threadInfo = ThreadInfo.getThreadInfo(token); 1202 if (threadInfo == null) { 1203 MessageOutput.println("Invalid <thread_id>:", token); 1204 return; 1205 } 1206 threadFilter = threadInfo.getThread(); 1207 token = t.nextToken(BreakpointSpec.locationTokenDelimiter); 1208 } catch (VMNotConnectedException vmnce) { 1209 MessageOutput.println("<thread_id> option not valid until the VM is started with the run command"); 1210 return; 1211 } 1212 1213 } 1214 1215 /* Make sure "at" or "in" comes next. */ 1216 if (!token.equals("at") && !token.equals("in")) { 1217 MessageOutput.println("Missing at or in"); 1218 printBreakpointCommandUsage("printstopcommandusage"); 1219 return; 1220 } 1221 1222 token = t.nextToken(BreakpointSpec.locationTokenDelimiter); 1223 1224 BreakpointSpec spec = parseBreakpointSpec(t, token, threadFilter, "printstopcommandusage"); 1225 if (spec != null) { 1226 spec.suspendPolicy = suspendPolicy; 1227 resolveNow(spec); 1228 } 1229 } 1230 commandClear(StringTokenizer t)1231 void commandClear(StringTokenizer t) { 1232 if (!t.hasMoreTokens()) { 1233 listBreakpoints(); 1234 return; 1235 } 1236 1237 String token = t.nextToken(BreakpointSpec.locationTokenDelimiter); 1238 BreakpointSpec spec = parseBreakpointSpec(t, token, null, "printclearcommandusage"); 1239 if (spec != null) { 1240 if (Env.specList.delete(spec)) { 1241 MessageOutput.println("Removed:", spec.toString()); 1242 } else { 1243 MessageOutput.println("Not found:", spec.toString()); 1244 } 1245 } 1246 } 1247 parseWatchpointSpec(StringTokenizer t)1248 private List<WatchpointSpec> parseWatchpointSpec(StringTokenizer t) { 1249 List<WatchpointSpec> list = new ArrayList<WatchpointSpec>(); 1250 boolean access = false; 1251 boolean modification = false; 1252 int suspendPolicy = EventRequest.SUSPEND_ALL; 1253 1254 String fieldName = t.nextToken(); 1255 if (fieldName.equals("go")) { 1256 suspendPolicy = EventRequest.SUSPEND_NONE; 1257 fieldName = t.nextToken(); 1258 } else if (fieldName.equals("thread")) { 1259 suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; 1260 fieldName = t.nextToken(); 1261 } 1262 if (fieldName.equals("access")) { 1263 access = true; 1264 fieldName = t.nextToken(); 1265 } else if (fieldName.equals("all")) { 1266 access = true; 1267 modification = true; 1268 fieldName = t.nextToken(); 1269 } else { 1270 modification = true; 1271 } 1272 int dot = fieldName.lastIndexOf('.'); 1273 if (dot < 0) { 1274 MessageOutput.println("Class containing field must be specified."); 1275 return list; 1276 } 1277 String className = fieldName.substring(0, dot); 1278 fieldName = fieldName.substring(dot+1); 1279 1280 try { 1281 WatchpointSpec spec; 1282 if (access) { 1283 spec = Env.specList.createAccessWatchpoint(className, 1284 fieldName); 1285 spec.suspendPolicy = suspendPolicy; 1286 list.add(spec); 1287 } 1288 if (modification) { 1289 spec = Env.specList.createModificationWatchpoint(className, 1290 fieldName); 1291 spec.suspendPolicy = suspendPolicy; 1292 list.add(spec); 1293 } 1294 } catch (MalformedMemberNameException exc) { 1295 MessageOutput.println("is not a valid field name", fieldName); 1296 } catch (ClassNotFoundException exc) { 1297 MessageOutput.println("is not a valid class name", className); 1298 } 1299 return list; 1300 } 1301 commandWatch(StringTokenizer t)1302 void commandWatch(StringTokenizer t) { 1303 if (!t.hasMoreTokens()) { 1304 MessageOutput.println("Field to watch not specified"); 1305 return; 1306 } 1307 1308 for (WatchpointSpec spec : parseWatchpointSpec(t)) { 1309 resolveNow(spec); 1310 } 1311 } 1312 commandUnwatch(StringTokenizer t)1313 void commandUnwatch(StringTokenizer t) { 1314 if (!t.hasMoreTokens()) { 1315 MessageOutput.println("Field to unwatch not specified"); 1316 return; 1317 } 1318 1319 for (WatchpointSpec spec : parseWatchpointSpec(t)) { 1320 if (Env.specList.delete(spec)) { 1321 MessageOutput.println("Removed:", spec.toString()); 1322 } else { 1323 MessageOutput.println("Not found:", spec.toString()); 1324 } 1325 } 1326 } 1327 turnOnExitTrace(ThreadInfo threadInfo, int suspendPolicy)1328 void turnOnExitTrace(ThreadInfo threadInfo, int suspendPolicy) { 1329 EventRequestManager erm = Env.vm().eventRequestManager(); 1330 MethodExitRequest exit = erm.createMethodExitRequest(); 1331 if (threadInfo != null) { 1332 exit.addThreadFilter(threadInfo.getThread()); 1333 } 1334 Env.addExcludes(exit); 1335 exit.setSuspendPolicy(suspendPolicy); 1336 exit.enable(); 1337 1338 } 1339 1340 static String methodTraceCommand = null; 1341 commandTrace(StringTokenizer t)1342 void commandTrace(StringTokenizer t) { 1343 String modif; 1344 int suspendPolicy = EventRequest.SUSPEND_ALL; 1345 ThreadInfo threadInfo = null; 1346 String goStr = " "; 1347 1348 /* 1349 * trace [go] methods [thread] 1350 * trace [go] method exit | exits [thread] 1351 */ 1352 if (t.hasMoreTokens()) { 1353 modif = t.nextToken(); 1354 if (modif.equals("go")) { 1355 suspendPolicy = EventRequest.SUSPEND_NONE; 1356 goStr = " go "; 1357 if (t.hasMoreTokens()) { 1358 modif = t.nextToken(); 1359 } 1360 } else if (modif.equals("thread")) { 1361 // this is undocumented as it doesn't work right. 1362 suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; 1363 if (t.hasMoreTokens()) { 1364 modif = t.nextToken(); 1365 } 1366 } 1367 1368 if (modif.equals("method")) { 1369 String traceCmd = null; 1370 1371 if (t.hasMoreTokens()) { 1372 String modif1 = t.nextToken(); 1373 if (modif1.equals("exits") || modif1.equals("exit")) { 1374 if (t.hasMoreTokens()) { 1375 threadInfo = doGetThread(t.nextToken()); 1376 } 1377 if (modif1.equals("exit")) { 1378 StackFrame frame; 1379 try { 1380 frame = ThreadInfo.getCurrentThreadInfo().getCurrentFrame(); 1381 } catch (IncompatibleThreadStateException ee) { 1382 MessageOutput.println("Current thread isnt suspended."); 1383 return; 1384 } 1385 Env.setAtExitMethod(frame.location().method()); 1386 traceCmd = MessageOutput.format("trace" + 1387 goStr + "method exit " + 1388 "in effect for", 1389 Env.atExitMethod().toString()); 1390 } else { 1391 traceCmd = MessageOutput.format("trace" + 1392 goStr + "method exits " + 1393 "in effect"); 1394 } 1395 commandUntrace(new StringTokenizer("methods")); 1396 turnOnExitTrace(threadInfo, suspendPolicy); 1397 methodTraceCommand = traceCmd; 1398 return; 1399 } 1400 } else { 1401 MessageOutput.println("Can only trace"); 1402 return; 1403 } 1404 } 1405 if (modif.equals("methods")) { 1406 // Turn on method entry trace 1407 MethodEntryRequest entry; 1408 EventRequestManager erm = Env.vm().eventRequestManager(); 1409 if (t.hasMoreTokens()) { 1410 threadInfo = doGetThread(t.nextToken()); 1411 } 1412 if (threadInfo != null) { 1413 /* 1414 * To keep things simple we want each 'trace' to cancel 1415 * previous traces. However in this case, we don't do that 1416 * to preserve backward compatibility with pre JDK 6.0. 1417 * IE, you can currently do 1418 * trace methods 0x21 1419 * trace methods 0x22 1420 * and you will get xxx traced just on those two threads 1421 * But this feature is kind of broken because if you then do 1422 * untrace 0x21 1423 * it turns off both traces instead of just the one. 1424 * Another bogosity is that if you do 1425 * trace methods 1426 * trace methods 1427 * and you will get two traces. 1428 */ 1429 1430 entry = erm.createMethodEntryRequest(); 1431 entry.addThreadFilter(threadInfo.getThread()); 1432 } else { 1433 commandUntrace(new StringTokenizer("methods")); 1434 entry = erm.createMethodEntryRequest(); 1435 } 1436 Env.addExcludes(entry); 1437 entry.setSuspendPolicy(suspendPolicy); 1438 entry.enable(); 1439 turnOnExitTrace(threadInfo, suspendPolicy); 1440 methodTraceCommand = MessageOutput.format("trace" + goStr + 1441 "methods in effect"); 1442 1443 return; 1444 } 1445 1446 MessageOutput.println("Can only trace"); 1447 return; 1448 } 1449 1450 // trace all by itself. 1451 if (methodTraceCommand != null) { 1452 MessageOutput.printDirectln(methodTraceCommand); 1453 } 1454 1455 // More trace lines can be added here. 1456 } 1457 commandUntrace(StringTokenizer t)1458 void commandUntrace(StringTokenizer t) { 1459 // untrace 1460 // untrace methods 1461 1462 String modif = null; 1463 EventRequestManager erm = Env.vm().eventRequestManager(); 1464 if (t.hasMoreTokens()) { 1465 modif = t.nextToken(); 1466 } 1467 if (modif == null || modif.equals("methods")) { 1468 erm.deleteEventRequests(erm.methodEntryRequests()); 1469 erm.deleteEventRequests(erm.methodExitRequests()); 1470 Env.setAtExitMethod(null); 1471 methodTraceCommand = null; 1472 } 1473 } 1474 commandList(StringTokenizer t)1475 void commandList(StringTokenizer t) { 1476 StackFrame frame = null; 1477 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 1478 if (threadInfo == null) { 1479 MessageOutput.println("No thread specified."); 1480 return; 1481 } 1482 try { 1483 frame = threadInfo.getCurrentFrame(); 1484 } catch (IncompatibleThreadStateException e) { 1485 MessageOutput.println("Current thread isnt suspended."); 1486 return; 1487 } 1488 1489 if (frame == null) { 1490 MessageOutput.println("No frames on the current call stack"); 1491 return; 1492 } 1493 1494 Location loc = frame.location(); 1495 if (loc.method().isNative()) { 1496 MessageOutput.println("Current method is native"); 1497 return; 1498 } 1499 1500 String sourceFileName = null; 1501 try { 1502 sourceFileName = loc.sourceName(); 1503 1504 ReferenceType refType = loc.declaringType(); 1505 int lineno = loc.lineNumber(); 1506 1507 if (t.hasMoreTokens()) { 1508 String id = t.nextToken(); 1509 1510 // See if token is a line number. 1511 try { 1512 NumberFormat nf = NumberFormat.getNumberInstance(); 1513 nf.setParseIntegerOnly(true); 1514 Number n = nf.parse(id); 1515 lineno = n.intValue(); 1516 } catch (java.text.ParseException jtpe) { 1517 // It isn't -- see if it's a method name. 1518 List<Method> meths = refType.methodsByName(id); 1519 if (meths == null || meths.size() == 0) { 1520 MessageOutput.println("is not a valid line number or method name for", 1521 new Object [] {id, refType.name()}); 1522 return; 1523 } else if (meths.size() > 1) { 1524 MessageOutput.println("is an ambiguous method name in", 1525 new Object [] {id, refType.name()}); 1526 return; 1527 } 1528 loc = meths.get(0).location(); 1529 lineno = loc.lineNumber(); 1530 } 1531 } 1532 int startLine = Math.max(lineno - 4, 1); 1533 int endLine = startLine + 9; 1534 if (lineno < 0) { 1535 MessageOutput.println("Line number information not available for"); 1536 } else if (Env.sourceLine(loc, lineno) == null) { 1537 MessageOutput.println("is an invalid line number for", 1538 new Object [] {Integer.valueOf(lineno), 1539 refType.name()}); 1540 } else { 1541 for (int i = startLine; i <= endLine; i++) { 1542 String sourceLine = Env.sourceLine(loc, i); 1543 if (sourceLine == null) { 1544 break; 1545 } 1546 if (i == lineno) { 1547 MessageOutput.println("source line number current line and line", 1548 new Object [] {Integer.valueOf(i), 1549 sourceLine}); 1550 } else { 1551 MessageOutput.println("source line number and line", 1552 new Object [] {Integer.valueOf(i), 1553 sourceLine}); 1554 } 1555 } 1556 } 1557 } catch (AbsentInformationException e) { 1558 MessageOutput.println("No source information available for:", loc.toString()); 1559 } catch(FileNotFoundException exc) { 1560 MessageOutput.println("Source file not found:", sourceFileName); 1561 } catch(IOException exc) { 1562 MessageOutput.println("I/O exception occurred:", exc.toString()); 1563 } 1564 } 1565 commandLines(StringTokenizer t)1566 void commandLines(StringTokenizer t) { // Undocumented command: useful for testing 1567 if (!t.hasMoreTokens()) { 1568 MessageOutput.println("Specify class and method"); 1569 } else { 1570 String idClass = t.nextToken(); 1571 String idMethod = t.hasMoreTokens() ? t.nextToken() : null; 1572 try { 1573 ReferenceType refType = Env.getReferenceTypeFromToken(idClass); 1574 if (refType != null) { 1575 List<Location> lines = null; 1576 if (idMethod == null) { 1577 lines = refType.allLineLocations(); 1578 } else { 1579 for (Method method : refType.allMethods()) { 1580 if (method.name().equals(idMethod)) { 1581 lines = method.allLineLocations(); 1582 } 1583 } 1584 if (lines == null) { 1585 MessageOutput.println("is not a valid method name", idMethod); 1586 } 1587 } 1588 for (Location line : lines) { 1589 MessageOutput.printDirectln(line.toString());// Special case: use printDirectln() 1590 } 1591 } else { 1592 MessageOutput.println("is not a valid id or class name", idClass); 1593 } 1594 } catch (AbsentInformationException e) { 1595 MessageOutput.println("Line number information not available for", idClass); 1596 } 1597 } 1598 } 1599 commandClasspath(StringTokenizer t)1600 void commandClasspath(StringTokenizer t) { 1601 if (Env.vm() instanceof PathSearchingVirtualMachine) { 1602 PathSearchingVirtualMachine vm = (PathSearchingVirtualMachine)Env.vm(); 1603 MessageOutput.println("base directory:", vm.baseDirectory()); 1604 MessageOutput.println("classpath:", vm.classPath().toString()); 1605 } else { 1606 MessageOutput.println("The VM does not use paths"); 1607 } 1608 } 1609 1610 /* Get or set the source file path list. */ commandUse(StringTokenizer t)1611 void commandUse(StringTokenizer t) { 1612 if (!t.hasMoreTokens()) { 1613 MessageOutput.printDirectln(Env.getSourcePath());// Special case: use printDirectln() 1614 } else { 1615 /* 1616 * Take the remainder of the command line, minus 1617 * leading or trailing whitespace. Embedded 1618 * whitespace is fine. 1619 */ 1620 Env.setSourcePath(t.nextToken("").trim()); 1621 } 1622 } 1623 1624 /* Print a stack variable */ printVar(LocalVariable var, Value value)1625 private void printVar(LocalVariable var, Value value) { 1626 MessageOutput.println("expr is value", 1627 new Object [] {var.name(), 1628 value == null ? "null" : value.toString()}); 1629 } 1630 1631 /* Print all local variables in current stack frame. */ commandLocals()1632 void commandLocals() { 1633 StackFrame frame; 1634 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 1635 if (threadInfo == null) { 1636 MessageOutput.println("No default thread specified:"); 1637 return; 1638 } 1639 try { 1640 frame = threadInfo.getCurrentFrame(); 1641 if (frame == null) { 1642 throw new AbsentInformationException(); 1643 } 1644 List<LocalVariable> vars = frame.visibleVariables(); 1645 1646 if (vars.size() == 0) { 1647 MessageOutput.println("No local variables"); 1648 return; 1649 } 1650 Map<LocalVariable, Value> values = frame.getValues(vars); 1651 1652 MessageOutput.println("Method arguments:"); 1653 for (LocalVariable var : vars) { 1654 if (var.isArgument()) { 1655 Value val = values.get(var); 1656 printVar(var, val); 1657 } 1658 } 1659 MessageOutput.println("Local variables:"); 1660 for (LocalVariable var : vars) { 1661 if (!var.isArgument()) { 1662 Value val = values.get(var); 1663 printVar(var, val); 1664 } 1665 } 1666 } catch (AbsentInformationException aie) { 1667 MessageOutput.println("Local variable information not available."); 1668 } catch (IncompatibleThreadStateException exc) { 1669 MessageOutput.println("Current thread isnt suspended."); 1670 } 1671 } 1672 dump(ObjectReference obj, ReferenceType refType, ReferenceType refTypeBase)1673 private void dump(ObjectReference obj, ReferenceType refType, 1674 ReferenceType refTypeBase) { 1675 for (Field field : refType.fields()) { 1676 StringBuilder sb = new StringBuilder(); 1677 sb.append(" "); 1678 if (!refType.equals(refTypeBase)) { 1679 sb.append(refType.name()); 1680 sb.append("."); 1681 } 1682 sb.append(field.name()); 1683 sb.append(MessageOutput.format("colon space")); 1684 sb.append(obj.getValue(field)); 1685 MessageOutput.printDirectln(sb.toString()); // Special case: use printDirectln() 1686 } 1687 if (refType instanceof ClassType) { 1688 ClassType sup = ((ClassType)refType).superclass(); 1689 if (sup != null) { 1690 dump(obj, sup, refTypeBase); 1691 } 1692 } else if (refType instanceof InterfaceType) { 1693 for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) { 1694 dump(obj, sup, refTypeBase); 1695 } 1696 } else { 1697 /* else refType is an instanceof ArrayType */ 1698 if (obj instanceof ArrayReference) { 1699 for (Iterator<Value> it = ((ArrayReference)obj).getValues().iterator(); 1700 it.hasNext(); ) { 1701 MessageOutput.printDirect(it.next().toString());// Special case: use printDirect() 1702 if (it.hasNext()) { 1703 MessageOutput.printDirect(", ");// Special case: use printDirect() 1704 } 1705 } 1706 MessageOutput.println(); 1707 } 1708 } 1709 } 1710 1711 /* Print a specified reference. 1712 */ doPrint(StringTokenizer t, boolean dumpObject)1713 void doPrint(StringTokenizer t, boolean dumpObject) { 1714 if (!t.hasMoreTokens()) { 1715 MessageOutput.println("No objects specified."); 1716 return; 1717 } 1718 1719 while (t.hasMoreTokens()) { 1720 String expr = t.nextToken(""); 1721 Value val = evaluate(expr); 1722 if (val == null) { 1723 MessageOutput.println("expr is null", expr.toString()); 1724 } else if (dumpObject && (val instanceof ObjectReference) && 1725 !(val instanceof StringReference)) { 1726 ObjectReference obj = (ObjectReference)val; 1727 ReferenceType refType = obj.referenceType(); 1728 MessageOutput.println("expr is value", 1729 new Object [] {expr.toString(), 1730 MessageOutput.format("grouping begin character")}); 1731 dump(obj, refType, refType); 1732 MessageOutput.println("grouping end character"); 1733 } else { 1734 String strVal = getStringValue(); 1735 if (strVal != null) { 1736 MessageOutput.println("expr is value", new Object [] {expr.toString(), 1737 strVal}); 1738 } 1739 } 1740 } 1741 } 1742 commandPrint(final StringTokenizer t, final boolean dumpObject)1743 void commandPrint(final StringTokenizer t, final boolean dumpObject) { 1744 new AsyncExecution() { 1745 @Override 1746 void action() { 1747 doPrint(t, dumpObject); 1748 } 1749 }; 1750 } 1751 commandSet(final StringTokenizer t)1752 void commandSet(final StringTokenizer t) { 1753 String all = t.nextToken(""); 1754 1755 /* 1756 * Bare bones error checking. 1757 */ 1758 if (all.indexOf('=') == -1) { 1759 MessageOutput.println("Invalid assignment syntax"); 1760 MessageOutput.printPrompt(); 1761 return; 1762 } 1763 1764 /* 1765 * The set command is really just syntactic sugar. Pass it on to the 1766 * print command. 1767 */ 1768 commandPrint(new StringTokenizer(all), false); 1769 } 1770 doLock(StringTokenizer t)1771 void doLock(StringTokenizer t) { 1772 if (!t.hasMoreTokens()) { 1773 MessageOutput.println("No object specified."); 1774 return; 1775 } 1776 1777 String expr = t.nextToken(""); 1778 Value val = evaluate(expr); 1779 1780 try { 1781 if ((val != null) && (val instanceof ObjectReference)) { 1782 ObjectReference object = (ObjectReference)val; 1783 String strVal = getStringValue(); 1784 if (strVal != null) { 1785 MessageOutput.println("Monitor information for expr", 1786 new Object [] {expr.trim(), 1787 strVal}); 1788 } 1789 ThreadReference owner = object.owningThread(); 1790 if (owner == null) { 1791 MessageOutput.println("Not owned"); 1792 } else { 1793 MessageOutput.println("Owned by:", 1794 new Object [] {owner.name(), 1795 Integer.valueOf(object.entryCount())}); 1796 } 1797 List<ThreadReference> waiters = object.waitingThreads(); 1798 if (waiters.size() == 0) { 1799 MessageOutput.println("No waiters"); 1800 } else { 1801 for (ThreadReference waiter : waiters) { 1802 MessageOutput.println("Waiting thread:", waiter.name()); 1803 } 1804 } 1805 } else { 1806 MessageOutput.println("Expression must evaluate to an object"); 1807 } 1808 } catch (IncompatibleThreadStateException e) { 1809 MessageOutput.println("Threads must be suspended"); 1810 } 1811 } 1812 commandLock(final StringTokenizer t)1813 void commandLock(final StringTokenizer t) { 1814 new AsyncExecution() { 1815 @Override 1816 void action() { 1817 doLock(t); 1818 } 1819 }; 1820 } 1821 printThreadLockInfo(ThreadInfo threadInfo)1822 private void printThreadLockInfo(ThreadInfo threadInfo) { 1823 ThreadReference thread = threadInfo.getThread(); 1824 try { 1825 MessageOutput.println("Monitor information for thread", thread.name()); 1826 List<ObjectReference> owned = thread.ownedMonitors(); 1827 if (owned.size() == 0) { 1828 MessageOutput.println("No monitors owned"); 1829 } else { 1830 for (ObjectReference monitor : owned) { 1831 MessageOutput.println("Owned monitor:", monitor.toString()); 1832 } 1833 } 1834 ObjectReference waiting = thread.currentContendedMonitor(); 1835 if (waiting == null) { 1836 MessageOutput.println("Not waiting for a monitor"); 1837 } else { 1838 MessageOutput.println("Waiting for monitor:", waiting.toString()); 1839 } 1840 } catch (IncompatibleThreadStateException e) { 1841 MessageOutput.println("Threads must be suspended"); 1842 } 1843 } 1844 commandThreadlocks(final StringTokenizer t)1845 void commandThreadlocks(final StringTokenizer t) { 1846 if (!t.hasMoreTokens()) { 1847 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 1848 if (threadInfo == null) { 1849 MessageOutput.println("Current thread not set."); 1850 } else { 1851 printThreadLockInfo(threadInfo); 1852 } 1853 return; 1854 } 1855 String token = t.nextToken(); 1856 if (token.toLowerCase().equals("all")) { 1857 for (ThreadInfo threadInfo : ThreadInfo.threads()) { 1858 printThreadLockInfo(threadInfo); 1859 } 1860 } else { 1861 ThreadInfo threadInfo = doGetThread(token); 1862 if (threadInfo != null) { 1863 ThreadInfo.setCurrentThreadInfo(threadInfo); 1864 printThreadLockInfo(threadInfo); 1865 } 1866 } 1867 } 1868 doDisableGC(StringTokenizer t)1869 void doDisableGC(StringTokenizer t) { 1870 if (!t.hasMoreTokens()) { 1871 MessageOutput.println("No object specified."); 1872 return; 1873 } 1874 1875 String expr = t.nextToken(""); 1876 Value val = evaluate(expr); 1877 if ((val != null) && (val instanceof ObjectReference)) { 1878 ObjectReference object = (ObjectReference)val; 1879 object.disableCollection(); 1880 String strVal = getStringValue(); 1881 if (strVal != null) { 1882 MessageOutput.println("GC Disabled for", strVal); 1883 } 1884 } else { 1885 MessageOutput.println("Expression must evaluate to an object"); 1886 } 1887 } 1888 commandDisableGC(final StringTokenizer t)1889 void commandDisableGC(final StringTokenizer t) { 1890 new AsyncExecution() { 1891 @Override 1892 void action() { 1893 doDisableGC(t); 1894 } 1895 }; 1896 } 1897 doEnableGC(StringTokenizer t)1898 void doEnableGC(StringTokenizer t) { 1899 if (!t.hasMoreTokens()) { 1900 MessageOutput.println("No object specified."); 1901 return; 1902 } 1903 1904 String expr = t.nextToken(""); 1905 Value val = evaluate(expr); 1906 if ((val != null) && (val instanceof ObjectReference)) { 1907 ObjectReference object = (ObjectReference)val; 1908 object.enableCollection(); 1909 String strVal = getStringValue(); 1910 if (strVal != null) { 1911 MessageOutput.println("GC Enabled for", strVal); 1912 } 1913 } else { 1914 MessageOutput.println("Expression must evaluate to an object"); 1915 } 1916 } 1917 commandEnableGC(final StringTokenizer t)1918 void commandEnableGC(final StringTokenizer t) { 1919 new AsyncExecution() { 1920 @Override 1921 void action() { 1922 doEnableGC(t); 1923 } 1924 }; 1925 } 1926 doSave(StringTokenizer t)1927 void doSave(StringTokenizer t) {// Undocumented command: useful for testing. 1928 if (!t.hasMoreTokens()) { 1929 MessageOutput.println("No save index specified."); 1930 return; 1931 } 1932 1933 String key = t.nextToken(); 1934 1935 if (!t.hasMoreTokens()) { 1936 MessageOutput.println("No expression specified."); 1937 return; 1938 } 1939 String expr = t.nextToken(""); 1940 Value val = evaluate(expr); 1941 if (val != null) { 1942 Env.setSavedValue(key, val); 1943 String strVal = getStringValue(); 1944 if (strVal != null) { 1945 MessageOutput.println("saved", strVal); 1946 } 1947 } else { 1948 MessageOutput.println("Expression cannot be void"); 1949 } 1950 } 1951 commandSave(final StringTokenizer t)1952 void commandSave(final StringTokenizer t) { // Undocumented command: useful for testing. 1953 if (!t.hasMoreTokens()) { 1954 Set<String> keys = Env.getSaveKeys(); 1955 if (keys.isEmpty()) { 1956 MessageOutput.println("No saved values"); 1957 return; 1958 } 1959 for (String key : keys) { 1960 Value value = Env.getSavedValue(key); 1961 if ((value instanceof ObjectReference) && 1962 ((ObjectReference)value).isCollected()) { 1963 MessageOutput.println("expr is value <collected>", 1964 new Object [] {key, value.toString()}); 1965 } else { 1966 if (value == null){ 1967 MessageOutput.println("expr is null", key); 1968 } else { 1969 MessageOutput.println("expr is value", 1970 new Object [] {key, value.toString()}); 1971 } 1972 } 1973 } 1974 } else { 1975 new AsyncExecution() { 1976 @Override 1977 void action() { 1978 doSave(t); 1979 } 1980 }; 1981 } 1982 1983 } 1984 commandBytecodes(final StringTokenizer t)1985 void commandBytecodes(final StringTokenizer t) { // Undocumented command: useful for testing. 1986 if (!t.hasMoreTokens()) { 1987 MessageOutput.println("No class specified."); 1988 return; 1989 } 1990 String className = t.nextToken(); 1991 1992 if (!t.hasMoreTokens()) { 1993 MessageOutput.println("No method specified."); 1994 return; 1995 } 1996 // Overloading is not handled here. 1997 String methodName = t.nextToken(); 1998 1999 List<ReferenceType> classes = Env.vm().classesByName(className); 2000 // TO DO: handle multiple classes found 2001 if (classes.size() == 0) { 2002 if (className.indexOf('.') < 0) { 2003 MessageOutput.println("not found (try the full name)", className); 2004 } else { 2005 MessageOutput.println("not found", className); 2006 } 2007 return; 2008 } 2009 2010 ReferenceType rt = classes.get(0); 2011 if (!(rt instanceof ClassType)) { 2012 MessageOutput.println("not a class", className); 2013 return; 2014 } 2015 2016 byte[] bytecodes = null; 2017 for (Method method : rt.methodsByName(methodName)) { 2018 if (!method.isAbstract()) { 2019 bytecodes = method.bytecodes(); 2020 break; 2021 } 2022 } 2023 2024 StringBuilder line = new StringBuilder(80); 2025 line.append("0000: "); 2026 for (int i = 0; i < bytecodes.length; i++) { 2027 if ((i > 0) && (i % 16 == 0)) { 2028 MessageOutput.printDirectln(line.toString());// Special case: use printDirectln() 2029 line.setLength(0); 2030 line.append(String.valueOf(i)); 2031 line.append(": "); 2032 int len = line.length(); 2033 for (int j = 0; j < 6 - len; j++) { 2034 line.insert(0, '0'); 2035 } 2036 } 2037 int val = 0xff & bytecodes[i]; 2038 String str = Integer.toHexString(val); 2039 if (str.length() == 1) { 2040 line.append('0'); 2041 } 2042 line.append(str); 2043 line.append(' '); 2044 } 2045 if (line.length() > 6) { 2046 MessageOutput.printDirectln(line.toString());// Special case: use printDirectln() 2047 } 2048 } 2049 commandExclude(StringTokenizer t)2050 void commandExclude(StringTokenizer t) { 2051 if (!t.hasMoreTokens()) { 2052 MessageOutput.printDirectln(Env.excludesString());// Special case: use printDirectln() 2053 } else { 2054 String rest = t.nextToken(""); 2055 if (rest.equals("none")) { 2056 rest = ""; 2057 } 2058 Env.setExcludes(rest); 2059 } 2060 } 2061 commandRedefine(StringTokenizer t)2062 void commandRedefine(StringTokenizer t) { 2063 if (!t.hasMoreTokens()) { 2064 MessageOutput.println("Specify classes to redefine"); 2065 } else { 2066 String className = t.nextToken(); 2067 List<ReferenceType> classes = Env.vm().classesByName(className); 2068 if (classes.size() == 0) { 2069 MessageOutput.println("No class named", className); 2070 return; 2071 } 2072 if (classes.size() > 1) { 2073 MessageOutput.println("More than one class named", className); 2074 return; 2075 } 2076 Env.setSourcePath(Env.getSourcePath()); 2077 ReferenceType refType = classes.get(0); 2078 if (!t.hasMoreTokens()) { 2079 MessageOutput.println("Specify file name for class", className); 2080 return; 2081 } 2082 String fileName = t.nextToken(); 2083 File phyl = new File(fileName); 2084 byte[] bytes = new byte[(int)phyl.length()]; 2085 try { 2086 InputStream in = new FileInputStream(phyl); 2087 in.read(bytes); 2088 in.close(); 2089 } catch (Exception exc) { 2090 MessageOutput.println("Error reading file", 2091 new Object [] {fileName, exc.toString()}); 2092 return; 2093 } 2094 Map<ReferenceType, byte[]> map 2095 = new HashMap<ReferenceType, byte[]>(); 2096 map.put(refType, bytes); 2097 try { 2098 Env.vm().redefineClasses(map); 2099 } catch (Throwable exc) { 2100 MessageOutput.println("Error redefining class to file", 2101 new Object [] {className, 2102 fileName, 2103 exc}); 2104 } 2105 } 2106 } 2107 commandPopFrames(StringTokenizer t, boolean reenter)2108 void commandPopFrames(StringTokenizer t, boolean reenter) { 2109 ThreadInfo threadInfo; 2110 2111 if (t.hasMoreTokens()) { 2112 String token = t.nextToken(); 2113 threadInfo = doGetThread(token); 2114 if (threadInfo == null) { 2115 return; 2116 } 2117 } else { 2118 threadInfo = ThreadInfo.getCurrentThreadInfo(); 2119 if (threadInfo == null) { 2120 MessageOutput.println("No thread specified."); 2121 return; 2122 } 2123 } 2124 2125 try { 2126 StackFrame frame = threadInfo.getCurrentFrame(); 2127 threadInfo.getThread().popFrames(frame); 2128 threadInfo = ThreadInfo.getCurrentThreadInfo(); 2129 ThreadInfo.setCurrentThreadInfo(threadInfo); 2130 if (reenter) { 2131 commandStepi(); 2132 } 2133 } catch (Throwable exc) { 2134 MessageOutput.println("Error popping frame", exc.toString()); 2135 } 2136 } 2137 commandExtension(StringTokenizer t)2138 void commandExtension(StringTokenizer t) { 2139 if (!t.hasMoreTokens()) { 2140 MessageOutput.println("No class specified."); 2141 return; 2142 } 2143 2144 String idClass = t.nextToken(); 2145 ReferenceType cls = Env.getReferenceTypeFromToken(idClass); 2146 String extension = null; 2147 if (cls != null) { 2148 try { 2149 extension = cls.sourceDebugExtension(); 2150 MessageOutput.println("sourcedebugextension", extension); 2151 } catch (AbsentInformationException e) { 2152 MessageOutput.println("No sourcedebugextension specified"); 2153 } 2154 } else { 2155 MessageOutput.println("is not a valid id or class name", idClass); 2156 } 2157 } 2158 commandVersion(String debuggerName, VirtualMachineManager vmm)2159 void commandVersion(String debuggerName, 2160 VirtualMachineManager vmm) { 2161 MessageOutput.println("minus version", 2162 new Object [] { debuggerName, 2163 vmm.majorInterfaceVersion(), 2164 vmm.minorInterfaceVersion(), 2165 System.getProperty("java.version")}); 2166 if (Env.connection() != null) { 2167 try { 2168 MessageOutput.printDirectln(Env.vm().description());// Special case: use printDirectln() 2169 } catch (VMNotConnectedException e) { 2170 MessageOutput.println("No VM connected"); 2171 } 2172 } 2173 } 2174 } 2175