Refactoring to handle multiple return values.

- Replace use of address + CpuState pair in Thread,
  SpecificImageDebugInfo::CreateStackTrace() with a ReturnValueInfoList.
  Adjust all implementing subclasses and callers accordingly.

- DwarfImageDebugInfo::CreateReturnValue() -> CreateReturnValues().
  Now processes a list of return value information structures rather
  than just a single one. This means we can now handle multiple return
  values in a single statement. This still isn't entirely correct though,
  since, e.g. for functions whose return types fit in a register we need
  to either retrieve them immediately after function return, or store the
  CPU state at that point in time for later use in value retrieval,
  otherwise the return values will all be those of the last called function.
This commit is contained in:
Rene Gollent 2013-03-27 23:21:42 -04:00
parent 3fa429781c
commit 76ed6d72a5
12 changed files with 167 additions and 140 deletions

View File

@ -144,6 +144,7 @@ Application Debugger :
FileSourceCode.cpp
Image.cpp
ImageInfo.cpp
ReturnValueInfo.cpp
SourceCode.cpp
StackFrame.cpp
StackFrameValues.cpp
@ -151,7 +152,6 @@ Application Debugger :
StackTrace.cpp
Statement.cpp
SymbolInfo.cpp
UserBreakpoint.cpp
Team.cpp
TeamMemory.cpp
TeamMemoryBlock.cpp
@ -161,6 +161,7 @@ Application Debugger :
Type.cpp
TypeComponentPath.cpp
TypeLookupConstraints.cpp
UserBreakpoint.cpp
Variable.cpp
Watchpoint.cpp

View File

