1 /*
2  * Copyright (c) 2001, 2018, 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.WatchpointEvent.valueCurrent;
25 
26 import com.sun.jdi.*;
27 import com.sun.jdi.event.*;
28 import com.sun.jdi.request.*;
29 
30 import java.io.*;
31 import java.util.Iterator;
32 import java.util.List;
33 
34 import nsk.share.*;
35 import nsk.share.jpda.*;
36 import nsk.share.jdi.*;
37 
38 
39 // This class is the debugger in the test
40 
41 public class valuecur001 {
42     static final int PASSED = 0;
43     static final int FAILED = 2;
44     static final int JCK_STATUS_BASE = 95;
45 
46     static final int TIMEOUT_DELTA = 1000; // milliseconds
47 
48     static final String COMMAND_READY = "ready";
49     static final String COMMAND_QUIT  = "quit";
50     static final String COMMAND_GO    = "go";
51     static final String COMMAND_DONE  = "done";
52 
53     static final String DEBUGGEE_NAME = "nsk.jdi.WatchpointEvent.valueCurrent.valuecur001a";
54     static final String CHECKED_CLASS_NAME = "nsk.jdi.WatchpointEvent.valueCurrent.CheckedClass";
55 
56     static private Debugee debuggee;
57     static private VirtualMachine vm;
58     static private IOPipe pipe;
59     static private Log log;
60     static private ArgumentHandler argHandler;
61     static private EventSet eventSet;
62 
63     static private ReferenceType rType;
64     static private WatchpointRequest checkedRequest;
65     static private List fieldsList;
66 
67     static private volatile boolean testFailed;
68     static private volatile boolean done;
69     static private volatile int requestsCount, awpEventsCount, mwpEventsCount;
70 
main(String args[])71     public static void main (String args[]) {
72           System.exit(run(args, System.out) + JCK_STATUS_BASE);
73     }
74 
run(final String args[], final PrintStream out)75     public static int run(final String args[], final PrintStream out) {
76 
77         testFailed = false;
78         requestsCount = 0;
79         awpEventsCount = 0;
80         mwpEventsCount = 0;
81 
82         argHandler = new ArgumentHandler(args);
83         log = new Log(out, argHandler);
84 
85         // launch debuggee
86         Binder binder = new Binder(argHandler, log);
87         log.display("Connecting to debuggee");
88         debuggee = binder.bindToDebugee(DEBUGGEE_NAME);
89         debuggee.redirectStderr(log, "valuecur001a >");
90         pipe = debuggee.createIOPipe();
91         vm = debuggee.VM();
92 
93         // resume debuggee
94         log.display("Resuming debuggee");
95         debuggee.resume();
96 
97         // check debuggee's capabilities
98         if (!debuggee.VM().canWatchFieldAccess()) {
99             log.display("TEST WARNING: test passed because JDI implementation does not support " +
100              "watchpoints for field access");
101             pipe.println(COMMAND_QUIT);
102             debuggee.waitFor();
103             return PASSED;
104         }
105 
106         if (!debuggee.VM().canWatchFieldModification()) {
107             log.display("TEST WARNING: test passed because JDI implementation does not support " +
108              "watchpoints for field modification");
109             pipe.println(COMMAND_QUIT);
110             debuggee.waitFor();
111             return PASSED;
112         }
113 
114         try {
115 
116             // wait for debuggee started
117             log.display("Waiting for command: " + COMMAND_READY);
118             String command = pipe.readln();
119             if (!command.equals(COMMAND_READY)) {
120                 throw new Failure("TEST BUG: unexpected debuggee's command: " + command);
121             }
122 
123             // get mirrors
124             if ((rType = debuggee.classByName(CHECKED_CLASS_NAME)) == null) {
125                 throw new Failure("TEST BUG: cannot find " + CHECKED_CLASS_NAME);
126             }
127 
128             // create events requests
129             log.display("Creating requests for WatchpointEvent");
130             EventRequestManager erManager = debuggee.VM().eventRequestManager();
131             Iterator fieldsIter;
132             try {
133                 fieldsList = rType.fields();
134                 fieldsIter = fieldsList.iterator();
135             } catch (ClassNotPreparedException e) {
136                 throw new Failure( "TEST_BUG: " + rType.name() + " is not prepared");
137             }
138             while (fieldsIter.hasNext()) {
139                 Field refField = (Field)fieldsIter.next();
140                 if ((checkedRequest = erManager.createAccessWatchpointRequest(refField)) == null) {
141                     throw new Failure("TEST BUG: unable to create AccessWatchpointRequest");
142                 } else {
143                     log.display("AccessWatchpointRequest for field " +  refField.name() + " created");
144                     checkedRequest.enable();
145                 }
146                 if ((checkedRequest = erManager.createModificationWatchpointRequest(refField)) == null) {
147                     throw new Failure("TEST BUG: unable to create ModificationWatchpointRequest");
148                 } else {
149                     log.display("ModificationWatchpointRequest for field " +  refField.name() + " created");
150                     checkedRequest.enable();
151                 }
152                 requestsCount++;
153             }
154             log.display("Created total " + requestsCount + " WatchpointRequests");
155 
156             // define separate thread for handling events
157             class EventHandler extends Thread {
158                   public void run() {
159                        eventSet = null;
160                        try {
161                             // handle events until all events generated and received
162                             while ( awpEventsCount < requestsCount
163                                     || mwpEventsCount < requestsCount ) {
164 
165                                  eventSet = null;
166                                  eventSet = vm.eventQueue().remove(TIMEOUT_DELTA);
167 
168                                  if (eventSet == null)
169                                      continue;
170 
171                                  EventIterator eventIterator = eventSet.eventIterator();
172                                  while (eventIterator.hasNext()) {
173 
174                                      Event event = eventIterator.nextEvent();
175 
176                                      // handle WatchpointEvent
177                                      if (event instanceof WatchpointEvent) {
178                                         WatchpointEvent castedEvent = (WatchpointEvent)event;
179                                         Value evValue = castedEvent.valueCurrent();
180                                         Field evField = castedEvent.field();
181 
182                                         if (event instanceof AccessWatchpointEvent) {
183                                             awpEventsCount++;
184                                             log.display("AccessWatchpointEvent received for " + evField.name());
185                                         } else if (event instanceof ModificationWatchpointEvent) {
186                                             mwpEventsCount++;
187                                             log.display("ModificationWatchpointEvent received for " + evField.name());
188                                         }
189 
190                                         if (evValue == null) {
191                                              log.complain("FAILURE 1: WatchpointEvent.valueCurrent() returns null for " + evField.name());
192                                              testFailed = true;
193                                         } else {
194                                              int ind = fieldsList.indexOf(evField);
195                                              if (ind == -1) {
196                                                  log.complain("FAILURE 2: Watchpoint.field() returns unknown field");
197                                                  testFailed = true;
198                                              } else {
199                                                  Value valueCur = castedEvent.valueCurrent();
200                                                  Value valueFld;
201                                                  try {
202                                                      valueFld = castedEvent.object().getValue(evField);
203                                                  } catch (NullPointerException e) {
204                                                      // field is static
205                                                      valueFld = rType.getValue(evField);
206                                                  }
207                                                  if (!valueFld.equals(valueCur)) {
208                                                      log.complain("FAILURE 3: Watchpoint.valueCurrent() returns incorrect value for " +
209                                                        evField.name() + "\nvalueCurrent(): " + valueCur + " ; getValue(): " + valueFld);
210                                                      testFailed = true;
211                                                  } else {
212                                                      valuecur001.log.display(evField.name() + " equals to " + castedEvent.valueCurrent().toString());
213                                                  }
214                                              }
215                                          }
216                                      }
217                                 }
218                                 eventSet.resume();
219                             }
220                        } catch (InterruptedException e) {
221                              log.complain("TEST INCOMPLETE: caught InterruptedException while waiting for event");
222                              testFailed = true;
223                        } catch (VMDisconnectedException e) {
224                              log.complain("TEST INCOMPLETE: caught VMDisconnectedException while waiting for event");
225                              testFailed = true;
226                        }
227                        log.display("eventHandler completed");
228                   }
229             }
230 
231             // start event handling thread
232             EventHandler eventHandler = new EventHandler();
233             log.display("Starting eventHandler");
234             eventHandler.start();
235 
236             // force debuggee to generate events
237             log.display("Sending command: " + COMMAND_GO);
238             pipe.println(COMMAND_GO);
239 
240             // wait for confirmation from debugee
241             log.display("Waiting for command: " + COMMAND_DONE);
242             command = pipe.readln();
243             if (command == null || !command.equals(COMMAND_DONE)) {
244                 throw new Failure("TEST BUG: unexpected debuggee's command: " + command);
245             }
246 
247             // notify EventHandler that all events generated
248             done = true;
249 
250             // wait for all expected events received
251             log.display("Waiting for all expected events received");
252             try {
253                 eventHandler.join(argHandler.getWaitTime()*60000);
254                 if (eventHandler.isAlive()) {
255                     log.complain("FAILURE 20: Timeout for waiting of event was exceeded");
256                     eventHandler.interrupt();
257                     testFailed = true;
258                 }
259             } catch (InterruptedException e) {
260                 log.complain("TEST INCOMPLETE: InterruptedException caught while waiting for eventHandler's death");
261                 testFailed = true;
262             }
263         } catch (Failure e) {
264             log.complain("TEST FAILURE: " + e.getMessage());
265             testFailed = true;
266         } catch (Exception e) {
267             log.complain("Unexpected exception: " + e);
268             e.printStackTrace(out);
269             testFailed = true;
270         } finally {
271 
272             log.display("");
273 
274             // force debugee to exit
275             log.display("Sending command: " + COMMAND_QUIT);
276             pipe.println(COMMAND_QUIT);
277 
278             // wait for debuggee exits and analize its exit code
279             log.display("Waiting for debuggee terminating");
280             int debuggeeStatus = debuggee.endDebugee();
281             if (debuggeeStatus == PASSED + JCK_STATUS_BASE) {
282                 log.display("Debuggee PASSED with exit code: " + debuggeeStatus);
283             } else {
284                 log.complain("Debuggee FAILED with exit code: " + debuggeeStatus);
285                 testFailed = true;
286             }
287         }
288 
289         // check test results
290         if (testFailed) {
291             log.complain("TEST FAILED");
292             return FAILED;
293         }
294 
295         log.display("TEST PASSED");
296         return PASSED;
297     }
298 }
299