Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
39642 views
//===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "NativeProcessSoftwareSingleStep.h"910#include "lldb/Core/EmulateInstruction.h"11#include "lldb/Host/common/NativeRegisterContext.h"12#include "lldb/Utility/RegisterValue.h"1314#include <unordered_map>1516using namespace lldb;17using namespace lldb_private;1819namespace {2021struct EmulatorBaton {22NativeProcessProtocol &m_process;23NativeRegisterContext &m_reg_context;2425// eRegisterKindDWARF -> RegsiterValue26std::unordered_map<uint32_t, RegisterValue> m_register_values;2728EmulatorBaton(NativeProcessProtocol &process,29NativeRegisterContext ®_context)30: m_process(process), m_reg_context(reg_context) {}31};3233} // anonymous namespace3435static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,36const EmulateInstruction::Context &context,37lldb::addr_t addr, void *dst, size_t length) {38EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);3940size_t bytes_read;41emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read);42return bytes_read;43}4445static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,46const RegisterInfo *reg_info,47RegisterValue ®_value) {48EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);4950auto it = emulator_baton->m_register_values.find(51reg_info->kinds[eRegisterKindDWARF]);52if (it != emulator_baton->m_register_values.end()) {53reg_value = it->second;54return true;55}5657// The emulator only fill in the dwarf regsiter numbers (and in some case the58// generic register numbers). Get the full register info from the register59// context based on the dwarf register numbers.60const RegisterInfo *full_reg_info =61emulator_baton->m_reg_context.GetRegisterInfo(62eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);6364Status error =65emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value);66if (error.Success())67return true;6869return false;70}7172static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,73const EmulateInstruction::Context &context,74const RegisterInfo *reg_info,75const RegisterValue ®_value) {76EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);77emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =78reg_value;79return true;80}8182static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,83const EmulateInstruction::Context &context,84lldb::addr_t addr, const void *dst,85size_t length) {86return length;87}8889static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) {90const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo(91eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);92return regsiter_context.ReadRegisterAsUnsigned(flags_info,93LLDB_INVALID_ADDRESS);94}9596static int GetSoftwareBreakpointSize(const ArchSpec &arch,97lldb::addr_t next_flags) {98if (arch.GetMachine() == llvm::Triple::arm) {99if (next_flags & 0x20)100// Thumb mode101return 2;102// Arm mode103return 4;104}105if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||106arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())107return 4;108return 0;109}110111static Status SetSoftwareBreakpointOnPC(const ArchSpec &arch, lldb::addr_t pc,112lldb::addr_t next_flags,113NativeProcessProtocol &process) {114int size_hint = GetSoftwareBreakpointSize(arch, next_flags);115Status error;116error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false);117118// If setting the breakpoint fails because pc is out of the address119// space, ignore it and let the debugee segfault.120if (error.GetError() == EIO || error.GetError() == EFAULT)121return Status();122if (error.Fail())123return error;124125return Status();126}127128Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(129NativeThreadProtocol &thread) {130Status error;131NativeProcessProtocol &process = thread.GetProcess();132NativeRegisterContext ®ister_context = thread.GetRegisterContext();133const ArchSpec &arch = process.GetArchitecture();134135std::unique_ptr<EmulateInstruction> emulator_up(136EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying,137nullptr));138139if (emulator_up == nullptr)140return Status("Instruction emulator not found!");141142EmulatorBaton baton(process, register_context);143emulator_up->SetBaton(&baton);144emulator_up->SetReadMemCallback(&ReadMemoryCallback);145emulator_up->SetReadRegCallback(&ReadRegisterCallback);146emulator_up->SetWriteMemCallback(&WriteMemoryCallback);147emulator_up->SetWriteRegCallback(&WriteRegisterCallback);148149if (!emulator_up->ReadInstruction()) {150// try to get at least the size of next instruction to set breakpoint.151auto instr_size = emulator_up->GetLastInstrSize();152if (!instr_size)153return Status("Read instruction failed!");154bool success = false;155auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric,156LLDB_REGNUM_GENERIC_PC,157LLDB_INVALID_ADDRESS, &success);158if (!success)159return Status("Reading pc failed!");160lldb::addr_t next_pc = pc + *instr_size;161auto result =162SetSoftwareBreakpointOnPC(arch, next_pc, /* next_flags */ 0x0, process);163m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});164return result;165}166167bool emulation_result =168emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);169170const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo(171eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);172const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo(173eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);174175auto pc_it =176baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);177auto flags_it = reg_info_flags == nullptr178? baton.m_register_values.end()179: baton.m_register_values.find(180reg_info_flags->kinds[eRegisterKindDWARF]);181182lldb::addr_t next_pc;183lldb::addr_t next_flags;184if (emulation_result) {185assert(pc_it != baton.m_register_values.end() &&186"Emulation was successfull but PC wasn't updated");187next_pc = pc_it->second.GetAsUInt64();188189if (flags_it != baton.m_register_values.end())190next_flags = flags_it->second.GetAsUInt64();191else192next_flags = ReadFlags(register_context);193} else if (pc_it == baton.m_register_values.end()) {194// Emulate instruction failed and it haven't changed PC. Advance PC with195// the size of the current opcode because the emulation of all196// PC modifying instruction should be successful. The failure most197// likely caused by a not supported instruction which don't modify PC.198next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize();199next_flags = ReadFlags(register_context);200} else {201// The instruction emulation failed after it modified the PC. It is an202// unknown error where we can't continue because the next instruction is203// modifying the PC but we don't know how.204return Status("Instruction emulation failed unexpectedly.");205}206auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process);207m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});208return result;209}210211212