@ -94,9 +94,8 @@ Architecture::InitRegisterRules(CfaContext& context) const
status_t
Architecture::CreateStackTrace(Team* team,
ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState,
StackTrace*& _stackTrace, target_addr_t returnFunctionAddress,
CpuState* returnFunctionState, int32 maxStackDepth, bool useExistingTrace,
bool getFullFrameInfo)
StackTrace*& _stackTrace, ReturnValueInfoList* returnValueInfos,
int32 maxStackDepth, bool useExistingTrace, bool getFullFrameInfo)
{
BReference<CpuState> cpuStateReference(cpuState);
@ -164,8 +163,8 @@ Architecture::CreateStackTrace(Team* team,
if (function != NULL) {
status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
->CreateFrame(image, function, cpuState, getFullFrameInfo,
nextFrame == NULL ? returnFunctionAddress : 0,
nextFrame == NULL ? returnFunctionState : 0, frame,
nextFrame == NULL
? returnValueInfos : NULL, frame,
previousCpuState);
if (error != B_OK && error != B_UNSUPPORTED)
break;
@ -174,8 +173,7 @@ Architecture::CreateStackTrace(Team* team,
// If we have no frame yet, let the architecture create it.
if (frame == NULL) {
status_t error = CreateStackFrame(image, functionDebugInfo,
cpuState, nextFrame == NULL, frame,
previousCpuState);
cpuState, nextFrame == NULL, frame, previousCpuState);
if (error != B_OK)
break;
}

View File

@ -13,6 +13,7 @@
#include <Referenceable.h>
#include <Variant.h>
#include "ReturnValueInfo.h"
#include "Types.h"
@ -110,8 +111,7 @@ public:
ImageDebugInfoProvider* imageInfoProvider,
CpuState* cpuState,
StackTrace*& _stackTrace,
target_addr_t returnFunctionAddress,
CpuState* returnFunctionState,
ReturnValueInfoList* returnValueInfos,
int32 maxStackDepth = -1,
bool useExistingTrace = false,
bool getFullFrameInfo = true);

View File

@ -253,7 +253,7 @@ ThreadHandler::HandleThreadAction(uint32 action)
if (stackTrace == NULL && cpuState != NULL) {
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
fThread->GetTeam(), this, cpuState, stackTrace, 0, NULL, 1,
fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1,
false, false) == B_OK) {
stackTraceReference.SetTo(stackTrace, true);
}
@ -484,11 +484,20 @@ ThreadHandler::_DoStepOver(CpuState* cpuState)
TRACE_CONTROL(" subroutine call -- installing breakpoint at address "
"%#" B_PRIx64 "\n", info.Address() + info.Size());
fThread->SetExecutedSubroutine(info.TargetAddress());
fThread->SetSubroutineCpuState(cpuState);
if (_InstallTemporaryBreakpoint(info.Address() + info.Size()) != B_OK)
return false;
ReturnValueInfo* returnInfo = new(std::nothrow) ReturnValueInfo(
info.TargetAddress(), cpuState);
if (returnInfo == NULL)
return false;
BReference<ReturnValueInfo> returnInfoReference(returnInfo, true);
if (fThread->AddReturnValueInfo(returnInfo) != B_OK)
return false;
returnInfoReference.Detach();
_RunThread(cpuState->InstructionPointer());
return true;
}
@ -567,8 +576,8 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState)
if (stackTrace == NULL && cpuState != NULL) {
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
fThread->GetTeam(), this, cpuState, stackTrace, 0,
NULL, 1, false, false) == B_OK) {
fThread->GetTeam(), this, cpuState, stackTrace, NULL,
1, false, false) == B_OK) {
stackTraceReference.SetTo(stackTrace, true);
}
}
@ -608,8 +617,16 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState)
{
// 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.
fThread->SetExecutedSubroutine(cpuState->InstructionPointer());
// exited the previous stack frame or not
ReturnValueInfo* info = new(std::nothrow) ReturnValueInfo(
cpuState->InstructionPointer(), cpuState);
if (info == NULL)
return false;
BReference<ReturnValueInfo> infoReference(info, true);
if (fThread->AddReturnValueInfo(info) != B_OK)
return false;
infoReference.Detach();
target_addr_t framePointer = cpuState->StackFramePointer();
bool hasExitedFrame = fDebuggerInterface->GetArchitecture()
->StackGrowthDirection() == STACK_GROWTH_DIRECTION_POSITIVE
@ -654,8 +671,8 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
if (stackTrace == NULL && cpuState != NULL) {
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
fThread->GetTeam(), this, cpuState, stackTrace, 0,
NULL, 1, false, false) == B_OK) {
fThread->GetTeam(), this, cpuState, stackTrace, NULL,
1, false, false) == B_OK) {
stackTraceReference.SetTo(stackTrace, true);
}
}
@ -686,7 +703,7 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
BReference<StackTrace> stackTraceReference(stackTrace);
if (stackTrace == NULL && cpuState != NULL) {
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
fThread->GetTeam(), this, cpuState, stackTrace, 0,
fThread->GetTeam(), this, cpuState, stackTrace,
NULL, 1, false, false) == B_OK) {
stackTraceReference.SetTo(stackTrace, true);
}
@ -694,8 +711,15 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
if (stackTrace != NULL && stackTrace->FrameAt(0)
->FrameAddress() != fPreviousFrameAddress) {
fThread->SetExecutedSubroutine(
cpuState->InstructionPointer());
ReturnValueInfo* info = new(std::nothrow) ReturnValueInfo(
cpuState->InstructionPointer(), cpuState);
if (info == NULL)
return false;
BReference<ReturnValueInfo> infoReference(info, true);
if (fThread->AddReturnValueInfo(info) != B_OK)
return false;
infoReference.Detach();
}
return false;

View File

@ -68,9 +68,8 @@ DebuggerImageDebugInfo::GetAddressSectionType(target_addr_t address)
status_t
DebuggerImageDebugInfo::CreateFrame(Image* image,
FunctionInstance* functionInstance, CpuState* cpuState,
bool getFullFrameInfo, target_addr_t returnFunctionAddress,
CpuState* returnFunctionState, StackFrame*& _previousFrame,
CpuState*& _previousCpuState)
bool getFullFrameInfo, ReturnValueInfoList* returnValueInfos,
StackFrame*& _previousFrame, CpuState*& _previousCpuState)
{
return B_UNSUPPORTED;
}

View File

