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.jdwp.ThreadReference.SuspendCount; 25 26 import java.io.*; 27 28 import nsk.share.*; 29 import nsk.share.jpda.*; 30 import nsk.share.jdwp.*; 31 32 /** 33 * Test for JDWP command: ThreadReference.SuspendCount. 34 * 35 * See suspendcnt001.README for description of test execution. 36 * 37 * This class represents debugger part of the test. 38 * Test is executed by invoking method runIt(). 39 * JDWP command is tested in the method testCommand(). 40 * 41 * @see #runIt() 42 * @see #testCommand() 43 */ 44 public class suspendcnt001 { 45 46 // exit status constants 47 static final int JCK_STATUS_BASE = 95; 48 static final int PASSED = 0; 49 static final int FAILED = 2; 50 51 // communication signals constants 52 static final String READY = "ready"; 53 static final String ERROR = "error"; 54 static final String QUIT = "quit"; 55 56 // package and classes names constants 57 static final String PACKAGE_NAME = "nsk.jdwp.ThreadReference.SuspendCount"; 58 static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "suspendcnt001"; 59 static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a"; 60 61 // tested JDWP command constants 62 static final String JDWP_COMMAND_NAME = "ThreadReference.SuspendCount"; 63 static final int JDWP_COMMAND_ID = JDWP.Command.ThreadReference.SuspendCount; 64 65 // tested class name and signature constants 66 static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedClass"; 67 static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";"; 68 69 // name of the tested thread and statioc field with thread value 70 static final String TESTED_CLASS_FIELD_NAME = suspendcnt001a.FIELD_NAME; 71 static final String TESTED_THREAD_NAME = suspendcnt001a.THREAD_NAME; 72 73 // expected number od suspend count 74 static final int SUSPEND_COUNT = 5; 75 76 // usual scaffold objects 77 ArgumentHandler argumentHandler = null; 78 Log log = null; 79 Binder binder = null; 80 Debugee debugee = null; 81 Transport transport = null; 82 IOPipe pipe = null; 83 84 // test passed or not 85 boolean success = true; 86 87 // ------------------------------------------------------------------- 88 89 /** 90 * Start test from command line. 91 */ main(String argv[])92 public static void main (String argv[]) { 93 System.exit(run(argv,System.out) + JCK_STATUS_BASE); 94 } 95 96 /** 97 * Start JCK-compilant test. 98 */ run(String argv[], PrintStream out)99 public static int run(String argv[], PrintStream out) { 100 return new suspendcnt001().runIt(argv, out); 101 } 102 103 // ------------------------------------------------------------------- 104 105 /** 106 * Perform test execution. 107 */ runIt(String argv[], PrintStream out)108 public int runIt(String argv[], PrintStream out) { 109 110 // make log for debugger messages 111 argumentHandler = new ArgumentHandler(argv); 112 log = new Log(out, argumentHandler); 113 114 // execute test and display results 115 try { 116 log.display("\n>>> Preparing debugee for testing \n"); 117 118 // launch debuggee 119 binder = new Binder(argumentHandler, log); 120 log.display("Launching debugee"); 121 debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME); 122 transport = debugee.getTransport(); 123 pipe = debugee.createIOPipe(); 124 125 // make debuggee ready for testing 126 prepareDebugee(); 127 128 long threadID = 0; 129 130 // work with prepared debuggee 131 try { 132 log.display("\n>>> Obtaining requred data from debugee \n"); 133 134 // query debuggee for classID of tested class 135 log.display("Getting classID by signature:\n" 136 + " " + TESTED_CLASS_SIGNATURE); 137 long classID = debugee.getReferenceTypeID(TESTED_CLASS_SIGNATURE); 138 log.display(" got classID: " + classID); 139 140 // query debuggee for threadID value from a static field 141 log.display("Getting threadID value from static field: " 142 + TESTED_CLASS_FIELD_NAME); 143 threadID = queryThreadID(classID, TESTED_CLASS_FIELD_NAME); 144 log.display(" got threadID: " + threadID); 145 146 // request debuggee to suspend tested thread 147 log.display("Suspendig thread " + SUSPEND_COUNT + " times for threadID: " + threadID); 148 for (int i = 0; i < SUSPEND_COUNT; i++) { 149 debugee.suspendThread(threadID); 150 } 151 152 // perform testing JDWP command 153 log.display("\n>>> Testing JDWP command \n"); 154 testCommand(threadID); 155 156 } finally { 157 158 log.display("\n>>> Finishing test \n"); 159 160 // resumme suspended thread 161 if (threadID != 0) { 162 log.display("Resuming " + SUSPEND_COUNT + " times suspended thread: " + threadID); 163 for (int i = 0; i < SUSPEND_COUNT; i++) { 164 debugee.resumeThread(threadID); 165 } 166 } 167 168 // quit debugee 169 quitDebugee(); 170 } 171 172 } catch (Failure e) { 173 log.complain("TEST FAILED: " + e.getMessage()); 174 success = false; 175 } catch (Exception e) { 176 e.printStackTrace(out); 177 log.complain("Caught unexpected exception while running the test:\n\t" + e); 178 success = false; 179 } 180 181 if (!success) { 182 log.complain("TEST FAILED"); 183 return FAILED; 184 } 185 186 out.println("TEST PASSED"); 187 return PASSED; 188 189 } 190 191 /** 192 * Prepare debugee for testing and waiting for ready signal. 193 */ prepareDebugee()194 void prepareDebugee() { 195 // wait for VM_INIT event from debugee 196 log.display("Waiting for VM_INIT event"); 197 debugee.waitForVMInit(); 198 199 // query debugee for VM-dependent ID sizes 200 log.display("Querying for IDSizes"); 201 debugee.queryForIDSizes(); 202 203 // resume initially suspended debugee 204 log.display("Resuming debugee VM"); 205 debugee.resume(); 206 207 // wait for READY signal from debugee 208 log.display("Waiting for signal from debugee: " + READY); 209 String signal = pipe.readln(); 210 log.display("Received signal from debugee: " + signal); 211 if (signal == null) { 212 throw new TestBug("Null signal received from debugee: " + signal 213 + " (expected: " + READY + ")"); 214 } else if (signal.equals(ERROR)) { 215 throw new TestBug("Debugee was not able to start tested thread" 216 + " (received signal: " + signal + ")"); 217 } else if (!signal.equals(READY)) { 218 throw new TestBug("Unexpected signal received from debugee: " + signal 219 + " (expected: " + READY + ")"); 220 } 221 } 222 223 /** 224 * Sending debugee signal to quit and waiting for it exits. 225 */ quitDebugee()226 void quitDebugee() { 227 // send debugee signal to quit 228 log.display("Sending signal to debugee: " + QUIT); 229 pipe.println(QUIT); 230 231 // wait for debugee exits 232 log.display("Waiting for debugee exits"); 233 int code = debugee.waitFor(); 234 235 // analize debugee exit status code 236 if (code == JCK_STATUS_BASE + PASSED) { 237 log.display("Debugee PASSED with exit code: " + code); 238 } else { 239 log.complain("Debugee FAILED with exit code: " + code); 240 success = false; 241 } 242 } 243 244 /** 245 * Query debuggee for threadID value of statuic field of the class. 246 */ queryThreadID(long classID, String fieldName)247 long queryThreadID(long classID, String fieldName) { 248 // get fieledID for static field (declared in the class) 249 long fieldID = debugee.getClassFieldID(classID, fieldName, true); 250 // get value of the field 251 JDWP.Value value = debugee.getStaticFieldValue(classID, fieldID); 252 253 // check that value has THREAD tag 254 if (value.getTag() != JDWP.Tag.THREAD) { 255 throw new Failure("Not threadID value returned from debuggee: " + value); 256 } 257 258 // extract threadID from the value 259 long threadID = ((Long)value.getValue()).longValue(); 260 return threadID; 261 } 262 263 /** 264 * Query debuggee for suspend status of the thread. 265 */ querySuspendStatus(long threadID)266 int querySuspendStatus(long threadID) { 267 log.display("Getting suspend status for threadID: " + threadID); 268 CommandPacket command = new CommandPacket(JDWP.Command.ThreadReference.Status); 269 command.addObjectID(threadID); 270 ReplyPacket reply = debugee.receiveReplyFor(command); 271 272 try { 273 reply.resetPosition(); 274 275 int threadStatus = reply.getInt(); 276 int suspendStatus = reply.getInt(); 277 log.display(" got suspendStatus: " + suspendStatusString(suspendStatus)); 278 return suspendStatus; 279 } catch (BoundException e) { 280 throw new Failure("Caught BoundException while parsing reply for ThreadReference.Status:\n\t" 281 + e); 282 } 283 } 284 285 /** 286 * Perform testing JDWP command for specified threadID. 287 */ testCommand(long threadID)288 void testCommand(long threadID) { 289 // create command packet and fill requred out data 290 log.display("Create command packet:"); 291 log.display("Command: " + JDWP_COMMAND_NAME); 292 CommandPacket command = new CommandPacket(JDWP_COMMAND_ID); 293 log.display(" threadID: " + threadID); 294 command.addObjectID(threadID); 295 command.setLength(); 296 297 // send command packet to debugee 298 try { 299 log.display("Sending command packet:\n" + command); 300 transport.write(command); 301 } catch (IOException e) { 302 log.complain("Unable to send command packet:\n\t" + e); 303 success = false; 304 return; 305 } 306 307 ReplyPacket reply = new ReplyPacket(); 308 309 // receive reply packet from debugee 310 try { 311 log.display("Waiting for reply packet"); 312 transport.read(reply); 313 log.display("Reply packet received:\n" + reply); 314 } catch (IOException e) { 315 log.complain("Unable to read reply packet:\n\t" + e); 316 success = false; 317 return; 318 } 319 320 // check reply packet header 321 try{ 322 log.display("Checking reply packet header"); 323 reply.checkHeader(command.getPacketID()); 324 } catch (BoundException e) { 325 log.complain("Bad header of reply packet:\n\t" + e.getMessage()); 326 success = false; 327 return; 328 } 329 330 // start parsing reply packet data 331 log.display("Parsing reply packet:"); 332 reply.resetPosition(); 333 334 int suspendCount = 0; 335 try { 336 suspendCount = reply.getInt(); 337 log.display(" suspendCount: " + suspendCount); 338 } catch (BoundException e) { 339 log.complain("Unable to extract suspend count number form the reply packet:\n\t" 340 + e.getMessage()); 341 success = false; 342 return; 343 } 344 345 // check for extra data in reply packet 346 if (!reply.isParsed()) { 347 log.complain("Extra trailing bytes found in reply packet at: " 348 + reply.offsetString()); 349 success = false; 350 } 351 352 if (suspendCount < 0) { 353 log.complain("Negative number of suspend count returned: " + suspendCount 354 + "(expected: " + SUSPEND_COUNT + ")"); 355 success = false; 356 } 357 358 if (suspendCount != SUSPEND_COUNT) { 359 log.complain("Unexpected number of suspend count returned: " + suspendCount 360 + "(expected: " + SUSPEND_COUNT + ")"); 361 success = false; 362 } 363 364 } 365 366 /** 367 * Return string representation of thread suspend status. 368 */ suspendStatusString(int status)369 private static String suspendStatusString(int status) { 370 String s = null; 371 if ((status & JDWP.SuspendStatus.SUSPEND_STATUS_SUSPENDED) != 0) { 372 s = "SUSPEND_STATUS_SUSPENDED"; 373 } else if (status == 0) { 374 s = "NONE"; 375 } else { 376 s = "unknown"; 377 } 378 return status + "=" + s; 379 } 380 } 381