blob: 8d44afe02096826e3bfbd980cca15a389fd29660 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#include "util.h"
27#include "stepControl.h"
28#include "eventHandler.h"
29#include "eventHelper.h"
30#include "threadControl.h"
31#include "SDE.h"
32
33static jrawMonitorID stepLock;
34
35static jint
36getFrameCount(jthread thread)
37{
38 jint count = 0;
39 jvmtiError error;
40
41 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
42 (gdata->jvmti, thread, &count);
43 if (error != JVMTI_ERROR_NONE) {
44 EXIT_ERROR(error, "getting frame count");
45 }
46 return count;
47}
48
49/*
50 * Most enabling/disabling of JVMTI events happens implicitly through
51 * the inserting and freeing of handlers for those events. Stepping is
52 * different because requested steps are usually not identical to JVMTI steps.
53 * They usually require multiple events step, and otherwise, before they
54 * complete. While a step request is pending, we may need to temporarily
55 * disable and re-enable stepping, but we can't just remove the handlers
56 * because that would break the application's ability to remove the
57 * events. So, for step events only, we directly enable and disable stepping.
58 * This is safe because there can only ever be one pending step request
59 * per thread.
60 */
61static void
62enableStepping(jthread thread)
63{
64 jvmtiError error;
65
66 LOG_STEP(("enableStepping: thread=%p", thread));
67
68 error = threadControl_setEventMode(JVMTI_ENABLE, EI_SINGLE_STEP,
69 thread);
70 if (error != JVMTI_ERROR_NONE) {
71 EXIT_ERROR(error, "enabling single step");
72 }
73}
74
75static void
76disableStepping(jthread thread)
77{
78 jvmtiError error;
79
80 LOG_STEP(("disableStepping: thread=%p", thread));
81
82 error = threadControl_setEventMode(JVMTI_DISABLE, EI_SINGLE_STEP,
83 thread);
84 if (error != JVMTI_ERROR_NONE) {
85 EXIT_ERROR(error, "disabling single step");
86 }
87}
88
89static jvmtiError
90getFrameLocation(jthread thread,
91 jclass *pclazz, jmethodID *pmethod, jlocation *plocation)
92{
93 jvmtiError error;
94
95 *pclazz = NULL;
96 *pmethod = NULL;
97 *plocation = -1;
98
99 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation)
100 (gdata->jvmti, thread, 0, pmethod, plocation);
101 if (error == JVMTI_ERROR_NONE && *pmethod!=NULL ) {
102 /* This also serves to verify that the methodID is valid */
103 error = methodClass(*pmethod, pclazz);
104 }
105 return error;
106}
107
108static void
109getLineNumberTable(jmethodID method, jint *pcount,
110 jvmtiLineNumberEntry **ptable)
111{
112 jvmtiError error;
113
114 *pcount = 0;
115 *ptable = NULL;
116
117 /* If the method is native or obsolete, don't even ask for the line table */
118 if ( isMethodObsolete(method) || isMethodNative(method)) {
119 return;
120 }
121
122 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLineNumberTable)
123 (gdata->jvmti, method, pcount, ptable);
124 if (error != JVMTI_ERROR_NONE) {
125 *pcount = 0;
126 }
127}
128
129static jint
130findLineNumber(jthread thread, jlocation location,
131 jvmtiLineNumberEntry *lines, jint count)
132{
133 jint line = -1;
134
135 if (location != -1) {
136 if (count > 0) {
137 jint i;
138 /* any preface before first line is assigned to first line */
139 for (i=1; i<count; i++) {
140 if (location < lines[i].start_location) {
141 break;
142 }
143 }
144 line = lines[i-1].line_number;
145 }
146 }
147 return line;
148}
149
150static jboolean
151hasLineNumbers(jmethodID method)
152{
153 jint count;
154 jvmtiLineNumberEntry *table;
155
156 getLineNumberTable(method, &count, &table);
157 if ( count == 0 ) {
158 return JNI_FALSE;
159 } else {
160 jvmtiDeallocate(table);
161 }
162 return JNI_TRUE;
163}
164
165static jvmtiError
166initState(JNIEnv *env, jthread thread, StepRequest *step)
167{
168 jvmtiError error;
169
170 /*
171 * Initial values that may be changed below
172 */
173 step->fromLine = -1;
174 step->fromNative = JNI_FALSE;
175 step->frameExited = JNI_FALSE;
176 step->fromStackDepth = getFrameCount(thread);
177
178 if (step->fromStackDepth <= 0) {
179 /*
180 * If there are no stack frames, treat the step as though
181 * from a native frame. This is most likely to occur at the
182 * beginning of a debug session, right after the VM_INIT event,
183 * so we need to do something intelligent.
184 */
185 step->fromNative = JNI_TRUE;
186 return JVMTI_ERROR_NONE;
187 }
188
189 /*
190 * Try to get a notification on frame pop. If we're in an opaque frame
191 * we won't be able to, but we can use other methods to detect that
192 * a native frame has exited.
193 *
194 * TO DO: explain the need for this notification.
195 */
196 error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
197 (gdata->jvmti, thread, 0);
198 if (error == JVMTI_ERROR_OPAQUE_FRAME) {
199 step->fromNative = JNI_TRUE;
200 error = JVMTI_ERROR_NONE;
201 /* continue without error */
202 } else if (error == JVMTI_ERROR_DUPLICATE) {
203 error = JVMTI_ERROR_NONE;
204 /* Already being notified, continue without error */
205 } else if (error != JVMTI_ERROR_NONE) {
206 return error;
207 }
208
209 LOG_STEP(("initState(): frame=%d", step->fromStackDepth));
210
211 /*
212 * Note: we can't undo the frame pop notify, so
213 * we'll just have to let the handler ignore it if
214 * there are any errors below.
215 */
216
217 if (step->granularity == JDWP_STEP_SIZE(LINE) ) {
218
219 LOG_STEP(("initState(): Begin line step"));
220
221 WITH_LOCAL_REFS(env, 1) {
222
223 jclass clazz;
224 jmethodID method;
225 jlocation location;
226
227 error = getFrameLocation(thread, &clazz, &method, &location);
228 if (error == JVMTI_ERROR_NONE) {
229 /* Clear out previous line table only if we changed methods */
230 if ( method != step->method ) {
231 step->lineEntryCount = 0;
232 if (step->lineEntries != NULL) {
233 jvmtiDeallocate(step->lineEntries);
234 step->lineEntries = NULL;
235 }
236 step->method = method;
237 getLineNumberTable(step->method,
238 &step->lineEntryCount, &step->lineEntries);
239 if (step->lineEntryCount > 0) {
240 convertLineNumberTable(env, clazz,
241 &step->lineEntryCount, &step->lineEntries);
242 }
243 }
244 step->fromLine = findLineNumber(thread, location,
245 step->lineEntries, step->lineEntryCount);
246 }
247
248 } END_WITH_LOCAL_REFS(env);
249
250 }
251
252 return error;
253}
254
255/*
256 * TO DO: The step handlers (handleFrameChange and handleStep can
257 * be broken down and made simpler now that we can install and de-install event
258 * handlers.
259 */
260static void
261handleFramePopEvent(JNIEnv *env, EventInfo *evinfo,
262 HandlerNode *node,
263 struct bag *eventBag)
264{
265 StepRequest *step;
266 jthread thread = evinfo->thread;
267
268 stepControl_lock();
269
270 step = threadControl_getStepRequest(thread);
271 if (step == NULL) {
272 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting step request");
273 }
274
275 if (step->pending) {
276 /*
277 * Note: current depth is reported as *before* the pending frame
278 * pop.
279 */
280 jint currentDepth;
281 jint fromDepth;
282 jint afterPopDepth;
283
284 currentDepth = getFrameCount(thread);
285 fromDepth = step->fromStackDepth;
286 afterPopDepth = currentDepth-1;
287
288 LOG_STEP(("handleFramePopEvent: BEGIN fromDepth=%d, currentDepth=%d",
289 fromDepth, currentDepth));
290
291 /*
292 * If we are exiting the original stepping frame, record that
293 * fact here. Once the next step event comes in, we can safely
294 * stop stepping there.
295 */
296 if (fromDepth > afterPopDepth ) {
297 step->frameExited = JNI_TRUE;
298 }
299
300 if (step->depth == JDWP_STEP_DEPTH(OVER)) {
301 /*
302 * Either
303 * 1) the original stepping frame is about to be popped
304 * [fromDepth == currentDepth]. Re-enable stepping to
305 * reach a point where we can stop.
306 * 2) a method called from the stepping frame has returned
307 * (during which we had stepping disabled)
308 * [fromDepth == currentDepth - 1]. Re-enable stepping
309 * so that we can continue instructions steps in the
310 * original stepping frame.
311 * 3) a method further down the call chain has notified
312 * of a frame pop [fromDepth < currentDepth - 1]. This
313 * *might* represent case (2) above if the stepping frame
314 * was calling a native method which in turn called a
315 * java method. If so, we must enable stepping to
316 * ensure that we get control back after the intervening
317 * native frame is popped (you can't get frame pop
318 * notifications on native frames). If the native caller
319 * calls another Java method before returning,
320 * stepping will be diabled again and another frame pop
321 * will be awaited.
322 *
323 * If it turns out that this is not case (2) with native
324 * methods, then the enabled stepping is benign and
325 * will be disabled again on the next step event.
326 *
327 * Note that the condition not covered above,
328 * [fromDepth > currentDepth] shouldn't happen since it means
329 * that too many frames have been popped. For robustness,
330 * we enable stepping in that case too, so that the errant
331 * step-over can be stopped.
332 *
333 */
334 LOG_STEP(("handleFramePopEvent: starting singlestep, depth==OVER"));
335 enableStepping(thread);
336 } else if (step->depth == JDWP_STEP_DEPTH(OUT) &&
337 fromDepth > afterPopDepth) {
338 /*
339 * The original stepping frame is about to be popped. Step
340 * until we reach the next safe place to stop.
341 */
342 LOG_STEP(("handleFramePopEvent: starting singlestep, depth==OUT && fromDepth > afterPopDepth (%d>%d)",fromDepth, afterPopDepth));
343 enableStepping(thread);
344 } else if (step->methodEnterHandlerNode != NULL &&
345 fromDepth >= afterPopDepth) {
346 /*
347 * We installed a method entry event handler as part of a
348 * step into operation. We've popped back to the original
349 * stepping frame without finding a place to stop.
350 * Resume stepping in the original frame.
351 */
352 LOG_STEP(("handleFramePopEvent: starting singlestep, have methodEnter handler && depth==OUT && fromDepth >= afterPopDepth (%d>%d)",fromDepth, afterPopDepth));
353 enableStepping(thread);
354 (void)eventHandler_free(step->methodEnterHandlerNode);
355 step->methodEnterHandlerNode = NULL;
356 }
357 LOG_STEP(("handleFramePopEvent: finished"));
358 }
359
360 stepControl_unlock();
361}
362
363static void
364handleExceptionCatchEvent(JNIEnv *env, EventInfo *evinfo,
365 HandlerNode *node,
366 struct bag *eventBag)
367{
368 StepRequest *step;
369 jthread thread = evinfo->thread;
370
371 stepControl_lock();
372
373 step = threadControl_getStepRequest(thread);
374 if (step == NULL) {
375 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting step request");
376 }
377
378 if (step->pending) {
379 /*
380 * Determine where we are on the call stack relative to where
381 * we started.
382 */
383 jint currentDepth = getFrameCount(thread);
384 jint fromDepth = step->fromStackDepth;
385
386 LOG_STEP(("handleExceptionCatchEvent: fromDepth=%d, currentDepth=%d",
387 fromDepth, currentDepth));
388
389 /*
390 * If we are exiting the original stepping frame, record that
391 * fact here. Once the next step event comes in, we can safely
392 * stop stepping there.
393 */
394 if (fromDepth > currentDepth) {
395 step->frameExited = JNI_TRUE;
396 }
397
398 if (step->depth == JDWP_STEP_DEPTH(OVER) &&
399 fromDepth >= currentDepth) {
400 /*
401 * Either the original stepping frame is done,
402 * or a called method has returned (during which we had stepping
403 * disabled). In either case we must resume stepping.
404 */
405 enableStepping(thread);
406 } else if (step->depth == JDWP_STEP_DEPTH(OUT) &&
407 fromDepth > currentDepth) {
408 /*
409 * The original stepping frame is done. Step
410 * until we reach the next safe place to stop.
411 */
412 enableStepping(thread);
413 } else if (step->methodEnterHandlerNode != NULL &&
414 fromDepth >= currentDepth) {
415 /*
416 * We installed a method entry event handler as part of a
417 * step into operation. We've popped back to the original
418 * stepping frame or higher without finding a place to stop.
419 * Resume stepping in the original frame.
420 */
421 enableStepping(thread);
422 (void)eventHandler_free(step->methodEnterHandlerNode);
423 step->methodEnterHandlerNode = NULL;
424 }
425 }
426
427 stepControl_unlock();
428}
429
430static void
431handleMethodEnterEvent(JNIEnv *env, EventInfo *evinfo,
432 HandlerNode *node,
433 struct bag *eventBag)
434{
435 StepRequest *step;
436 jthread thread;
437
438 thread = evinfo->thread;
439
440 stepControl_lock();
441
442 step = threadControl_getStepRequest(thread);
443 if (step == NULL) {
444 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting step request");
445 }
446
447 if (step->pending) {
448 jclass clazz;
449 jmethodID method;
450 char *classname;
451
452 LOG_STEP(("handleMethodEnterEvent: thread=%p", thread));
453
454 clazz = evinfo->clazz;
455 method = evinfo->method;
456 classname = getClassname(clazz);
457
458 /*
459 * This handler is relevant only to step into
460 */
461 JDI_ASSERT(step->depth == JDWP_STEP_DEPTH(INTO));
462
463 if ( (!eventFilter_predictFiltering(step->stepHandlerNode,
464 clazz, classname))
465 && ( step->granularity != JDWP_STEP_SIZE(LINE)
466 || hasLineNumbers(method) ) ) {
467 /*
468 * We've found a suitable method in which to stop. Step
469 * until we reach the next safe location to complete the step->,
470 * and we can get rid of the method entry handler.
471 */
472 enableStepping(thread);
473 if ( step->methodEnterHandlerNode != NULL ) {
474 (void)eventHandler_free(step->methodEnterHandlerNode);
475 step->methodEnterHandlerNode = NULL;
476 }
477 }
478 jvmtiDeallocate(classname);
479 classname = NULL;
480 }
481
482 stepControl_unlock();
483}
484
485static void
486completeStep(JNIEnv *env, jthread thread, StepRequest *step)
487{
488 jvmtiError error;
489
490 /*
491 * We've completed a step; reset state for the next one, if any
492 */
493
494 LOG_STEP(("completeStep: thread=%p", thread));
495
496 if (step->methodEnterHandlerNode != NULL) {
497 (void)eventHandler_free(step->methodEnterHandlerNode);
498 step->methodEnterHandlerNode = NULL;
499 }
500
501 error = initState(env, thread, step);
502 if (error != JVMTI_ERROR_NONE) {
503 /*
504 * None of the initState errors should happen after one step
505 * has successfully completed.
506 */
507 EXIT_ERROR(error, "initializing step state");
508 }
509}
510
511jboolean
512stepControl_handleStep(JNIEnv *env, jthread thread,
513 jclass clazz, jmethodID method)
514{
515 jboolean completed = JNI_FALSE;
516 StepRequest *step;
517 jint currentDepth;
518 jint fromDepth;
519 jvmtiError error;
520 char *classname;
521
522 classname = NULL;
523 stepControl_lock();
524
525 step = threadControl_getStepRequest(thread);
526 if (step == NULL) {
527 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting step request");
528 }
529
530 /*
531 * If no step is currently pending, ignore the event
532 */
533 if (!step->pending) {
534 goto done;
535 }
536
537 LOG_STEP(("stepControl_handleStep: thread=%p", thread));
538
539 /*
540 * We never filter step into instruction. It's always over on the
541 * first step event.
542 */
543 if (step->depth == JDWP_STEP_DEPTH(INTO) &&
544 step->granularity == JDWP_STEP_SIZE(MIN)) {
545 completed = JNI_TRUE;
546 LOG_STEP(("stepControl_handleStep: completed, into min"));
547 goto done;
548 }
549
550 /*
551 * If we have left the method in which
552 * stepping started, the step is always complete.
553 */
554 if (step->frameExited) {
555 completed = JNI_TRUE;
556 LOG_STEP(("stepControl_handleStep: completed, frame exited"));
557 goto done;
558 }
559
560 /*
561 * Determine where we are on the call stack relative to where
562 * we started.
563 */
564 currentDepth = getFrameCount(thread);
565 fromDepth = step->fromStackDepth;
566
567 if (fromDepth > currentDepth) {
568 /*
569 * We have returned from the caller. There are cases where
570 * we don't get frame pop notifications
571 * (e.g. stepping from opaque frames), and that's when
572 * this code will be reached. Complete the step->
573 */
574 completed = JNI_TRUE;
575 LOG_STEP(("stepControl_handleStep: completed, fromDepth>currentDepth(%d>%d)", fromDepth, currentDepth));
576 } else if (fromDepth < currentDepth) {
577 /* We have dropped into a called method. */
578 if ( step->depth == JDWP_STEP_DEPTH(INTO)
579 && (!eventFilter_predictFiltering(step->stepHandlerNode, clazz,
580 (classname = getClassname(clazz))))
581 && hasLineNumbers(method) ) {
582
583 /* Stepped into a method with lines, so we're done */
584 completed = JNI_TRUE;
585 LOG_STEP(("stepControl_handleStep: completed, fromDepth<currentDepth(%d<%d) and into method with lines", fromDepth, currentDepth));
586 } else {
587 /*
588 * We need to continue, but don't want the overhead of step
589 * events from this method. So, we disable stepping and
590 * enable a frame pop. If we're stepping into, we also
591 * enable method enter events because a called frame may be
592 * where we want to stop.
593 */
594 disableStepping(thread);
595
596 if (step->depth == JDWP_STEP_DEPTH(INTO)) {
597 step->methodEnterHandlerNode =
598 eventHandler_createInternalThreadOnly(
599 EI_METHOD_ENTRY,
600 handleMethodEnterEvent, thread);
601 if (step->methodEnterHandlerNode == NULL) {
602 EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,
603 "installing event method enter handler");
604 }
605 }
606
607 error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
608 (gdata->jvmti, thread, 0);
609 if (error == JVMTI_ERROR_DUPLICATE) {
610 error = JVMTI_ERROR_NONE;
611 } else if (error != JVMTI_ERROR_NONE) {
612 EXIT_ERROR(error, "setting up notify frame pop");
613 }
614 }
615 jvmtiDeallocate(classname);
616 classname = NULL;
617 } else {
618 /*
619 * We are at the same stack depth where stepping started.
620 * Instruction steps are complete at this point. For line
621 * steps we must check to see whether we've moved to a
622 * different line.
623 */
624 if (step->granularity == JDWP_STEP_SIZE(MIN)) {
625 completed = JNI_TRUE;
626 LOG_STEP(("stepControl_handleStep: completed, fromDepth==currentDepth(%d) and min", fromDepth));
627 } else {
628 if (step->fromLine != -1) {
629 jint line = -1;
630 jlocation location;
631 jmethodID method;
632 WITH_LOCAL_REFS(env, 1) {
633 jclass clazz;
634 error = getFrameLocation(thread,
635 &clazz, &method, &location);
636 if ( isMethodObsolete(method)) {
637 method = NULL;
638 location = -1;
639 }
640 if (error != JVMTI_ERROR_NONE || location == -1) {
641 EXIT_ERROR(error, "getting frame location");
642 }
643 if ( method == step->method ) {
644 LOG_STEP(("stepControl_handleStep: checking line location"));
645 log_debugee_location("stepControl_handleStep: checking line loc",
646 thread, method, location);
647 line = findLineNumber(thread, location,
648 step->lineEntries, step->lineEntryCount);
649 }
650 if (line != step->fromLine) {
651 completed = JNI_TRUE;
652 LOG_STEP(("stepControl_handleStep: completed, fromDepth==currentDepth(%d) and different line", fromDepth));
653 }
654 } END_WITH_LOCAL_REFS(env);
655 } else {
656 /*
657 * This is a rare case. We have stepped from a location
658 * inside a native method to a location within a Java
659 * method at the same stack depth. This means that
660 * the original native method returned to another
661 * native method which, in turn, invoked a Java method.
662 *
663 * Since the original frame was native, we were unable
664 * to ask for a frame pop event, and, thus, could not
665 * set the step->frameExited flag when the original
666 * method was done. Instead we end up here
667 * and act just as though the frameExited flag was set
668 * and complete the step immediately.
669 */
670 completed = JNI_TRUE;
671 LOG_STEP(("stepControl_handleStep: completed, fromDepth==currentDepth(%d) and no line", fromDepth));
672 }
673 }
674 LOG_STEP(("stepControl_handleStep: finished"));
675 }
676done:
677 if (completed) {
678 completeStep(env, thread, step);
679 }
680 stepControl_unlock();
681 return completed;
682}
683
684
685void
686stepControl_initialize(void)
687{
688 stepLock = debugMonitorCreate("JDWP Step Handler Lock");
689}
690
691void
692stepControl_reset(void)
693{
694}
695
696/*
697 * Reset step control request stack depth and line number.
698 */
699void
700stepControl_resetRequest(jthread thread)
701{
702
703 StepRequest *step;
704 jvmtiError error;
705
706 LOG_STEP(("stepControl_resetRequest: thread=%p", thread));
707
708 stepControl_lock();
709
710 step = threadControl_getStepRequest(thread);
711
712 if (step != NULL) {
713 JNIEnv *env;
714 env = getEnv();
715 error = initState(env, thread, step);
716 if (error != JVMTI_ERROR_NONE) {
717 EXIT_ERROR(error, "initializing step state");
718 }
719 } else {
720 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting step request");
721 }
722
723 stepControl_unlock();
724}
725
726static void
727initEvents(jthread thread, StepRequest *step)
728{
729 /* Need to install frame pop handler and exception catch handler when
730 * single-stepping is enabled (i.e. step-into or step-over/step-out
731 * when fromStackDepth > 0).
732 */
733 if (step->depth == JDWP_STEP_DEPTH(INTO) || step->fromStackDepth > 0) {
734 /*
735 * TO DO: These might be able to applied more selectively to
736 * boost performance.
737 */
738 step->catchHandlerNode = eventHandler_createInternalThreadOnly(
739 EI_EXCEPTION_CATCH,
740 handleExceptionCatchEvent,
741 thread);
742 step->framePopHandlerNode = eventHandler_createInternalThreadOnly(
743 EI_FRAME_POP,
744 handleFramePopEvent,
745 thread);
746
747 if (step->catchHandlerNode == NULL ||
748 step->framePopHandlerNode == NULL) {
749 EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,
750 "installing step event handlers");
751 }
752
753 }
754 /*
755 * Initially enable stepping:
756 * 1) For step into, always
757 * 2) For step over, unless right after the VM_INIT.
758 * Enable stepping for STEP_MIN or STEP_LINE with or without line numbers.
759 * If the class is redefined then non EMCP methods may not have line
760 * number info. So enable line stepping for non line number so that it
761 * behaves like STEP_MIN/STEP_OVER.
762 * 3) For step out, only if stepping from native, except right after VM_INIT
763 *
764 * (right after VM_INIT, a step->over or out is identical to running
765 * forever)
766 */
767 switch (step->depth) {
768 case JDWP_STEP_DEPTH(INTO):
769 enableStepping(thread);
770 break;
771 case JDWP_STEP_DEPTH(OVER):
772 if (step->fromStackDepth > 0 && !step->fromNative ) {
773 enableStepping(thread);
774 }
775 break;
776 case JDWP_STEP_DEPTH(OUT):
777 if (step->fromNative &&
778 (step->fromStackDepth > 0)) {
779 enableStepping(thread);
780 }
781 break;
782 default:
783 JDI_ASSERT(JNI_FALSE);
784 }
785}
786
787jvmtiError
788stepControl_beginStep(JNIEnv *env, jthread thread, jint size, jint depth,
789 HandlerNode *node)
790{
791 StepRequest *step;
792 jvmtiError error;
793 jvmtiError error2;
794
795 LOG_STEP(("stepControl_beginStep: thread=%p,size=%d,depth=%d",
796 thread, size, depth));
797
798 eventHandler_lock(); /* for proper lock order */
799 stepControl_lock();
800
801 step = threadControl_getStepRequest(thread);
802 if (step == NULL) {
803 error = AGENT_ERROR_INVALID_THREAD;
804 /* Normally not getting a StepRequest struct pointer is a fatal error
805 * but on a beginStep, we just return an error code.
806 */
807 } else {
808 /*
809 * In case the thread isn't already suspended, do it again.
810 */
811 error = threadControl_suspendThread(thread, JNI_FALSE);
812 if (error == JVMTI_ERROR_NONE) {
813 /*
814 * Overwrite any currently executing step.
815 */
816 step->granularity = size;
817 step->depth = depth;
818 step->catchHandlerNode = NULL;
819 step->framePopHandlerNode = NULL;
820 step->methodEnterHandlerNode = NULL;
821 step->stepHandlerNode = node;
822 error = initState(env, thread, step);
823 if (error == JVMTI_ERROR_NONE) {
824 initEvents(thread, step);
825 }
826 /* false means it is not okay to unblock the commandLoop thread */
827 error2 = threadControl_resumeThread(thread, JNI_FALSE);
828 if (error2 != JVMTI_ERROR_NONE && error == JVMTI_ERROR_NONE) {
829 error = error2;
830 }
831
832 /*
833 * If everything went ok, indicate a step is pending.
834 */
835 if (error == JVMTI_ERROR_NONE) {
836 step->pending = JNI_TRUE;
837 }
838 } else {
839 EXIT_ERROR(error, "stepControl_beginStep: cannot suspend thread");
840 }
841 }
842
843 stepControl_unlock();
844 eventHandler_unlock();
845
846 return error;
847}
848
849
850static void
851clearStep(jthread thread, StepRequest *step)
852{
853 if (step->pending) {
854
855 disableStepping(thread);
856 if ( step->catchHandlerNode != NULL ) {
857 (void)eventHandler_free(step->catchHandlerNode);
858 step->catchHandlerNode = NULL;
859 }
860 if ( step->framePopHandlerNode!= NULL ) {
861 (void)eventHandler_free(step->framePopHandlerNode);
862 step->framePopHandlerNode = NULL;
863 }
864 if ( step->methodEnterHandlerNode != NULL ) {
865 (void)eventHandler_free(step->methodEnterHandlerNode);
866 step->methodEnterHandlerNode = NULL;
867 }
868 step->pending = JNI_FALSE;
869
870 /*
871 * Warning: Do not clear step->method, step->lineEntryCount,
872 * or step->lineEntries here, they will likely
873 * be needed on the next step.
874 */
875
876 }
877}
878
879jvmtiError
880stepControl_endStep(jthread thread)
881{
882 StepRequest *step;
883 jvmtiError error;
884
885 LOG_STEP(("stepControl_endStep: thread=%p", thread));
886
887 eventHandler_lock(); /* for proper lock order */
888 stepControl_lock();
889
890 step = threadControl_getStepRequest(thread);
891 if (step != NULL) {
892 clearStep(thread, step);
893 error = JVMTI_ERROR_NONE;
894 } else {
895 /* If the stepRequest can't be gotten, then this thread no longer
896 * exists, just return, don't die here, this is normal at
897 * termination time. Return JVMTI_ERROR_NONE so the thread Ref
898 * can be tossed.
899 */
900 error = JVMTI_ERROR_NONE;
901 }
902
903 stepControl_unlock();
904 eventHandler_unlock();
905
906 return error;
907}
908
909void
910stepControl_clearRequest(jthread thread, StepRequest *step)
911{
912 LOG_STEP(("stepControl_clearRequest: thread=%p", thread));
913 clearStep(thread, step);
914}
915
916void
917stepControl_lock(void)
918{
919 debugMonitorEnter(stepLock);
920}
921
922void
923stepControl_unlock(void)
924{
925 debugMonitorExit(stepLock);
926}