From 840c76534f7caaca52752d147778a4929e66c361 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Jun 2009 16:37:11 +0000 Subject: [PATCH] * 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 --- src/apps/debugger/arch/Architecture.cpp | 2 +- src/apps/debugger/arch/Architecture.h | 2 +- .../debugger/arch/x86/ArchitectureX86.cpp | 51 +++++++++++++++++-- src/apps/debugger/arch/x86/ArchitectureX86.h | 2 +- src/apps/debugger/arch/x86/CpuStateX86.cpp | 8 ++- src/apps/debugger/arch/x86/CpuStateX86.h | 4 ++ .../arch/x86/disasm/DisassemblerX86.cpp | 22 ++++++++ .../arch/x86/disasm/DisassemblerX86.h | 4 ++ 8 files changed, 86 insertions(+), 9 deletions(-) diff --git a/src/apps/debugger/arch/Architecture.cpp b/src/apps/debugger/arch/Architecture.cpp index c76e6d8b28..80b39052b3 100644 --- a/src/apps/debugger/arch/Architecture.cpp +++ b/src/apps/debugger/arch/Architecture.cpp @@ -91,7 +91,7 @@ Architecture::CreateStackTrace(Team* team, // If we have no frame yet, let the architecture create it. if (previousFrame == NULL) { status_t error = CreateStackFrame(image, function, cpuState, - previousFrame, previousCpuState); + frame == NULL, previousFrame, previousCpuState); if (error != B_OK) break; } diff --git a/src/apps/debugger/arch/Architecture.h b/src/apps/debugger/arch/Architecture.h index 80d207aecd..607462fb7d 100644 --- a/src/apps/debugger/arch/Architecture.h +++ b/src/apps/debugger/arch/Architecture.h @@ -37,7 +37,7 @@ public: size_t size, CpuState*& _state) = 0; virtual status_t CreateStackFrame(Image* image, FunctionDebugInfo* function, - CpuState* cpuState, + CpuState* cpuState, bool isTopFrame, StackFrame*& _previousFrame, CpuState*& _previousCpuState) = 0; // returns reference to previous frame diff --git a/src/apps/debugger/arch/x86/ArchitectureX86.cpp b/src/apps/debugger/arch/x86/ArchitectureX86.cpp index b51e0e3903..48f4f22b90 100644 --- a/src/apps/debugger/arch/x86/ArchitectureX86.cpp +++ b/src/apps/debugger/arch/x86/ArchitectureX86.cpp @@ -111,16 +111,54 @@ ArchitectureX86::CreateCpuState(const void* cpuStateData, size_t size, status_t ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function, - CpuState* _cpuState, StackFrame*& _previousFrame, + CpuState* _cpuState, bool isTopFrame, StackFrame*& _previousFrame, CpuState*& _previousCpuState) { CpuStateX86* cpuState = dynamic_cast(_cpuState); 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 - StackFrame* frame = new(std::nothrow) StackFrame( - STACK_FRAME_TYPE_STANDARD, cpuState, framePointer); + StackFrame* frame = new(std::nothrow) StackFrame(frameType, cpuState, + framePointer, eip); if (frame == NULL) return B_NO_MEMORY; Reference frameReference(frame, true); @@ -135,9 +173,14 @@ ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function, if (previousCpuState == NULL) return B_NO_MEMORY; + frame->SetReturnAddress(frameData[1]); previousCpuState->SetIntRegister(X86_REGISTER_EBP, frameData[0]); 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(); diff --git a/src/apps/debugger/arch/x86/ArchitectureX86.h b/src/apps/debugger/arch/x86/ArchitectureX86.h index d142be72cd..abdd7bd019 100644 --- a/src/apps/debugger/arch/x86/ArchitectureX86.h +++ b/src/apps/debugger/arch/x86/ArchitectureX86.h @@ -25,7 +25,7 @@ public: size_t size, CpuState*& _state); virtual status_t CreateStackFrame(Image* image, FunctionDebugInfo* function, - CpuState* cpuState, + CpuState* cpuState, bool isTopFrame, StackFrame*& _previousFrame, CpuState*& _previousCpuState); virtual status_t DisassembleCode(FunctionDebugInfo* function, diff --git a/src/apps/debugger/arch/x86/CpuStateX86.cpp b/src/apps/debugger/arch/x86/CpuStateX86.cpp index ec351a7d92..a047bf1184 100644 --- a/src/apps/debugger/arch/x86/CpuStateX86.cpp +++ b/src/apps/debugger/arch/x86/CpuStateX86.cpp @@ -10,14 +10,16 @@ CpuStateX86::CpuStateX86() : - fSetRegisters() + fSetRegisters(), + fInterruptVector(0) { } CpuStateX86::CpuStateX86(const debug_cpu_state_x86& state) : - fSetRegisters() + fSetRegisters(), + fInterruptVector(0) { SetIntRegister(X86_REGISTER_EIP, state.eip); 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_GS, state.gs); SetIntRegister(X86_REGISTER_SS, state.user_ss); + + fInterruptVector = state.vector; } diff --git a/src/apps/debugger/arch/x86/CpuStateX86.h b/src/apps/debugger/arch/x86/CpuStateX86.h index 6ac30a1a51..9fdab15109 100644 --- a/src/apps/debugger/arch/x86/CpuStateX86.h +++ b/src/apps/debugger/arch/x86/CpuStateX86.h @@ -50,6 +50,9 @@ public: virtual bool GetRegisterValue(const Register* reg, BVariant& _value); + uint32 InterruptVector() const + { return fInterruptVector; } + bool IsRegisterSet(int32 index) const; uint32 IntRegisterValue(int32 index) const; void SetIntRegister(int32 index, uint32 value); @@ -61,6 +64,7 @@ private: private: uint32 fIntRegisters[X86_REGISTER_COUNT]; RegisterBitSet fSetRegisters; + uint32 fInterruptVector; }; diff --git a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp index 7f026c3e47..31f4fe819f 100644 --- a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp +++ b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp @@ -86,3 +86,25 @@ DisassemblerX86::GetNextInstruction(BString& line, target_addr_t& _address, 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; + } + } +} diff --git a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h index c93a443303..6383750018 100644 --- a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h +++ b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h @@ -22,6 +22,10 @@ public: target_addr_t& _address, target_size_t& _size, bool& _breakpointAllowed); + virtual status_t GetPreviousInstruction( + target_addr_t nextAddress, + target_addr_t& _address, + target_size_t& _size); private: struct UdisData;