Revert "[lldb][RISCV] fix LR/SC atomic sequence handling in lldb-server" (#145597)

Reverts llvm/llvm-project#127505 because
`riscv/step/TestSoftwareStep.py` is failing on the bots.
This commit is contained in:
Jonas Devlieghere
2025-06-24 16:04:58 -05:00
committed by GitHub
parent 830b2c842e
commit aa3c5d0297
19 changed files with 188 additions and 643 deletions

View File

@@ -588,99 +588,7 @@ EmulateInstruction::GetInternalRegisterNumber(RegisterContext *reg_ctx,
return LLDB_INVALID_REGNUM;
}
std::unique_ptr<SingleStepBreakpointLocationsPredictor>
EmulateInstruction::CreateBreakpointLocationPredictor(
std::unique_ptr<EmulateInstruction> emulator_up) {
auto creator =
emulator_up->GetSingleStepBreakpointLocationsPredictorCreator();
return creator(std::move(emulator_up));
}
std::optional<lldb::addr_t> EmulateInstruction::ReadPC() {
bool success = false;
auto addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
LLDB_INVALID_ADDRESS, &success);
return success ? std::optional<addr_t>(addr) : std::nullopt;
}
bool EmulateInstruction::WritePC(lldb::addr_t addr) {
EmulateInstruction::Context ctx;
ctx.type = eContextAdvancePC;
ctx.SetNoArgs();
return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC, addr);
}
bool EmulateInstruction::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
return false;
}
BreakpointLocations
SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(Status &status) {
if (!m_emulator_up->ReadInstruction()) {
// try to get at least the size of next instruction to set breakpoint.
lldb::addr_t next_pc = GetNextInstructionAddress(status);
return BreakpointLocations{next_pc};
}
auto entry_pc = m_emulator_up->ReadPC();
if (!entry_pc) {
status = Status("Can't read PC");
return {};
}
m_emulation_result = m_emulator_up->EvaluateInstruction(
eEmulateInstructionOptionAutoAdvancePC);
lldb::addr_t next_pc = GetBreakpointLocationAddress(*entry_pc, status);
return BreakpointLocations{next_pc};
}
lldb::addr_t SingleStepBreakpointLocationsPredictor::GetNextInstructionAddress(
Status &error) {
auto instr_size = m_emulator_up->GetLastInstrSize();
if (!instr_size) {
error = Status("Read instruction failed!");
return LLDB_INVALID_ADDRESS;
}
auto pc = m_emulator_up->ReadPC();
if (!pc) {
error = Status("Can't read PC");
return LLDB_INVALID_ADDRESS;
}
lldb::addr_t next_pc = *pc + *instr_size;
return next_pc;
}
lldb::addr_t
SingleStepBreakpointLocationsPredictor::GetBreakpointLocationAddress(
lldb::addr_t entry_pc, Status &error) {
auto addr = m_emulator_up->ReadPC();
if (!addr) {
error = Status("Can't read PC");
return LLDB_INVALID_ADDRESS;
}
lldb::addr_t pc = *addr;
if (m_emulation_result) {
assert(entry_pc != pc && "Emulation was successfull but PC wasn't updated");
return pc;
}
if (entry_pc == pc) {
// Emulate instruction failed and it hasn't changed PC. Advance PC with
// the size of the current opcode because the emulation of all
// PC modifying instruction should be successful. The failure most
// likely caused by an unsupported instruction which does not modify PC.
return pc + m_emulator_up->GetOpcode().GetByteSize();
}
// The instruction emulation failed after it modified the PC. It is an
// unknown error where we can't continue because the next instruction is
// modifying the PC but we don't know how.
error = Status("Instruction emulation failed unexpectedly.");
return LLDB_INVALID_ADDRESS;
}

View File

@@ -14471,16 +14471,3 @@ bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
unwind_plan.SetReturnAddressRegister(dwarf_lr);
return true;
}
llvm::Expected<unsigned>
ARMSingleStepBreakpointLocationsPredictor::GetBreakpointSize(
lldb::addr_t bp_addr) {
auto flags = m_emulator_up->ReadRegisterUnsigned(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_ADDRESS,
nullptr);
if (flags == LLDB_INVALID_ADDRESS)
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Reading flags failed!");
return (flags & 0x20) ? /* Thumb mode */ 2 : /* Arm mode */ 4;
}

