diff options
| author | ita-sc <109672931+ita-sc@users.noreply.github.com> | 2024-07-16 12:03:42 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-16 10:03:42 +0100 |
| commit | a1ffabc403d4ce55ab2e665511b0b68a16d4850b (patch) | |
| tree | 3c61df0bca4bf67eef3f31172c9ae69002db5ca2 /lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp | |
| parent | 762a47828ef6c19426e37e1ecae6768035a4ccac (diff) | |
[lldb][riscv] Fix setting breakpoint for undecoded instruction (#90075)
This patch adds an interface GetLastInstrSize to get information about
the size of last tried to be decoded instruction and uses it to set
software breakpoint if the memory can be decoded as instruction.
RISC-V architecture instruction format specifies the length of
instruction in first bits, so we can set a breakpoint for these cases.
This is needed as RISCV have a lot of extensions, that are not supported
by `EmulateInstructionRISCV`.
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp')
| -rw-r--r-- | lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp | 77 |
1 files changed, 51 insertions, 26 deletions
diff --git a/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp index 6bf8a0dc28b2..ef71a964eaf2 100644 --- a/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp +++ b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp @@ -94,6 +94,38 @@ static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { LLDB_INVALID_ADDRESS); } +static int GetSoftwareBreakpointSize(const ArchSpec &arch, + lldb::addr_t next_flags) { + if (arch.GetMachine() == llvm::Triple::arm) { + if (next_flags & 0x20) + // Thumb mode + return 2; + // Arm mode + return 4; + } + if (arch.IsMIPS() || arch.GetTriple().isPPC64() || + arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch()) + return 4; + return 0; +} + +static Status SetSoftwareBreakpointOnPC(const ArchSpec &arch, lldb::addr_t pc, + lldb::addr_t next_flags, + NativeProcessProtocol &process) { + int size_hint = GetSoftwareBreakpointSize(arch, next_flags); + Status error; + error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false); + + // If setting the breakpoint fails because pc is out of the address + // space, ignore it and let the debugee segfault. + if (error.GetError() == EIO || error.GetError() == EFAULT) + return Status(); + if (error.Fail()) + return error; + + return Status(); +} + Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( NativeThreadProtocol &thread) { Status error; @@ -115,8 +147,23 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( emulator_up->SetWriteMemCallback(&WriteMemoryCallback); emulator_up->SetWriteRegCallback(&WriteRegisterCallback); - if (!emulator_up->ReadInstruction()) - return Status("Read instruction failed!"); + if (!emulator_up->ReadInstruction()) { + // try to get at least the size of next instruction to set breakpoint. + auto instr_size = emulator_up->GetLastInstrSize(); + if (!instr_size) + return Status("Read instruction failed!"); + bool success = false; + auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC, + LLDB_INVALID_ADDRESS, &success); + if (!success) + return Status("Reading pc failed!"); + lldb::addr_t next_pc = pc + *instr_size; + auto result = + SetSoftwareBreakpointOnPC(arch, next_pc, /* next_flags */ 0x0, process); + m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); + return result; + } bool emulation_result = emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); @@ -157,29 +204,7 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( // modifying the PC but we don't know how. return Status("Instruction emulation failed unexpectedly."); } - - int size_hint = 0; - if (arch.GetMachine() == llvm::Triple::arm) { - if (next_flags & 0x20) { - // Thumb mode - size_hint = 2; - } else { - // Arm mode - size_hint = 4; - } - } else if (arch.IsMIPS() || arch.GetTriple().isPPC64() || - arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch()) - size_hint = 4; - error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false); - - // If setting the breakpoint fails because next_pc is out of the address - // space, ignore it and let the debugee segfault. - if (error.GetError() == EIO || error.GetError() == EFAULT) { - return Status(); - } else if (error.Fail()) - return error; - + auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process); m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); - - return Status(); + return result; } |
