test/jdk/com/sun/jdi/JDIScaffold.java
branchihse-cflags-rewrite-branch
changeset 56214 0544ba555e67
parent 56213 85ee4e5a2f92
parent 49076 1d879babed52
child 56215 1c5a3127046f
equal deleted inserted replaced
56213:85ee4e5a2f92 56214:0544ba555e67
     1 /*
       
     2  * Copyright (c) 1999, 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 /**
       
    32  * Framework used by all JDI regression tests
       
    33  */
       
    34 abstract public class JDIScaffold {
       
    35     private boolean shouldTrace = false;
       
    36     private VMConnection connection;
       
    37     private VirtualMachine vm;
       
    38     private EventRequestManager requestManager;
       
    39     private List listeners = Collections.synchronizedList(new LinkedList());
       
    40     ThreadReference vmStartThread = null;
       
    41     boolean vmDied = false;
       
    42     boolean vmDisconnected = false;
       
    43 
       
    44     static private class ArgInfo {
       
    45         String targetVMArgs = "";
       
    46         String targetAppCommandLine = "";
       
    47         String connectorSpec = "com.sun.jdi.CommandLineLaunch:";
       
    48         int traceFlags = 0;
       
    49     }
       
    50 
       
    51     static public interface TargetListener {
       
    52         boolean eventSetReceived(EventSet set);
       
    53         boolean eventSetComplete(EventSet set);
       
    54         boolean eventReceived(Event event);
       
    55         boolean breakpointReached(BreakpointEvent event);
       
    56         boolean exceptionThrown(ExceptionEvent event);
       
    57         boolean stepCompleted(StepEvent event);
       
    58         boolean classPrepared(ClassPrepareEvent event);
       
    59         boolean classUnloaded(ClassUnloadEvent event);
       
    60         boolean methodEntered(MethodEntryEvent event);
       
    61         boolean methodExited(MethodExitEvent event);
       
    62         boolean fieldAccessed(AccessWatchpointEvent event);
       
    63         boolean fieldModified(ModificationWatchpointEvent event);
       
    64         boolean threadStarted(ThreadStartEvent event);
       
    65         boolean threadDied(ThreadDeathEvent event);
       
    66         boolean vmStarted(VMStartEvent event);
       
    67         boolean vmDied(VMDeathEvent event);
       
    68         boolean vmDisconnected(VMDisconnectEvent event);
       
    69     }
       
    70 
       
    71     static public class TargetAdapter implements TargetListener {
       
    72         public boolean eventSetReceived(EventSet set) {
       
    73             return false;
       
    74         }
       
    75         public boolean eventSetComplete(EventSet set) {
       
    76             return false;
       
    77         }
       
    78         public boolean eventReceived(Event event) {
       
    79             return false;
       
    80         }
       
    81         public boolean breakpointReached(BreakpointEvent event) {
       
    82             return false;
       
    83         }
       
    84         public boolean exceptionThrown(ExceptionEvent event) {
       
    85             return false;
       
    86         }
       
    87         public boolean stepCompleted(StepEvent event) {
       
    88             return false;
       
    89         }
       
    90         public boolean classPrepared(ClassPrepareEvent event) {
       
    91             return false;
       
    92         }
       
    93         public boolean classUnloaded(ClassUnloadEvent event) {
       
    94             return false;
       
    95         }
       
    96         public boolean methodEntered(MethodEntryEvent event) {
       
    97             return false;
       
    98         }
       
    99         public boolean methodExited(MethodExitEvent event) {
       
   100             return false;
       
   101         }
       
   102         public boolean fieldAccessed(AccessWatchpointEvent event) {
       
   103             return false;
       
   104         }
       
   105         public boolean fieldModified(ModificationWatchpointEvent event) {
       
   106             return false;
       
   107         }
       
   108         public boolean threadStarted(ThreadStartEvent event) {
       
   109             return false;
       
   110         }
       
   111         public boolean threadDied(ThreadDeathEvent event) {
       
   112             return false;
       
   113         }
       
   114         public boolean vmStarted(VMStartEvent event) {
       
   115             return false;
       
   116         }
       
   117         public boolean vmDied(VMDeathEvent event) {
       
   118             return false;
       
   119         }
       
   120         public boolean vmDisconnected(VMDisconnectEvent event) {
       
   121             return false;
       
   122         }
       
   123     }
       
   124 
       
   125     private class EventHandler implements Runnable {
       
   126         EventHandler() {
       
   127             Thread thread = new Thread(this);
       
   128             thread.setDaemon(true);
       
   129             thread.start();
       
   130         }
       
   131 
       
   132         private boolean notifyEvent(TargetListener listener, Event event) {
       
   133             if (listener.eventReceived(event) == true) {
       
   134                 return true;
       
   135             } else if (event instanceof BreakpointEvent) {
       
   136                 return listener.breakpointReached((BreakpointEvent)event);
       
   137             } else if (event instanceof ExceptionEvent) {
       
   138                 return listener.exceptionThrown((ExceptionEvent)event);
       
   139             } else if (event instanceof StepEvent) {
       
   140                 return listener.stepCompleted((StepEvent)event);
       
   141             } else if (event instanceof ClassPrepareEvent) {
       
   142                 return listener.classPrepared((ClassPrepareEvent)event);
       
   143             } else if (event instanceof ClassUnloadEvent) {
       
   144                 return listener.classUnloaded((ClassUnloadEvent)event);
       
   145             } else if (event instanceof MethodEntryEvent) {
       
   146                 return listener.methodEntered((MethodEntryEvent)event);
       
   147             } else if (event instanceof MethodExitEvent) {
       
   148                 return listener.methodExited((MethodExitEvent)event);
       
   149             } else if (event instanceof AccessWatchpointEvent) {
       
   150                 return listener.fieldAccessed((AccessWatchpointEvent)event);
       
   151             } else if (event instanceof ModificationWatchpointEvent) {
       
   152                 return listener.fieldModified((ModificationWatchpointEvent)event);
       
   153             } else if (event instanceof ThreadStartEvent) {
       
   154                 return listener.threadStarted((ThreadStartEvent)event);
       
   155             } else if (event instanceof ThreadDeathEvent) {
       
   156                 return listener.threadDied((ThreadDeathEvent)event);
       
   157             } else if (event instanceof VMStartEvent) {
       
   158                 return listener.vmStarted((VMStartEvent)event);
       
   159             } else if (event instanceof VMDeathEvent) {
       
   160                 return listener.vmDied((VMDeathEvent)event);
       
   161             } else if (event instanceof VMDisconnectEvent) {
       
   162                 return listener.vmDisconnected((VMDisconnectEvent)event);
       
   163             } else {
       
   164                 throw new InternalError("Unknown event type: " + event.getClass());
       
   165             }
       
   166         }
       
   167 
       
   168         private void traceSuspendPolicy(int policy) {
       
   169             if (shouldTrace) {
       
   170                 switch (policy) {
       
   171                 case EventRequest.SUSPEND_NONE:
       
   172                     traceln("JDI: runloop: suspend = SUSPEND_NONE");
       
   173                     break;
       
   174                 case EventRequest.SUSPEND_ALL:
       
   175                     traceln("JDI: runloop: suspend = SUSPEND_ALL");
       
   176                     break;
       
   177                 case EventRequest.SUSPEND_EVENT_THREAD:
       
   178                     traceln("JDI: runloop: suspend = SUSPEND_EVENT_THREAD");
       
   179                     break;
       
   180                 }
       
   181             }
       
   182         }
       
   183 
       
   184         public void run() {
       
   185             boolean connected = true;
       
   186             do {
       
   187                 try {
       
   188                     EventSet set = vm.eventQueue().remove();
       
   189                     traceSuspendPolicy(set.suspendPolicy());
       
   190                     synchronized (listeners) {
       
   191                         ListIterator iter = listeners.listIterator();
       
   192                         while (iter.hasNext()) {
       
   193                             TargetListener listener = (TargetListener)iter.next();
       
   194                             traceln("JDI: runloop: listener = " + listener);
       
   195                             if (listener.eventSetReceived(set) == true) {
       
   196                                 iter.remove();
       
   197                             } else {
       
   198                                 Iterator jter = set.iterator();
       
   199                                 while (jter.hasNext()) {
       
   200                                     Event event = (Event)jter.next();
       
   201                                     traceln("JDI: runloop:    event = " + event.getClass());
       
   202                                     if (event instanceof VMDisconnectEvent) {
       
   203                                         connected = false;
       
   204                                     }
       
   205                                     if (notifyEvent(listener, event) == true) {
       
   206                                         iter.remove();
       
   207                                         break;
       
   208                                     }
       
   209                                 }
       
   210                                 traceln("JDI: runloop:   end of events loop");
       
   211                                 if (listener.eventSetComplete(set) == true) {
       
   212                                     iter.remove();
       
   213                                 }
       
   214                             }
       
   215                         traceln("JDI: runloop: end of listener");
       
   216                         }
       
   217                     }
       
   218                 } catch (InterruptedException e) {
       
   219                 }
       
   220                 traceln("JDI: runloop: end of outer loop");
       
   221             } while (connected);
       
   222         }
       
   223     }
       
   224 
       
   225     /**
       
   226      * Constructor
       
   227      */
       
   228     public JDIScaffold() {
       
   229     }
       
   230 
       
   231     public void enableScaffoldTrace() {
       
   232         this.shouldTrace = true;
       
   233     }
       
   234 
       
   235     public void disableScaffoldTrace() {
       
   236         this.shouldTrace = false;
       
   237     }
       
   238 
       
   239 
       
   240     /*
       
   241      * Test cases should implement tests in runTests and should
       
   242      * initiate testing by calling run().
       
   243      */
       
   244     abstract protected void runTests() throws Exception;
       
   245 
       
   246     final public void startTests() throws Exception {
       
   247         try {
       
   248             runTests();
       
   249         } finally {
       
   250             shutdown();
       
   251         }
       
   252     }
       
   253 
       
   254     protected void println(String str) {
       
   255         System.err.println(str);
       
   256     }
       
   257 
       
   258     protected void traceln(String str) {
       
   259         if (shouldTrace) {
       
   260             println(str);
       
   261         }
       
   262     }
       
   263 
       
   264     private ArgInfo parseArgs(String args[]) {
       
   265         ArgInfo argInfo = new ArgInfo();
       
   266         for (int i = 0; i < args.length; i++) {
       
   267             if (args[i].equals("-connect")) {
       
   268                 i++;
       
   269                 argInfo.connectorSpec = args[i];
       
   270             } else if (args[i].equals("-trace")) {
       
   271                 i++;
       
   272                 argInfo.traceFlags = Integer.decode(args[i]).intValue();
       
   273             } else if (args[i].startsWith("-J")) {
       
   274                 argInfo.targetVMArgs += (args[i].substring(2) + ' ');
       
   275 
       
   276                 /*
       
   277                  * classpath can span two arguments so we need to handle
       
   278                  * it specially.
       
   279                  */
       
   280                 if (args[i].equals("-J-classpath")) {
       
   281                     i++;
       
   282                     argInfo.targetVMArgs += (args[i] + ' ');
       
   283                 }
       
   284             } else {
       
   285                 argInfo.targetAppCommandLine += (args[i] + ' ');
       
   286             }
       
   287         }
       
   288         return argInfo;
       
   289     }
       
   290 
       
   291     public void connect(String args[]) {
       
   292         ArgInfo argInfo = parseArgs(args);
       
   293 
       
   294         argInfo.targetVMArgs += VMConnection.getDebuggeeVMOptions();
       
   295         connection = new VMConnection(argInfo.connectorSpec,
       
   296                                       argInfo.traceFlags);
       
   297         if (!connection.isLaunch()) {
       
   298             throw new UnsupportedOperationException(
       
   299                                  "Listening and Attaching not yet supported");
       
   300         }
       
   301 
       
   302         /*
       
   303          * Add a listener to track VM start/death/disconnection and
       
   304          * to update status fields accordingly.
       
   305          */
       
   306         addListener(new TargetAdapter() {
       
   307                         public boolean vmStarted(VMStartEvent event) {
       
   308                             traceln("JDI: listener1:  got VMStart");
       
   309                             synchronized(JDIScaffold.this) {
       
   310                                 vmStartThread = event.thread();
       
   311                                 JDIScaffold.this.notifyAll();
       
   312                             }
       
   313                             return false;
       
   314                         }
       
   315 
       
   316                         public boolean vmDied(VMDeathEvent event) {
       
   317                             traceln("JDI: listener1:  got VMDeath");
       
   318                             synchronized(JDIScaffold.this) {
       
   319                                 vmDied = true;
       
   320                                 JDIScaffold.this.notifyAll();
       
   321                             }
       
   322                             return false;
       
   323                         }
       
   324 
       
   325                         public boolean vmDisconnected(VMDisconnectEvent event) {
       
   326                             traceln("JDI: listener1:  got VMDisconnectedEvent");
       
   327                             synchronized(JDIScaffold.this) {
       
   328                                 vmDisconnected = true;
       
   329                                 JDIScaffold.this.notifyAll();
       
   330                             }
       
   331                             return false;
       
   332                         }
       
   333                     });
       
   334 
       
   335         if (connection.connector().name().equals("com.sun.jdi.CommandLineLaunch")) {
       
   336             if (argInfo.targetVMArgs.length() > 0) {
       
   337                 if (connection.connectorArg("options").length() > 0) {
       
   338                     throw new IllegalArgumentException("VM options in two places");
       
   339                 }
       
   340                 connection.setConnectorArg("options", argInfo.targetVMArgs);
       
   341             }
       
   342             if (argInfo.targetAppCommandLine.length() > 0) {
       
   343                 if (connection.connectorArg("main").length() > 0) {
       
   344                     throw new IllegalArgumentException("Command line in two places");
       
   345                 }
       
   346                 connection.setConnectorArg("main", argInfo.targetAppCommandLine);
       
   347             }
       
   348         }
       
   349 
       
   350         vm = connection.open();
       
   351         requestManager = vm.eventRequestManager();
       
   352         new EventHandler();
       
   353     }
       
   354 
       
   355 
       
   356     public VirtualMachine vm() {
       
   357         return vm;
       
   358     }
       
   359 
       
   360     public EventRequestManager eventRequestManager() {
       
   361         return requestManager;
       
   362     }
       
   363 
       
   364     public void addListener(TargetListener listener) {
       
   365         listeners.add(listener);
       
   366     }
       
   367 
       
   368     public void removeListener(TargetListener listener) {
       
   369         listeners.remove(listener);
       
   370     }
       
   371 
       
   372     public synchronized ThreadReference waitForVMStart() {
       
   373         while ((vmStartThread == null) && !vmDisconnected) {
       
   374             try {
       
   375                 wait();
       
   376             } catch (InterruptedException e) {
       
   377             }
       
   378         }
       
   379 
       
   380         if (vmStartThread == null) {
       
   381             throw new VMDisconnectedException();
       
   382         }
       
   383 
       
   384         return vmStartThread;
       
   385     }
       
   386 
       
   387     public synchronized void waitForVMDeath() {
       
   388         while (!vmDied && !vmDisconnected) {
       
   389             try {
       
   390                 traceln("JDI: waitForVMDeath:  waiting");
       
   391                 wait();
       
   392             } catch (InterruptedException e) {
       
   393             }
       
   394         }
       
   395         traceln("JDI: waitForVMDeath:  done waiting");
       
   396 
       
   397         if (!vmDied) {
       
   398             throw new VMDisconnectedException();
       
   399         }
       
   400     }
       
   401 
       
   402     public Event waitForRequestedEvent(final EventRequest request) {
       
   403         class EventNotification {
       
   404             Event event;
       
   405             boolean disconnected = false;
       
   406         }
       
   407         final EventNotification en = new EventNotification();
       
   408 
       
   409         TargetAdapter adapter = new TargetAdapter() {
       
   410             public boolean eventReceived(Event event) {
       
   411                 if (request.equals(event.request())) {
       
   412                     synchronized (en) {
       
   413                         en.event = event;
       
   414                         en.notifyAll();
       
   415                     }
       
   416                     return true;
       
   417                 } else if (event instanceof VMDisconnectEvent) {
       
   418                     synchronized (en) {
       
   419                         en.disconnected = true;
       
   420                         en.notifyAll();
       
   421                     }
       
   422                     return true;
       
   423                 } else {
       
   424                     return false;
       
   425                 }
       
   426             }
       
   427         };
       
   428 
       
   429         addListener(adapter);
       
   430 
       
   431         try {
       
   432             synchronized (en) {
       
   433                 vm.resume();
       
   434                 while (!en.disconnected && (en.event == null)) {
       
   435                     en.wait();
       
   436                 }
       
   437             }
       
   438         } catch (InterruptedException e) {
       
   439             return null;
       
   440         }
       
   441 
       
   442         if (en.disconnected) {
       
   443             throw new RuntimeException("VM Disconnected before requested event occurred");
       
   444         }
       
   445         return en.event;
       
   446     }
       
   447 
       
   448     private StepEvent doStep(ThreadReference thread, int gran, int depth) {
       
   449         final StepRequest sr =
       
   450                   requestManager.createStepRequest(thread, gran, depth);
       
   451 
       
   452         sr.addClassExclusionFilter("java.*");
       
   453         sr.addClassExclusionFilter("javax.*");
       
   454         sr.addClassExclusionFilter("sun.*");
       
   455         sr.addClassExclusionFilter("com.sun.*");
       
   456         sr.addClassExclusionFilter("com.oracle.*");
       
   457         sr.addClassExclusionFilter("oracle.*");
       
   458         sr.addClassExclusionFilter("jdk.internal.*");
       
   459         sr.addCountFilter(1);
       
   460         sr.enable();
       
   461         StepEvent retEvent = (StepEvent)waitForRequestedEvent(sr);
       
   462         requestManager.deleteEventRequest(sr);
       
   463         return retEvent;
       
   464     }
       
   465 
       
   466     public StepEvent stepIntoInstruction(ThreadReference thread) {
       
   467         return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO);
       
   468     }
       
   469 
       
   470     public StepEvent stepIntoLine(ThreadReference thread) {
       
   471         return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO);
       
   472     }
       
   473 
       
   474     public StepEvent stepOverInstruction(ThreadReference thread) {
       
   475         return doStep(thread, StepRequest.STEP_MIN, StepRequest.STEP_OVER);
       
   476     }
       
   477 
       
   478     public StepEvent stepOverLine(ThreadReference thread) {
       
   479         return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OVER);
       
   480     }
       
   481 
       
   482     public StepEvent stepOut(ThreadReference thread) {
       
   483         return doStep(thread, StepRequest.STEP_LINE, StepRequest.STEP_OUT);
       
   484     }
       
   485 
       
   486     public BreakpointEvent resumeTo(Location loc) {
       
   487         final BreakpointRequest request =
       
   488             requestManager.createBreakpointRequest(loc);
       
   489         request.addCountFilter(1);
       
   490         request.enable();
       
   491         return (BreakpointEvent)waitForRequestedEvent(request);
       
   492     }
       
   493 
       
   494     public ReferenceType findReferenceType(String name) {
       
   495         List rts = vm.classesByName(name);
       
   496         Iterator iter = rts.iterator();
       
   497         while (iter.hasNext()) {
       
   498             ReferenceType rt = (ReferenceType)iter.next();
       
   499             if (rt.name().equals(name)) {
       
   500                 return rt;
       
   501             }
       
   502         }
       
   503         return null;
       
   504     }
       
   505 
       
   506     public Method findMethod(ReferenceType rt, String name, String signature) {
       
   507         List methods = rt.methods();
       
   508         Iterator iter = methods.iterator();
       
   509         while (iter.hasNext()) {
       
   510             Method method = (Method)iter.next();
       
   511             if (method.name().equals(name) &&
       
   512                 method.signature().equals(signature)) {
       
   513                 return method;
       
   514             }
       
   515         }
       
   516         return null;
       
   517     }
       
   518 
       
   519     public Location findLocation(ReferenceType rt, int lineNumber)
       
   520                          throws AbsentInformationException {
       
   521         List locs = rt.locationsOfLine(lineNumber);
       
   522         if (locs.size() == 0) {
       
   523             throw new IllegalArgumentException("Bad line number");
       
   524         } else if (locs.size() > 1) {
       
   525             throw new IllegalArgumentException("Line number has multiple locations");
       
   526         }
       
   527 
       
   528         return (Location)locs.get(0);
       
   529     }
       
   530 
       
   531     public BreakpointEvent resumeTo(String clsName, String methodName,
       
   532                                          String methodSignature) {
       
   533         ReferenceType rt = findReferenceType(clsName);
       
   534         if (rt == null) {
       
   535             rt = resumeToPrepareOf(clsName).referenceType();
       
   536         }
       
   537 
       
   538         Method method = findMethod(rt, methodName, methodSignature);
       
   539         if (method == null) {
       
   540             throw new IllegalArgumentException("Bad method name/signature");
       
   541         }
       
   542 
       
   543         return resumeTo(method.location());
       
   544     }
       
   545 
       
   546     public BreakpointEvent resumeTo(String clsName, int lineNumber) throws AbsentInformationException {
       
   547         ReferenceType rt = findReferenceType(clsName);
       
   548         if (rt == null) {
       
   549             rt = resumeToPrepareOf(clsName).referenceType();
       
   550         }
       
   551 
       
   552         return resumeTo(findLocation(rt, lineNumber));
       
   553     }
       
   554 
       
   555     public ClassPrepareEvent resumeToPrepareOf(String className) {
       
   556         final ClassPrepareRequest request =
       
   557             requestManager.createClassPrepareRequest();
       
   558         request.addClassFilter(className);
       
   559         request.addCountFilter(1);
       
   560         request.enable();
       
   561         return (ClassPrepareEvent)waitForRequestedEvent(request);
       
   562     }
       
   563 
       
   564     public void resumeToVMDeath() {
       
   565         // If we are very close to VM death, we might get a VM disconnect
       
   566         // before resume is complete. In that case ignore any VMDisconnectException
       
   567         // and let the waitForVMDeath to clean up.
       
   568         try {
       
   569             traceln("JDI: resumeToVMDeath:  resuming");
       
   570             vm.resume();
       
   571             traceln("JDI: resumeToVMDeath:  resumed");
       
   572         } catch (VMDisconnectedException e) {
       
   573             // clean up below
       
   574         }
       
   575         waitForVMDeath();
       
   576     }
       
   577 
       
   578     public void shutdown() {
       
   579         shutdown(null);
       
   580     }
       
   581 
       
   582     public void shutdown(String message) {
       
   583         if ((connection != null) && !vmDied) {
       
   584             try {
       
   585                 connection.disposeVM();
       
   586             } catch (VMDisconnectedException e) {
       
   587                 // Shutting down after the VM has gone away. This is
       
   588                 // not an error, and we just ignore it.
       
   589             }
       
   590         }
       
   591         if (message != null) {
       
   592             System.out.println(message);
       
   593         }
       
   594     }
       
   595 }