View File

@@ -16,16 +16,6 @@
namespace lldb_private {
class ARMSingleStepBreakpointLocationsPredictor
: public SingleStepBreakpointLocationsPredictor {
public:
ARMSingleStepBreakpointLocationsPredictor(
std::unique_ptr<EmulateInstruction> emulator_up)
: SingleStepBreakpointLocationsPredictor{std::move(emulator_up)} {}
llvm::Expected<unsigned> GetBreakpointSize(lldb::addr_t bp_addr) override;
};
// ITSession - Keep track of the IT Block progression.
class ITSession {
public:
@@ -780,14 +770,6 @@ protected:
// B6.2.13 SUBS PC, LR and related instructions
bool EmulateSUBSPcLrEtc(const uint32_t opcode, const ARMEncoding encoding);
BreakpointLocationsPredictorCreator
GetSingleStepBreakpointLocationsPredictorCreator() override {
return [](std::unique_ptr<EmulateInstruction> emulator_up) {
return std::make_unique<ARMSingleStepBreakpointLocationsPredictor>(
std::move(emulator_up));
};
}
uint32_t m_arm_isa;
Mode m_opcode_mode;
uint32_t m_opcode_cpsr;

View File

@@ -86,6 +86,7 @@ bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {
uint32_t inst_size = m_opcode.GetByteSize();
uint32_t inst = m_opcode.GetOpcode32();
bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC;
bool success = false;
Opcode *opcode_data = GetOpcodeForInstruction(inst);
if (!opcode_data)
@@ -93,10 +94,9 @@ bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {
lldb::addr_t old_pc = 0;
if (increase_pc) {
auto addr = ReadPC();
if (!addr)
old_pc = ReadPC(&success);
if (!success)
return false;
old_pc = *addr;
}
// Call the Emulate... function.
@@ -104,10 +104,9 @@ bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {
return false;
if (increase_pc) {
auto addr = ReadPC();
if (!addr)
lldb::addr_t new_pc = ReadPC(&success);
if (!success)
return false;
lldb::addr_t new_pc = *addr;
if (new_pc == old_pc && !WritePC(old_pc + inst_size))
return false;
@@ -116,14 +115,13 @@ bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {
}
bool EmulateInstructionLoongArch::ReadInstruction() {
auto addr = ReadPC();
if (!addr) {
bool success = false;
m_addr = ReadPC(&success);
if (!success) {
m_addr = LLDB_INVALID_ADDRESS;
return false;
}
m_addr = *addr;
bool success = false;
Context ctx;
ctx.type = eContextReadOpcode;
ctx.SetNoArgs();
@@ -133,6 +131,19 @@ bool EmulateInstructionLoongArch::ReadInstruction() {
return true;
}
lldb::addr_t EmulateInstructionLoongArch::ReadPC(bool *success) {
return ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
LLDB_INVALID_ADDRESS, success);
}
bool EmulateInstructionLoongArch::WritePC(lldb::addr_t pc) {
EmulateInstruction::Context ctx;
ctx.type = eContextAdvancePC;
ctx.SetNoArgs();
return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC, pc);
}
std::optional<RegisterInfo>
EmulateInstructionLoongArch::GetRegisterInfo(lldb::RegisterKind reg_kind,
uint32_t reg_index) {
@@ -262,12 +273,9 @@ bool EmulateInstructionLoongArch::EmulateNonJMP(uint32_t inst) { return false; }
bool EmulateInstructionLoongArch::EmulateBEQZ64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
@@ -285,12 +293,9 @@ bool EmulateInstructionLoongArch::EmulateBEQZ64(uint32_t inst) {
bool EmulateInstructionLoongArch::EmulateBNEZ64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
@@ -308,12 +313,9 @@ bool EmulateInstructionLoongArch::EmulateBNEZ64(uint32_t inst) {
bool EmulateInstructionLoongArch::EmulateBCEQZ64(uint32_t inst) {
bool success = false;
uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
uint8_t cj_val =
(uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);
@@ -333,12 +335,9 @@ bool EmulateInstructionLoongArch::EmulateBCEQZ64(uint32_t inst) {
bool EmulateInstructionLoongArch::EmulateBCNEZ64(uint32_t inst) {
bool success = false;
uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
uint8_t cj_val =
(uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);
@@ -359,12 +358,9 @@ bool EmulateInstructionLoongArch::EmulateJIRL64(uint32_t inst) {
uint32_t rj = Bits32(inst, 9, 5);
uint32_t rd = Bits32(inst, 4, 0);
bool success = false;
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
EmulateInstruction::Context ctx;
if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, rd, pc + 4))
return false;
@@ -378,11 +374,10 @@ bool EmulateInstructionLoongArch::EmulateJIRL64(uint32_t inst) {
// b offs26
// PC = PC + SignExtend({offs26, 2' b0}, GRLEN)
bool EmulateInstructionLoongArch::EmulateB64(uint32_t inst) {
auto addr = ReadPC();
if (!addr)
bool success = false;
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint32_t offs26 = Bits32(inst, 25, 10) + (Bits32(inst, 9, 0) << 16);
uint64_t next_pc = pc + llvm::SignExtend64<28>(offs26 << 2);
return WritePC(next_pc);
@@ -392,11 +387,10 @@ bool EmulateInstructionLoongArch::EmulateB64(uint32_t inst) {
// GR[1] = PC + 4
// PC = PC + SignExtend({offs26, 2'b0}, GRLEN)
bool EmulateInstructionLoongArch::EmulateBL64(uint32_t inst) {
auto addr = ReadPC();
if (!addr)
bool success = false;
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
EmulateInstruction::Context ctx;
if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_loongarch, pc + 4))
return false;
@@ -412,12 +406,9 @@ bool EmulateInstructionLoongArch::EmulateBEQ64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
uint32_t rd = Bits32(inst, 4, 0);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
return false;
@@ -438,12 +429,9 @@ bool EmulateInstructionLoongArch::EmulateBNE64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
uint32_t rd = Bits32(inst, 4, 0);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
return false;
@@ -464,12 +452,9 @@ bool EmulateInstructionLoongArch::EmulateBLT64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
uint32_t rd = Bits32(inst, 4, 0);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
int64_t rj_val =
(int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
@@ -492,12 +477,9 @@ bool EmulateInstructionLoongArch::EmulateBGE64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
uint32_t rd = Bits32(inst, 4, 0);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
int64_t rj_val =
(int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
@@ -520,12 +502,9 @@ bool EmulateInstructionLoongArch::EmulateBLTU64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
uint32_t rd = Bits32(inst, 4, 0);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
return false;
@@ -546,12 +525,9 @@ bool EmulateInstructionLoongArch::EmulateBGEU64(uint32_t inst) {
bool success = false;
uint32_t rj = Bits32(inst, 9, 5);
uint32_t rd = Bits32(inst, 4, 0);
auto addr = ReadPC();
if (!addr)
uint64_t pc = ReadPC(&success);
if (!success)
return false;
uint64_t pc = *addr;
uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
if (!success)
return false;

View File

@@ -57,6 +57,8 @@ public:
std::optional<RegisterInfo> GetRegisterInfo(lldb::RegisterKind reg_kind,
uint32_t reg_num) override;
lldb::addr_t ReadPC(bool *success);
bool WritePC(lldb::addr_t pc);
bool IsLoongArch64() { return m_arch_subtype == llvm::Triple::loongarch64; }
bool TestExecute(uint32_t inst);

View File

@@ -650,10 +650,9 @@ std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) {
for (const InstrPattern &pat : PATTERNS) {
if ((inst & pat.type_mask) == pat.eigen &&
(inst_type & pat.inst_type) != 0) {
LLDB_LOGF(log,
"EmulateInstructionRISCV::%s: inst(%x at %" PRIx64
") was decoded to %s",
__FUNCTION__, inst, m_addr, pat.name);
LLDB_LOGF(
log, "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64 ") was decoded to %s",
__FUNCTION__, inst, m_addr, pat.name);
auto decoded = is_16b ? pat.decode(try_rvc) : pat.decode(inst);
return DecodeResult{decoded, inst, is_16b, pat};
}
@@ -1650,6 +1649,21 @@ bool EmulateInstructionRISCV::ReadInstruction() {
return true;
}
std::optional<addr_t> EmulateInstructionRISCV::ReadPC() {
bool success = false;
auto addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
LLDB_INVALID_ADDRESS, &success);
return success ? std::optional<addr_t>(addr) : std::nullopt;
}
bool EmulateInstructionRISCV::WritePC(addr_t pc) {
EmulateInstruction::Context ctx;
ctx.type = eContextAdvancePC;
ctx.SetNoArgs();
return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC, pc);
}
RoundingMode EmulateInstructionRISCV::GetRoundingMode() {
bool success = false;
auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv,
@@ -1778,128 +1792,4 @@ bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec &arch) {
return arch.GetTriple().isRISCV();
}
BreakpointLocations
RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointLocations(
Status &status) {
EmulateInstructionRISCV *riscv_emulator =
static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());
auto pc = riscv_emulator->ReadPC();
if (!pc) {
status = Status("Can't read PC");
return {};
}
auto inst = riscv_emulator->ReadInstructionAt(*pc);
if (!inst) {
// Can't read instruction. Try default handler.
return SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(
status);
}
if (FoundLoadReserve(inst->decoded))
return HandleAtomicSequence(*pc, status);
if (FoundStoreConditional(inst->decoded)) {
// Ill-formed atomic sequence (SC doesn't have corresponding LR
// instruction). Consider SC instruction like a non-atomic store and set a
// breakpoint at the next instruction.
Log *log = GetLog(LLDBLog::Unwind);
LLDB_LOGF(log,
"RISCVSingleStepBreakpointLocationsPredictor::%s: can't find "
"corresponding load reserve insturuction",
__FUNCTION__);
return {*pc + (inst->is_rvc ? 2u : 4u)};
}
return SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(status);
}
llvm::Expected<unsigned>
RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointSize(
lldb::addr_t bp_addr) {
EmulateInstructionRISCV *riscv_emulator =
static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());
if (auto inst = riscv_emulator->ReadInstructionAt(bp_addr); inst)
return inst->is_rvc ? 2 : 4;
// Try last instruction size.
if (auto last_instr_size = riscv_emulator->GetLastInstrSize();
last_instr_size)
return *last_instr_size;
// Just place non-compressed software trap.
return 4;
}
BreakpointLocations
RISCVSingleStepBreakpointLocationsPredictor::HandleAtomicSequence(
lldb::addr_t pc, Status &error) {
EmulateInstructionRISCV *riscv_emulator =
static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());
// Handle instructions between LR and SC. According to unprivilleged
// RISC-V ISA there can be at most 16 instructions in the sequence.
lldb::addr_t entry_pc = pc; // LR instruction address
auto lr_inst = riscv_emulator->ReadInstructionAt(entry_pc);
pc += lr_inst->is_rvc ? 2 : 4;
size_t atomic_length = 0;
std::optional<DecodeResult> inst;
std::vector<lldb::addr_t> bp_addrs;
do {
inst = riscv_emulator->ReadInstructionAt(pc);
if (!inst) {
error = Status("Can't read instruction");
return {};
}
if (B *branch = std::get_if<B>(&inst->decoded))
bp_addrs.push_back(pc + SignExt(branch->imm));
unsigned addent = inst->is_rvc ? 2 : 4;
pc += addent;
atomic_length += addent;
} while ((atomic_length < s_max_atomic_sequence_length) &&
!FoundStoreConditional(inst->decoded));
if (atomic_length >= s_max_atomic_sequence_length) {
// Ill-formed atomic sequence (LR doesn't have corresponding SC
// instruction). In this case consider LR like a non-atomic load instruction
// and set a breakpoint at the next after LR instruction.
Log *log = GetLog(LLDBLog::Unwind);
LLDB_LOGF(log,
"RISCVSingleStepBreakpointLocationsPredictor::%s: can't find "
"corresponding store conditional insturuction",
__FUNCTION__);
return {entry_pc + (lr_inst->is_rvc ? 2u : 4u)};
}
lldb::addr_t exit_pc = pc;
// Check if we have a branch to the start of the atomic sequence after SC
// instruction. If we have such branch, consider it as a part of the atomic
// sequence.
inst = riscv_emulator->ReadInstructionAt(exit_pc);
if (inst) {
B *branch = std::get_if<B>(&inst->decoded);
if (branch && (exit_pc + SignExt(branch->imm)) == entry_pc)
exit_pc += inst->is_rvc ? 2 : 4;
}
// Set breakpoints at the jump addresses of the forward branches that points
// after the end of the atomic sequence.
bp_addrs.erase(llvm::remove_if(bp_addrs,
[exit_pc](lldb::addr_t bp_addr) {
return exit_pc >= bp_addr;
}),
bp_addrs.end());
// Set breakpoint at the end of atomic sequence.
bp_addrs.push_back(exit_pc);
return bp_addrs;
}
} // namespace lldb_private

View File

@@ -20,33 +20,6 @@
namespace lldb_private {
class RISCVSingleStepBreakpointLocationsPredictor
: public SingleStepBreakpointLocationsPredictor {
public:
RISCVSingleStepBreakpointLocationsPredictor(
std::unique_ptr<EmulateInstruction> emulator)
: SingleStepBreakpointLocationsPredictor{std::move(emulator)} {}
BreakpointLocations GetBreakpointLocations(Status &status) override;
llvm::Expected<unsigned> GetBreakpointSize(lldb::addr_t bp_addr) override;
private:
static bool FoundLoadReserve(const RISCVInst &inst) {
return std::holds_alternative<LR_W>(inst) ||
std::holds_alternative<LR_D>(inst);
}
static bool FoundStoreConditional(const RISCVInst &inst) {
return std::holds_alternative<SC_W>(inst) ||
std::holds_alternative<SC_D>(inst);
}
BreakpointLocations HandleAtomicSequence(lldb::addr_t pc, Status &error);
static constexpr size_t s_max_atomic_sequence_length = 64;
};
class EmulateInstructionRISCV : public EmulateInstruction {
public:
static llvm::StringRef GetPluginNameStatic() { return "riscv"; }
@@ -94,6 +67,9 @@ public:
std::optional<RegisterInfo> GetRegisterInfo(lldb::RegisterKind reg_kind,
uint32_t reg_num) override;
std::optional<lldb::addr_t> ReadPC();
bool WritePC(lldb::addr_t pc);
std::optional<DecodeResult> ReadInstructionAt(lldb::addr_t addr);
std::optional<DecodeResult> Decode(uint32_t inst);
bool Execute(DecodeResult inst, bool ignore_cond);
@@ -122,13 +98,6 @@ public:
bool SetAccruedExceptions(llvm::APFloatBase::opStatus);
private:
BreakpointLocationsPredictorCreator
GetSingleStepBreakpointLocationsPredictorCreator() override {
return [](std::unique_ptr<EmulateInstruction> emulator_up) {
return std::make_unique<RISCVSingleStepBreakpointLocationsPredictor>(
std::move(emulator_up));
};
}
/// Last decoded instruction from m_opcode
DecodeResult m_decoded;
/// Last decoded instruction size estimate.

View File

@@ -324,14 +324,12 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
auto thread_info =
m_threads_stepping_with_breakpoint.find(thread->GetID());
if (thread_info != m_threads_stepping_with_breakpoint.end() &&
llvm::is_contained(thread_info->second, regctx.GetPC())) {
thread_info->second == regctx.GetPC()) {
thread->SetStoppedByTrace();
for (auto &&bp_addr : thread_info->second) {
Status brkpt_error = RemoveBreakpoint(bp_addr);
if (brkpt_error.Fail())
LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
thread_info->first, brkpt_error);
}
Status brkpt_error = RemoveBreakpoint(thread_info->second);
if (brkpt_error.Fail())
LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
thread_info->first, brkpt_error);
m_threads_stepping_with_breakpoint.erase(thread_info);
} else
thread->SetStoppedByBreakpoint();

View File

@@ -833,7 +833,7 @@ void NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread) {
auto stepping_with_bp_it =
m_threads_stepping_with_breakpoint.find(thread.GetID());
if (stepping_with_bp_it != m_threads_stepping_with_breakpoint.end() &&
llvm::is_contained(stepping_with_bp_it->second, reg_ctx.GetPC()))
stepping_with_bp_it->second == reg_ctx.GetPC())
thread.SetStoppedByTrace();
StopRunningThreads(thread.GetID());
@@ -1960,12 +1960,10 @@ void NativeProcessLinux::SignalIfAllThreadsStopped() {
// Clear any temporary breakpoints we used to implement software single
// stepping.
for (const auto &thread_info : m_threads_stepping_with_breakpoint) {
for (auto &&bp_addr : thread_info.second) {
Status error = RemoveBreakpoint(bp_addr);
if (error.Fail())
LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
thread_info.first, error);
}
Status error = RemoveBreakpoint(thread_info.second);
if (error.Fail())
LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
thread_info.first, error);
}
m_threads_stepping_with_breakpoint.clear();

View File

@@ -87,10 +87,34 @@ static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
return length;
}
static Status SetSoftwareBreakpoint(lldb::addr_t bp_addr, unsigned bp_size,
NativeProcessProtocol &process) {
static lldb::addr_t ReadFlags(NativeRegisterContext &regsiter_context) {
const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
return regsiter_context.ReadRegisterAsUnsigned(flags_info,
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(bp_addr, bp_size, /*hardware=*/false);
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.
@@ -112,6 +136,7 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
std::unique_ptr<EmulateInstruction> emulator_up(
EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying,
nullptr));
if (emulator_up == nullptr)
return Status::FromErrorString("Instruction emulator not found!");
@@ -122,24 +147,65 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
auto bp_locaions_predictor =
EmulateInstruction::CreateBreakpointLocationPredictor(
std::move(emulator_up));
auto bp_locations = bp_locaions_predictor->GetBreakpointLocations(error);
if (error.Fail())
return error;
for (auto &&bp_addr : bp_locations) {
auto bp_size = bp_locaions_predictor->GetBreakpointSize(bp_addr);
if (auto err = bp_size.takeError())
return Status(toString(std::move(err)));
error = SetSoftwareBreakpoint(bp_addr, *bp_size, process);
if (error.Fail())
return error;
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::FromErrorString("Read instruction failed!");
bool success = false;
auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC,
LLDB_INVALID_ADDRESS, &success);
if (!success)
return Status::FromErrorString("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;
}
m_threads_stepping_with_breakpoint.insert({thread.GetID(), bp_locations});
return error;
bool emulation_result =
emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
auto pc_it =
baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
auto flags_it = reg_info_flags == nullptr
? baton.m_register_values.end()
: baton.m_register_values.find(
reg_info_flags->kinds[eRegisterKindDWARF]);
lldb::addr_t next_pc;
lldb::addr_t next_flags;
if (emulation_result) {
assert(pc_it != baton.m_register_values.end() &&
"Emulation was successfull but PC wasn't updated");
next_pc = pc_it->second.GetAsUInt64();
if (flags_it != baton.m_register_values.end())
next_flags = flags_it->second.GetAsUInt64();
else
next_flags = ReadFlags(register_context);
} else if (pc_it == baton.m_register_values.end()) {
// Emulate instruction failed and it haven't changed PC. Advance PC with
// the size of the current opcode because the emulation of all
// PC modifying instruction should be successful. The failure most
// likely caused by a not supported instruction which don't modify PC.
next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize();
next_flags = ReadFlags(register_context);
} else {
// The instruction emulation failed after it modified the PC. It is an
// unknown error where we can't continue because the next instruction is
// modifying the PC but we don't know how.
return Status::FromErrorString(
"Instruction emulation failed unexpectedly.");
}
auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process);
m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
return result;
}

View File

@@ -23,8 +23,7 @@ public:
protected:
// List of thread ids stepping with a breakpoint with the address of
// the relevan breakpoint
std::map<lldb::tid_t, std::vector<lldb::addr_t>>
m_threads_stepping_with_breakpoint;
std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
};
} // namespace lldb_private