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