Rework how return values are handled.
- ArchitectureX86 now hands off the work for GetInstructionInfo() to DisassemblerX86, since the latter has all the information we need to properly classify and evaluate instructions. Correspondingly a CpuState is passed down to it in order to perform address calculations for the instruction if it's a jump or call instruction. The latter's targets are then stored on the thread for later retrieval when constructing a stack trace. Adjust X86_64 accordingly for the signature changes. This also fixes a bug where Step Over would sometimes result in a Step Into instead due to the previous implementation of GetInstructionInfo() occasionally failing to classify call instructions correctly. - Architecture::CreateStackTrace() now takes an argument specifying the address of the last executed function if applicable. This is used to decide who/where to decode a return value from. Adjust callers. - DwarfImageDebugInfo::_CreateReturnValue() uses the above information in order to know directly who the caller it needs to look up a return value for is, rather than trying to walk backwards to find them. Type resolution is now also a bit more sophisticated due to various cases where the subprogram entry didn't directly contain the return type but referred to another DIE that did. Retrieving return value now appears to work properly in all cases except when position independent code is involved. The latter however will require resolving the appropriate function address in the PLT, which will need some additional work.
This commit is contained in:
parent
bdbbc10b44
commit
5745a40dd1
@ -94,8 +94,8 @@ Architecture::InitRegisterRules(CfaContext& context) const
|
||||
status_t
|
||||
Architecture::CreateStackTrace(Team* team,
|
||||
ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState,
|
||||
StackTrace*& _stackTrace, bool getReturnValue, int32 maxStackDepth,
|
||||
bool useExistingTrace, bool getFullFrameInfo)
|
||||
StackTrace*& _stackTrace, target_addr_t returnFunctionAddress,
|
||||
int32 maxStackDepth, bool useExistingTrace, bool getFullFrameInfo)
|
||||
{
|
||||
BReference<CpuState> cpuStateReference(cpuState);
|
||||
|
||||
@ -163,7 +163,7 @@ Architecture::CreateStackTrace(Team* team,
|
||||
if (function != NULL) {
|
||||
status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
|
||||
->CreateFrame(image, function, cpuState, getFullFrameInfo,
|
||||
nextFrame == NULL ? getReturnValue : false, frame,
|
||||
nextFrame == NULL ? returnFunctionAddress : 0, frame,
|
||||
previousCpuState);
|
||||
if (error != B_OK && error != B_UNSUPPORTED)
|
||||
break;
|
||||
|
@ -103,13 +103,14 @@ public:
|
||||
target_addr_t address,
|
||||
Statement*& _statement) = 0;
|
||||
virtual status_t GetInstructionInfo(target_addr_t address,
|
||||
InstructionInfo& _info) = 0;
|
||||
InstructionInfo& _info,
|
||||
CpuState* state) = 0;
|
||||
|
||||
status_t CreateStackTrace(Team* team,
|
||||
ImageDebugInfoProvider* imageInfoProvider,
|
||||
CpuState* cpuState,
|
||||
StackTrace*& _stackTrace,
|
||||
bool getReturnValue,
|
||||
target_addr_t returnFunctionAddress,
|
||||
int32 maxStackDepth = -1,
|
||||
bool useExistingTrace = false,
|
||||
bool getFullFrameInfo = true);
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
enum instruction_type {
|
||||
INSTRUCTION_TYPE_SUBROUTINE_CALL,
|
||||
INSTRUCTION_TYPE_JUMP,
|
||||
INSTRUCTION_TYPE_OTHER
|
||||
};
|
||||
|
||||
|
@ -561,7 +561,7 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function,
|
||||
// TODO: This is not architecture dependent anymore!
|
||||
// get the instruction info
|
||||
InstructionInfo info;
|
||||
status_t error = GetInstructionInfo(address, info);
|
||||
status_t error = GetInstructionInfo(address, info, NULL);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@ -578,7 +578,7 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function,
|
||||
|
||||
status_t
|
||||
ArchitectureX86::GetInstructionInfo(target_addr_t address,
|
||||
InstructionInfo& _info)
|
||||
InstructionInfo& _info, CpuState* state)
|
||||
{
|
||||
// read the code - maximum x86{-64} instruction size = 15 bytes
|
||||
uint8 buffer[16];
|
||||
@ -593,40 +593,7 @@ ArchitectureX86::GetInstructionInfo(target_addr_t address,
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// disassemble the instruction
|
||||
BString line;
|
||||
target_addr_t instructionAddress;
|
||||
target_addr_t targetAddress = 0;
|
||||
target_size_t instructionSize;
|
||||
bool breakpointAllowed;
|
||||
error = disassembler.GetNextInstruction(line, instructionAddress,
|
||||
instructionSize, breakpointAllowed);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
instruction_type instructionType = INSTRUCTION_TYPE_OTHER;
|
||||
if (buffer[0] == 0xff && (buffer[1] & 0x34) == 0x10) {
|
||||
// absolute call with r/m32
|
||||
instructionType = INSTRUCTION_TYPE_SUBROUTINE_CALL;
|
||||
// TODO: retrieve target address (might be in a register)
|
||||
} else if (buffer[0] == 0xe8 && instructionSize == 5) {
|
||||
// relative call with rel32 -- don't categorize the call with 0 as
|
||||
// subroutine call, since it is only used to get the address of the GOT
|
||||
if (buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0
|
||||
|| buffer[4] != 0) {
|
||||
instructionType = INSTRUCTION_TYPE_SUBROUTINE_CALL;
|
||||
int32 offset;
|
||||
memcpy(&offset, &buffer[1], 4);
|
||||
targetAddress = instructionAddress + instructionSize + offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_info.SetTo(instructionAddress, targetAddress, instructionSize,
|
||||
instructionType, breakpointAllowed, line)) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
return disassembler.GetNextInstructionInfo(_info, state);
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
target_addr_t address,
|
||||
Statement*& _statement);
|
||||
virtual status_t GetInstructionInfo(target_addr_t address,
|
||||
InstructionInfo& _info);
|
||||
InstructionInfo& _info, CpuState* state);
|
||||
|
||||
virtual status_t GetWatchpointDebugCapabilities(
|
||||
int32& _maxRegisterCount,
|
||||
|
@ -12,6 +12,36 @@
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include "CpuStateX86.h"
|
||||
#include "InstructionInfo.h"
|
||||
|
||||
|
||||
static uint8 RegisterNumberFromUdisIndex(int32 udisIndex)
|
||||
{
|
||||
switch (udisIndex) {
|
||||
case UD_R_RIP: return X86_REGISTER_EIP;
|
||||
case UD_R_ESP: return X86_REGISTER_ESP;
|
||||
case UD_R_EBP: return X86_REGISTER_EBP;
|
||||
|
||||
case UD_R_EAX: return X86_REGISTER_EAX;
|
||||
case UD_R_EBX: return X86_REGISTER_EBX;
|
||||
case UD_R_ECX: return X86_REGISTER_ECX;
|
||||
case UD_R_EDX: return X86_REGISTER_EDX;
|
||||
|
||||
case UD_R_ESI: return X86_REGISTER_ESI;
|
||||
case UD_R_EDI: return X86_REGISTER_EDI;
|
||||
|
||||
case UD_R_CS: return X86_REGISTER_CS;
|
||||
case UD_R_DS: return X86_REGISTER_DS;
|
||||
case UD_R_ES: return X86_REGISTER_ES;
|
||||
case UD_R_FS: return X86_REGISTER_FS;
|
||||
case UD_R_GS: return X86_REGISTER_GS;
|
||||
case UD_R_SS: return X86_REGISTER_SS;
|
||||
}
|
||||
|
||||
return X86_INT_REGISTER_END;
|
||||
}
|
||||
|
||||
|
||||
struct DisassemblerX86::UdisData : ud_t {
|
||||
};
|
||||
@ -108,3 +138,85 @@ DisassemblerX86::GetPreviousInstruction(target_addr_t nextAddress,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DisassemblerX86::GetNextInstructionInfo(InstructionInfo& _info,
|
||||
CpuState* state)
|
||||
{
|
||||
unsigned int size = ud_disassemble(fUdisData);
|
||||
if (size < 1)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
uint32 address = (uint32)ud_insn_off(fUdisData);
|
||||
|
||||
instruction_type type = INSTRUCTION_TYPE_OTHER;
|
||||
target_addr_t targetAddress = 0;
|
||||
|
||||
if (fUdisData->mnemonic == UD_Icall)
|
||||
type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
|
||||
else if (fUdisData->mnemonic == UD_Ijmp)
|
||||
type = INSTRUCTION_TYPE_JUMP;
|
||||
if (state != NULL)
|
||||
targetAddress = GetInstructionTargetAddress(state);
|
||||
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx32 ": %16.16s %s", address,
|
||||
ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
|
||||
// TODO: Resolve symbols!
|
||||
|
||||
if (!_info.SetTo(address, targetAddress, size, type, true, buffer))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
DisassemblerX86::GetInstructionTargetAddress(CpuState* state) const
|
||||
{
|
||||
if (fUdisData->mnemonic != UD_Icall && fUdisData->mnemonic != UD_Ijmp)
|
||||
return 0;
|
||||
|
||||
CpuStateX86* x86State = dynamic_cast<CpuStateX86*>(state);
|
||||
if (x86State == NULL)
|
||||
return 0;
|
||||
|
||||
target_addr_t targetAddress = 0;
|
||||
switch (fUdisData->operand[0].type) {
|
||||
case UD_OP_REG:
|
||||
{
|
||||
targetAddress = x86State->IntRegisterValue(
|
||||
RegisterNumberFromUdisIndex(fUdisData->operand[0].base));
|
||||
targetAddress += fUdisData->operand[0].offset;
|
||||
}
|
||||
break;
|
||||
case UD_OP_MEM:
|
||||
{
|
||||
targetAddress = x86State->IntRegisterValue(
|
||||
RegisterNumberFromUdisIndex(fUdisData->operand[0].base));
|
||||
targetAddress += x86State->IntRegisterValue(
|
||||
RegisterNumberFromUdisIndex(fUdisData->operand[0].index))
|
||||
* fUdisData->operand[0].scale;
|
||||
}
|
||||
break;
|
||||
case UD_OP_JIMM:
|
||||
{
|
||||
targetAddress = ud_insn_off(fUdisData)
|
||||
+ fUdisData->operand[0].lval.sdword + ud_insn_len(fUdisData);
|
||||
}
|
||||
break;
|
||||
|
||||
case UD_OP_IMM:
|
||||
case UD_OP_CONST:
|
||||
{
|
||||
targetAddress = fUdisData->operand[0].lval.udword;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return targetAddress;
|
||||
}
|
||||
|
@ -10,6 +10,10 @@
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
class CpuState;
|
||||
class InstructionInfo;
|
||||
|
||||
|
||||
class DisassemblerX86 {
|
||||
public:
|
||||
DisassemblerX86();
|
||||
@ -27,6 +31,14 @@ public:
|
||||
target_addr_t& _address,
|
||||
target_size_t& _size);
|
||||
|
||||
virtual status_t GetNextInstructionInfo(
|
||||
InstructionInfo& _info,
|
||||
CpuState* state);
|
||||
|
||||
|
||||
private:
|
||||
target_addr_t GetInstructionTargetAddress(
|
||||
CpuState* state) const;
|
||||
private:
|
||||
struct UdisData;
|
||||
|
||||
|
@ -3,9 +3,12 @@ SubDir HAIKU_TOP src apps debugger arch x86 disasm ;
|
||||
CCFLAGS += -Werror ;
|
||||
C++FLAGS += -Werror ;
|
||||
|
||||
UsePrivateHeaders shared ;
|
||||
|
||||
UseHeaders [ LibraryHeaders udis86 ] ;
|
||||
UseHeaders [ LibraryHeaders [ FDirName udis86 libudis86 ] ] ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) types ] ;
|
||||
|
||||
|
@ -451,7 +451,7 @@ ArchitectureX8664::GetStatement(FunctionDebugInfo* function,
|
||||
// TODO: This is not architecture dependent anymore!
|
||||
// get the instruction info
|
||||
InstructionInfo info;
|
||||
status_t error = GetInstructionInfo(address, info);
|
||||
status_t error = GetInstructionInfo(address, info, NULL);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@ -468,7 +468,7 @@ ArchitectureX8664::GetStatement(FunctionDebugInfo* function,
|
||||
|
||||
status_t
|
||||
ArchitectureX8664::GetInstructionInfo(target_addr_t address,
|
||||
InstructionInfo& _info)
|
||||
InstructionInfo& _info, CpuState* state)
|
||||
{
|
||||
// read the code
|
||||
uint8 buffer[16];
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
target_addr_t address,
|
||||
Statement*& _statement);
|
||||
virtual status_t GetInstructionInfo(target_addr_t address,
|
||||
InstructionInfo& _info);
|
||||
InstructionInfo& _info, CpuState* state);
|
||||
|
||||
virtual status_t GetWatchpointDebugCapabilities(
|
||||
int32& _maxRegisterCount,
|
||||
|
@ -253,7 +253,7 @@ ThreadHandler::HandleThreadAction(uint32 action)
|
||||
|
||||
if (stackTrace == NULL && cpuState != NULL) {
|
||||
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, false, 1,
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, 0, 1,
|
||||
false, false) == B_OK) {
|
||||
stackTraceReference.SetTo(stackTrace, true);
|
||||
}
|
||||
@ -469,7 +469,7 @@ ThreadHandler::_DoStepOver(CpuState* cpuState)
|
||||
// just single-step, otherwise we set a breakpoint after the instruction.
|
||||
InstructionInfo info;
|
||||
if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo(
|
||||
cpuState->InstructionPointer(), info) != B_OK) {
|
||||
cpuState->InstructionPointer(), info, cpuState) != B_OK) {
|
||||
TRACE_CONTROL(" failed to get instruction info\n");
|
||||
return false;
|
||||
}
|
||||
@ -484,7 +484,7 @@ ThreadHandler::_DoStepOver(CpuState* cpuState)
|
||||
TRACE_CONTROL(" subroutine call -- installing breakpoint at address "
|
||||
"%#" B_PRIx64 "\n", info.Address() + info.Size());
|
||||
|
||||
fThread->SetExecutedSubroutine();
|
||||
fThread->SetExecutedSubroutine(info.TargetAddress());
|
||||
if (_InstallTemporaryBreakpoint(info.Address() + info.Size()) != B_OK)
|
||||
return false;
|
||||
|
||||
@ -566,8 +566,8 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState)
|
||||
|
||||
if (stackTrace == NULL && cpuState != NULL) {
|
||||
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, false,
|
||||
1, false, false) == B_OK) {
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, 0, 1,
|
||||
false, false) == B_OK) {
|
||||
stackTraceReference.SetTo(stackTrace, true);
|
||||
}
|
||||
}
|
||||
@ -608,7 +608,7 @@ 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();
|
||||
fThread->SetExecutedSubroutine(cpuState->InstructionPointer());
|
||||
target_addr_t framePointer = cpuState->StackFramePointer();
|
||||
bool hasExitedFrame = fDebuggerInterface->GetArchitecture()
|
||||
->StackGrowthDirection() == STACK_GROWTH_DIRECTION_POSITIVE
|
||||
@ -653,8 +653,8 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
|
||||
|
||||
if (stackTrace == NULL && cpuState != NULL) {
|
||||
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, false,
|
||||
1, false, false) == B_OK) {
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, 0, 1,
|
||||
false, false) == B_OK) {
|
||||
stackTraceReference.SetTo(stackTrace, true);
|
||||
}
|
||||
}
|
||||
@ -685,7 +685,7 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
|
||||
BReference<StackTrace> stackTraceReference(stackTrace);
|
||||
if (stackTrace == NULL && cpuState != NULL) {
|
||||
if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, false,
|
||||
fThread->GetTeam(), this, cpuState, stackTrace, 0,
|
||||
1, false, false) == B_OK) {
|
||||
stackTraceReference.SetTo(stackTrace, true);
|
||||
}
|
||||
@ -693,7 +693,8 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
|
||||
|
||||
if (stackTrace != NULL && stackTrace->FrameAt(0)
|
||||
->FrameAddress() != fPreviousFrameAddress) {
|
||||
fThread->SetExecutedSubroutine();
|
||||
fThread->SetExecutedSubroutine(
|
||||
cpuState->InstructionPointer());
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -68,8 +68,8 @@ DebuggerImageDebugInfo::GetAddressSectionType(target_addr_t address)
|
||||
status_t
|
||||
DebuggerImageDebugInfo::CreateFrame(Image* image,
|
||||
FunctionInstance* functionInstance, CpuState* cpuState,
|
||||
bool getFullFrameInfo, bool getReturnValue, StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState)
|
||||
bool getFullFrameInfo, target_addr_t returnFunctionAddress,
|
||||
StackFrame*& _previousFrame, CpuState*& _previousCpuState)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
FunctionInstance* functionInstance,
|
||||
CpuState* cpuState,
|
||||
bool getFullFrameInfo,
|
||||
bool getReturnValue,
|
||||
target_addr_t returnFunctionAddress,
|
||||
StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState);
|
||||
virtual status_t GetStatement(FunctionDebugInfo* function,
|
||||
|
@ -522,8 +522,8 @@ DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address)
|
||||
status_t
|
||||
DwarfImageDebugInfo::CreateFrame(Image* image,
|
||||
FunctionInstance* functionInstance, CpuState* cpuState,
|
||||
bool getFullFrameInfo, bool getReturnValue, StackFrame*& _frame,
|
||||
CpuState*& _previousCpuState)
|
||||
bool getFullFrameInfo, target_addr_t returnFunctionAddress,
|
||||
StackFrame*& _frame, CpuState*& _previousCpuState)
|
||||
{
|
||||
DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
|
||||
functionInstance->GetFunctionDebugInfo());
|
||||
@ -673,9 +673,9 @@ DwarfImageDebugInfo::CreateFrame(Image* image,
|
||||
instructionPointer, functionInstance->Address() - fRelocationDelta,
|
||||
subprogramEntry->Variables(), subprogramEntry->Blocks());
|
||||
|
||||
if (getReturnValue) {
|
||||
_CreateReturnValue(functionInstance, image, function, frame,
|
||||
*stackFrameDebugInfo, instructionPointer);
|
||||
if (returnFunctionAddress != 0) {
|
||||
_CreateReturnValue(returnFunctionAddress, image, frame,
|
||||
*stackFrameDebugInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1086,75 +1086,28 @@ DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit,
|
||||
|
||||
|
||||
status_t
|
||||
DwarfImageDebugInfo::_CreateReturnValue(FunctionInstance* functionInstance,
|
||||
Image* image, DwarfFunctionDebugInfo* function, StackFrame* frame,
|
||||
DwarfStackFrameDebugInfo& factory, target_addr_t instructionPointer)
|
||||
DwarfImageDebugInfo::_CreateReturnValue(target_addr_t returnFunctionAddress,
|
||||
Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory)
|
||||
{
|
||||
// the thread just executed a subroutine, look for the last call
|
||||
// instruction.
|
||||
DisassembledCode* sourceCode = NULL;
|
||||
target_size_t bufferSize = std::min(functionInstance->Size(),
|
||||
(target_size_t)64 * 1024);
|
||||
void* buffer = malloc(bufferSize);
|
||||
if (buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
MemoryDeleter bufferDeleter(buffer);
|
||||
ssize_t bytesRead = function->GetSpecificImageDebugInfo()
|
||||
->ReadCode(functionInstance->Address(), buffer, bufferSize);
|
||||
if (bytesRead < 0)
|
||||
return bytesRead;
|
||||
|
||||
status_t result = fArchitecture->DisassembleCode(function, buffer,
|
||||
bytesRead, sourceCode);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
BReference<DisassembledCode> sourceCodeReference(sourceCode, true);
|
||||
target_addr_t previousStatementAddress = instructionPointer + fRelocationDelta - 1;
|
||||
Statement* statement = sourceCode->StatementAtAddress(
|
||||
previousStatementAddress);
|
||||
if (statement == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
InstructionInfo info;
|
||||
do {
|
||||
TargetAddressRange range = statement->CoveringAddressRange();
|
||||
result = fArchitecture->GetInstructionInfo(range.Start(), info);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (info.Type() == INSTRUCTION_TYPE_SUBROUTINE_CALL)
|
||||
break;
|
||||
|
||||
previousStatementAddress = statement->CoveringAddressRange().Start() - 1;
|
||||
statement = sourceCode->StatementAtAddress(
|
||||
previousStatementAddress);
|
||||
} while (statement != NULL);
|
||||
|
||||
// we weren't able to find a subroutine call by stepping back
|
||||
// so we can't retrieve a return value
|
||||
if (info.Type() != INSTRUCTION_TYPE_SUBROUTINE_CALL)
|
||||
return B_OK;
|
||||
|
||||
target_addr_t targetAddress = info.TargetAddress();
|
||||
if (targetAddress == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!image->ContainsAddress(targetAddress)) {
|
||||
if (!image->ContainsAddress(returnFunctionAddress)) {
|
||||
// our current image doesn't contain the target function,
|
||||
// locate the one which does.
|
||||
image = image->GetTeam()->ImageByAddress(targetAddress);
|
||||
image = image->GetTeam()->ImageByAddress(returnFunctionAddress);
|
||||
if (image == NULL)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
status_t result = B_OK;
|
||||
FunctionInstance* targetFunction;
|
||||
if (targetAddress >= fPLTSectionStart && targetAddress < fPLTSectionEnd) {
|
||||
// TODO: resolve actual target address in the PIC case
|
||||
// and adjust targetAddress accordingly
|
||||
if (returnFunctionAddress >= fPLTSectionStart
|
||||
&& returnFunctionAddress < fPLTSectionEnd) {
|
||||
// TODO: handle resolving PLT entries
|
||||
// to their target function
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
ImageDebugInfo* imageInfo = image->GetImageDebugInfo();
|
||||
targetFunction = imageInfo->FunctionAtAddress(targetAddress);
|
||||
targetFunction = imageInfo->FunctionAtAddress(returnFunctionAddress);
|
||||
if (targetFunction != NULL) {
|
||||
DwarfFunctionDebugInfo* targetInfo =
|
||||
dynamic_cast<DwarfFunctionDebugInfo*>(
|
||||
@ -1163,15 +1116,30 @@ DwarfImageDebugInfo::_CreateReturnValue(FunctionInstance* functionInstance,
|
||||
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.
|
||||
return B_OK;
|
||||
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,
|
||||
returnType->ByteSize()->constant, location);
|
||||
byteSize, location);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
BReference<ValueLocation> locationReference(location, true);
|
||||
Variable* variable = NULL;
|
||||
BReference<FunctionID> idReference(
|
||||
@ -1180,6 +1148,7 @@ DwarfImageDebugInfo::_CreateReturnValue(FunctionInstance* functionInstance,
|
||||
location, variable);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
BReference<Variable> variableReference(variable, true);
|
||||
if (!frame->AddLocalVariable(variable))
|
||||
return B_NO_MEMORY;
|
||||
|
@ -64,7 +64,7 @@ public:
|
||||
FunctionInstance* functionInstance,
|
||||
CpuState* cpuState,
|
||||
bool getFullFrameInfo,
|
||||
bool getReturnValue,
|
||||
target_addr_t returnFunctionAddress,
|
||||
StackFrame*& _frame,
|
||||
CpuState*& _previousCpuState);
|
||||
virtual status_t GetStatement(FunctionDebugInfo* function,
|
||||
@ -104,12 +104,11 @@ private:
|
||||
const EntryListWrapper& variableEntries,
|
||||
const EntryListWrapper& blockEntries);
|
||||
|
||||
status_t _CreateReturnValue(FunctionInstance* instance,
|
||||
status_t _CreateReturnValue(
|
||||
target_addr_t returnFunctionAddress,
|
||||
Image* image,
|
||||
DwarfFunctionDebugInfo* info,
|
||||
StackFrame* frame,
|
||||
DwarfStackFrameDebugInfo& factory,
|
||||
target_addr_t instructionPointer);
|
||||
DwarfStackFrameDebugInfo& factory);
|
||||
|
||||
bool _EvaluateBaseTypeConstraints(DIEType* type,
|
||||
const TypeLookupConstraints& constraints);
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
FunctionInstance* functionInstance,
|
||||
CpuState* cpuState,
|
||||
bool getFullFrameInfo,
|
||||
bool getReturnValue,
|
||||
target_addr_t returnFunctionAddress,
|
||||
StackFrame*& _Frame,
|
||||
CpuState*& _previousCpuState) = 0;
|
||||
// returns reference to previous frame
|
||||
|
@ -58,7 +58,8 @@ GetStackTraceJob::Do()
|
||||
// get the stack trace
|
||||
StackTrace* stackTrace;
|
||||
status_t error = fArchitecture->CreateStackTrace(fThread->GetTeam(), this,
|
||||
fCpuState, stackTrace, fThread->ExecutedSubroutine());
|
||||
fCpuState, stackTrace, fThread->ExecutedSubroutine()
|
||||
? fThread->SubroutineAddress() : 0);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
BReference<StackTrace> stackTraceReference(stackTrace, true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user