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.StackFrame.GetValues; 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: StackFrame.GetValues. 34 * 35 * See getvalues001.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 getvalues001 { 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.StackFrame.GetValues"; 58 static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "getvalues001"; 59 static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a"; 60 61 // tested JDWP command constants 62 static final String JDWP_COMMAND_NAME = "StackFrame.GetValues"; 63 static final int JDWP_COMMAND_ID = JDWP.Command.StackFrame.GetValues; 64 65 // tested class name and signature constants 66 static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + getvalues001a.OBJECT_CLASS_NAME; 67 static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";"; 68 69 // names of the static fields with the tested thread and object values 70 static final String TESTED_THREAD_FIELD_NAME = getvalues001a.THREAD_FIELD_NAME; 71 static final String TESTED_OBJECT_FIELD_NAME = getvalues001a.OBJECT_FIELD_NAME; 72 static final String TESTED_OBJECT_METHOD_NAME = getvalues001a.OBJECT_METHOD_NAME; 73 74 // list of tested variables names and values 75 static final Object variables[][] = { 76 { "booleanValue", "boolean", new Boolean(true), new Byte(JDWP.Tag.BOOLEAN)}, 77 { "byteValue", "byte", new Byte((byte)0x0F), new Byte(JDWP.Tag.BYTE) }, 78 { "charValue", "char", new Character('Z'), new Byte(JDWP.Tag.CHAR) }, 79 { "intValue", "int", new Integer(100), new Byte(JDWP.Tag.INT) }, 80 { "shortValue", "short", new Short((short)10), new Byte(JDWP.Tag.SHORT) }, 81 { "longValue", "long", new Long((long)1000000), new Byte(JDWP.Tag.LONG) }, 82 { "floatValue", "float", new Float((float)3.14), new Byte(JDWP.Tag.FLOAT) }, 83 { "doubleValue", "double", new Double((double)2.8e-12), new Byte(JDWP.Tag.DOUBLE) }, 84 { "objectValue", "objectID", new Long((long)0), new Byte(JDWP.Tag.OBJECT) } 85 }; 86 static final int VARIABLES_COUNT = variables.length; 87 88 // usual scaffold objects 89 ArgumentHandler argumentHandler = null; 90 Log log = null; 91 Binder binder = null; 92 Debugee debugee = null; 93 Transport transport = null; 94 IOPipe pipe = null; 95 96 // test passed or not 97 boolean success = true; 98 99 // ------------------------------------------------------------------- 100 101 /** 102 * Start test from command line. 103 */ main(String argv[])104 public static void main (String argv[]) { 105 System.exit(run(argv,System.out) + JCK_STATUS_BASE); 106 } 107 108 /** 109 * Start JCK-compilant test. 110 */ run(String argv[], PrintStream out)111 public static int run(String argv[], PrintStream out) { 112 return new getvalues001().runIt(argv, out); 113 } 114 115 // ------------------------------------------------------------------- 116 117 /** 118 * Perform test execution. 119 */ runIt(String argv[], PrintStream out)120 public int runIt(String argv[], PrintStream out) { 121 122 // make log for debugger messages 123 argumentHandler = new ArgumentHandler(argv); 124 log = new Log(out, argumentHandler); 125 126 // execute test and display results 127 try { 128 log.display("\n>>> Preparing debugee for testing \n"); 129 130 // launch debuggee 131 binder = new Binder(argumentHandler, log); 132 log.display("Launching debugee"); 133 debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME); 134 transport = debugee.getTransport(); 135 pipe = debugee.createIOPipe(); 136 137 // make debuggee ready for testing 138 prepareDebugee(); 139 140 // work with prepared debuggee 141 long threadID = 0; 142 try { 143 log.display("\n>>> Obtaining requred data from debugee \n"); 144 145 // query debuggee for classID of tested class 146 log.display("Getting tested classID by signature:\n" 147 + " " + TESTED_CLASS_SIGNATURE); 148 long classID = debugee.getReferenceTypeID(TESTED_CLASS_SIGNATURE); 149 log.display(" got classID: " + classID); 150 151 // query debuggee for tested methodID 152 log.display("Getting tested methodID by name: " + TESTED_OBJECT_METHOD_NAME); 153 long methodID = debugee.getMethodID(classID, TESTED_OBJECT_METHOD_NAME, true); 154 log.display(" got methodID: " + methodID); 155 156 // query debugee for indexes of the method local variables 157 log.display("Getting indexes of the tested local variables for methodID: " + methodID); 158 int indexes[] = queryVariableIndexes(classID, methodID); 159 log.display(" got indexes: " + indexes.length); 160 161 // query debuggee for tested objectID value from static field 162 log.display("Getting tested objectID value from static field: " 163 + TESTED_OBJECT_FIELD_NAME); 164 long objectID = queryObjectID(classID, TESTED_OBJECT_FIELD_NAME, JDWP.Tag.OBJECT); 165 log.display(" got objectID: " + objectID); 166 167 // query debuggee for tested threadID value from static field 168 log.display("Getting tested threadID value from static field: " 169 + TESTED_THREAD_FIELD_NAME); 170 threadID = queryObjectID(classID, TESTED_THREAD_FIELD_NAME, JDWP.Tag.THREAD); 171 log.display(" got threadID: " + threadID); 172 173 // suspend tested thread into debuggee 174 log.display("Suspending thread into debuggee for threadID: " + threadID); 175 debugee.suspendThread(threadID); 176 log.display(" thread suspended"); 177 178 // query debuggee for current frameID of the tested thread 179 log.display("Getting current frameID for the threadID: " 180 + threadID); 181 long frameID = debugee.getCurrentFrameID(threadID); 182 log.display(" got frameID: " + frameID); 183 184 // perform testing JDWP command 185 log.display("\n>>> Testing JDWP command \n"); 186 testCommand(frameID, threadID, indexes); 187 188 } finally { 189 log.display("\n>>> Finishing test \n"); 190 191 // resume suspended thread 192 if (threadID != 0) { 193 log.display("Resuming suspended thread"); 194 debugee.resumeThread(threadID); 195 } 196 197 // quit debugee 198 quitDebugee(); 199 } 200 201 } catch (Failure e) { 202 log.complain("TEST FAILED: " + e.getMessage()); 203 success = false; 204 } catch (Exception e) { 205 e.printStackTrace(out); 206 log.complain("Caught unexpected exception while running the test:\n\t" + e); 207 success = false; 208 } 209 210 if (!success) { 211 log.complain("TEST FAILED"); 212 return FAILED; 213 } 214 215 out.println("TEST PASSED"); 216 return PASSED; 217 218 } 219 220 /** 221 * Prepare debugee for testing and waiting for ready signal. 222 */ prepareDebugee()223 void prepareDebugee() { 224 // wait for VM_INIT event from debugee 225 log.display("Waiting for VM_INIT event"); 226 debugee.waitForVMInit(); 227 228 // query debugee for VM-dependent ID sizes 229 log.display("Querying for IDSizes"); 230 debugee.queryForIDSizes(); 231 232 // resume initially suspended debugee 233 log.display("Resuming debugee VM"); 234 debugee.resume(); 235 236 // wait for READY signal from debugee 237 log.display("Waiting for signal from debugee: " + READY); 238 String signal = pipe.readln(); 239 log.display("Received signal from debugee: " + signal); 240 if (signal == null) { 241 throw new TestBug("Null signal received from debugee: " + signal 242 + " (expected: " + READY + ")"); 243 } else if (signal.equals(ERROR)) { 244 throw new TestBug("Debugee was not able to start tested thread" 245 + " (received signal: " + signal + ")"); 246 } else if (!signal.equals(READY)) { 247 throw new TestBug("Unexpected signal received from debugee: " + signal 248 + " (expected: " + READY + ")"); 249 } 250 } 251 252 /** 253 * Sending debugee signal to quit and waiting for it exits. 254 */ quitDebugee()255 void quitDebugee() { 256 // send debugee signal to quit 257 log.display("Sending signal to debugee: " + QUIT); 258 pipe.println(QUIT); 259 260 // wait for debugee exits 261 log.display("Waiting for debugee exits"); 262 int code = debugee.waitFor(); 263 264 // analize debugee exit status code 265 if (code == JCK_STATUS_BASE + PASSED) { 266 log.display("Debugee PASSED with exit code: " + code); 267 } else { 268 log.complain("Debugee FAILED with exit code: " + code); 269 success = false; 270 } 271 } 272 273 /** 274 * Query debuggee for objectID value of static field of the class. 275 */ queryObjectID(long classID, String fieldName, byte tag)276 long queryObjectID(long classID, String fieldName, byte tag) { 277 // get fieledID for static field (declared in the class) 278 long fieldID = debugee.getClassFieldID(classID, fieldName, true); 279 // get value of the field 280 JDWP.Value value = debugee.getStaticFieldValue(classID, fieldID); 281 282 // check that value has expected tag 283 if (value.getTag() != tag) { 284 throw new Failure("Unexpected tag for object value returned: " 285 + value.getTag() + " (expected: " + tag + ")"); 286 } 287 288 // extract objectID from the value 289 long objectID = ((Long)value.getValue()).longValue(); 290 return objectID; 291 } 292 293 /** 294 * Query debugee for indexes of the local method variables. 295 */ queryVariableIndexes(long classID, long methodID)296 int[] queryVariableIndexes(long classID, long methodID) { 297 // create array for expected indexes 298 int indexes[] = new int[VARIABLES_COUNT]; 299 for (int i = 0; i < VARIABLES_COUNT; i++) { 300 indexes[i] = 0; 301 } 302 303 // obtain variable indexes from debuggee 304 int count = 0; 305 try { 306 CommandPacket command = new CommandPacket(JDWP.Command.Method.VariableTable); 307 command.addReferenceTypeID(classID); 308 command.addMethodID(methodID); 309 command.setLength(); 310 311 ReplyPacket reply = debugee.receiveReplyFor(command); 312 reply.resetPosition(); 313 314 int argCount = reply.getInt(); 315 long slots = reply.getInt(); 316 if (slots < VARIABLES_COUNT) { 317 throw new Failure("Too few method local variables returned: " + slots 318 + " (expected: at least " + VARIABLES_COUNT + ")"); 319 } 320 321 for (int i = 0; i < slots; i++ ) { 322 long codeindex = reply.getLong(); 323 String name = reply.getString(); 324 String signature = reply.getString(); 325 int length = reply.getInt(); 326 int slot = reply.getInt(); 327 328 for (int j = 0; j < VARIABLES_COUNT; j++) { 329 if (variables[j][0].equals(name)) { 330 indexes[j] = slot; 331 break; 332 } 333 } 334 } 335 336 } catch (BoundException e) { 337 log.complain("Unable to extract local variable indexes from the reply packet:\n\t" 338 + e.getMessage()); 339 throw new Failure("Error occured while getting local variable indexes for methodID:" 340 + methodID); 341 } 342 343 return indexes; 344 } 345 346 /** 347 * Check i-th value from the reply packet. 348 */ checkValue(int i, JDWP.Value value)349 void checkValue(int i, JDWP.Value value) { 350 if (!variables[i][2].equals(value.getValue())) { 351 log.complain("Unexpected value for " + i + " variable (" 352 + variables[i][0] + ") received: " + value 353 + " (expected: " + variables[i][2] + ")"); 354 success = false; 355 } 356 } 357 358 /** 359 * Perform testing JDWP command for specified frameID. 360 */ testCommand(long frameID, long threadID, int indexes[])361 void testCommand(long frameID, long threadID, int indexes[]) { 362 int slots = indexes.length; 363 364 // create command packet and fill requred out data 365 log.display("Create command packet:"); 366 log.display("Command: " + JDWP_COMMAND_NAME); 367 CommandPacket command = new CommandPacket(JDWP_COMMAND_ID); 368 log.display(" threadID: " + threadID); 369 command.addObjectID(threadID); 370 log.display(" frameID: " + frameID); 371 command.addFrameID(frameID); 372 log.display(" slots: " + slots); 373 command.addInt(slots); 374 375 // add code indexes of the requested variables 376 for (int i = 0; i < slots; i++) { 377 log.display(" slot #" + i + ":"); 378 log.display(" slot: " + indexes[i]); 379 command.addInt(indexes[i]); 380 byte tag = ((Byte)variables[i][3]).byteValue(); 381 log.display(" sigbyte: " + tag); 382 command.addByte(tag); 383 } 384 command.setLength(); 385 386 // send command packet to debugee 387 try { 388 log.display("Sending command packet:\n" + command); 389 transport.write(command); 390 } catch (IOException e) { 391 log.complain("Unable to send command packet:\n\t" + e); 392 success = false; 393 return; 394 } 395 396 ReplyPacket reply = new ReplyPacket(); 397 398 // receive reply packet from debugee 399 try { 400 log.display("Waiting for reply packet"); 401 transport.read(reply); 402 log.display("Reply packet received:\n" + reply); 403 } catch (IOException e) { 404 log.complain("Unable to read reply packet:\n\t" + e); 405 success = false; 406 return; 407 } 408 409 // check reply packet header 410 try{ 411 log.display("Checking reply packet header"); 412 reply.checkHeader(command.getPacketID()); 413 } catch (BoundException e) { 414 log.complain("Bad header of reply packet:\n\t" + e.getMessage()); 415 success = false; 416 return; 417 } 418 419 // start parsing reply packet data 420 log.display("Parsing reply packet:"); 421 reply.resetPosition(); 422 423 // extract and check number of values 424 int values = 0; 425 try { 426 values = reply.getInt(); 427 log.display(" values: " + values); 428 429 } catch (BoundException e) { 430 log.complain("Unable to extract number of values form reply packet:\n\t" 431 + e.getMessage()); 432 success = false; 433 return; 434 } 435 436 // check if number of values are as expected 437 if (values < 0) { 438 log.complain("Negative number of values received:" + values 439 + " (expected: " + slots + ")"); 440 success = false; 441 } else if (values != slots) { 442 log.complain("Unexpected number of values received:" + values 443 + " (expected: " + slots + ")"); 444 success = false; 445 } 446 447 // extract and check each value 448 for (int i = 0; i < values; i++ ) { 449 log.display(" value #" + i + " (variable: " + variables[i][0] + ")"); 450 451 // extract value 452 JDWP.Value value = null; 453 try { 454 value = reply.getValue(); 455 log.display(" slotValue: " + value); 456 } catch (BoundException e) { 457 log.complain("Unable to extract " + i + " slot value:\n\t" 458 + e.getMessage()); 459 success = false; 460 break; 461 } 462 463 // extract and check value by known type tag 464 checkValue(i, value); 465 } 466 467 // check for extra data in reply packet 468 if (!reply.isParsed()) { 469 log.complain("Extra trailing bytes found in reply packet at: " 470 + reply.offsetString()); 471 success = false; 472 } 473 474 } 475 476 } 477