Exemplo n.º 1
0
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;
}