• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1998, 2005, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * 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 
33 static jrawMonitorID stepLock;
34 
35 static jint
getFrameCount(jthread thread)36 getFrameCount(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  */
61 static void
enableStepping(jthread thread)62 enableStepping(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 
75 static void
disableStepping(jthread thread)76 disableStepping(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 
89 static jvmtiError
getFrameLocation(jthread thread,jclass * pclazz,jmethodID * pmethod,jlocation * plocation)90 getFrameLocation(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 
108 static void
getLineNumberTable(jmethodID method,jint * pcount,jvmtiLineNumberEntry ** ptable)109 getLineNumberTable(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 
129 static jint
findLineNumber(jthread thread,jlocation location,jvmtiLineNumberEntry * lines,jint count)130 findLineNumber(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 
150 static jboolean
hasLineNumbers(jmethodID method)151 hasLineNumbers(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 
165 static jvmtiError
initState(JNIEnv * env,jthread thread,StepRequest * step)166 initState(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  */
260 static void
handleFramePopEvent(JNIEnv * env,EventInfo * evinfo,HandlerNode * node,struct bag * eventBag)261 handleFramePopEvent(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 
363 static void
handleExceptionCatchEvent(JNIEnv * env,EventInfo * evinfo,HandlerNode * node,struct bag * eventBag)364 handleExceptionCatchEvent(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 
430 static void
handleMethodEnterEvent(JNIEnv * env,EventInfo * evinfo,HandlerNode * node,struct bag * eventBag)431 handleMethodEnterEvent(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 
485 static void
completeStep(JNIEnv * env,jthread thread,StepRequest * step)486 completeStep(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 
511 jboolean
stepControl_handleStep(JNIEnv * env,jthread thread,jclass clazz,jmethodID method)512 stepControl_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     }
676 done:
677     if (completed) {
678         completeStep(env, thread, step);
679     }
680     stepControl_unlock();
681     return completed;
682 }
683 
684 
685 void
stepControl_initialize(void)686 stepControl_initialize(void)
687 {
688     stepLock = debugMonitorCreate("JDWP Step Handler Lock");
689 }
690 
691 void
stepControl_reset(void)692 stepControl_reset(void)
693 {
694 }
695 
696 /*
697  * Reset step control request stack depth and line number.
698  */
699 void
stepControl_resetRequest(jthread thread)700 stepControl_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 
726 static void
initEvents(jthread thread,StepRequest * step)727 initEvents(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 
787 jvmtiError
stepControl_beginStep(JNIEnv * env,jthread thread,jint size,jint depth,HandlerNode * node)788 stepControl_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 
850 static void
clearStep(jthread thread,StepRequest * step)851 clearStep(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 
879 jvmtiError
stepControl_endStep(jthread thread)880 stepControl_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 
909 void
stepControl_clearRequest(jthread thread,StepRequest * step)910 stepControl_clearRequest(jthread thread, StepRequest *step)
911 {
912     LOG_STEP(("stepControl_clearRequest: thread=%p", thread));
913     clearStep(thread, step);
914 }
915 
916 void
stepControl_lock(void)917 stepControl_lock(void)
918 {
919     debugMonitorEnter(stepLock);
920 }
921 
922 void
stepControl_unlock(void)923 stepControl_unlock(void)
924 {
925     debugMonitorExit(stepLock);
926 }
927