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.ObjectReference.InvokeMethod; 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: ObjectReference.InvokeMethod. 34 * 35 * See invokemeth001.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 invokemeth001 { 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 // package and classes names 52 static final String PACKAGE_NAME = "nsk.jdwp.ObjectReference.InvokeMethod"; 53 static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "invokemeth001"; 54 static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a"; 55 56 // tested JDWP command 57 static final String JDWP_COMMAND_NAME = "ObjectReference.InvokeMethod"; 58 static final int JDWP_COMMAND_ID = JDWP.Command.ObjectReference.InvokeMethod; 59 60 // tested class name and signature 61 static final String TESTED_CLASS_NAME = DEBUGEE_CLASS_NAME + "$" + "TestedObjectClass"; 62 static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";"; 63 64 // field and method names 65 static final String OBJECT_FIELD_NAME = "object"; 66 static final String RESULT_FIELD_NAME = "result"; 67 static final String TESTED_METHOD_NAME = "testedMethod"; 68 static final String BREAKPOINT_METHOD_NAME = "run"; 69 static final int BREAKPOINT_LINE_NUMBER = invokemeth001a.BREAKPOINT_LINE_NUMBER; 70 71 // data for invoked method 72 static final int ARGUMENTS_COUNT = 1; 73 static final int INITIAL_VALUE = invokemeth001a.INITIAL_VALUE; 74 static final int ARGUMENT_VALUE = invokemeth001a.FINAL_VALUE; 75 static final int RETURN_VALUE = INITIAL_VALUE; 76 static final int INVOKE_OPTIONS = 0; 77 78 // usual scaffold objects 79 ArgumentHandler argumentHandler = null; 80 Log log = null; 81 Binder binder = null; 82 Debugee debugee = null; 83 Transport transport = null; 84 IOPipe pipe = null; 85 boolean dead = false; 86 87 // data obtained from debuggee 88 long classID = 0; 89 long threadID = 0; 90 long methodID = 0; 91 long objectID = 0; 92 93 // test passed or not 94 boolean success = true; 95 96 // ------------------------------------------------------------------- 97 98 /** 99 * Start test from command line. 100 */ main(String argv[])101 public static void main (String argv[]) { 102 System.exit(run(argv,System.out) + JCK_STATUS_BASE); 103 } 104 105 /** 106 * Start JCK-compilant test. 107 */ run(String argv[], PrintStream out)108 public static int run(String argv[], PrintStream out) { 109 return new invokemeth001().runIt(argv, out); 110 } 111 112 // ------------------------------------------------------------------- 113 114 /** 115 * Perform test execution. 116 */ runIt(String argv[], PrintStream out)117 public int runIt(String argv[], PrintStream out) { 118 119 // make log for debugger messages 120 argumentHandler = new ArgumentHandler(argv); 121 log = new Log(out, argumentHandler); 122 123 // execute test and display results 124 try { 125 log.display("\n>>> Starting debugee \n"); 126 127 // launch debuggee 128 binder = new Binder(argumentHandler, log); 129 log.display("Launching debugee VM"); 130 debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME); 131 transport = debugee.getTransport(); 132 log.display(" ... debuggee launched"); 133 134 // set timeout for debuggee responces 135 int waitTime = argumentHandler.getWaitTime(); // minutes 136 long timeout = waitTime * 60 * 1000; // milliseconds 137 log.display("Setting timeout for debuggee responces: " + waitTime + " minute(s)"); 138 transport.setReadTimeout(timeout); 139 log.display(" ... timeout set"); 140 141 // wait for VM_INIT event 142 log.display("Waiting for VM_INIT event"); 143 debugee.waitForVMInit(); 144 log.display(" ... VM_INIT event received"); 145 146 // query debugee for VM-dependent ID sizes 147 log.display("Querying for IDSizes"); 148 debugee.queryForIDSizes(); 149 log.display(" ... size of VM-dependent types adjusted"); 150 151 // run the test 152 runTest(); 153 154 // wait for VM_DEATH event 155 log.display("Waiting for VM_DEATH event"); 156 debugee.waitForVMDeath(); 157 log.display(" ... VM_DEATH event received"); 158 dead = true; 159 160 } catch (Failure e) { 161 log.complain("TEST FAILED: " + e.getMessage()); 162 success = false; 163 } catch (Exception e) { 164 e.printStackTrace(out); 165 log.complain("Caught unexpected exception while running the test:\n\t" + e); 166 success = false; 167 } finally { 168 log.display("\n>>> Finishing test \n"); 169 170 // disconnect debugee and wait for its exit 171 if (debugee != null) { 172 quitDebugee(); 173 } 174 } 175 176 // check result 177 if (!success) { 178 log.complain("TEST FAILED"); 179 return FAILED; 180 } 181 out.println("TEST PASSED"); 182 return PASSED; 183 } 184 185 /** 186 * Obtain required data and test JDWP command. 187 */ runTest()188 void runTest() { 189 log.display("\n>>> Obtaining required data \n"); 190 191 // wait for tested class loaded on debuggee startup and obtain its classID 192 log.display("Waiting for class loaded:\n\t" + TESTED_CLASS_NAME); 193 classID = debugee.waitForClassLoaded(TESTED_CLASS_NAME, JDWP.SuspendPolicy.ALL); 194 log.display(" ... got classID: " + classID); 195 log.display(""); 196 197 // query debuggee for tested methodID 198 log.display("Getting tested methodID by name: " + TESTED_METHOD_NAME); 199 methodID = debugee.getMethodID(classID, TESTED_METHOD_NAME, true); 200 log.display(" ... got methodID: " + methodID); 201 log.display(""); 202 203 // set breakpoint and wait for debugee reached it 204 log.display("Waiting for breakpoint reached at: " 205 + BREAKPOINT_METHOD_NAME + ":" + BREAKPOINT_LINE_NUMBER); 206 threadID = debugee.waitForBreakpointReached(classID, 207 BREAKPOINT_METHOD_NAME, 208 BREAKPOINT_LINE_NUMBER, 209 JDWP.SuspendPolicy.EVENT_THREAD); 210 log.display(" ... breakpoint reached with threadID: " + threadID); 211 log.display(""); 212 213 // get object value from static field 214 log.display("Getting object value from static field: " + OBJECT_FIELD_NAME); 215 objectID = queryObjectID(classID, OBJECT_FIELD_NAME, JDWP.Tag.OBJECT); 216 log.display(" ... got objectID: " + objectID); 217 218 219 // test JDWP command 220 log.display("\n>> Testing JDWP command \n"); 221 testCommand(); 222 223 // check command results 224 if (success) { 225 log.display("\n>>> Checking command results \n"); 226 checkResult(); 227 } 228 229 // resume debuggee after the command 230 log.display("Resuming debuggee"); 231 debugee.resume(); 232 log.display(" ... debuggee resumed"); 233 } 234 235 /** 236 * Perform testing JDWP command. 237 */ testCommand()238 void testCommand() { 239 // create command packet and fill requred out data 240 log.display("Create command packet:"); 241 log.display("Command: " + JDWP_COMMAND_NAME); 242 CommandPacket command = new CommandPacket(JDWP_COMMAND_ID); 243 log.display(" objectID: " + objectID); 244 command.addObjectID(objectID); 245 log.display(" threadID: " + threadID); 246 command.addObjectID(threadID); 247 log.display(" classID: " + classID); 248 command.addReferenceTypeID(classID); 249 log.display(" methodID: " + methodID); 250 command.addMethodID(methodID); 251 log.display(" arguments: " + ARGUMENTS_COUNT); 252 command.addInt(ARGUMENTS_COUNT); 253 for (int i = 0; i < ARGUMENTS_COUNT; i++) { 254 JDWP.Value value = new JDWP.Value(JDWP.Tag.INT, new Integer(ARGUMENT_VALUE)); 255 log.display(" arg: " + value); 256 command.addValue(value); 257 } 258 log.display(" options: " + INVOKE_OPTIONS); 259 command.addInt(INVOKE_OPTIONS); 260 command.setLength(); 261 262 // send command packet to debugee 263 try { 264 log.display("Sending command packet:\n" + command); 265 transport.write(command); 266 } catch (IOException e) { 267 log.complain("Unable to send command packet:\n\t" + e); 268 success = false; 269 return; 270 } 271 272 // receive reply packet from debugee 273 ReplyPacket reply = new ReplyPacket(); 274 try { 275 log.display("Waiting for reply packet"); 276 transport.read(reply); 277 log.display(" ... reply packet received:\n" + reply); 278 } catch (IOException e) { 279 log.complain("Unable to read reply packet for tested command:\n\t" + e); 280 success = false; 281 return; 282 } 283 284 // check reply packet header 285 try{ 286 log.display("Checking header of reply packet"); 287 reply.checkHeader(command.getPacketID()); 288 log.display(" ... packet header is correct"); 289 } catch (BoundException e) { 290 log.complain("Wrong header of reply packet for tested command:\n\t" 291 + e.getMessage()); 292 success = false; 293 return; 294 } 295 296 // start parsing reply packet data 297 log.display("Parsing reply packet data:"); 298 reply.resetPosition(); 299 300 // extract return value 301 JDWP.Value returnValue = null; 302 try { 303 returnValue = reply.getValue(); 304 log.display(" returnValue: " + returnValue); 305 } catch (BoundException e) { 306 log.complain("Unable to extract returnValues from reply packet:\n\t" 307 + e.getMessage()); 308 success = false; 309 return; 310 } 311 312 // extract exception tag 313 JDWP.Value exception = null; 314 try { 315 exception = reply.getValue(); 316 log.display(" exception: " + exception); 317 } catch (BoundException e) { 318 log.complain("Unable to extract exception from reply packet:\n\t" 319 + e.getMessage()); 320 success = false; 321 return; 322 } 323 324 // check for extra data in reply packet 325 if (!reply.isParsed()) { 326 log.complain("Extra trailing bytes found in reply packet at: " 327 + reply.offsetString()); 328 success = false; 329 } 330 331 log.display(" ... packed data parsed"); 332 333 // check that return value is an integer 334 if (returnValue.getTag() != JDWP.Tag.INT) { 335 log.complain("Unexpected tag of returnValue returned: " + returnValue.getTag() 336 + " (expected: " + JDWP.Tag.INT + ")"); 337 success = false; 338 } 339 340 // check that return value is as expected 341 int intValue = ((Integer)returnValue.getValue()).intValue(); 342 if (intValue != RETURN_VALUE) { 343 log.complain("Unexpected value of returnValue returned: " + intValue 344 + " (expected: " + RETURN_VALUE + ")"); 345 success = false; 346 } 347 348 // check that exception value is an object 349 if (exception.getTag() != JDWP.Tag.OBJECT) { 350 log.complain("Unexpected tag of exception returned: " + exception.getTag() 351 + " (expected: " + JDWP.Tag.OBJECT + ")"); 352 success = false; 353 } 354 355 // check that exception object is null 356 long exceptionID = ((Long)exception.getValue()).longValue(); 357 if (exceptionID != 0) { 358 log.complain("Non-null exception object returned: " + exceptionID 359 + " (expected: " + 0 + ")"); 360 success = false; 361 } 362 } 363 364 /** 365 * Check result of the tested JDWP command. 366 */ checkResult()367 void checkResult() { 368 // query debuggee for result value from a static field 369 log.display("Getting result value from static field: " + RESULT_FIELD_NAME); 370 int result = queryInt(classID, RESULT_FIELD_NAME, JDWP.Tag.INT); 371 log.display(" ... got result: " + result); 372 373 // check if the result value is changed as expected 374 if (result != ARGUMENT_VALUE) { 375 log.complain("Method has not been really invoked: \n\t" 376 + "variable not changed by the method: " + result 377 + " (expected: " + ARGUMENT_VALUE + ")"); 378 success = false; 379 } else { 380 log.display("Method has been really invoked: \n\t" 381 + " variable changed by the method: " + result 382 + " (expected: " + ARGUMENT_VALUE + ")"); 383 } 384 } 385 386 /** 387 * Query debuggee for value of static field of the class. 388 */ queryFieldValue(long classID, String fieldName, byte tag)389 JDWP.Value queryFieldValue(long classID, String fieldName, byte tag) { 390 // get fieledID for static field (declared in the class) 391 long fieldID = debugee.getClassFieldID(classID, fieldName, true); 392 // get value of the field 393 JDWP.Value value = debugee.getStaticFieldValue(classID, fieldID); 394 395 // check that value has THREAD tag 396 if (value.getTag() != tag) { 397 log.complain("unexpedted value tag returned from debuggee: " + value.getTag() 398 + " (expected: " + tag + ")"); 399 throw new Failure("Error occured while getting value from static field: " 400 + fieldName); 401 } 402 403 return value; 404 } 405 406 /** 407 * Query debuggee for objectID value of static field of the class. 408 */ queryObjectID(long classID, String fieldName, byte tag)409 long queryObjectID(long classID, String fieldName, byte tag) { 410 JDWP.Value value = queryFieldValue(classID, fieldName, tag); 411 long objectID = ((Long)value.getValue()).longValue(); 412 return objectID; 413 } 414 415 /** 416 * Query debuggee for int value of static field of the class. 417 */ queryInt(long classID, String fieldName, byte tag)418 int queryInt(long classID, String fieldName, byte tag) { 419 JDWP.Value value = queryFieldValue(classID, fieldName, tag); 420 int intValue = ((Integer)value.getValue()).intValue(); 421 return intValue; 422 } 423 424 /** 425 * Sending debugee signal to quit and waiting for it exits. 426 */ quitDebugee()427 void quitDebugee() { 428 if (debugee == null) 429 return; 430 431 // disconnect debuggee if not dead 432 if (!dead) { 433 try { 434 log.display("Disconnecting debuggee"); 435 debugee.dispose(); 436 log.display(" ... debuggee disconnected"); 437 } catch (Failure e) { 438 log.display("Failed to finally dispose debuggee:\n\t" + e.getMessage()); 439 } 440 } 441 442 // wait for debugee exits 443 log.display("Waiting for debuggee exits"); 444 int code = debugee.waitFor(); 445 log.display(" ... debuggee finished with exit code: " + code); 446 447 // analize debuggee exit status code 448 if (code != JCK_STATUS_BASE + PASSED) { 449 log.complain("Debuggee FAILED with exit code: " + code); 450 } 451 } 452 453 } 454