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.Status; 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.Status. 34 * 35 * See status001.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 status001 { 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.Status"; 58 static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "status001"; 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.Status"; 63 static final int JDWP_COMMAND_ID = JDWP.Command.ThreadReference.Status; 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 = status001a.FIELD_NAME; 71 static final String TESTED_THREAD_NAME = status001a.THREAD_NAME; 72 73 // usual scaffold objects 74 ArgumentHandler argumentHandler = null; 75 Log log = null; 76 Binder binder = null; 77 Debugee debugee = null; 78 Transport transport = null; 79 IOPipe pipe = null; 80 81 // test passed or not 82 boolean success = true; 83 84 // ------------------------------------------------------------------- 85 86 /** 87 * Start test from command line. 88 */ main(String argv[])89 public static void main (String argv[]) { 90 System.exit(run(argv,System.out) + JCK_STATUS_BASE); 91 } 92 93 /** 94 * Start JCK-compilant test. 95 */ run(String argv[], PrintStream out)96 public static int run(String argv[], PrintStream out) { 97 return new status001().runIt(argv, out); 98 } 99 100 // ------------------------------------------------------------------- 101 102 /** 103 * Perform test execution. 104 */ runIt(String argv[], PrintStream out)105 public int runIt(String argv[], PrintStream out) { 106 107 // make log for debugger messages 108 argumentHandler = new ArgumentHandler(argv); 109 log = new Log(out, argumentHandler); 110 111 // execute test and display results 112 try { 113 log.display("\n>>> Preparing debugee for testing \n"); 114 115 // launch debuggee 116 binder = new Binder(argumentHandler, log); 117 log.display("Launching debugee"); 118 debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME); 119 transport = debugee.getTransport(); 120 pipe = debugee.createIOPipe(); 121 122 // make debuggee ready for testing 123 prepareDebugee(); 124 125 // work with prepared debuggee 126 try { 127 log.display("\n>>> Obtaining requred data from debugee \n"); 128 129 // query debuggee for classID of tested class 130 log.display("Getting classID by signature:\n" 131 + " " + TESTED_CLASS_SIGNATURE); 132 long classID = debugee.getReferenceTypeID(TESTED_CLASS_SIGNATURE); 133 log.display(" got classID: " + classID); 134 135 // query debuggee for threadID value from a static field 136 log.display("Getting threadID value from static field: " 137 + TESTED_CLASS_FIELD_NAME); 138 long threadID = queryThreadID(classID, TESTED_CLASS_FIELD_NAME); 139 log.display(" got threadID: " + threadID); 140 141 // perform testing JDWP command 142 log.display("\n>>> Testing JDWP command \n"); 143 testCommand(threadID); 144 145 } finally { 146 // quit debugee 147 log.display("\n>>> Finishing test \n"); 148 quitDebugee(); 149 } 150 151 } catch (Failure e) { 152 log.complain("TEST FAILED: " + e.getMessage()); 153 success = false; 154 } catch (Exception e) { 155 e.printStackTrace(out); 156 log.complain("Caught unexpected exception while running the test:\n\t" + e); 157 success = false; 158 } 159 160 if (!success) { 161 log.complain("TEST FAILED"); 162 return FAILED; 163 } 164 165 out.println("TEST PASSED"); 166 return PASSED; 167 168 } 169 170 /** 171 * Prepare debugee for testing and waiting for ready signal. 172 */ prepareDebugee()173 void prepareDebugee() { 174 // wait for VM_INIT event from debugee 175 log.display("Waiting for VM_INIT event"); 176 debugee.waitForVMInit(); 177 178 // query debugee for VM-dependent ID sizes 179 log.display("Querying for IDSizes"); 180 debugee.queryForIDSizes(); 181 182 // resume initially suspended debugee 183 log.display("Resuming debugee VM"); 184 debugee.resume(); 185 186 // wait for READY signal from debugee 187 log.display("Waiting for signal from debugee: " + READY); 188 String signal = pipe.readln(); 189 log.display("Received signal from debugee: " + signal); 190 if (signal == null) { 191 throw new TestBug("Null signal received from debugee: " + signal 192 + " (expected: " + READY + ")"); 193 } else if (signal.equals(ERROR)) { 194 throw new TestBug("Debugee was not able to start tested thread" 195 + " (received signal: " + signal + ")"); 196 } else if (!signal.equals(READY)) { 197 throw new TestBug("Unexpected signal received from debugee: " + signal 198 + " (expected: " + READY + ")"); 199 } 200 } 201 202 /** 203 * Sending debugee signal to quit and waiting for it exits. 204 */ quitDebugee()205 void quitDebugee() { 206 // send debugee signal to quit 207 log.display("Sending signal to debugee: " + QUIT); 208 pipe.println(QUIT); 209 210 // wait for debugee exits 211 log.display("Waiting for debugee exits"); 212 int code = debugee.waitFor(); 213 214 // analize debugee exit status code 215 if (code == JCK_STATUS_BASE + PASSED) { 216 log.display("Debugee PASSED with exit code: " + code); 217 } else { 218 log.complain("Debugee FAILED with exit code: " + code); 219 success = false; 220 } 221 } 222 223 /** 224 * Query debuggee for threadID value of statuic field of the class. 225 */ queryThreadID(long classID, String fieldName)226 long queryThreadID(long classID, String fieldName) { 227 // get fieledID for static field (declared in the class) 228 long fieldID = debugee.getClassFieldID(classID, fieldName, true); 229 // get value of the field 230 JDWP.Value value = debugee.getStaticFieldValue(classID, fieldID); 231 232 // check that value has THREAD tag 233 if (value.getTag() != JDWP.Tag.THREAD) { 234 throw new Failure("Not threadID value returned from debuggee: " + value); 235 } 236 237 // extract threadID from the value 238 long threadID = ((Long)value.getValue()).longValue(); 239 return threadID; 240 } 241 242 /** 243 * Perform testing JDWP command for specified threadID. 244 */ testCommand(long threadID)245 void testCommand(long threadID) { 246 // create command packet and fill requred out data 247 log.display("Create command packet:"); 248 log.display("Command: " + JDWP_COMMAND_NAME); 249 CommandPacket command = new CommandPacket(JDWP_COMMAND_ID); 250 log.display(" threadID: " + threadID); 251 command.addObjectID(threadID); 252 command.setLength(); 253 254 // send command packet to debugee 255 try { 256 log.display("Sending command packet:\n" + command); 257 transport.write(command); 258 } catch (IOException e) { 259 log.complain("Unable to send command packet:\n\t" + e); 260 success = false; 261 return; 262 } 263 264 ReplyPacket reply = new ReplyPacket(); 265 266 // receive reply packet from debugee 267 try { 268 log.display("Waiting for reply packet"); 269 transport.read(reply); 270 log.display("Reply packet received:\n" + reply); 271 } catch (IOException e) { 272 log.complain("Unable to read reply packet:\n\t" + e); 273 success = false; 274 return; 275 } 276 277 // check reply packet header 278 try{ 279 log.display("Checking reply packet header"); 280 reply.checkHeader(command.getPacketID()); 281 } catch (BoundException e) { 282 log.complain("Bad header of reply packet:\n\t" + e.getMessage()); 283 success = false; 284 return; 285 } 286 287 // start parsing reply packet data 288 log.display("Parsing reply packet:"); 289 reply.resetPosition(); 290 291 // extract thread status 292 int threadStatus = 0; 293 try { 294 threadStatus = reply.getInt(); 295 log.display(" threadStatus: " + threadStatusString(threadStatus)); 296 } catch (BoundException e) { 297 log.complain("Unable to extract thread status from reply packet:\n\t" 298 + e.getMessage()); 299 success = false; 300 return; 301 } 302 303 // extract suspend status 304 int suspendStatus = 0; 305 try { 306 suspendStatus = reply.getInt(); 307 log.display(" suspendStatus: " + suspendStatusString(suspendStatus)); 308 } catch (BoundException e) { 309 log.complain("Unable to extract thread status from reply packet:\n\t" 310 + e.getMessage()); 311 success = false; 312 return; 313 } 314 315 // check that both status code are not negative values 316 if (threadStatus < 0) { 317 log.complain("Negative value of thread status in reply packet: " 318 + threadStatusString(threadStatus)); 319 success = false; 320 } 321 if (suspendStatus < 0) { 322 log.complain("Negative value of suspend status in reply packet: " 323 + suspendStatusString(suspendStatus)); 324 success = false; 325 } 326 327 // check that thread has an expected state 328 if (!(threadStatus == JDWP.ThreadStatus.RUNNING 329 || threadStatus == JDWP.ThreadStatus.MONITOR)) { 330 log.complain("Unexpected thread status returned in the reply packet: " 331 + threadStatusString(threadStatus) 332 + " (expected: " + threadStatusString(JDWP.ThreadStatus.RUNNING) 333 + " or " + threadStatusString(JDWP.ThreadStatus.MONITOR) + ")"); 334 success = false; 335 } 336 337 // check that thread was not suspended 338 if ((suspendStatus & JDWP.SuspendStatus.SUSPEND_STATUS_SUSPENDED) != 0) { 339 log.complain("Unexpected suspend status returned in the reply packet: " 340 + threadStatusString(threadStatus) 341 + " (expected: " + "not suspended" + ")"); 342 success = false; 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 353 /** 354 * Return string representation of thread status code. 355 */ threadStatusString(int status)356 private static String threadStatusString(int status) { 357 String s = null; 358 switch (status) { 359 case JDWP.ThreadStatus.MONITOR: 360 s = "MONITOR"; 361 break; 362 case JDWP.ThreadStatus.RUNNING: 363 s = "RUNNING"; 364 break; 365 case JDWP.ThreadStatus.SLEEPING: 366 s = "SLEEPING"; 367 break; 368 case JDWP.ThreadStatus.WAIT: 369 s = "WAIT"; 370 break; 371 case JDWP.ThreadStatus.ZOMBIE: 372 s = "ZOMBIE"; 373 break; 374 default: 375 s = "unknown"; 376 break; 377 } 378 return status + "=" + s; 379 } 380 381 /** 382 * Return string representation of thread suspend status. 383 */ suspendStatusString(int status)384 private static String suspendStatusString(int status) { 385 String s = null; 386 if ((status & JDWP.SuspendStatus.SUSPEND_STATUS_SUSPENDED) != 0) { 387 s = "SUSPEND_STATUS_SUSPENDED"; 388 } else if (status == 0) { 389 s = "NONE"; 390 } else { 391 s = "unknown"; 392 } 393 return status + "=" + s; 394 } 395 } 396