1 /* 2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import com.sun.jdi.*; 25 import com.sun.jdi.request.*; 26 import com.sun.jdi.event.*; 27 import java.util.*; 28 import java.io.*; 29 30 /** 31 * Framework used by all JDI regression tests 32 */ 33 abstract public class TestScaffold extends TargetAdapter { 34 private boolean shouldTrace = false; 35 private VMConnection connection; 36 private VirtualMachine vm; 37 private EventRequestManager requestManager; 38 private List listeners = Collections.synchronizedList(new LinkedList()); 39 private boolean redefineAtStart = false; 40 private boolean redefineAtEvents = false; 41 private boolean redefineAsynchronously = false; 42 private ReferenceType mainStartClass = null; 43 44 ThreadReference mainThread; 45 /** 46 * We create a VMDeathRequest, SUSPEND_ALL, to sync the BE and FE. 47 */ 48 private VMDeathRequest ourVMDeathRequest = null; 49 50 /** 51 * We create an ExceptionRequest, SUSPEND_NONE so that we can 52 * catch it and output a msg if an exception occurs in the 53 * debuggee. 54 */ 55 private ExceptionRequest ourExceptionRequest = null; 56 57 /** 58 * If we do catch an uncaught exception, we set this true 59 * so the testcase can find out if it wants to. 60 */ 61 private boolean exceptionCaught = false; 62 ThreadReference vmStartThread = null; 63 boolean vmDied = false; 64 boolean vmDisconnected = false; 65 final String[] args; 66 protected boolean testFailed = false; 67 protected long startTime; 68 69 static private class ArgInfo { 70 String targetVMArgs = ""; 71 String targetAppCommandLine = ""; 72 String connectorSpec = "com.sun.jdi.CommandLineLaunch:"; 73 int traceFlags = 0; 74 } 75 76 /** 77 * An easy way to sleep for awhile 78 */ 79 public void mySleep(int millis) { 80 try { 81 Thread.sleep(millis); 82 } catch (InterruptedException ee) { 83 } 84 } 85 86 boolean getExceptionCaught() { 87 return exceptionCaught; 88 } 89 90 void setExceptionCaught(boolean value) { 91 exceptionCaught = value; 92 } 93 94 /** 95 * Return true if eventSet contains the VMDeathEvent for the request in 96 * the ourVMDeathRequest ivar. 97 */ 98 private boolean containsOurVMDeathRequest(EventSet eventSet) { 99 if (ourVMDeathRequest != null) { 100 Iterator myIter = eventSet.iterator(); 101 while (myIter.hasNext()) { 102 Event myEvent = (Event)myIter.next(); 103 if (!(myEvent instanceof VMDeathEvent)) { 104 // We assume that an EventSet contains only VMDeathEvents 105 // or no VMDeathEvents. 106 break; 107 } 108 if (ourVMDeathRequest.equals(myEvent.request())) { 109 return true; 110 } 111 } 112 } 113 return false; 114 } 115 116 /************************************************************************ 117 * The following methods override those in our base class, TargetAdapter. 118 *************************************************************************/ 119 120 /** 121 * Events handled directly by scaffold always resume (well, almost always) 122 */ 123 public void eventSetComplete(EventSet set) { 124 // The listener in connect(..) resumes after receiving our 125 // special VMDeathEvent. We can't also do the resume 126 // here or we will probably get a VMDisconnectedException 127 if (!containsOurVMDeathRequest(set)) { 128 traceln("TS: set.resume() called"); 129 set.resume(); 130 } 131 } 132 133 /** 134 * This method sets up default requests. 135 * Testcases can override this to change default behavior. 136 */ 137 protected void createDefaultEventRequests() { 138 createDefaultVMDeathRequest(); 139 createDefaultExceptionRequest(); 140 } 141 142 /** 143 * We want the BE to stop when it issues a VMDeathEvent in order to 144 * give the FE time to complete handling events that occured before 145 * the VMDeath. When we get the VMDeathEvent for this request in 146 * the listener in connect(), we will do a resume. 147 * If a testcase wants to do something special with VMDeathEvent's, 148 * then it should override this method with an empty method or 149 * whatever in order to suppress the automatic resume. The testcase 150 * will then be responsible for the handling of VMDeathEvents. It 151 * has to be sure that it does a resume if it gets a VMDeathEvent 152 * with SUSPEND_ALL, and it has to be sure that it doesn't do a 153 * resume after getting a VMDeath with SUSPEND_NONE (the automatically 154 * generated VMDeathEvent.) 155 */ 156 protected void createDefaultVMDeathRequest() { 157 ourVMDeathRequest = requestManager.createVMDeathRequest(); 158 ourVMDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); 159 ourVMDeathRequest.enable(); 160 } 161 162 /** 163 * This will allow us to print a warning if a debuggee gets an 164 * unexpected exception. The unexpected exception will be handled in 165 * the exceptionThrown method in the listener created in the connect() 166 * method. 167 * If a testcase does not want an uncaught exception to cause a 168 * msg, it must override this method. 169 */ 170 protected void createDefaultExceptionRequest() { 171 ourExceptionRequest = requestManager.createExceptionRequest(null, 172 false, true); 173 174 // We can't afford to make this be other than SUSPEND_NONE. Otherwise, 175 // it would have to be resumed. If our connect() listener resumes it, 176 // what about the case where the EventSet contains other events with 177 // SUSPEND_ALL and there are other listeners who expect the BE to still 178 // be suspended when their handlers get called? 179 ourExceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE); 180 ourExceptionRequest.enable(); 181 } 182 183 private class EventHandler implements Runnable { 184 EventHandler() { 185 Thread thread = new Thread(this); 186 thread.setDaemon(true); 187 thread.start(); 188 } 189 190 private void notifyEvent(TargetListener listener, Event event) { 191 if (event instanceof BreakpointEvent) { 192 listener.breakpointReached((BreakpointEvent)event); 193 } else if (event instanceof ExceptionEvent) { 194 listener.exceptionThrown((ExceptionEvent)event); 195 } else if (event instanceof StepEvent) { 196 listener.stepCompleted((StepEvent)event); 197 } else if (event instanceof ClassPrepareEvent) { 198 listener.classPrepared((ClassPrepareEvent)event); 199 } else if (event instanceof ClassUnloadEvent) { 200 listener.classUnloaded((ClassUnloadEvent)event); 201 } else if (event instanceof MethodEntryEvent) { 202 listener.methodEntered((MethodEntryEvent)event); 203 } else if (event instanceof MethodExitEvent) { 204 listener.methodExited((MethodExitEvent)event); 205 } else if (event instanceof MonitorContendedEnterEvent) { 206 listener.monitorContendedEnter((MonitorContendedEnterEvent)event); 207 } else if (event instanceof MonitorContendedEnteredEvent) { 208 listener.monitorContendedEntered((MonitorContendedEnteredEvent)event); 209 } else if (event instanceof MonitorWaitEvent) { 210 listener.monitorWait((MonitorWaitEvent)event); 211 } else if (event instanceof MonitorWaitedEvent) { 212 listener.monitorWaited((MonitorWaitedEvent)event); 213 } else if (event instanceof AccessWatchpointEvent) { 214 listener.fieldAccessed((AccessWatchpointEvent)event); 215 } else if (event instanceof ModificationWatchpointEvent) { 216 listener.fieldModified((ModificationWatchpointEvent)event); 217 } else if (event instanceof ThreadStartEvent) { 218 listener.threadStarted((ThreadStartEvent)event); 219 } else if (event instanceof ThreadDeathEvent) { 220 listener.threadDied((ThreadDeathEvent)event); 221 } else if (event instanceof VMStartEvent) { 222 listener.vmStarted((VMStartEvent)event); 223 } else if (event instanceof VMDeathEvent) { 224 listener.vmDied((VMDeathEvent)event); 225 } else if (event instanceof VMDisconnectEvent) { 226 listener.vmDisconnected((VMDisconnectEvent)event); 227 } else { 228 throw new InternalError("Unknown event type: " + event.getClass()); 229 } 230 } 231 232 private void traceSuspendPolicy(int policy) { 233 if (shouldTrace) { 234 switch (policy) { 235 case EventRequest.SUSPEND_NONE: 236 traceln("TS: eventHandler: suspend = SUSPEND_NONE"); 237 break; 238 case EventRequest.SUSPEND_ALL: 239 traceln("TS: eventHandler: suspend = SUSPEND_ALL"); 240 break; 241 case EventRequest.SUSPEND_EVENT_THREAD: 242 traceln("TS: eventHandler: suspend = SUSPEND_EVENT_THREAD"); 243 break; 244 } 245 } 246 } 247 248 public void run() { 249 boolean connected = true; 250 do { 251 try { 252 EventSet set = vm.eventQueue().remove(); 253 traceSuspendPolicy(set.suspendPolicy()); 254 synchronized (listeners) { 255 ListIterator iter = listeners.listIterator(); 256 while (iter.hasNext()) { 257 TargetListener listener = (TargetListener)iter.next(); 258 traceln("TS: eventHandler: listener = " + listener); 259 listener.eventSetReceived(set); 260 if (listener.shouldRemoveListener()) { 261 iter.remove(); 262 } else { 263 Iterator jter = set.iterator(); 264 while (jter.hasNext()) { 265 Event event = (Event)jter.next(); 266 traceln("TS: eventHandler: event = " + event.getClass()); 267 268 if (event instanceof VMDisconnectEvent) { 269 connected = false; 270 } 271 listener.eventReceived(event); 272 if (listener.shouldRemoveListener()) { 273 iter.remove(); 274 break; 275 } 276 notifyEvent(listener, event); 277 if (listener.shouldRemoveListener()) { 278 iter.remove(); 279 break; 280 } 281 } 282 traceln("TS: eventHandler: end of events loop"); 283 if (!listener.shouldRemoveListener()) { 284 traceln("TS: eventHandler: calling ESC"); 285 listener.eventSetComplete(set); 286 if (listener.shouldRemoveListener()) { 287 iter.remove(); 288 } 289 } 290 } 291 traceln("TS: eventHandler: end of listeners loop"); 292 } 293 } 294 } catch (InterruptedException e) { 295 traceln("TS: eventHandler: InterruptedException"); 296 } catch (Exception e) { 297 failure("FAILED: Exception occured in eventHandler: " + e); 298 e.printStackTrace(); 299 connected = false; 300 synchronized(TestScaffold.this) { 301 // This will make the waiters such as waitForVMDisconnect 302 // exit their wait loops. 303 vmDisconnected = true; 304 TestScaffold.this.notifyAll(); 305 } 306 } 307 traceln("TS: eventHandler: End of outerloop"); 308 } while (connected); 309 traceln("TS: eventHandler: finished"); 310 } 311 } 312 313 /** 314 * Constructor 315 */ 316 public TestScaffold(String[] args) { 317 this.args = args; 318 } 319 320 public void enableScaffoldTrace() { 321 this.shouldTrace = true; 322 } 323 324 public void disableScaffoldTrace() { 325 this.shouldTrace = false; 326 } 327 328 /** 329 * Helper for the redefine method. Build the map 330 * needed for a redefine. 331 */ 332 protected Map makeRedefineMap(ReferenceType rt) throws Exception { 333 String className = rt.name(); 334 File path = new File(System.getProperty("test.classes", ".")); 335 className = className.replace('.', File.separatorChar); 336 File phyl = new File(path, className + ".class"); 337 byte[] bytes = new byte[(int)phyl.length()]; 338 InputStream in = new FileInputStream(phyl); 339 in.read(bytes); 340 in.close(); 341 342 Map map = new HashMap(); 343 map.put(rt, bytes); 344 345 return map; 346 } 347 348 /** 349 * Redefine a class - HotSwap it 350 */ 351 protected void redefine(ReferenceType rt) { 352 try { 353 println("Redefining " + rt); 354 vm().redefineClasses(makeRedefineMap(rt)); 355 } catch (Exception exc) { 356 failure("FAIL: redefine - unexpected exception: " + exc); 357 } 358 } 359 360 protected void startUp(String targetName) { 361 List argList = new ArrayList(Arrays.asList(args)); 362 argList.add(targetName); 363 println("run args: " + argList); 364 connect((String[]) argList.toArray(args)); 365 waitForVMStart(); 366 } 367 368 protected BreakpointEvent startToMain(String targetName) { 369 return startTo(targetName, "main", "([Ljava/lang/String;)V"); 370 } 371 372 protected BreakpointEvent startTo(String targetName, 373 String methodName, String signature) { 374 startUp(targetName); 375 traceln("TS: back from startUp"); 376 377 BreakpointEvent bpr = resumeTo(targetName, methodName, 378 signature); 379 Location loc = bpr.location(); 380 mainStartClass = loc.declaringType(); 381 if (redefineAtStart) { 382 redefine(mainStartClass); 383 } 384 if (redefineAsynchronously) { 385 Thread asyncDaemon = new Thread("Async Redefine") { 386 public void run() { 387 try { 388 Map redefMap = makeRedefineMap(mainStartClass); 389 390 while (true) { 391 println("Redefining " + mainStartClass); 392 vm().redefineClasses(redefMap); 393 Thread.sleep(100); 394 } 395 } catch (VMDisconnectedException vmde) { 396 println("async redefine - VM disconnected"); 397 } catch (Exception exc) { 398 failure("FAIL: async redefine - unexpected exception: " + exc); 399 } 400 } 401 }; 402 asyncDaemon.setDaemon(true); 403 asyncDaemon.start(); 404 } 405 406 if (System.getProperty("jpda.wait") != null) { 407 waitForInput(); 408 } 409 return bpr; 410 } 411 412 protected void waitForInput() { 413 try { 414 System.err.println("Press <enter> to continue"); 415 System.in.read(); 416 System.err.println("running..."); 417 418 } catch(Exception e) { 419 } 420 } 421 422 /* 423 * Test cases should implement tests in runTests and should 424 * initiate testing by calling run(). 425 */ 426 abstract protected void runTests() throws Exception; 427 428 final public void startTests() throws Exception { 429 startTime = System.currentTimeMillis(); 430 try { 431 runTests(); 432 } finally { 433 shutdown(); 434 } 435 } 436 437 protected void println(String str) { 438 long elapsed = System.currentTimeMillis() - startTime; 439 System.err.println("[" + elapsed + "ms] " + str); 440 } 441 442 protected void print(String str) { 443 System.err.print(str); 444 } 445 446 protected void traceln(String str) { 447 if (shouldTrace) { 448 println(str); 449 } 450 } 451 452 protected void failure(String str) { 453 println(str); 454 testFailed = true; 455 } 456 457 private ArgInfo parseArgs(String args[]) { 458 ArgInfo argInfo = new ArgInfo(); 459 for (int i = 0; i < args.length; i++) { 460 if (args[i].equals("-connect")) { 461 i++; 462 argInfo.connectorSpec = args[i]; 463 } else if (args[i].equals("-trace")) { 464 i++; 465 argInfo.traceFlags = Integer.decode(args[i]).intValue(); 466 } else if (args[i].equals("-redefstart")) { 467 redefineAtStart = true; 468 } else if (args[i].equals("-redefevent")) { 469 redefineAtEvents = true; 470 } else if (args[i].equals("-redefasync")) { 471 redefineAsynchronously = true; 472 } else if (args[i].startsWith("-J")) { 473 argInfo.targetVMArgs += (args[i].substring(2) + ' '); 474 475 /* 476 * classpath can span two arguments so we need to handle 477 * it specially. 478 */ 479 if (args[i].equals("-J-classpath")) { 480 i++; 481 argInfo.targetVMArgs += (args[i] + ' '); 482 } 483 } else { 484 argInfo.targetAppCommandLine += (args[i] + ' '); 485 } 486 } 487 return argInfo; 488 } 489 490 /** 491 * This is called to connect to a debuggee VM. It starts the VM and 492 * installs a listener to catch VMStartEvent, our default events, and 493 * VMDisconnectedEvent. When these events appear, that is remembered 494 * and waiters are notified. 495 * This is normally called in the main thread of the test case. 496 * It starts up an EventHandler thread that gets events coming in 497 * from the debuggee and distributes them to listeners. That thread 498 * keeps running until a VMDisconnectedEvent occurs or some exception 499 * occurs during its processing. 500 * 501 * The 'listenUntilVMDisconnect' method adds 'this' as a listener. 502 * This means that 'this's vmDied method will get called. This has a 503 * default impl in TargetAdapter.java which can be overridden in the 504 * testcase. 505 * 506 * waitForRequestedEvent also adds an adaptor listener that listens 507 * for the particular event it is supposed to wait for (and it also 508 * catches VMDisconnectEvents.) This listener is removed once 509 * its eventReceived method is called. 510 * waitForRequestedEvent is called by most of the methods to do bkpts, 511 * etc. 512 */ 513 public void connect(String args[]) { 514 ArgInfo argInfo = parseArgs(args); 515 516 argInfo.targetVMArgs += VMConnection.getDebuggeeVMOptions(); 517 connection = new VMConnection(argInfo.connectorSpec, 518 argInfo.traceFlags); 519 520 addListener(new TargetAdapter() { 521 public void eventSetComplete(EventSet set) { 522 if (TestScaffold.this.containsOurVMDeathRequest(set)) { 523 traceln("TS: connect: set.resume() called"); 524 set.resume(); 525 526 // Note that we want to do the above resume before 527 // waking up any sleepers. 528 synchronized(TestScaffold.this) { 529 TestScaffold.this.notifyAll(); 530 } 531 } 532 } 533 public void eventReceived(Event event) { 534 if (redefineAtEvents && event instanceof Locatable) { 535 Location loc = ((Locatable)event).location(); 536 ReferenceType rt = loc.declaringType(); 537 String name = rt.name(); 538 if (name.startsWith("java.") && 539 !name.startsWith("sun.") && 540 !name.startsWith("com.")) { 541 if (mainStartClass != null) { 542 redefine(mainStartClass); 543 } 544 } else { 545 redefine(rt); 546 } 547 } 548 } 549 550 public void vmStarted(VMStartEvent event) { 551 synchronized(TestScaffold.this) { 552 vmStartThread = event.thread(); 553 TestScaffold.this.notifyAll(); 554 } 555 } 556 /** 557 * By default, we catch uncaught exceptions and print a msg. 558 * The testcase must override the createDefaultExceptionRequest 559 * method if it doesn't want this behavior. 560 */ 561 public void exceptionThrown(ExceptionEvent event) { 562 if (TestScaffold.this.ourExceptionRequest != null && 563 TestScaffold.this.ourExceptionRequest.equals( 564 event.request())) { 565 /* 566 * See 567 * 5038723: com/sun/jdi/sde/TemperatureTableTest.java: 568 * intermittent ObjectCollectedException 569 * Since this request was SUSPEND_NONE, the debuggee 570 * could keep running and the calls below back into 571 * the debuggee might not work. That is why we 572 * have this try/catch. 573 */ 574 try { 575 println("Note: Unexpected Debuggee Exception: " + 576 event.exception().referenceType().name() + 577 " at line " + event.location().lineNumber()); 578 TestScaffold.this.exceptionCaught = true; 579 580 ObjectReference obj = event.exception(); 581 ReferenceType rtt = obj.referenceType(); 582 Field detail = rtt.fieldByName("detailMessage"); 583 Value val = obj.getValue(detail); 584 println("detailMessage = " + val); 585 586 /* 587 * This code is commented out because it needs a thread 588 * in which to do the invokeMethod and we don't have 589 * one. To enable this code change the request 590 * to be SUSPEND_ALL in createDefaultExceptionRequest, 591 * and then put this line 592 * mainThread = bpe.thread(); 593 * in the testcase after the line 594 * BreakpointEvent bpe = startToMain("...."); 595 */ 596 if (false) { 597 List lll = rtt.methodsByName("printStackTrace"); 598 Method mm = (Method)lll.get(0); 599 obj.invokeMethod(mainThread, mm, new ArrayList(0), 0); 600 } 601 } catch (Exception ee) { 602 println("TestScaffold Exception while handling debuggee Exception: " 603 + ee); 604 } 605 } 606 } 607 608 public void vmDied(VMDeathEvent event) { 609 vmDied = true; 610 traceln("TS: vmDied called"); 611 } 612 613 public void vmDisconnected(VMDisconnectEvent event) { 614 synchronized(TestScaffold.this) { 615 vmDisconnected = true; 616 TestScaffold.this.notifyAll(); 617 } 618 } 619 }); 620 if (connection.connector().name().equals("com.sun.jdi.CommandLineLaunch")) { 621 if (argInfo.targetVMArgs.length() > 0) { 622 if (connection.connectorArg("options").length() > 0) { 623 throw new IllegalArgumentException("VM options in two places"); 624 } 625 connection.setConnectorArg("options", argInfo.targetVMArgs); 626 } 627 if (argInfo.targetAppCommandLine.length() > 0) { 628 if (connection.connectorArg("main").length() > 0) { 629 throw new IllegalArgumentException("Command line in two places"); 630 } 631 connection.setConnectorArg("main", argInfo.targetAppCommandLine); 632 } 633 } 634 635 vm = connection.open(); 636 requestManager = vm.eventRequestManager(); 637 createDefaultEventRequests(); 638 new EventHandler(); 639 } 640 641 642 public VirtualMachine vm() { 643 return vm; 644 } 645 646 public EventRequestManager eventRequestManager() { 647 return requestManager; 648 } 649 650 public void addListener(TargetListener listener) { 651 traceln("TS: Adding listener " + listener); 652 listeners.add(listener); 653 } 654 655 public void removeListener(TargetListener listener) { 656 traceln("TS: Removing listener " + listener); 657 listeners.remove(listener); 658 } 659 660 661 protected void listenUntilVMDisconnect() { 662 try { 663 addListener (this); 664 } catch (Exception ex){ 665 ex.printStackTrace(); 666 testFailed = true; 667 } finally { 668 // Allow application to complete and shut down 669 resumeToVMDisconnect(); 670 } 671 } 672 673 public synchronized ThreadReference waitForVMStart() { 674 while ((vmStartThread == null) && !vmDisconnected) { 675 try { 676 wait(); 677 } catch (InterruptedException e) { 678 } 679 } 680 681 if (vmStartThread == null) { 682 throw new VMDisconnectedException(); 683 } 684 685 return vmStartThread; 686 } 687 688 public synchronized void waitForVMDisconnect() { 689 traceln("TS: waitForVMDisconnect"); 690 while (!vmDisconnected) { 691 try { 692 wait(); 693 } catch (InterruptedException e) { 694 } 695 } 696 traceln("TS: waitForVMDisconnect: done"); 697 } 698 699 public Event waitForRequestedEvent(final EventRequest request) { 700 class EventNotification { 701 Event event; 702 boolean disconnected = false; 703 } 704 final EventNotification en = new EventNotification(); 705 706 TargetAdapter adapter = new TargetAdapter() { 707 public void eventReceived(Event event) { 708 if (request.equals(event.request())) { 709 traceln("TS:Listener2: got requested event"); 710 synchronized (en) { 711 en.event = event; 712 en.notifyAll(); 713 } 714 removeThisListener(); 715 } else if (event instanceof VMDisconnectEvent) { 716 traceln("TS:Listener2: got VMDisconnectEvent"); 717 synchronized (en) { 718 en.disconnected = true; 719 en.notifyAll(); 720 } 721 removeThisListener(); 722 } 723 } 724 }; 725 726 addListener(adapter); 727 728 try { 729 synchronized (en) { 730 traceln("TS: waitForRequestedEvent: vm.resume called"); 731 vm.resume(); 732 733 while (!en.disconnected && (en.event == null)) { 734 en.wait(); 735 } 736 } 737 } catch (InterruptedException e) { 738 return null; 739 } 740 741 if (en.disconnected) { 742 throw new RuntimeException("VM Disconnected before requested event occurred"); 743 } 744 return en.event; 745 } 746 747 private StepEvent doStep(ThreadReference thread, int gran, int depth) { 748 final StepRequest sr = 749 requestManager.createStepRequest(thread, gran, depth); 750 751 sr.addClassExclusionFilter("java.*"); 752 sr.addClassExclusionFilter("javax.*"); 753 sr.addClassExclusionFilter("sun.*"); 754 sr.addClassExclusionFilter("com.sun.*"); 755 sr.addClassExclusionFilter("com.oracle.*"); 756 sr.addClassExclusionFilter("oracle.*"); 757 sr.addClassExclusionFilter("jdk.internal.*"); 758 sr.addClassExclusionFilter("jdk.jfr.*"); 759 sr.addCountFilter(1); 760 sr.enable(); 761 StepEvent retEvent = (StepEvent)waitForRequestedEvent(sr); 762 requestManager.deleteEventRequest(sr); 763 return retEvent; 764 } 765 766 public StepEvent stepIntoInstruction(ThreadReference thread) { 767 return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO); 768 } 769 770 public StepEvent stepIntoLine(ThreadReference thread) { 771 return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO); 772 } 773 774 public StepEvent stepOverInstruction(ThreadReference thread) { 775 return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_OVER); 776 } 777 778 public StepEvent stepOverLine(ThreadReference thread) { 779 return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OVER); 780 } 781 782 public StepEvent stepOut(ThreadReference thread) { 783 return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OUT); 784 } 785 786 public BreakpointEvent resumeTo(Location loc) { 787 final BreakpointRequest request = 788 requestManager.createBreakpointRequest(loc); 789 request.addCountFilter(1); 790 request.enable(); 791 return (BreakpointEvent)waitForRequestedEvent(request); 792 } 793 794 public ReferenceType findReferenceType(String name) { 795 List rts = vm.classesByName(name); 796 Iterator iter = rts.iterator(); 797 while (iter.hasNext()) { 798 ReferenceType rt = (ReferenceType)iter.next(); 799 if (rt.name().equals(name)) { 800 return rt; 801 } 802 } 803 return null; 804 } 805 806 public Method findMethod(ReferenceType rt, String name, String signature) { 807 List methods = rt.methods(); 808 Iterator iter = methods.iterator(); 809 while (iter.hasNext()) { 810 Method method = (Method)iter.next(); 811 if (method.name().equals(name) && 812 method.signature().equals(signature)) { 813 return method; 814 } 815 } 816 return null; 817 } 818 819 public Location findLocation(ReferenceType rt, int lineNumber) 820 throws AbsentInformationException { 821 List locs = rt.locationsOfLine(lineNumber); 822 if (locs.size() == 0) { 823 throw new IllegalArgumentException("Bad line number"); 824 } else if (locs.size() > 1) { 825 throw new IllegalArgumentException("Line number has multiple locations"); 826 } 827 828 return (Location)locs.get(0); 829 } 830 831 public BreakpointEvent resumeTo(String clsName, String methodName, 832 String methodSignature) { 833 ReferenceType rt = findReferenceType(clsName); 834 if (rt == null) { 835 rt = resumeToPrepareOf(clsName).referenceType(); 836 } 837 838 Method method = findMethod(rt, methodName, methodSignature); 839 if (method == null) { 840 throw new IllegalArgumentException("Bad method name/signature: " 841 + clsName + "." + methodName + ":" + methodSignature); 842 } 843 844 return resumeTo(method.location()); 845 } 846 847 public BreakpointEvent resumeTo(String clsName, int lineNumber) throws AbsentInformationException { 848 ReferenceType rt = findReferenceType(clsName); 849 if (rt == null) { 850 rt = resumeToPrepareOf(clsName).referenceType(); 851 } 852 853 return resumeTo(findLocation(rt, lineNumber)); 854 } 855 856 public ClassPrepareEvent resumeToPrepareOf(String className) { 857 final ClassPrepareRequest request = 858 requestManager.createClassPrepareRequest(); 859 request.addClassFilter(className); 860 request.addCountFilter(1); 861 request.enable(); 862 return (ClassPrepareEvent)waitForRequestedEvent(request); 863 } 864 865 public void resumeForMsecs(long msecs) { 866 try { 867 addListener (this); 868 } catch (Exception ex){ 869 ex.printStackTrace(); 870 testFailed = true; 871 return; 872 } 873 874 try { 875 vm().resume(); 876 } catch (VMDisconnectedException e) { 877 } 878 879 if (!vmDisconnected) { 880 try { 881 System.out.println("Sleeping for " + msecs + " milleseconds"); 882 Thread.sleep(msecs); 883 vm().suspend(); 884 } catch (InterruptedException e) { 885 } 886 } 887 } 888 889 public void resumeToVMDisconnect() { 890 try { 891 traceln("TS: resumeToVMDisconnect: vm.resume called"); 892 vm.resume(); 893 } catch (VMDisconnectedException e) { 894 // clean up below 895 } 896 waitForVMDisconnect(); 897 } 898 899 public void shutdown() { 900 shutdown(null); 901 } 902 903 public void shutdown(String message) { 904 traceln("TS: shutdown: vmDied= " + vmDied + 905 ", vmDisconnected= " + vmDisconnected + 906 ", connection = " + connection); 907 908 if ((connection != null)) { 909 try { 910 connection.disposeVM(); 911 } catch (VMDisconnectedException e) { 912 // Shutting down after the VM has gone away. This is 913 // not an error, and we just ignore it. 914 } 915 } else { 916 traceln("TS: shutdown: disposeVM not called"); 917 } 918 if (message != null) { 919 println(message); 920 } 921 922 vmDied = true; 923 vmDisconnected = true; 924 } 925 }