status_t ArchitectureX8664::ResolvePICFunctionAddress(target_addr_t instructionAddress, CpuState* state, target_addr_t& _targetAddress) { target_addr_t previousIP = state->InstructionPointer(); // if the function in question is position-independent, the call // will actually have taken us to its corresponding PLT slot. // in such a case, look at the disassembled jump to determine // where to find the actual function address. InstructionInfo info; if (GetInstructionInfo(instructionAddress, info, state) != B_OK) return B_BAD_VALUE; // x86-64 is likely to use a RIP-relative jump here // as such, set our instruction pointer to the address // after this instruction (where it would be during actual // execution), and recalculate the target address of the jump state->SetInstructionPointer(info.Address() + info.Size()); status_t result = GetInstructionInfo(info.Address(), info, state); state->SetInstructionPointer(previousIP); if (result != B_OK) return result; target_addr_t subroutineAddress; ssize_t bytesRead = fTeamMemory->ReadMemory(info.TargetAddress(), &subroutineAddress, fAddressSize); if (bytesRead != fAddressSize) return B_BAD_VALUE; _targetAddress = subroutineAddress; return B_OK; }
status_t DisassemblerX8664::GetNextInstructionInfo(InstructionInfo& _info, CpuState* state) { unsigned int size = ud_disassemble(fUdisData); if (size < 1) return B_ENTRY_NOT_FOUND; target_addr_t address = ud_insn_off(fUdisData); instruction_type type = INSTRUCTION_TYPE_OTHER; target_addr_t targetAddress = 0; ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData); if (mnemonic == UD_Icall) type = INSTRUCTION_TYPE_SUBROUTINE_CALL; else if (mnemonic == UD_Ijmp) type = INSTRUCTION_TYPE_JUMP; if (state != NULL) targetAddress = GetInstructionTargetAddress(state); char buffer[256]; snprintf(buffer, sizeof(buffer), "0x%016" B_PRIx64 ": %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; }
bool ThreadHandler::_DoStepOver(CpuState* cpuState) { TRACE_CONTROL("ThreadHandler::_DoStepOver()\n"); // The basic strategy is to single-step out of the statement like for // "step into", only we have to avoid stepping into subroutines. Hence we // check whether the current instruction is a subroutine call. If not, we // just single-step, otherwise we set a breakpoint after the instruction. InstructionInfo info; if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo( cpuState->InstructionPointer(), info, cpuState) != B_OK) { TRACE_CONTROL(" failed to get instruction info\n"); return false; } if (info.Type() != INSTRUCTION_TYPE_SUBROUTINE_CALL) { _SingleStepThread(cpuState->InstructionPointer()); TRACE_CONTROL(" not a subroutine call\n"); return true; } TRACE_CONTROL(" subroutine call -- installing breakpoint at address " "%#" B_PRIx64 "\n", info.Address() + info.Size()); if (_InstallTemporaryBreakpoint(info.Address() + info.Size()) != B_OK) return false; fSteppedOverFunctionAddress = info.TargetAddress(); _RunThread(cpuState->InstructionPointer()); return true; }
status_t ArchitectureX8664::GetStatement(FunctionDebugInfo* function, target_addr_t address, Statement*& _statement) { // TODO: This is not architecture dependent anymore! // get the instruction info InstructionInfo info; status_t error = GetInstructionInfo(address, info, NULL); if (error != B_OK) return error; // create a statement ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( SourceLocation(-1), TargetAddressRange(info.Address(), info.Size())); if (statement == NULL) return B_NO_MEMORY; _statement = statement; return B_OK; }