status_t ArchitectureX8664::CreateStackFrame(Image* image, FunctionDebugInfo* function, CpuState* _cpuState, bool isTopFrame, StackFrame*& _frame, CpuState*& _previousCpuState) { CpuStateX8664* cpuState = dynamic_cast<CpuStateX8664*>(_cpuState); uint64 framePointer = cpuState->IntRegisterValue(X86_64_REGISTER_RBP); uint64 rip = cpuState->IntRegisterValue(X86_64_REGISTER_RIP); bool readStandardFrame = true; uint64 previousFramePointer = 0; uint64 returnAddress = 0; // check for syscall frames stack_frame_type frameType; bool hasPrologue = false; 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 rip. frameType = STACK_FRAME_TYPE_SYSCALL; rip -= 2; // int 99, sysenter, and syscall all are 2 byte instructions // The syscall stubs are frameless, the return address is on top of the // stack. uint32 rsp = cpuState->IntRegisterValue(X86_64_REGISTER_RSP); uint32 address; if (fTeamMemory->ReadMemory(rsp, &address, 8) == 8) { returnAddress = address; previousFramePointer = framePointer; framePointer = 0; readStandardFrame = false; } } else { hasPrologue = _HasFunctionPrologue(function); if (hasPrologue) frameType = STACK_FRAME_TYPE_STANDARD; else frameType = STACK_FRAME_TYPE_FRAMELESS; // TODO: Handling for frameless functions. It's not trivial to find the // return address on the stack, though. // If the function is not frameless and we're at the top frame we need // to check whether the prologue has not been executed (completely) or // we're already after the epilogue. if (isTopFrame) { uint64 stack = 0; if (hasPrologue) { if (rip < function->Address() + kFunctionPrologueSize) { // The prologue has not been executed yet, i.e. there's no // stack frame yet. Get the return address from the stack. stack = cpuState->IntRegisterValue(X86_64_REGISTER_RSP); if (rip > function->Address()) { // The "push %rbp" has already been executed. stack += 8; } } else { // Not in the function prologue, but maybe after the // epilogue. The epilogue is a single "pop %rbp", so we // check whether the current instruction is already a // "ret". uint8 code[1]; if (fTeamMemory->ReadMemory(rip, &code, 1) == 1 && code[0] == 0xc3) { stack = cpuState->IntRegisterValue( X86_64_REGISTER_RSP); } } } else { // Check if the instruction pointer is at a readable location. // If it isn't, then chances are we got here via a bogus // function pointer, and the prologue hasn't actually been // executed. In such a case, what we need is right at the top // of the stack. uint8 data[1]; if (fTeamMemory->ReadMemory(rip, &data, 1) != 1) stack = cpuState->IntRegisterValue(X86_64_REGISTER_RSP); } if (stack != 0) { uint64 address; if (fTeamMemory->ReadMemory(stack, &address, 8) == 8) { returnAddress = address; previousFramePointer = framePointer; framePointer = 0; readStandardFrame = false; frameType = STACK_FRAME_TYPE_FRAMELESS; } } } } // create the stack frame StackFrameDebugInfo* stackFrameDebugInfo = new(std::nothrow) NoOpStackFrameDebugInfo; if (stackFrameDebugInfo == NULL) return B_NO_MEMORY; BReference<StackFrameDebugInfo> stackFrameDebugInfoReference( stackFrameDebugInfo, true); StackFrame* frame = new(std::nothrow) StackFrame(frameType, cpuState, framePointer, rip, stackFrameDebugInfo); if (frame == NULL) return B_NO_MEMORY; BReference<StackFrame> frameReference(frame, true); status_t error = frame->Init(); if (error != B_OK) return error; // read the previous frame and return address, if this is a standard frame if (readStandardFrame) { uint64 frameData[2]; if (framePointer != 0 && fTeamMemory->ReadMemory(framePointer, frameData, 16) == 16) { previousFramePointer = frameData[0]; returnAddress = frameData[1]; } } // create the CPU state, if we have any info CpuStateX8664* previousCpuState = NULL; if (returnAddress != 0) { // prepare the previous CPU state previousCpuState = new(std::nothrow) CpuStateX8664; if (previousCpuState == NULL) return B_NO_MEMORY; previousCpuState->SetIntRegister(X86_64_REGISTER_RBP, previousFramePointer); previousCpuState->SetIntRegister(X86_64_REGISTER_RIP, returnAddress); frame->SetPreviousCpuState(previousCpuState); } frame->SetReturnAddress(returnAddress); _frame = frameReference.Detach(); _previousCpuState = previousCpuState; return B_OK; }