Skip to content

Commit 2520b8d

Browse files
committed
[lldb][RISCV] handle lr/sc single step
lldb-server had limited support for single-stepping through the lr/sc atomic sequence. This patch enhances that support for all possible atomic sequences.
1 parent 4194192 commit 2520b8d

12 files changed

+422
-183
lines changed

lldb/include/lldb/Core/EmulateInstruction.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,31 @@ class RegisterValue;
3232
class Stream;
3333
class Target;
3434
class UnwindPlan;
35+
class EmulateInstruction;
36+
37+
using BreakpointLocations = std::vector<lldb::addr_t>;
38+
39+
class SingleStepBreakpointLocationsPredictor {
40+
public:
41+
SingleStepBreakpointLocationsPredictor(
42+
std::unique_ptr<EmulateInstruction> emulator_up)
43+
: m_emulator_up{std::move(emulator_up)} {}
44+
45+
virtual BreakpointLocations GetBreakpointLocations(Status &status);
46+
47+
virtual unsigned GetBreakpointSize(lldb::addr_t, Status &) { return 4; }
48+
49+
virtual ~SingleStepBreakpointLocationsPredictor() = default;
50+
51+
protected:
52+
lldb::addr_t GetSequentiallyNextInstructionPC(Status &error);
53+
54+
lldb::addr_t GetBreakpointLocationAddress(lldb::addr_t entry_pc,
55+
Status &error);
56+
57+
std::unique_ptr<EmulateInstruction> m_emulator_up;
58+
bool m_emulation_result = false;
59+
};
3560

3661
/// \class EmulateInstruction EmulateInstruction.h
3762
/// "lldb/Core/EmulateInstruction.h"
@@ -497,7 +522,19 @@ class EmulateInstruction : public PluginInterface {
497522
static uint32_t GetInternalRegisterNumber(RegisterContext *reg_ctx,
498523
const RegisterInfo &reg_info);
499524

525+
static std::unique_ptr<SingleStepBreakpointLocationsPredictor>
526+
CreateBreakpointLocationPredictor(
527+
std::unique_ptr<EmulateInstruction> emulator_up);
528+
529+
// Helper functions
530+
std::optional<lldb::addr_t> ReadPC();
531+
bool WritePC(lldb::addr_t addr);
532+
500533
protected:
534+
using BreakpointLocationsPredictorCreator =
535+
std::function<std::unique_ptr<SingleStepBreakpointLocationsPredictor>(
536+
std::unique_ptr<EmulateInstruction>)>;
537+
501538
ArchSpec m_arch;
502539
void *m_baton = nullptr;
503540
ReadMemoryCallback m_read_mem_callback = &ReadMemoryDefault;
@@ -508,6 +545,14 @@ class EmulateInstruction : public PluginInterface {
508545
Opcode m_opcode;
509546

510547
private:
548+
virtual BreakpointLocationsPredictorCreator
549+
GetSingleStepBreakpointLocationsPredictorCreator() {
550+
return [](std::unique_ptr<EmulateInstruction> emulator_up) {
551+
return std::make_unique<SingleStepBreakpointLocationsPredictor>(
552+
std::move(emulator_up));
553+
};
554+
}
555+
511556
// For EmulateInstruction only
512557
EmulateInstruction(const EmulateInstruction &) = delete;
513558
const EmulateInstruction &operator=(const EmulateInstruction &) = delete;

lldb/source/Core/EmulateInstruction.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,100 @@ EmulateInstruction::GetInternalRegisterNumber(RegisterContext *reg_ctx,
588588
return LLDB_INVALID_REGNUM;
589589
}
590590

591+
std::unique_ptr<SingleStepBreakpointLocationsPredictor>
592+
EmulateInstruction::CreateBreakpointLocationPredictor(
593+
std::unique_ptr<EmulateInstruction> emulator_up) {
594+
auto creator =
595+
emulator_up->GetSingleStepBreakpointLocationsPredictorCreator();
596+
return creator(std::move(emulator_up));
597+
}
598+
599+
std::optional<lldb::addr_t> EmulateInstruction::ReadPC() {
600+
bool success = false;
601+
auto addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
602+
LLDB_INVALID_ADDRESS, &success);
603+
return success ? std::optional<addr_t>(addr) : std::nullopt;
604+
}
605+
606+
bool EmulateInstruction::WritePC(lldb::addr_t addr) {
607+
EmulateInstruction::Context ctx;
608+
ctx.type = eContextAdvancePC;
609+
ctx.SetNoArgs();
610+
return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,
611+
LLDB_REGNUM_GENERIC_PC, addr);
612+
}
613+
591614
bool EmulateInstruction::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
592615
unwind_plan.Clear();
593616
return false;
594617
}
618+
619+
BreakpointLocations
620+
SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(Status &status) {
621+
if (!m_emulator_up->ReadInstruction()) {
622+
// try to get at least the size of next instruction to set breakpoint.
623+
lldb::addr_t next_pc = GetSequentiallyNextInstructionPC(status);
624+
return BreakpointLocations{next_pc};
625+
}
626+
627+
auto entry_pc = m_emulator_up->ReadPC();
628+
if (!entry_pc) {
629+
status = Status("Can't read PC");
630+
return {};
631+
}
632+
633+
m_emulation_result = m_emulator_up->EvaluateInstruction(
634+
eEmulateInstructionOptionAutoAdvancePC);
635+
636+
lldb::addr_t next_pc = GetBreakpointLocationAddress(*entry_pc, status);
637+
return BreakpointLocations{next_pc};
638+
}
639+
640+
lldb::addr_t
641+
SingleStepBreakpointLocationsPredictor::GetSequentiallyNextInstructionPC(
642+
Status &error) {
643+
auto instr_size = m_emulator_up->GetLastInstrSize();
644+
if (!instr_size) {
645+
error = Status("Read instruction failed!");
646+
return LLDB_INVALID_ADDRESS;
647+
}
648+
649+
auto pc = m_emulator_up->ReadPC();
650+
if (!pc) {
651+
error = Status("Can't read PC");
652+
return LLDB_INVALID_ADDRESS;
653+
}
654+
655+
lldb::addr_t next_pc = *pc + *instr_size;
656+
return next_pc;
657+
}
658+
659+
lldb::addr_t
660+
SingleStepBreakpointLocationsPredictor::GetBreakpointLocationAddress(
661+
lldb::addr_t entry_pc, Status &error) {
662+
auto addr = m_emulator_up->ReadPC();
663+
if (!addr) {
664+
error = Status("Can't read PC");
665+
return LLDB_INVALID_ADDRESS;
666+
}
667+
lldb::addr_t pc = *addr;
668+
669+
if (m_emulation_result) {
670+
assert(entry_pc != pc && "Emulation was successfull but PC wasn't updated");
671+
return pc;
672+
}
673+
674+
if (entry_pc == pc) {
675+
// Emulate instruction failed and it haven't changed PC. Advance PC with
676+
// the size of the current opcode because the emulation of all
677+
// PC modifying instruction should be successful. The failure most
678+
// likely caused by a not supported instruction which don't modify PC.
679+
return pc + m_emulator_up->GetOpcode().GetByteSize();
680+
}
681+
682+
// The instruction emulation failed after it modified the PC. It is an
683+
// unknown error where we can't continue because the next instruction is
684+
// modifying the PC but we don't know how.
685+
error = Status("Instruction emulation failed unexpectedly.");
686+
return LLDB_INVALID_ADDRESS;
687+
}

lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14471,3 +14471,14 @@ bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
1447114471
unwind_plan.SetReturnAddressRegister(dwarf_lr);
1447214472
return true;
1447314473
}
14474+
14475+
unsigned ARMSingleStepBreakpointLocationsPredictor::GetBreakpointSize(
14476+
lldb::addr_t bp_addr, Status &error) {
14477+
auto flags = m_emulator_up->ReadRegisterUnsigned(
14478+
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_ADDRESS,
14479+
nullptr);
14480+
if (flags == LLDB_INVALID_ADDRESS)
14481+
error = Status("Reading flags failed!");
14482+
14483+
return (flags & 0x20) ? /* Thumb mode */ 2 : /* Arm mode */ 4;
14484+
}

lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@
1616

1717
namespace lldb_private {
1818

19+
class ARMSingleStepBreakpointLocationsPredictor
20+
: public SingleStepBreakpointLocationsPredictor {
21+
public:
22+
ARMSingleStepBreakpointLocationsPredictor(
23+
std::unique_ptr<EmulateInstruction> emulator_up)
24+
: SingleStepBreakpointLocationsPredictor{std::move(emulator_up)} {}
25+
26+
unsigned GetBreakpointSize(lldb::addr_t bp_addr, Status &error) override;
27+
};
28+
1929
// ITSession - Keep track of the IT Block progression.
2030
class ITSession {
2131
public:
@@ -770,6 +780,14 @@ class EmulateInstructionARM : public EmulateInstruction {
770780
// B6.2.13 SUBS PC, LR and related instructions
771781
bool EmulateSUBSPcLrEtc(const uint32_t opcode, const ARMEncoding encoding);
772782

783+
BreakpointLocationsPredictorCreator
784+
GetSingleStepBreakpointLocationsPredictorCreator() override {
785+
return [](std::unique_ptr<EmulateInstruction> emulator_up) {
786+
return std::make_unique<ARMSingleStepBreakpointLocationsPredictor>(
787+
std::move(emulator_up));
788+
};
789+
}
790+
773791
uint32_t m_arm_isa;
774792
Mode m_opcode_mode;
775793
uint32_t m_opcode_cpsr;

0 commit comments

Comments
 (0)