/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "util.h"
#include "stepControl.h"
#include "eventHandler.h"
#include "eventHelper.h"
#include "threadControl.h"
#include "SDE.h"
static jint
{
if (error != JVMTI_ERROR_NONE) {
}
return count;
}
/*
* the inserting and freeing of handlers for those events. Stepping is
* different because requested steps are usually not identical to JVMTI steps.
* They usually require multiple events step, and otherwise, before they
* complete. While a step request is pending, we may need to temporarily
* disable and re-enable stepping, but we can't just remove the handlers
* because that would break the application's ability to remove the
* events. So, for step events only, we directly enable and disable stepping.
* This is safe because there can only ever be one pending step request
* per thread.
*/
static void
{
thread);
if (error != JVMTI_ERROR_NONE) {
}
}
static void
{
thread);
if (error != JVMTI_ERROR_NONE) {
}
}
static jvmtiError
{
*plocation = -1;
/* This also serves to verify that the methodID is valid */
}
return error;
}
static void
{
*pcount = 0;
/* If the method is native or obsolete, don't even ask for the line table */
return;
}
if (error != JVMTI_ERROR_NONE) {
*pcount = 0;
}
}
static jint
{
if (location != -1) {
if (count > 0) {
jint i;
/* any preface before first line is assigned to first line */
for (i=1; i<count; i++) {
break;
}
}
}
}
return line;
}
static jboolean
{
if ( count == 0 ) {
return JNI_FALSE;
} else {
}
return JNI_TRUE;
}
static jvmtiError
{
/*
* Initial values that may be changed below
*/
if (step->fromStackDepth <= 0) {
/*
* If there are no stack frames, treat the step as though
* from a native frame. This is most likely to occur at the
* beginning of a debug session, right after the VM_INIT event,
* so we need to do something intelligent.
*/
return JVMTI_ERROR_NONE;
}
/*
* Try to get a notification on frame pop. If we're in an opaque frame
* we won't be able to, but we can use other methods to detect that
* a native frame has exited.
*
* TO DO: explain the need for this notification.
*/
if (error == JVMTI_ERROR_OPAQUE_FRAME) {
/* continue without error */
} else if (error == JVMTI_ERROR_DUPLICATE) {
/* Already being notified, continue without error */
} else if (error != JVMTI_ERROR_NONE) {
return error;
}
/*
* Note: we can't undo the frame pop notify, so
* we'll just have to let the handler ignore it if
* there are any errors below.
*/
LOG_STEP(("initState(): Begin line step"));
if (error == JVMTI_ERROR_NONE) {
/* Clear out previous line table only if we changed methods */
step->lineEntryCount = 0;
}
if (step->lineEntryCount > 0) {
}
}
}
}
return error;
}
/*
* TO DO: The step handlers (handleFrameChange and handleStep can
* be broken down and made simpler now that we can install and de-install event
* handlers.
*/
static void
{
}
/*
* Note: current depth is reported as *before* the pending frame
* pop.
*/
LOG_STEP(("handleFramePopEvent: BEGIN fromDepth=%d, currentDepth=%d",
/*
* If we are exiting the original stepping frame, record that
* fact here. Once the next step event comes in, we can safely
* stop stepping there.
*/
if (fromDepth > afterPopDepth ) {
}
/*
* Either
* 1) the original stepping frame is about to be popped
* [fromDepth == currentDepth]. Re-enable stepping to
* reach a point where we can stop.
* 2) a method called from the stepping frame has returned
* (during which we had stepping disabled)
* [fromDepth == currentDepth - 1]. Re-enable stepping
* so that we can continue instructions steps in the
* original stepping frame.
* 3) a method further down the call chain has notified
* of a frame pop [fromDepth < currentDepth - 1]. This
* *might* represent case (2) above if the stepping frame
* was calling a native method which in turn called a
* java method. If so, we must enable stepping to
* ensure that we get control back after the intervening
* native frame is popped (you can't get frame pop
* notifications on native frames). If the native caller
* calls another Java method before returning,
* stepping will be diabled again and another frame pop
* will be awaited.
*
* If it turns out that this is not case (2) with native
* methods, then the enabled stepping is benign and
* will be disabled again on the next step event.
*
* Note that the condition not covered above,
* [fromDepth > currentDepth] shouldn't happen since it means
* that too many frames have been popped. For robustness,
* we enable stepping in that case too, so that the errant
* step-over can be stopped.
*
*/
LOG_STEP(("handleFramePopEvent: starting singlestep, depth==OVER"));
fromDepth > afterPopDepth) {
/*
* The original stepping frame is about to be popped. Step
* until we reach the next safe place to stop.
*/
LOG_STEP(("handleFramePopEvent: starting singlestep, depth==OUT && fromDepth > afterPopDepth (%d>%d)",fromDepth, afterPopDepth));
fromDepth >= afterPopDepth) {
/*
* We installed a method entry event handler as part of a
* step into operation. We've popped back to the original
* stepping frame without finding a place to stop.
* Resume stepping in the original frame.
*/
LOG_STEP(("handleFramePopEvent: starting singlestep, have methodEnter handler && depth==OUT && fromDepth >= afterPopDepth (%d>%d)",fromDepth, afterPopDepth));
}
LOG_STEP(("handleFramePopEvent: finished"));
}
}
static void
{
}
/*
* Determine where we are on the call stack relative to where
* we started.
*/
LOG_STEP(("handleExceptionCatchEvent: fromDepth=%d, currentDepth=%d",
/*
* If we are exiting the original stepping frame, record that
* fact here. Once the next step event comes in, we can safely
* stop stepping there.
*/
if (fromDepth > currentDepth) {
}
fromDepth >= currentDepth) {
/*
* Either the original stepping frame is done,
* or a called method has returned (during which we had stepping
* disabled). In either case we must resume stepping.
*/
fromDepth > currentDepth) {
/*
* The original stepping frame is done. Step
* until we reach the next safe place to stop.
*/
fromDepth >= currentDepth) {
/*
* We installed a method entry event handler as part of a
* step into operation. We've popped back to the original
* stepping frame or higher without finding a place to stop.
* Resume stepping in the original frame.
*/
}
}
}
static void
{
}
char *classname;
/*
* This handler is relevant only to step into
*/
|| hasLineNumbers(method) ) ) {
/*
* We've found a suitable method in which to stop. Step
* until we reach the next safe location to complete the step->,
* and we can get rid of the method entry handler.
*/
}
}
}
}
static void
{
/*
* We've completed a step; reset state for the next one, if any
*/
}
if (error != JVMTI_ERROR_NONE) {
/*
* None of the initState errors should happen after one step
* has successfully completed.
*/
}
}
{
char *classname;
}
/*
* If no step is currently pending, ignore the event
*/
goto done;
}
/*
* We never filter step into instruction. It's always over on the
* first step event.
*/
LOG_STEP(("stepControl_handleStep: completed, into min"));
goto done;
}
/*
* If we have left the method in which
* stepping started, the step is always complete.
*/
if (step->frameExited) {
LOG_STEP(("stepControl_handleStep: completed, frame exited"));
goto done;
}
/*
* Determine where we are on the call stack relative to where
* we started.
*/
if (fromDepth > currentDepth) {
/*
* We have returned from the caller. There are cases where
* we don't get frame pop notifications
* (e.g. stepping from opaque frames), and that's when
* this code will be reached. Complete the step->
*/
LOG_STEP(("stepControl_handleStep: completed, fromDepth>currentDepth(%d>%d)", fromDepth, currentDepth));
} else if (fromDepth < currentDepth) {
/* We have dropped into a called method. */
&& hasLineNumbers(method) ) {
/* Stepped into a method with lines, so we're done */
LOG_STEP(("stepControl_handleStep: completed, fromDepth<currentDepth(%d<%d) and into method with lines", fromDepth, currentDepth));
} else {
/*
* We need to continue, but don't want the overhead of step
* events from this method. So, we disable stepping and
* enable a frame pop. If we're stepping into, we also
* enable method enter events because a called frame may be
* where we want to stop.
*/
"installing event method enter handler");
}
}
if (error == JVMTI_ERROR_DUPLICATE) {
} else if (error != JVMTI_ERROR_NONE) {
}
}
} else {
/*
* We are at the same stack depth where stepping started.
* Instruction steps are complete at this point. For line
* steps we must check to see whether we've moved to a
* different line.
*/
} else {
if ( isMethodObsolete(method)) {
location = -1;
}
}
LOG_STEP(("stepControl_handleStep: checking line location"));
log_debugee_location("stepControl_handleStep: checking line loc",
}
LOG_STEP(("stepControl_handleStep: completed, fromDepth==currentDepth(%d) and different line", fromDepth));
}
} else {
/*
* This is a rare case. We have stepped from a location
* inside a native method to a location within a Java
* method at the same stack depth. This means that
* the original native method returned to another
* native method which, in turn, invoked a Java method.
*
* Since the original frame was native, we were unable
* to ask for a frame pop event, and, thus, could not
* set the step->frameExited flag when the original
* method was done. Instead we end up here
* and act just as though the frameExited flag was set
* and complete the step immediately.
*/
LOG_STEP(("stepControl_handleStep: completed, fromDepth==currentDepth(%d) and no line", fromDepth));
}
}
LOG_STEP(("stepControl_handleStep: finished"));
}
done:
if (completed) {
}
return completed;
}
void
stepControl_initialize(void)
{
}
void
stepControl_reset(void)
{
}
/*
* Reset step control request stack depth and line number.
*/
void
{
if (error != JVMTI_ERROR_NONE) {
}
} else {
}
}
static void
{
/* Need to install frame pop handler and exception catch handler when
* when fromStackDepth > 0).
*/
/*
* TO DO: These might be able to applied more selectively to
* boost performance.
*/
thread);
thread);
"installing step event handlers");
}
}
/*
* Initially enable stepping:
* 1) For step into, always
* 2) For step over, unless right after the VM_INIT.
* Enable stepping for STEP_MIN or STEP_LINE with or without line numbers.
* If the class is redefined then non EMCP methods may not have line
* number info. So enable line stepping for non line number so that it
* 3) For step out, only if stepping from native, except right after VM_INIT
*
* (right after VM_INIT, a step->over or out is identical to running
* forever)
*/
case JDWP_STEP_DEPTH(INTO):
break;
}
break;
if (step->fromNative &&
(step->fromStackDepth > 0)) {
}
break;
default:
}
}
{
LOG_STEP(("stepControl_beginStep: thread=%p,size=%d,depth=%d",
eventHandler_lock(); /* for proper lock order */
/* Normally not getting a StepRequest struct pointer is a fatal error
* but on a beginStep, we just return an error code.
*/
} else {
/*
* In case the thread isn't already suspended, do it again.
*/
if (error == JVMTI_ERROR_NONE) {
/*
* Overwrite any currently executing step.
*/
if (error == JVMTI_ERROR_NONE) {
}
/* false means it is not okay to unblock the commandLoop thread */
}
/*
* If everything went ok, indicate a step is pending.
*/
if (error == JVMTI_ERROR_NONE) {
}
} else {
}
}
return error;
}
static void
{
}
}
}
/*
* Warning: Do not clear step->method, step->lineEntryCount,
* or step->lineEntries here, they will likely
* be needed on the next step.
*/
}
}
{
eventHandler_lock(); /* for proper lock order */
} else {
/* If the stepRequest can't be gotten, then this thread no longer
* exists, just return, don't die here, this is normal at
* termination time. Return JVMTI_ERROR_NONE so the thread Ref
* can be tossed.
*/
}
return error;
}
void
{
}
void
stepControl_lock(void)
{
}
void
stepControl_unlock(void)
{
}