* Added StackFrame classification as syscall frame and added correct
identification for x86. * For non-top stack frames adjust the instruction pointer so that it points to the calling function instead of the return address. * SourceView: Consider a syscall frame a non-top frame (the arrow is drawn differently). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31228 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -91,7 +91,7 @@ Architecture::CreateStackTrace(Team* team,
|
|||||||
// If we have no frame yet, let the architecture create it.
|
// If we have no frame yet, let the architecture create it.
|
||||||
if (previousFrame == NULL) {
|
if (previousFrame == NULL) {
|
||||||
status_t error = CreateStackFrame(image, function, cpuState,
|
status_t error = CreateStackFrame(image, function, cpuState,
|
||||||
previousFrame, previousCpuState);
|
frame == NULL, previousFrame, previousCpuState);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
size_t size, CpuState*& _state) = 0;
|
size_t size, CpuState*& _state) = 0;
|
||||||
virtual status_t CreateStackFrame(Image* image,
|
virtual status_t CreateStackFrame(Image* image,
|
||||||
FunctionDebugInfo* function,
|
FunctionDebugInfo* function,
|
||||||
CpuState* cpuState,
|
CpuState* cpuState, bool isTopFrame,
|
||||||
StackFrame*& _previousFrame,
|
StackFrame*& _previousFrame,
|
||||||
CpuState*& _previousCpuState) = 0;
|
CpuState*& _previousCpuState) = 0;
|
||||||
// returns reference to previous frame
|
// returns reference to previous frame
|
||||||
|
|||||||
@@ -111,16 +111,54 @@ ArchitectureX86::CreateCpuState(const void* cpuStateData, size_t size,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function,
|
ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function,
|
||||||
CpuState* _cpuState, StackFrame*& _previousFrame,
|
CpuState* _cpuState, bool isTopFrame, StackFrame*& _previousFrame,
|
||||||
CpuState*& _previousCpuState)
|
CpuState*& _previousCpuState)
|
||||||
{
|
{
|
||||||
CpuStateX86* cpuState = dynamic_cast<CpuStateX86*>(_cpuState);
|
CpuStateX86* cpuState = dynamic_cast<CpuStateX86*>(_cpuState);
|
||||||
|
|
||||||
uint32 framePointer = cpuState->IntRegisterValue(X86_REGISTER_EBP);
|
uint32 framePointer = cpuState->IntRegisterValue(X86_REGISTER_EBP);
|
||||||
|
uint32 eip = cpuState->IntRegisterValue(X86_REGISTER_EIP);
|
||||||
|
|
||||||
|
// check for syscall frames
|
||||||
|
stack_frame_type frameType;
|
||||||
|
if (isTopFrame && cpuState->InterruptVector() == 99) {
|
||||||
|
// The thread is performing a syscall. So this frame is not really the
|
||||||
|
// top-most frame and we need to adjust the eip.
|
||||||
|
frameType = STACK_FRAME_TYPE_SYSCALL;
|
||||||
|
eip -= 2;
|
||||||
|
// int 99, sysenter, and syscall all are 2 byte instructions
|
||||||
|
} else {
|
||||||
|
frameType = STACK_FRAME_TYPE_STANDARD;
|
||||||
|
|
||||||
|
// If this is not a top-frame, we offset eip to the previous (calling)
|
||||||
|
// instruction.
|
||||||
|
if (!isTopFrame && function != NULL && eip > function->Address()) {
|
||||||
|
size_t bufferSize = eip - function->Address();
|
||||||
|
void* buffer = malloc(bufferSize);
|
||||||
|
if (buffer != NULL) {
|
||||||
|
ssize_t bytesRead = fDebuggerInterface->ReadMemory(
|
||||||
|
function->Address(), buffer, bufferSize);
|
||||||
|
if (bytesRead == (ssize_t)bufferSize) {
|
||||||
|
DisassemblerX86 disassembler;
|
||||||
|
target_addr_t instructionAddress;
|
||||||
|
target_size_t instructionSize;
|
||||||
|
if (disassembler.Init(function->Address(),
|
||||||
|
buffer, bufferSize) == B_OK
|
||||||
|
&& disassembler.GetPreviousInstruction(eip,
|
||||||
|
instructionAddress, instructionSize) == B_OK) {
|
||||||
|
eip -= instructionSize;
|
||||||
|
cpuState->SetIntRegister(X86_REGISTER_EIP, eip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create the stack frame
|
// create the stack frame
|
||||||
StackFrame* frame = new(std::nothrow) StackFrame(
|
StackFrame* frame = new(std::nothrow) StackFrame(frameType, cpuState,
|
||||||
STACK_FRAME_TYPE_STANDARD, cpuState, framePointer);
|
framePointer, eip);
|
||||||
if (frame == NULL)
|
if (frame == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
Reference<StackFrame> frameReference(frame, true);
|
Reference<StackFrame> frameReference(frame, true);
|
||||||
@@ -135,9 +173,14 @@ ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function,
|
|||||||
if (previousCpuState == NULL)
|
if (previousCpuState == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
frame->SetReturnAddress(frameData[1]);
|
||||||
previousCpuState->SetIntRegister(X86_REGISTER_EBP, frameData[0]);
|
previousCpuState->SetIntRegister(X86_REGISTER_EBP, frameData[0]);
|
||||||
previousCpuState->SetIntRegister(X86_REGISTER_EIP, frameData[1]);
|
previousCpuState->SetIntRegister(X86_REGISTER_EIP, frameData[1]);
|
||||||
// TODO: Actually it's the instruction before!
|
// TODO: Actually it's the instruction before! We're currently
|
||||||
|
// offsetting it at the beginning of this method, but that's not
|
||||||
|
// correct, since for the previous stack frame there could be more
|
||||||
|
// debug info. Problem is that we don't have the function for the
|
||||||
|
// previous stack frame available at this point.
|
||||||
}
|
}
|
||||||
|
|
||||||
_previousFrame = frameReference.Detach();
|
_previousFrame = frameReference.Detach();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public:
|
|||||||
size_t size, CpuState*& _state);
|
size_t size, CpuState*& _state);
|
||||||
virtual status_t CreateStackFrame(Image* image,
|
virtual status_t CreateStackFrame(Image* image,
|
||||||
FunctionDebugInfo* function,
|
FunctionDebugInfo* function,
|
||||||
CpuState* cpuState,
|
CpuState* cpuState, bool isTopFrame,
|
||||||
StackFrame*& _previousFrame,
|
StackFrame*& _previousFrame,
|
||||||
CpuState*& _previousCpuState);
|
CpuState*& _previousCpuState);
|
||||||
virtual status_t DisassembleCode(FunctionDebugInfo* function,
|
virtual status_t DisassembleCode(FunctionDebugInfo* function,
|
||||||
|
|||||||
@@ -10,14 +10,16 @@
|
|||||||
|
|
||||||
CpuStateX86::CpuStateX86()
|
CpuStateX86::CpuStateX86()
|
||||||
:
|
:
|
||||||
fSetRegisters()
|
fSetRegisters(),
|
||||||
|
fInterruptVector(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CpuStateX86::CpuStateX86(const debug_cpu_state_x86& state)
|
CpuStateX86::CpuStateX86(const debug_cpu_state_x86& state)
|
||||||
:
|
:
|
||||||
fSetRegisters()
|
fSetRegisters(),
|
||||||
|
fInterruptVector(0)
|
||||||
{
|
{
|
||||||
SetIntRegister(X86_REGISTER_EIP, state.eip);
|
SetIntRegister(X86_REGISTER_EIP, state.eip);
|
||||||
SetIntRegister(X86_REGISTER_ESP, state.user_esp);
|
SetIntRegister(X86_REGISTER_ESP, state.user_esp);
|
||||||
@@ -34,6 +36,8 @@ CpuStateX86::CpuStateX86(const debug_cpu_state_x86& state)
|
|||||||
SetIntRegister(X86_REGISTER_FS, state.fs);
|
SetIntRegister(X86_REGISTER_FS, state.fs);
|
||||||
SetIntRegister(X86_REGISTER_GS, state.gs);
|
SetIntRegister(X86_REGISTER_GS, state.gs);
|
||||||
SetIntRegister(X86_REGISTER_SS, state.user_ss);
|
SetIntRegister(X86_REGISTER_SS, state.user_ss);
|
||||||
|
|
||||||
|
fInterruptVector = state.vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ public:
|
|||||||
virtual bool GetRegisterValue(const Register* reg,
|
virtual bool GetRegisterValue(const Register* reg,
|
||||||
BVariant& _value);
|
BVariant& _value);
|
||||||
|
|
||||||
|
uint32 InterruptVector() const
|
||||||
|
{ return fInterruptVector; }
|
||||||
|
|
||||||
bool IsRegisterSet(int32 index) const;
|
bool IsRegisterSet(int32 index) const;
|
||||||
uint32 IntRegisterValue(int32 index) const;
|
uint32 IntRegisterValue(int32 index) const;
|
||||||
void SetIntRegister(int32 index, uint32 value);
|
void SetIntRegister(int32 index, uint32 value);
|
||||||
@@ -61,6 +64,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
uint32 fIntRegisters[X86_REGISTER_COUNT];
|
uint32 fIntRegisters[X86_REGISTER_COUNT];
|
||||||
RegisterBitSet fSetRegisters;
|
RegisterBitSet fSetRegisters;
|
||||||
|
uint32 fInterruptVector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -86,3 +86,25 @@ DisassemblerX86::GetNextInstruction(BString& line, target_addr_t& _address,
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DisassemblerX86::GetPreviousInstruction(target_addr_t nextAddress,
|
||||||
|
target_addr_t& _address, target_size_t& _size)
|
||||||
|
{
|
||||||
|
if (nextAddress < fAddress || nextAddress > fAddress + fCodeSize)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// loop until hitting the last instruction
|
||||||
|
while (true) {
|
||||||
|
unsigned int size = ud_disassemble(fUdisData);
|
||||||
|
if (size < 1)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
uint32 address = (uint32)ud_insn_off(fUdisData);
|
||||||
|
if (address + size == nextAddress) {
|
||||||
|
_address = address;
|
||||||
|
_size = size;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ public:
|
|||||||
target_addr_t& _address,
|
target_addr_t& _address,
|
||||||
target_size_t& _size,
|
target_size_t& _size,
|
||||||
bool& _breakpointAllowed);
|
bool& _breakpointAllowed);
|
||||||
|
virtual status_t GetPreviousInstruction(
|
||||||
|
target_addr_t nextAddress,
|
||||||
|
target_addr_t& _address,
|
||||||
|
target_size_t& _size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct UdisData;
|
struct UdisData;
|
||||||
|
|||||||
Reference in New Issue
Block a user