1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package org.apache.harmony.jpda.tests.jdwp.Events; 20 21 import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket; 22 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants; 23 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.StepDepth; 24 import org.apache.harmony.jpda.tests.framework.jdwp.Location; 25 import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent; 26 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket; 27 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer; 28 29 /** 30 * JDWP unit test checking that we can report different events, requested during 31 * an EXCEPTION event where the exception is caught (by a catch handler). 32 */ 33 public class EventWithExceptionTest extends JDWPEventTestCase { 34 private static final String TEST_METHOD_NAME = "catchMethod"; 35 36 private static final String WATCHED_FIELD_NAME = "watchedField"; 37 38 private static final Class<? extends Throwable> EXCEPTION_CLASS = 39 EventWithExceptionDebuggee.TestException.class; 40 41 @Override 42 protected String getDebuggeeClassName() { 43 return EventWithExceptionDebuggee.class.getName(); 44 } 45 46 /** 47 * Tests we properly SINGLE-STEP OUT to the catch handler. 48 */ 49 public void testSingleStepOut() { 50 runSingleStepTest(JDWPConstants.StepDepth.OUT); 51 } 52 53 /** 54 * Tests we properly SINGLE-STEP OVER to the catch handler. 55 */ 56 public void testSingleStepOver() { 57 runSingleStepTest(JDWPConstants.StepDepth.OVER); 58 } 59 60 /** 61 * Tests we properly SINGLE-STEP INTO to the catch handler. 62 */ 63 public void testSingleStepInto() { 64 runSingleStepTest(JDWPConstants.StepDepth.INTO); 65 } 66 67 /** 68 * Tests we properly BREAKPOINT in the catch handler if we request it before the EXCEPTION 69 * event happens. 70 */ 71 public void testBreakpoint_BeforeException() { 72 logWriter.println(getName() + " STARTS"); 73 74 // Wait for debuggee. 75 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 76 77 // Set EXCEPTION event 78 int exceptionRequestId = setException(); 79 80 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 81 82 // Wait for EXCEPTION event 83 ParsedEvent exceptionEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION, 84 exceptionRequestId); 85 86 // Get catch handler location 87 Location catchHandlerLocation = 88 ((ParsedEvent.Event_EXCEPTION) exceptionEvent).getCatchLocation(); 89 90 // Remove EXCEPTION event. 91 clearEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId, true); 92 93 // Resume debuggee suspended on EXCEPTION event. 94 logWriter.println("Resume debuggee after EXCEPTION event"); 95 debuggeeWrapper.resume(); 96 97 // Wait for debuggee. 98 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 99 100 // Install BREAKPOINT in catch handler. 101 int breakpointRequestId = setBreakpoint(catchHandlerLocation); 102 103 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 104 105 // Wait for BREAKPOINT. 106 ParsedEvent breakpointEvent = waitForEvent(JDWPConstants.EventKind.BREAKPOINT, 107 breakpointRequestId); 108 109 // Check location of BREAKPOINT event. 110 Location eventLocation = ((ParsedEvent.EventThreadLocation) breakpointEvent).getLocation(); 111 assertEquals("Not the expected location", catchHandlerLocation, eventLocation); 112 113 // Remove BREAKPOINT request. 114 clearEvent(JDWPConstants.EventKind.BREAKPOINT, breakpointRequestId, true); 115 116 // Resume debuggee suspended on BREAKPOINT event. 117 logWriter.println("Resume debuggee after BREAKPOINT event"); 118 debuggeeWrapper.resume(); 119 120 // Continue debuggee 121 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 122 123 logWriter.println(getName() + " ENDS"); 124 } 125 126 /** 127 * Tests we properly BREAKPOINT in the catch handler if we request it upon the EXCEPTION 128 * event happens. 129 */ 130 public void testBreakpoint_UponException() { 131 logWriter.println(getName() + " STARTS"); 132 133 // Wait for debuggee. 134 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 135 136 // Set EXCEPTION event 137 int exceptionRequestId = setException(); 138 139 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 140 141 // Wait for EXCEPTION event 142 ParsedEvent exceptionEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION, 143 exceptionRequestId); 144 145 // Get catch handler location 146 Location catchHandlerLocation = 147 ((ParsedEvent.Event_EXCEPTION) exceptionEvent).getCatchLocation(); 148 149 // Resume debuggee suspended on EXCEPTION event. 150 logWriter.println("Resume debuggee after EXCEPTION event"); 151 debuggeeWrapper.resume(); 152 153 // Wait for debuggee. 154 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 155 156 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 157 158 waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId); 159 160 // Install BREAKPOINT in catch handler. 161 int breakpointRequestId = setBreakpoint(catchHandlerLocation); 162 163 debuggeeWrapper.resume(); 164 165 // Wait for BREAKPOINT. 166 ParsedEvent breakpointEvent = waitForEvent(JDWPConstants.EventKind.BREAKPOINT, 167 breakpointRequestId); 168 169 // Check location of BREAKPOINT event. 170 Location eventLocation = ((ParsedEvent.EventThreadLocation) breakpointEvent).getLocation(); 171 assertEquals("Not the expected location", catchHandlerLocation, eventLocation); 172 173 // Remove BREAKPOINT request. 174 clearEvent(JDWPConstants.EventKind.BREAKPOINT, breakpointRequestId, true); 175 176 // Resume debuggee suspended on BREAKPOINT event. 177 logWriter.println("Resume debuggee after BREAKPOINT event"); 178 debuggeeWrapper.resume(); 179 180 // Continue debuggee 181 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 182 183 logWriter.println(getName() + " ENDS"); 184 } 185 186 /** 187 * Tests we properly FIELD_ACCESS in the method catching the exception. 188 */ 189 public void testFieldAccess() { 190 runFieldWatchpointTest(JDWPConstants.EventKind.FIELD_ACCESS); 191 } 192 193 /** 194 * Tests we properly FIELD_MODIFICATION in the method catching the exception. 195 */ 196 public void testFieldModification() { 197 runFieldWatchpointTest(JDWPConstants.EventKind.FIELD_MODIFICATION); 198 } 199 200 /** 201 * Tests we properly detect METHOD_EXIT event in the method catching the exception. 202 */ 203 public void testMethodExit() { 204 runMethodExitTest(JDWPConstants.EventKind.METHOD_EXIT); 205 } 206 207 /** 208 * Tests we properly detect METHOD_EXIT event in the method catching the exception. 209 */ 210 public void testMethodExitWithReturnValue() { 211 runMethodExitTest(JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE); 212 } 213 214 /** 215 * Tests we properly single-step to the catch handler. 216 * 217 * @param singleStepDepth 218 * the kind of single-step 219 */ 220 private void runSingleStepTest(byte singleStepDepth) { 221 logWriter.println(getName() + " STARTS"); 222 223 // Wait for debuggee. 224 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 225 226 // Set EXCEPTION event 227 int exceptionRequestId = setException(); 228 229 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 230 231 // Wait for EXCEPTION event 232 ParsedEvent exceptionEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION, 233 exceptionRequestId); 234 235 // Get catch handler location 236 Location catchHandlerLocation = 237 ((ParsedEvent.Event_EXCEPTION) exceptionEvent).getCatchLocation(); 238 239 // Resume debuggee suspended on EXCEPTION event. 240 logWriter.println("Resume debuggee after EXCEPTION event #1"); 241 debuggeeWrapper.resume(); 242 243 // Wait for debuggee. 244 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 245 246 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 247 248 // Wait for EXCEPTION event 249 ParsedEvent parsedEvent = waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId); 250 long eventThreadId = ((ParsedEvent.EventThread)parsedEvent).getThreadID(); 251 252 // Install SINGLE_STEP in catch handler. 253 int singleStepRequestId = setSingleStep(eventThreadId, singleStepDepth); 254 255 // Resume debuggee suspended on EXCEPTION event. 256 logWriter.println("Resume debuggee after EXCEPTION event #2"); 257 debuggeeWrapper.resume(); 258 259 // Wait for SINGLE_STEP. 260 ParsedEvent singleStepEvent = waitForEvent(JDWPConstants.EventKind.SINGLE_STEP, 261 singleStepRequestId); 262 263 // Check location of SINGLE_STEP event. 264 Location eventLocation = ((ParsedEvent.EventThreadLocation) singleStepEvent).getLocation(); 265 assertEquals("Not the expected location, ", catchHandlerLocation, eventLocation); 266 267 // Remove SINGLE_STEP request. 268 clearEvent(JDWPConstants.EventKind.SINGLE_STEP, singleStepRequestId, true); 269 270 // Resume debuggee suspended on SINGLE_STEP event. 271 logWriter.println("Resume debuggee after SINGLE_STEP event"); 272 debuggeeWrapper.resume(); 273 274 // Continue debuggee 275 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 276 277 logWriter.println(getName() + " ENDS"); 278 } 279 280 /** 281 * Tests we properly detect field watchpoint events in the method catching the exception. 282 * 283 * @param fieldEventKind 284 * the desired field event kind 285 */ 286 private void runFieldWatchpointTest(byte fieldEventKind) { 287 logWriter.println(getName() + " STARTS"); 288 289 // Skip first method call since we do not need to know the location of 290 // the catch handler. 291 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 292 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 293 294 // Wait for second method call. 295 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 296 297 // Set EXCEPTION event 298 int exceptionRequestId = setException(); 299 300 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 301 302 // Wait for EXCEPTION event 303 waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId); 304 305 // Install FIELD watchpoint event 306 int fieldWatchpointRequestId = setFieldWatchpoint(fieldEventKind); 307 308 // Resume debuggee suspended on EXCEPTION event. 309 logWriter.println("Resume debuggee after EXCEPTION event"); 310 debuggeeWrapper.resume(); 311 312 // Wait for FIELD event. 313 ParsedEvent fieldWatchpointEvent = waitForEvent(fieldEventKind, 314 fieldWatchpointRequestId); 315 316 // Check location of FIELD event. 317 Location eventLocation = 318 ((ParsedEvent.EventThreadLocation) fieldWatchpointEvent).getLocation(); 319 assertNotNull(eventLocation); 320 long classId = getClassIDBySignature(getDebuggeeClassSignature()); 321 long methodId = getMethodID(classId, TEST_METHOD_NAME); 322 assertEquals("Invalid class ID", classId, eventLocation.classID); 323 assertEquals("Invalid method ID", methodId, eventLocation.methodID); 324 325 // Remove FIELD watchpoint request. 326 clearEvent(fieldEventKind, fieldWatchpointRequestId, true); 327 328 // Resume debuggee suspended on FIELD event. 329 logWriter.println("Resume debuggee after " + 330 JDWPConstants.EventKind.getName(fieldEventKind) + " event"); 331 debuggeeWrapper.resume(); 332 333 // Continue debuggee 334 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 335 336 logWriter.println(getName() + " ENDS"); 337 } 338 339 /** 340 * Tests we properly detect method exit event in the method catching the exception. 341 * 342 * @param methodExitEventKind 343 * the desired method exit event kind 344 */ 345 private void runMethodExitTest(byte methodExitEventKind) { 346 347 logWriter.println(getName() + " STARTS"); 348 349 // Skip first method call since we do not need to know the location of 350 // the catch handler. 351 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 352 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 353 354 // Wait for second method call. 355 synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); 356 357 // Set EXCEPTION event 358 int exceptionRequestId = setException(); 359 360 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 361 362 // Wait for EXCEPTION event 363 waitForEvent(JDWPConstants.EventKind.EXCEPTION, exceptionRequestId); 364 365 // Install METHOD_EXIT event 366 int methodExitRequestId = setMethodExit(methodExitEventKind); 367 368 logWriter.println("Resume debuggee after EXCEPTION event"); 369 debuggeeWrapper.resume(); 370 371 // Wait for METHOD_EXIT event. 372 ParsedEvent methodExitEvent = waitForEvent(methodExitEventKind, methodExitRequestId); 373 374 // Check location of METHOD_EXIT event. 375 Location eventLocation = 376 ((ParsedEvent.EventThreadLocation) methodExitEvent).getLocation(); 377 assertNotNull(eventLocation); 378 long classId = getClassIDBySignature(getDebuggeeClassSignature()); 379 long methodId = getMethodID(classId, TEST_METHOD_NAME); 380 checkLocation(classId, methodId, eventLocation); 381 382 // Remove METHOD_EXIT request. 383 clearEvent(methodExitEventKind, methodExitRequestId, true); 384 385 // Resume debuggee suspended on METHOD_EXIT event. 386 logWriter.println("Resume debuggee after " + 387 JDWPConstants.EventKind.getName(methodExitEventKind) + " event"); 388 debuggeeWrapper.resume(); 389 390 // Continue debuggee 391 synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); 392 393 logWriter.println(getName() + " ENDS"); 394 } 395 396 private void checkLocation(long expectedClassId, long expectedMethodId, Location actualLocation) { 397 if (expectedClassId != actualLocation.classID || expectedMethodId != actualLocation.methodID) { 398 String expectedClassName = getClassSignature(expectedClassId); 399 String expectedMethodName = getMethodName(expectedClassId, expectedMethodId); 400 String actualClassName = getClassSignature(actualLocation.classID); 401 String actualMethodName = getMethodName(actualLocation.classID, actualLocation.methodID); 402 fail(String.format("Invalid method, expected \"%s.%s\" (classId=%d, methodId=%d)" + 403 " but got \"%s.%s\" (classId=%d, methodId=%d)", 404 expectedClassName, expectedMethodName, expectedClassId, expectedMethodId, 405 actualClassName, actualMethodName, actualLocation.classID, actualLocation.methodID)); 406 } 407 } 408 409 private int setException() { 410 logWriter.println("Set EXCEPTION on class " + EXCEPTION_CLASS.getName()); 411 ReplyPacket exceptionReplyPacket = 412 debuggeeWrapper.vmMirror.setException(getClassSignature(EXCEPTION_CLASS), true, 413 false); 414 checkReplyPacket(exceptionReplyPacket, "Failed to install EXCEPTION"); 415 return readRequestId(exceptionReplyPacket); 416 } 417 418 private int setSingleStep(long eventThreadId, byte singleStepDepth) { 419 logWriter.println("Set SINGLE_STEP " + JDWPConstants.StepDepth.getName(singleStepDepth) + 420 " in thread " + eventThreadId); 421 ReplyPacket replyPacket = debuggeeWrapper.vmMirror.setStep(eventThreadId, 422 JDWPConstants.StepSize.LINE, singleStepDepth); 423 checkReplyPacket(replyPacket, "Failed to set SINGLE_STEP " + 424 StepDepth.getName(singleStepDepth)); 425 return readRequestId(replyPacket); 426 } 427 428 private int setBreakpoint(Location catchHandlerLocation) { 429 logWriter.println("Set BREAKPOINT at " + catchHandlerLocation); 430 ReplyPacket breakpointReplyPacket = 431 debuggeeWrapper.vmMirror.setBreakpoint(catchHandlerLocation); 432 checkReplyPacket(breakpointReplyPacket, "Failed to install BREAKPOINT"); 433 return readRequestId(breakpointReplyPacket); 434 } 435 436 private int setFieldWatchpoint(byte fieldEventKind) { 437 String eventKindName = JDWPConstants.EventKind.getName(fieldEventKind); 438 logWriter.println("Set " + eventKindName + " on field " + WATCHED_FIELD_NAME); 439 final String classSignature = getDebuggeeClassSignature(); 440 final byte classTypeTag = JDWPConstants.TypeTag.CLASS; 441 ReplyPacket replyPacket = null; 442 if (fieldEventKind == JDWPConstants.EventKind.FIELD_ACCESS) { 443 replyPacket = debuggeeWrapper.vmMirror.setFieldAccess(classSignature, classTypeTag, 444 WATCHED_FIELD_NAME); 445 } else if (fieldEventKind == JDWPConstants.EventKind.FIELD_MODIFICATION) { 446 replyPacket = debuggeeWrapper.vmMirror.setFieldModification(classSignature, 447 classTypeTag, WATCHED_FIELD_NAME); 448 } else { 449 fail("Unsupported eventkind " + fieldEventKind); 450 } 451 checkReplyPacket(replyPacket, "Failed to set " + eventKindName); 452 return readRequestId(replyPacket); 453 } 454 455 private int setMethodExit(byte methodExitEventKind) { 456 String eventKindName = JDWPConstants.EventKind.getName(methodExitEventKind); 457 logWriter.println("Set " + eventKindName + " on class " + getDebuggeeClassName()); 458 ReplyPacket replyPacket = null; 459 if (methodExitEventKind == JDWPConstants.EventKind.METHOD_EXIT) { 460 replyPacket = debuggeeWrapper.vmMirror.setMethodExit(getDebuggeeClassName()); 461 } else if (methodExitEventKind == JDWPConstants.EventKind.METHOD_EXIT_WITH_RETURN_VALUE) { 462 replyPacket = 463 debuggeeWrapper.vmMirror.setMethodExitWithReturnValue(getDebuggeeClassName()); 464 } else { 465 fail("Not a method exit event: " + methodExitEventKind); 466 } 467 checkReplyPacket(replyPacket, "Failed to set " + eventKindName); 468 return readRequestId(replyPacket); 469 } 470 471 private int readRequestId(ReplyPacket replyPacket) { 472 int requestId = replyPacket.getNextValueAsInt(); 473 assertAllDataRead(replyPacket); 474 return requestId; 475 } 476 477 private ParsedEvent waitForEvent(byte eventKind, int requestId) { 478 logWriter.println("Waiting for " + JDWPConstants.EventKind.getName(eventKind) + 479 " (request " + requestId + ")"); 480 481 // Wait for event. 482 EventPacket eventPacket = debuggeeWrapper.vmMirror.receiveCertainEvent(eventKind); 483 ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(eventPacket); 484 485 // Check that this event is the expected one. 486 assertEquals(1, parsedEvents.length); 487 ParsedEvent parsedEvent = parsedEvents[0]; 488 assertEventKindEquals("Invalid event kind", eventKind, parsedEvent.getEventKind()); 489 assertEquals("Invalid request id", requestId, parsedEvent.getRequestID()); 490 return parsedEvent; 491 } 492 } 493