1 /*
2  * Copyright (c) 2001, 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.
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 package nsk.jdi.StackFrame.thisObject;
25 
26 import nsk.share.*;
27 import nsk.share.jpda.*;
28 import nsk.share.jdi.*;
29 
30 import com.sun.jdi.*;
31 import java.util.*;
32 import java.io.*;
33 
34 import com.sun.jdi.event.*;
35 import com.sun.jdi.request.*;
36 
37 
38 /**
39  * The test for the implementation of an object of the type     <BR>
40  * StackFrame.                                                  <BR>
41  *                                                              <BR>
42  * The test checks up that results of the method                <BR>
43  * <code>com.sun.jdi.StackFrame.thisObject()</code>             <BR>
44  * complies with its spec for a static method.                  <BR>
45  * <BR>
46  * The cases for testing are as follows.                        <BR>
47  * After being started up,                                              <BR>
48  * a debuggee creates a 'lockingObject' for synchronizing threads,      <BR>
49  * enters a synchronized block in which it creates new thread, thread2, <BR>
50  * informs a debugger of the thread2 creation, and is waiting for reply.<BR>
51  * Since the thread2 uses the same locking object as main one           <BR>
52  * it is locked up until the main thread leaves the synchronized block. <BR>
53  * Upon the receiption a message from the debuggee, the debugger        <BR>
54  * sets up a breakpoint, and performs the following.                    <BR>
55  * 1) After getting a thread2 suspended but before to resume it,        <BR>
56  *    StackFrame.thisObject() is invoked and                            <BR>
57  *    its returned value must be null.                                  <BR>
58  *    Since the thread is not resumed yet,                              <BR>
59  *    InvalidStackFrameException must not be throw.                     <BR>
60  * 2) After resuming the thread2, the tested method is invoked          <BR>
61  *    second time and InvalidStackFrameException must be thrown.        <BR>
62  *  <BR>
63  */
64 
65 public class thisobject002 {
66 
67     //----------------------------------------------------- templete section
68     static final int PASSED = 0;
69     static final int FAILED = 2;
70     static final int PASS_BASE = 95;
71 
72     //----------------------------------------------------- templete parameters
73     static final String
74     sHeader1 = "\n==> nsk/jdi/StackFrame/thisObject/thisobject002  ",
75     sHeader2 = "--> debugger: ",
76     sHeader3 = "##> debugger: ";
77 
78     //----------------------------------------------------- main method
79 
main(String argv[])80     public static void main (String argv[]) {
81         int result = run(argv, System.out);
82         System.exit(result + PASS_BASE);
83     }
84 
run(String argv[], PrintStream out)85     public static int run (String argv[], PrintStream out) {
86         return new thisobject002().runThis(argv, out);
87     }
88 
89     //--------------------------------------------------   log procedures
90 
91     private static Log  logHandler;
92 
log1(String message)93     private static void log1(String message) {
94         logHandler.display(sHeader1 + message);
95     }
log2(String message)96     private static void log2(String message) {
97         logHandler.display(sHeader2 + message);
98     }
log3(String message)99     private static void log3(String message) {
100         logHandler.complain(sHeader3 + message);
101     }
102 
103     //  ************************************************    test parameters
104 
105     private String debuggeeName =
106         "nsk.jdi.StackFrame.thisObject.thisobject002a";
107 
108     private String testedClassName =
109         "nsk.jdi.StackFrame.thisObject.Threadthisobject002a";
110 
111     //String mName = "nsk.jdi.StackFrame.thisObject";
112 
113     //====================================================== test program
114     //------------------------------------------------------ common section
115     static ArgumentHandler      argsHandler;
116 
117     static int waitTime;
118 
119     static VirtualMachine      vm            = null;
120     static EventRequestManager eventRManager = null;
121     static EventQueue          eventQueue    = null;
122     static EventSet            eventSet      = null;
123 
124     ReferenceType     testedclass  = null;
125     ThreadReference   thread2      = null;
126     ThreadReference   mainThread   = null;
127 
128     static int  testExitCode = PASSED;
129 
130     static final int returnCode0 = 0;
131     static final int returnCode1 = 1;
132     static final int returnCode2 = 2;
133     static final int returnCode3 = 3;
134     static final int returnCode4 = 4;
135 
136     //------------------------------------------------------ methods
137 
runThis(String argv[], PrintStream out)138     private int runThis (String argv[], PrintStream out) {
139 
140         Debugee debuggee;
141 
142         argsHandler     = new ArgumentHandler(argv);
143         logHandler      = new Log(out, argsHandler);
144         Binder binder   = new Binder(argsHandler, logHandler);
145 
146         if (argsHandler.verbose()) {
147             debuggee = binder.bindToDebugee(debuggeeName + " -vbs");  // *** tp
148         } else {
149             debuggee = binder.bindToDebugee(debuggeeName);            // *** tp
150         }
151 
152         waitTime = argsHandler.getWaitTime();
153 
154 
155         IOPipe pipe     = new IOPipe(debuggee);
156 
157         debuggee.redirectStderr(out);
158         log2(debuggeeName + " debuggee launched");
159         debuggee.resume();
160 
161         String line = pipe.readln();
162         if ((line == null) || !line.equals("ready")) {
163             log3("signal received is not 'ready' but: " + line);
164             return FAILED;
165         } else {
166             log2("'ready' recieved");
167         }
168 
169         VirtualMachine vm = debuggee.VM();
170 
171     //------------------------------------------------------  testing section
172         log1("      TESTING BEGINS");
173 
174         for (int i = 0; ; i++) {
175         pipe.println("newcheck");
176             line = pipe.readln();
177 
178             if (line.equals("checkend")) {
179                 log2("     : returned string is 'checkend'");
180                 break ;
181             } else if (!line.equals("checkready")) {
182                 log3("ERROR: returned string is not 'checkready'");
183                 testExitCode = FAILED;
184                 break ;
185             }
186 
187             log1("new check: #" + i);
188 
189             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part
190 
191             int expresult = returnCode0;
192 
193 
194             eventRManager = vm.eventRequestManager();
195             eventQueue    = vm.eventQueue();
196 
197             String threadName = "testedThread";
198 
199             String breakpointMethod1 = "runt1";
200             String breakpointMethod2 = "runt2";
201 
202             String bpLine1 = "breakpointLineNumber1";
203             String bpLine2 = "breakpointLineNumber2";
204             //String bpLine3 = "breakpointLineNumber3";
205 
206 
207             List            allThreads   = null;
208             ListIterator    listIterator = null;
209             List            classes      = null;
210 
211             BreakpointRequest breakpRequest1 = null;
212             BreakpointRequest breakpRequest2 = null;
213             //BreakpointRequest breakpRequest3 = null;
214 
215             int suspCount = 0;
216             int frameCount;
217 
218             StackFrame    stackFrame = null;
219             LocalVariable locvar1    = null;
220             LocalVariable locvar2    = null;
221 
222             label0: {
223 
224                 log2("getting ThreadReference object");
225                 try {
226                     allThreads  = vm.allThreads();
227                     classes     = vm.classesByName(testedClassName);
228                     testedclass = (ReferenceType) classes.get(0);
229                 } catch ( Exception e) {
230                     log3("ERROR: Exception at very beginning !? : " + e);
231                     expresult = returnCode1;
232                     break label0;
233                 }
234 
235                 thread2 = debuggee.threadByName(threadName);
236 
237                 log2("setting up breakpoints");
238 
239                 breakpRequest1 = settingBreakpoint(breakpointMethod1, bpLine1, "one");
240                 if (breakpRequest1 == null) {
241                     expresult = returnCode1;
242                     break label0;
243                 }
244                 breakpRequest2 = settingBreakpoint(breakpointMethod2, bpLine2, "two");
245                 if (breakpRequest2 == null) {
246                     expresult = returnCode1;
247                     break label0;
248                 }
249             }
250 
251             label1: {
252 
253                 if (expresult != returnCode0)
254                        break label1;
255 
256                 log2("     enabling breakpRequest1");
257                 breakpRequest1.enable();
258 
259                 log2("       forcing the main thread to leave synchronized block");
260                 pipe.println("continue");
261                 line = pipe.readln();
262                 if (!line.equals("docontinue")) {
263                     log3("ERROR: returned string is not 'docontinue'");
264                     expresult = returnCode4;
265                     break label1;
266                 }
267 
268                 expresult = breakpoint();
269                 if (expresult != returnCode0)
270                     break label1;
271 
272                 log2("      the thread2 is at the breakpoint");
273                 log2("      the check that the thread2 is suspended at the breakpoint");
274                 if ( thread2.isSuspended() ) {
275                     log2("     :   thread2.isSuspended()");
276                 } else {
277                     log3("ERROR:  !thread2.isSuspended()");
278                     expresult = returnCode1;
279                     break label1;
280                 }
281 
282                 log2("      getting StackFrame");
283                 try {
284                     stackFrame = thread2.frame(0);
285                 } catch ( Exception e ) {
286                     log3("ERROR: Exception for stackFrame = thread2.frame(0)    :" + e);
287                     expresult = returnCode1;
288                     break label1;
289                 }
290 
291                 ObjectReference thisobj;
292 
293                 log2("      getting stackFrame.thisObject() which must not be null");
294                 try {
295                     thisobj = stackFrame.thisObject();
296                     if (thisobj != null) {
297                         log3("ERROR:  stackFrame.thisObject() != null for a static method");
298                     expresult = returnCode1;
299                     break label1;
300                     }
301                 } catch ( InvalidStackFrameException e ) {
302                     log3("ERROR:  InvalidStackFrameExceprtion before the thread2 is resumed");
303                     expresult = returnCode1;
304                     break label1;
305                 } catch ( ClassCastException e ) {
306                     log3("ERROR:  ClassCastException for ThreadReference t = (ThreadReference) thisobj;");
307                     expresult = returnCode1;
308                     break label1;
309                 }
310 
311                 log2("      resuming the thread2");
312                 eventSet.resume();
313 
314                 log2("      checking up throwing InvalidStackFrameExceprtion after the thread2 is resumed");
315                 try {
316                     thisobj = stackFrame.thisObject();
317                     log3("ERROR:  no InvalidStackFrameExceprtion after the thread2 is resumed");
318                     expresult = returnCode1;
319                     break label1;
320                 } catch ( InvalidStackFrameException e ) {
321                 }
322             }
323 
324             log2("      resuming the thread2 for case it was suspended but not resumed yet");
325             eventSet.resume();
326 
327             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
328             log2("     the end of testing");
329             if (expresult != returnCode0)
330                 testExitCode = FAILED;
331         }
332         log1("      TESTING ENDS");
333 
334     //--------------------------------------------------   test summary section
335     //-------------------------------------------------    standard end section
336 
337         pipe.println("quit");
338         log2("waiting for the debuggee to finish ...");
339         debuggee.waitFor();
340 
341         int status = debuggee.getStatus();
342         if (status != PASSED + PASS_BASE) {
343             log3("debuggee returned UNEXPECTED exit status: " +
344                     status + " != PASS_BASE");
345             testExitCode = FAILED;
346         } else {
347             log2("debuggee returned expected exit status: " +
348                     status + " == PASS_BASE");
349         }
350 
351         if (testExitCode != PASSED) {
352             logHandler.complain("TEST FAILED");
353         }
354         return testExitCode;
355     }
356 
357    /*
358     * private BreakpointRequest settingBreakpoint(String, String, String)
359     *
360     * It sets up a breakpoint within a given method at given line number
361     * for the thread2 only.
362     * Third parameter is required for any case in future debugging, as if.
363     *
364     * Return codes:
365     *  = BreakpointRequest object  in case of success
366     *  = null   in case of an Exception thrown within the method
367     */
368 
settingBreakpoint( String methodName, String bpLine, String property)369     private BreakpointRequest settingBreakpoint ( String methodName,
370                                                   String bpLine,
371                                                   String property) {
372 
373         log2("setting up a breakpoint: method: '" + methodName + "' line: " + bpLine );
374 
375         List              alllineLocations = null;
376         Location          lineLocation     = null;
377         BreakpointRequest breakpRequest    = null;
378 
379         try {
380             Method  method  = (Method) testedclass.methodsByName(methodName).get(0);
381 
382             alllineLocations = method.allLineLocations();
383 
384             int n =
385                 ( (IntegerValue) testedclass.getValue(testedclass.fieldByName(bpLine) ) ).value();
386             if (n > alllineLocations.size()) {
387                 log3("ERROR:  TEST_ERROR_IN_settingBreakpoint(): number is out of bound of method's lines");
388             } else {
389                 lineLocation = (Location) alllineLocations.get(n);
390                 try {
391                     breakpRequest = eventRManager.createBreakpointRequest(lineLocation);
392                     breakpRequest.putProperty("number", property);
393                     breakpRequest.addThreadFilter(thread2);
394                     breakpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD);
395                 } catch ( Exception e1 ) {
396                     log3("ERROR: inner Exception within settingBreakpoint() : " + e1);
397                     breakpRequest    = null;
398                 }
399             }
400         } catch ( Exception e2 ) {
401             log3("ERROR: ATTENTION:  outer Exception within settingBreakpoint() : " + e2);
402             breakpRequest    = null;
403         }
404 
405         if (breakpRequest == null)
406             log2("      A BREAKPOINT HAS NOT BEEN SET UP");
407         else
408             log2("      a breakpoint has been set up");
409 
410         return breakpRequest;
411     }
412 
413 
414     /*
415      * private int breakpoint ()
416      *
417      * It removes events from EventQueue until gets first BreakpointEvent.
418      * To get next EventSet value, it uses the method
419      *    EventQueue.remove(int timeout)
420      * The timeout argument passed to the method, is "waitTime*60000".
421      * Note: the value of waitTime is set up with
422      *       the method ArgumentHandler.getWaitTime() at the beginning of the test.
423      *
424      * Return codes:
425      *  = returnCode0 - success;
426      *  = returnCode2 - Exception when "eventSet = eventQueue.remove()" is executed
427      *  = returnCode3 - default case when loop of processing an event, that is,
428      *                  an unspecified event was taken from the EventQueue
429      */
430 
breakpoint()431     private int breakpoint () {
432 
433         int returnCode = returnCode0;
434 
435         log2("       waiting for BreakpointEvent");
436 
437         labelBP:
438             for (;;) {
439 
440                 log2("       new:  eventSet = eventQueue.remove();");
441                 try {
442                     eventSet = eventQueue.remove(waitTime*60000);
443                     if (eventSet == null) {
444                         log3("ERROR:  timeout for waiting for a BreakpintEvent");
445                         returnCode = returnCode3;
446                         break labelBP;
447                     }
448                 } catch ( Exception e ) {
449                     log3("ERROR: Exception for  eventSet = eventQueue.remove(); : " + e);
450                     returnCode = 1;
451                     break labelBP;
452                 }
453 
454                 if (eventSet != null) {
455 
456                     log2("     :  eventSet != null;  size == " + eventSet.size());
457 
458                     EventIterator eIter = eventSet.eventIterator();
459                     Event         ev    = null;
460 
461                     for (; eIter.hasNext(); ) {
462 
463                         if (returnCode != returnCode0)
464                             break;
465 
466                         ev = eIter.nextEvent();
467 
468                     ll: for (int ifor =0;  ; ifor++) {
469 
470                         try {
471                           switch (ifor) {
472 
473                           case 0:  AccessWatchpointEvent awe = (AccessWatchpointEvent) ev;
474                                    log2("      AccessWatchpointEvent removed");
475                                    break ll;
476                           case 1:  BreakpointEvent be = (BreakpointEvent) ev;
477                                    log2("      BreakpointEvent removed");
478                                    break labelBP;
479                           case 2:  ClassPrepareEvent cpe = (ClassPrepareEvent) ev;
480                                    log2("      ClassPreparEvent removed");
481                                    break ll;
482                           case 3:  ClassUnloadEvent cue = (ClassUnloadEvent) ev;
483                                    log2("      ClassUnloadEvent removed");
484                                    break ll;
485                           case 4:  ExceptionEvent ee = (ExceptionEvent) ev;
486                                    log2("      ExceptionEvent removed");
487                                    break ll;
488                           case 5:  MethodEntryEvent mene = (MethodEntryEvent) ev;
489                                    log2("      MethodEntryEvent removed");
490                                    break ll;
491                           case 6:  MethodExitEvent mexe = (MethodExitEvent) ev;
492                                    log2("      MethodExiEvent removed");
493                                    break ll;
494                           case 7:  ModificationWatchpointEvent mwe = (ModificationWatchpointEvent) ev;
495                                    log2("      ModificationWatchpointEvent removed");
496                                    break ll;
497                           case 8:  StepEvent se = (StepEvent) ev;
498                                    log2("      StepEvent removed");
499                                    break ll;
500                           case 9:  ThreadDeathEvent tde = (ThreadDeathEvent) ev;
501                                    log2("      ThreadDeathEvent removed");
502                                    break ll;
503                           case 10: ThreadStartEvent tse = (ThreadStartEvent) ev;
504                                    log2("      ThreadStartEvent removed");
505                                    break ll;
506                           case 11: VMDeathEvent vmde = (VMDeathEvent) ev;
507                                    log2("      VMDeathEvent removed");
508                                    break ll;
509                           case 12: VMStartEvent vmse = (VMStartEvent) ev;
510                                    log2("      VMStartEvent removed");
511                                    break ll;
512                           case 13: WatchpointEvent we = (WatchpointEvent) ev;
513                                    log2("      WatchpointEvent removed");
514                                    break ll;
515 
516                           default: log3("ERROR:  default case for casting event");
517                                    returnCode = returnCode3;
518                                    break ll;
519                           } // switch
520                         } catch ( ClassCastException e ) {
521                         }   // try
522                     }       // ll: for (int ifor =0;  ; ifor++)
523                 }           // for (; ev.hasNext(); )
524             }
525         }
526         if (returnCode == returnCode0)
527             log2("     :  eventSet == null:  EventQueue is empty");
528 
529         return returnCode;
530     }
531 }
532