@ -36,8 +36,7 @@ public:
FunctionInstance* functionInstance,
CpuState* cpuState,
bool getFullFrameInfo,
target_addr_t returnFunctionAddress,
CpuState* returnFunctionState,
ReturnValueInfoList* returnValueInfos,
StackFrame*& _previousFrame,
CpuState*& _previousCpuState);
virtual status_t GetStatement(FunctionDebugInfo* function,

View File

@ -522,9 +522,8 @@ DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address)
status_t
DwarfImageDebugInfo::CreateFrame(Image* image,
FunctionInstance* functionInstance, CpuState* cpuState,
bool getFullFrameInfo, target_addr_t returnFunctionAddress,
CpuState* returnFunctionState, StackFrame*& _frame,
CpuState*& _previousCpuState)
bool getFullFrameInfo, ReturnValueInfoList* returnValueInfos,
StackFrame*& _frame, CpuState*& _previousCpuState)
{
DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
functionInstance->GetFunctionDebugInfo());
@ -674,9 +673,9 @@ DwarfImageDebugInfo::CreateFrame(Image* image,
instructionPointer, functionInstance->Address() - fRelocationDelta,
subprogramEntry->Variables(), subprogramEntry->Blocks());
if (returnFunctionAddress != 0) {
_CreateReturnValue(returnFunctionAddress, returnFunctionState,
image, frame, *stackFrameDebugInfo);
if (!returnValueInfos->IsEmpty()) {
_CreateReturnValues(returnValueInfos, image, frame,
*stackFrameDebugInfo);
}
}
@ -1087,88 +1086,94 @@ DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit,
status_t
DwarfImageDebugInfo::_CreateReturnValue(target_addr_t returnFunctionAddress,
CpuState* returnFunctionState, Image* image, StackFrame* frame,
DwarfStackFrameDebugInfo& factory)
DwarfImageDebugInfo::_CreateReturnValues(ReturnValueInfoList* returnValueInfos,
Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory)
{
if (!image->ContainsAddress(returnFunctionAddress)) {
// our current image doesn't contain the target function,
// locate the one which does.
image = image->GetTeam()->ImageByAddress(returnFunctionAddress);
if (image == NULL)
return B_BAD_VALUE;
}
status_t result = B_OK;
ImageDebugInfo* imageInfo = image->GetImageDebugInfo();
FunctionInstance* targetFunction;
if (returnFunctionAddress >= fPLTSectionStart
&& returnFunctionAddress < fPLTSectionEnd) {
// if the function in question is position-independent, the call
// will actually have taken us to its corresponding PLT slot.
// in such a case, look at the disassembled jump to determine
// where to find the actual function address.
InstructionInfo info;
if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo(
returnFunctionAddress, info, returnFunctionState) != B_OK) {
return B_BAD_VALUE;
for (int32 i = 0; i < returnValueInfos->CountItems(); i++) {
ReturnValueInfo* valueInfo = returnValueInfos->ItemAt(i);
target_addr_t subroutineAddress = valueInfo->SubroutineAddress();
CpuState* subroutineState = valueInfo->State();
if (!image->ContainsAddress(subroutineAddress)) {
// our current image doesn't contain the target function,
// locate the one which does.
image = image->GetTeam()->ImageByAddress(subroutineAddress);
if (image == NULL) {
// nothing we can do, try the next entry (if any)
continue;
}
}
target_size_t addressSize = fDebuggerInterface->GetArchitecture()
->AddressSize();
ssize_t bytesRead = fDebuggerInterface->ReadMemory(info.TargetAddress(),
&returnFunctionAddress, addressSize);
if (bytesRead != (ssize_t)addressSize)
return B_BAD_VALUE;
}
targetFunction = imageInfo->FunctionAtAddress(returnFunctionAddress);
if (targetFunction != NULL) {
DwarfFunctionDebugInfo* targetInfo =
dynamic_cast<DwarfFunctionDebugInfo*>(
targetFunction->GetFunctionDebugInfo());
if (targetInfo != NULL) {
DIESubprogram* subProgram = targetInfo->SubprogramEntry();
DIEType* returnType = subProgram->ReturnType();
if (returnType == NULL) {
// check if we have a specification, and if so, if that has
// a return type
subProgram = dynamic_cast<DIESubprogram*>(subProgram->Specification());
if (subProgram != NULL)
returnType = subProgram->ReturnType();
// function doesn't return a value, we're done.
if (returnType == NULL)
return B_OK;
status_t result = B_OK;
ImageDebugInfo* imageInfo = image->GetImageDebugInfo();
FunctionInstance* targetFunction;
if (subroutineAddress >= fPLTSectionStart
&& subroutineAddress < fPLTSectionEnd) {
// if the function in question is position-independent, the call
// will actually have taken us to its corresponding PLT slot.
// in such a case, look at the disassembled jump to determine
// where to find the actual function address.
InstructionInfo info;
if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo(
subroutineAddress, info, subroutineState) != B_OK) {
return B_BAD_VALUE;
}
uint32 byteSize = 0;
if (returnType->ByteSize() == NULL) {
if (dynamic_cast<DIEAddressingType*>(returnType) != NULL)
byteSize = fArchitecture->AddressSize();
} else
byteSize = returnType->ByteSize()->constant;
target_size_t addressSize = fDebuggerInterface->GetArchitecture()
->AddressSize();
ssize_t bytesRead = fDebuggerInterface->ReadMemory(
info.TargetAddress(), &subroutineAddress, addressSize);
ValueLocation* location;
result = fArchitecture->GetReturnAddressLocation(frame,
byteSize, location);
if (result != B_OK)
return result;
if (bytesRead != (ssize_t)addressSize)
return B_BAD_VALUE;
}
BReference<ValueLocation> locationReference(location, true);
Variable* variable = NULL;
BReference<FunctionID> idReference(
targetFunction->GetFunctionID(), true);
result = factory.CreateReturnValue(idReference, returnType,
location, variable);
if (result != B_OK)
return result;
targetFunction = imageInfo->FunctionAtAddress(subroutineAddress);
if (targetFunction != NULL) {
DwarfFunctionDebugInfo* targetInfo =
dynamic_cast<DwarfFunctionDebugInfo*>(
targetFunction->GetFunctionDebugInfo());
if (targetInfo != NULL) {
DIESubprogram* subProgram = targetInfo->SubprogramEntry();
DIEType* returnType = subProgram->ReturnType();
if (returnType == NULL) {
// check if we have a specification, and if so, if that has
// a return type
subProgram = dynamic_cast<DIESubprogram*>(
subProgram->Specification());
if (subProgram != NULL)
returnType = subProgram->ReturnType();
BReference<Variable> variableReference(variable, true);
if (!frame->AddLocalVariable(variable))
return B_NO_MEMORY;
// function doesn't return a value, we're done.
if (returnType == NULL)
return B_OK;
}
uint32 byteSize = 0;
if (returnType->ByteSize() == NULL) {
if (dynamic_cast<DIEAddressingType*>(returnType) != NULL)
byteSize = fArchitecture->AddressSize();
} else
byteSize = returnType->ByteSize()->constant;
ValueLocation* location;
result = fArchitecture->GetReturnAddressLocation(frame,
byteSize, location);
if (result != B_OK)
return result;
BReference<ValueLocation> locationReference(location, true);
Variable* variable = NULL;
BReference<FunctionID> idReference(
targetFunction->GetFunctionID(), true);
result = factory.CreateReturnValue(idReference, returnType,
location, variable);
if (result != B_OK)
return result;
BReference<Variable> variableReference(variable, true);
if (!frame->AddLocalVariable(variable))
return B_NO_MEMORY;
}
}
}

View File

@ -64,8 +64,7 @@ public:
FunctionInstance* functionInstance,
CpuState* cpuState,
bool getFullFrameInfo,
target_addr_t returnFunctionAddress,
CpuState* returnFunctionState,
ReturnValueInfoList* returnValueInfos,
StackFrame*& _frame,
CpuState*& _previousCpuState);
virtual status_t GetStatement(FunctionDebugInfo* function,
@ -105,9 +104,8 @@ private:
const EntryListWrapper& variableEntries,
const EntryListWrapper& blockEntries);
status_t _CreateReturnValue(
target_addr_t returnFunctionAddress,
CpuState* returnFunctionState,
status_t _CreateReturnValues(
ReturnValueInfoList* returnValueInfos,
Image* image,
StackFrame* frame,
DwarfStackFrameDebugInfo& factory);

View File

@ -10,6 +10,7 @@
#include <Referenceable.h>
#include "AddressSectionTypes.h"
#include "ReturnValueInfo.h"
#include "Types.h"
@ -56,8 +57,7 @@ public:
FunctionInstance* functionInstance,
CpuState* cpuState,
bool getFullFrameInfo,
target_addr_t returnFunctionAddress,
CpuState* returnFunctionState,
ReturnValueInfoList* returnValueInfos,
StackFrame*& _Frame,
CpuState*& _previousCpuState) = 0;
// returns reference to previous frame

View File

@ -58,9 +58,7 @@ GetStackTraceJob::Do()
// get the stack trace
StackTrace* stackTrace;
status_t error = fArchitecture->CreateStackTrace(fThread->GetTeam(), this,
fCpuState, stackTrace, fThread->ExecutedSubroutine()
? fThread->SubroutineAddress() : 0, fThread->ExecutedSubroutine()
? fThread->SubroutineCpuState() : NULL);
fCpuState, stackTrace, fThread->ReturnValueInfos());
if (error != B_OK)
return error;
BReference<StackTrace> stackTraceReference(stackTrace, true);

View File

@ -18,8 +18,7 @@ Thread::Thread(Team* team, thread_id threadID)
fID(threadID),
fState(THREAD_STATE_UNKNOWN),
fExecutedSubroutine(false),
fSubroutineAddress(0),
fSubroutineState(NULL),
fReturnValueInfos(NULL),
fStoppedReason(THREAD_STOPPED_UNKNOWN),
fCpuState(NULL),
fStackTrace(NULL)
@ -33,14 +32,19 @@ Thread::~Thread()
fCpuState->ReleaseReference();
if (fStackTrace != NULL)
fStackTrace->ReleaseReference();
if (fSubroutineState != NULL)
fSubroutineState->ReleaseReference();
ClearReturnValueInfos();
delete fReturnValueInfos;
}
status_t
Thread::Init()
{
fReturnValueInfos = new(std::nothrow) ReturnValueInfoList;
if (fReturnValueInfos == NULL)
return B_NO_MEMORY;
return B_OK;
}
@ -74,7 +78,7 @@ Thread::SetState(uint32 state, uint32 reason, const BString& info)
SetCpuState(NULL);
SetStackTrace(NULL);
fExecutedSubroutine = false;
fSubroutineAddress = 0;
ClearReturnValueInfos();
}
fTeam->NotifyThreadStateChanged(this);
@ -117,20 +121,23 @@ Thread::SetStackTrace(StackTrace* trace)
}
void
Thread::SetExecutedSubroutine(target_addr_t address)
status_t
Thread::AddReturnValueInfo(ReturnValueInfo* info)
{
if (!fReturnValueInfos->AddItem(info))
return B_NO_MEMORY;
info->AcquireReference();
fExecutedSubroutine = true;
fSubroutineAddress = address;
return B_OK;
}
void
Thread::SetSubroutineCpuState(CpuState* state)
Thread::ClearReturnValueInfos()
{
if (fSubroutineState != NULL)
fSubroutineState->ReleaseReference();
for (int32 i = 0; i < fReturnValueInfos->CountItems(); i++)
fReturnValueInfos->ItemAt(i)->ReleaseReference();
fSubroutineState = state;
fSubroutineState->AcquireReference();
fReturnValueInfos->MakeEmpty();
}

View File

@ -11,6 +11,7 @@
#include <Referenceable.h>
#include <util/DoublyLinkedList.h>
#include "ReturnValueInfo.h"
#include "types/Types.h"
@ -69,14 +70,11 @@ public:
StackTrace* GetStackTrace() const { return fStackTrace; }
void SetStackTrace(StackTrace* trace);
bool ExecutedSubroutine() const
{ return fExecutedSubroutine; }
target_addr_t SubroutineAddress() const
{ return fSubroutineAddress; }
void SetExecutedSubroutine(target_addr_t address);
CpuState* SubroutineCpuState() const
{ return fSubroutineState; }
void SetSubroutineCpuState(CpuState* state);
ReturnValueInfoList*
ReturnValueInfos() const
{ return fReturnValueInfos; }
status_t AddReturnValueInfo(ReturnValueInfo* info);
void ClearReturnValueInfos();
private:
Team* fTeam;
@ -84,8 +82,8 @@ private:
BString fName;
uint32 fState;
bool fExecutedSubroutine;
target_addr_t fSubroutineAddress;
CpuState* fSubroutineState;
ReturnValueInfoList*
fReturnValueInfos;
uint32 fStoppedReason;
BString fStoppedReasonInfo;
CpuState* fCpuState;