Fix step out for recursive functions.

When asked to step out, we now store the frame pointer of the current
stack frame. Upon hitting our temporary breakpoint, we then verify that
the current frame pointer is in fact in the previous frame. If not, we
reinstate the breakpoint and continue running.
This commit is contained in:
Rene Gollent
2011-12-11 22:32:42 -05:00
parent 12b1aa817a
commit 673c1e4d07
2 changed files with 23 additions and 7 deletions
+22 -7
View File
@@ -1,6 +1,6 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2010, Rene Gollent, [email protected].
* Copyright 2010-2011, Rene Gollent, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -22,6 +22,7 @@
#include "InstructionInfo.h"
#include "Jobs.h"
#include "MessageCodes.h"
#include "Register.h"
#include "SourceCode.h"
#include "SpecificImageDebugInfo.h"
#include "StackTrace.h"
@@ -52,6 +53,7 @@ ThreadHandler::ThreadHandler(Thread* thread, Worker* worker,
fStepStatement(NULL),
fBreakpointAddress(0),
fPreviousInstructionPointer(0),
fPreviousFrameAddress(0),
fSingleStepping(false)
{
fDebuggerInterface->AcquireReference();
@@ -294,16 +296,12 @@ ThreadHandler::HandleThreadAction(uint32 action)
// For "step out" just set a temporary breakpoint on the return address.
if (action == MSG_THREAD_STEP_OUT) {
// TODO: That's OK in principle, but needs additional work with recursive
// functions. We need to store some information that allows us to determine
// whether we've actually stepped out of the current frame when we have hit
// the breakpoint.
status_t error = _InstallTemporaryBreakpoint(frame->ReturnAddress());
if (error != B_OK) {
_StepFallback();
return;
}
fPreviousFrameAddress = frame->FrameAddress();
fStepMode = STEP_OUT;
_RunThread(frame->GetCpuState()->InstructionPointer());
return;
@@ -571,8 +569,25 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState)
case STEP_INTO:
// Should never happen -- we don't set a breakpoint in this case.
return false;
case STEP_OUT:
// That's the return address, so we're done.
{
// That's the return address, so we're done in theory,
// unless we're a recursive function. Check if we've actually
// exited the previous stack frame or not.
if (cpuState->StackFramePointer() <= fPreviousFrameAddress) {
status_t error = _InstallTemporaryBreakpoint(
cpuState->InstructionPointer());
if (error != B_OK)
_StepFallback();
else
_RunThread(cpuState->InstructionPointer());
return true;
}
fPreviousFrameAddress = 0;
}
default:
return false;
}
+1
View File
@@ -100,6 +100,7 @@ private:
Statement* fStepStatement;
target_addr_t fBreakpointAddress;
target_addr_t fPreviousInstructionPointer;
target_addr_t fPreviousFrameAddress;
bool fSingleStepping;
public: