Skip to content

Commit a95314e

Browse files
committed
[lldb][riscv] Fix setting breakpoint for undecoded instruction
Copy gdb behaviour: For RISCV we can set breakpoint even for unknown instruction, as RISCV encoding have information about size of instruction.
1 parent 3d1145a commit a95314e

File tree

3 files changed

+75
-29
lines changed

3 files changed

+75
-29
lines changed

lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,9 +624,26 @@ std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
624624
uint16_t try_rvc = uint16_t(inst & 0x0000ffff);
625625
// check whether the compressed encode could be valid
626626
uint16_t mask = try_rvc & 0b11;
627-
bool is_rvc = try_rvc != 0 && mask != 3;
628627
uint8_t inst_type = RV64;
629628

629+
// Try to get size of RISCV instruction.
630+
// 1.2 Instruction Length Encoding
631+
bool is_16b = (inst & 0b11) != 0b11;
632+
bool is_32b = (inst & 0x1f) != 0x1f;
633+
bool is_48b = (inst & 0x3f) != 0x1f;
634+
bool is_64b = (inst & 0x7f) != 0x3f;
635+
if (is_16b)
636+
m_last_size = 2;
637+
else if (is_32b)
638+
m_last_size = 4;
639+
else if (is_48b)
640+
m_last_size = 6;
641+
else if (is_64b)
642+
m_last_size = 8;
643+
else
644+
// Not Valid
645+
m_last_size = std::nullopt;
646+
630647
// if we have ArchSpec::eCore_riscv128 in the future,
631648
// we also need to check it here
632649
if (m_arch.GetCore() == ArchSpec::eCore_riscv32)
@@ -638,8 +655,8 @@ std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
638655
LLDB_LOGF(
639656
log, "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64 ") was decoded to %s",
640657
__FUNCTION__, inst, m_addr, pat.name);
641-
auto decoded = is_rvc ? pat.decode(try_rvc) : pat.decode(inst);
642-
return DecodeResult{decoded, inst, is_rvc, pat};
658+
auto decoded = is_16b ? pat.decode(try_rvc) : pat.decode(inst);
659+
return DecodeResult{decoded, inst, is_16b, pat};
643660
}
644661
}
645662
LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported",

lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class EmulateInstructionRISCV : public EmulateInstruction {
6060

6161
bool SetTargetTriple(const ArchSpec &arch) override;
6262
bool ReadInstruction() override;
63+
virtual std::optional<uint32_t> GetLastInstrSize() { return std::nullopt; }
6364
bool EvaluateInstruction(uint32_t options) override;
6465
bool TestEmulation(Stream &out_stream, ArchSpec &arch,
6566
OptionValueDictionary *test_data) override;
@@ -99,6 +100,8 @@ class EmulateInstructionRISCV : public EmulateInstruction {
99100
private:
100101
/// Last decoded instruction from m_opcode
101102
DecodeResult m_decoded;
103+
/// Last decoded instruction size estimate.
104+
std::optional<uint32_t> m_last_size;
102105
};
103106

104107
} // namespace lldb_private

lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,39 @@ static lldb::addr_t ReadFlags(NativeRegisterContext &regsiter_context) {
9494
LLDB_INVALID_ADDRESS);
9595
}
9696

97+
static int GetSoftwareWatchpointSize(const ArchSpec &arch,
98+
lldb::addr_t next_flags) {
99+
if (arch.GetMachine() == llvm::Triple::arm) {
100+
if (next_flags & 0x20)
101+
// Thumb mode
102+
return 2;
103+
else
104+
// Arm mode
105+
return 4;
106+
}
107+
if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
108+
arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())
109+
return 4;
110+
return 0;
111+
}
112+
113+
static Status SetSoftwareBreakPointOnPC(const ArchSpec &arch, lldb::addr_t pc,
114+
lldb::addr_t next_flags,
115+
NativeProcessProtocol &process) {
116+
int size_hint = GetSoftwareWatchpointSize(arch, next_flags);
117+
Status error;
118+
error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false);
119+
120+
// If setting the breakpoint fails because pc is out of the address
121+
// space, ignore it and let the debugee segfault.
122+
if (error.GetError() == EIO || error.GetError() == EFAULT) {
123+
return Status();
124+
} else if (error.Fail())
125+
return error;
126+
127+
return Status();
128+
}
129+
97130
Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
98131
NativeThreadProtocol &thread) {
99132
Status error;
@@ -115,8 +148,23 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
115148
emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
116149
emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
117150

118-
if (!emulator_up->ReadInstruction())
119-
return Status("Read instruction failed!");
151+
if (!emulator_up->ReadInstruction()) {
152+
// try to get at least the size of next instruction to set breakpoint.
153+
auto instrSizeOpt = emulator_up->GetLastInstrSize();
154+
if (!instrSizeOpt)
155+
return Status("Read instruction failed!");
156+
bool success = false;
157+
auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric,
158+
LLDB_REGNUM_GENERIC_PC,
159+
LLDB_INVALID_ADDRESS, &success);
160+
if (!success)
161+
return Status("Reading pc failed!");
162+
lldb::addr_t next_pc = pc + *instrSizeOpt;
163+
auto Result =
164+
SetSoftwareBreakPointOnPC(arch, next_pc, /* next_flags */ 0x0, process);
165+
m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
166+
return Result;
167+
}
120168

121169
bool emulation_result =
122170
emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
@@ -157,29 +205,7 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
157205
// modifying the PC but we don't know how.
158206
return Status("Instruction emulation failed unexpectedly.");
159207
}
160-
161-
int size_hint = 0;
162-
if (arch.GetMachine() == llvm::Triple::arm) {
163-
if (next_flags & 0x20) {
164-
// Thumb mode
165-
size_hint = 2;
166-
} else {
167-
// Arm mode
168-
size_hint = 4;
169-
}
170-
} else if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
171-
arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())
172-
size_hint = 4;
173-
error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false);
174-
175-
// If setting the breakpoint fails because next_pc is out of the address
176-
// space, ignore it and let the debugee segfault.
177-
if (error.GetError() == EIO || error.GetError() == EFAULT) {
178-
return Status();
179-
} else if (error.Fail())
180-
return error;
181-
208+
auto Result = SetSoftwareBreakPointOnPC(arch, next_pc, next_flags, process);
182209
m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
183-
184-
return Status();
210+
return Result;
185211
}

0 commit comments

Comments
 (0)