Skip to content

Commit 41a410a

Browse files
committed
add comments
1 parent b25477e commit 41a410a

File tree

8 files changed

+80
-79
lines changed

8 files changed

+80
-79
lines changed

lldb/include/lldb/Core/EmulateInstruction.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "lldb/lldb-private-types.h"
2323
#include "lldb/lldb-types.h"
2424

25+
#include "llvm/Support/Error.h"
26+
2527
#include <cstddef>
2628
#include <cstdint>
2729

@@ -44,12 +46,18 @@ class SingleStepBreakpointLocationsPredictor {
4446

4547
virtual BreakpointLocations GetBreakpointLocations(Status &status);
4648

47-
virtual unsigned GetBreakpointSize(lldb::addr_t, Status &) { return 4; }
49+
virtual llvm::Expected<unsigned> GetBreakpointSize(lldb::addr_t bp_addr) {
50+
return 4;
51+
}
4852

4953
virtual ~SingleStepBreakpointLocationsPredictor() = default;
5054

5155
protected:
52-
lldb::addr_t GetSequentiallyNextInstructionPC(Status &error);
56+
// This function retrieves the address of the next instruction as it appears
57+
// in the binary file. Essentially, it reads the value of the PC register,
58+
// determines the size of the current instruction (where the PC is pointing),
59+
// and returns the sum of these two values.
60+
lldb::addr_t GetNextInstructionAddress(Status &error);
5361

5462
lldb::addr_t GetBreakpointLocationAddress(lldb::addr_t entry_pc,
5563
Status &error);
@@ -547,6 +555,13 @@ class EmulateInstruction : public PluginInterface {
547555
private:
548556
virtual BreakpointLocationsPredictorCreator
549557
GetSingleStepBreakpointLocationsPredictorCreator() {
558+
if (!m_arch.IsMIPS() && !m_arch.GetTriple().isPPC64() &&
559+
!m_arch.GetTriple().isLoongArch()) {
560+
// Unsupported architecture
561+
return [](std::unique_ptr<EmulateInstruction> emulator_up) {
562+
return nullptr;
563+
};
564+
}
550565
return [](std::unique_ptr<EmulateInstruction> emulator_up) {
551566
return std::make_unique<SingleStepBreakpointLocationsPredictor>(
552567
std::move(emulator_up));

lldb/source/Core/EmulateInstruction.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ BreakpointLocations
620620
SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(Status &status) {
621621
if (!m_emulator_up->ReadInstruction()) {
622622
// try to get at least the size of next instruction to set breakpoint.
623-
lldb::addr_t next_pc = GetSequentiallyNextInstructionPC(status);
623+
lldb::addr_t next_pc = GetNextInstructionAddress(status);
624624
return BreakpointLocations{next_pc};
625625
}
626626

@@ -637,8 +637,7 @@ SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(Status &status) {
637637
return BreakpointLocations{next_pc};
638638
}
639639

640-
lldb::addr_t
641-
SingleStepBreakpointLocationsPredictor::GetSequentiallyNextInstructionPC(
640+
lldb::addr_t SingleStepBreakpointLocationsPredictor::GetNextInstructionAddress(
642641
Status &error) {
643642
auto instr_size = m_emulator_up->GetLastInstrSize();
644643
if (!instr_size) {
@@ -672,10 +671,10 @@ SingleStepBreakpointLocationsPredictor::GetBreakpointLocationAddress(
672671
}
673672

674673
if (entry_pc == pc) {
675-
// Emulate instruction failed and it haven't changed PC. Advance PC with
674+
// Emulate instruction failed and it hasn't changed PC. Advance PC with
676675
// the size of the current opcode because the emulation of all
677676
// PC modifying instruction should be successful. The failure most
678-
// likely caused by a not supported instruction which don't modify PC.
677+
// likely caused by an unsupported instruction which does not modify PC.
679678
return pc + m_emulator_up->GetOpcode().GetByteSize();
680679
}
681680

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14472,13 +14472,15 @@ bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
1447214472
return true;
1447314473
}
1447414474

14475-
unsigned ARMSingleStepBreakpointLocationsPredictor::GetBreakpointSize(
14476-
lldb::addr_t bp_addr, Status &error) {
14475+
llvm::Expected<unsigned>
14476+
ARMSingleStepBreakpointLocationsPredictor::GetBreakpointSize(
14477+
lldb::addr_t bp_addr) {
1447714478
auto flags = m_emulator_up->ReadRegisterUnsigned(
1447814479
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_ADDRESS,
1447914480
nullptr);
1448014481
if (flags == LLDB_INVALID_ADDRESS)
14481-
error = Status("Reading flags failed!");
14482+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
14483+
"Reading flags failed!");
1448214484

1448314485
return (flags & 0x20) ? /* Thumb mode */ 2 : /* Arm mode */ 4;
1448414486
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class ARMSingleStepBreakpointLocationsPredictor
2323
std::unique_ptr<EmulateInstruction> emulator_up)
2424
: SingleStepBreakpointLocationsPredictor{std::move(emulator_up)} {}
2525

26-
unsigned GetBreakpointSize(lldb::addr_t bp_addr, Status &error) override;
26+
llvm::Expected<unsigned> GetBreakpointSize(lldb::addr_t bp_addr) override;
2727
};
2828

2929
// ITSession - Keep track of the IT Block progression.

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,14 +1809,15 @@ RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointLocations(
18091809
"RISCVSingleStepBreakpointLocationsPredictor::%s: can't find "
18101810
"corresponding load reserve insturuction",
18111811
__FUNCTION__);
1812-
return {*pc + 4};
1812+
return {*pc + inst->is_rvc ? 2u : 4u};
18131813
}
18141814

18151815
return SingleStepBreakpointLocationsPredictor::GetBreakpointLocations(status);
18161816
}
18171817

1818-
unsigned RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointSize(
1819-
lldb::addr_t bp_addr, Status &error) {
1818+
llvm::Expected<unsigned>
1819+
RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointSize(
1820+
lldb::addr_t bp_addr) {
18201821
EmulateInstructionRISCV *riscv_emulator =
18211822
static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());
18221823

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class RISCVSingleStepBreakpointLocationsPredictor
2929

3030
BreakpointLocations GetBreakpointLocations(Status &status) override;
3131

32-
unsigned GetBreakpointSize(lldb::addr_t bp_addr, Status &error) override;
32+
llvm::Expected<unsigned> GetBreakpointSize(lldb::addr_t bp_addr) override;
3333

3434
private:
3535
static bool FoundLoadReserve(const RISCVInst &inst) {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,11 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
131131
return error;
132132

133133
for (auto &&bp_addr : bp_locations) {
134-
unsigned bp_size = bp_locaions_predictor->GetBreakpointSize(bp_addr, error);
135-
if (error.Fail())
136-
return error;
134+
auto bp_size = bp_locaions_predictor->GetBreakpointSize(bp_addr);
135+
if (auto err = bp_size.takeError())
136+
return Status(toString(std::move(err)));
137137

138-
error = SetSoftwareBreakpoint(bp_addr, bp_size, process);
138+
error = SetSoftwareBreakpoint(bp_addr, *bp_size, process);
139139
if (error.Fail())
140140
return error;
141141

Lines changed: 44 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Test software step-inst
2+
Test software step-inst, also known as instruction level single step, in risc-v atomic sequence.
33
"""
44

55
import lldb
@@ -9,11 +9,13 @@
99

1010

1111
class TestSoftwareStep(TestBase):
12-
@skipIf(archs=no_match(re.compile("rv*")))
13-
def test_cas(self):
14-
self.build()
12+
def do_sequence_test(filename, bkpt_name):
13+
source_file = filename + ".c"
14+
exe_file = filename + ".x"
15+
16+
self.build(dictionary={"C_SOURCES": source_file, "EXE": exe_file})
1517
(target, process, cur_thread, bkpt) = lldbutil.run_to_name_breakpoint(
16-
self, "cas"
18+
self, bkpt_name, exe_name=exe_file
1719
)
1820
entry_pc = cur_thread.GetFrameAtIndex(0).GetPC()
1921

@@ -24,67 +26,49 @@ def test_cas(self):
2426
)
2527

2628
pc = cur_thread.GetFrameAtIndex(0).GetPC()
27-
self.assertTrue((pc - entry_pc) > 0x10)
2829

29-
@skipIf(archs=no_match(re.compile("rv*")))
30-
def test_branch_cas(self):
31-
self.build(dictionary={"C_SOURCES": "branch.c", "EXE": "branch.x"})
32-
(target, process, cur_thread, bkpt) = lldbutil.run_to_name_breakpoint(
33-
self, "branch_cas", exe_name="branch.x"
34-
)
35-
entry_pc = cur_thread.GetFrameAtIndex(0).GetPC()
30+
return pc - entry_pc
3631

37-
self.runCmd("thread step-inst")
38-
self.expect(
39-
"thread list",
40-
substrs=["stopped", "stop reason = instruction step into"],
41-
)
32+
@skipIf(archs=no_match(re.compile("rv*")))
33+
def test_cas(self):
34+
"""
35+
This test verifies LLDB instruction step handling of a proper lr/sc pair.
36+
"""
37+
difference = do_sequence_test("main", "cas")
38+
self.assertTrue(difference > 0x10)
4239

43-
pc = cur_thread.GetFrameAtIndex(0).GetPC()
44-
self.assertTrue((pc - entry_pc) > 0x10)
40+
@skipIf(archs=no_match(re.compile("rv*")))
41+
def test_branch_cas(self):
42+
"""
43+
LLDB cannot predict the actual state of registers within a critical section (i.e., inside an atomic
44+
sequence). Therefore, it should identify all forward branches inside the atomic sequence and set
45+
breakpoints at every jump address that lies beyond the end of the sequence (after the sc instruction).
46+
This ensures that if any such branch is taken, execution will pause at its target address.
47+
48+
This test includes an lr/sc sequence containing an active forward branch with a jump address located
49+
after the end of the atomic section. LLDB should correctly stop at this branch's target address. The
50+
test is nearly identical to the previous one, except for the branch condition, which is inverted and
51+
will result in a taken jump.
52+
"""
53+
difference = do_sequence_test("branch", "branch_cas")
54+
self.assertTrue(difference > 0x10)
4555

4656
@skipIf(archs=no_match(re.compile("rv*")))
4757
def test_incomplete_sequence_without_lr(self):
48-
self.build(
49-
dictionary={
50-
"C_SOURCES": "incomplete_sequence_without_lr.c",
51-
"EXE": "incomplete_lr.x",
52-
}
53-
)
54-
(target, process, cur_thread, bkpt) = lldbutil.run_to_name_breakpoint(
55-
self, "incomplete_cas", exe_name="incomplete_lr.x"
56-
)
57-
entry_pc = cur_thread.GetFrameAtIndex(0).GetPC()
58-
59-
self.runCmd("thread step-inst")
60-
61-
self.expect(
62-
"thread list",
63-
substrs=["stopped", "stop reason = instruction step into"],
64-
)
65-
66-
pc = cur_thread.GetFrameAtIndex(0).GetPC()
67-
self.assertTrue((pc - entry_pc) == 0x4)
58+
"""
59+
This test verifies the behavior of a standalone sc instruction without a preceding lr. Since the sc
60+
lacks the required lr pairing, LLDB should treat it as a non-atomic store rather than part of an
61+
atomic sequence.
62+
"""
63+
difference = do_sequence_test("incomplete_sequence_without_lr", "incomplete_cas")
64+
self.assertTrue(difference == 0x4)
6865

6966
@skipIf(archs=no_match(re.compile("rv*")))
7067
def test_incomplete_sequence_without_sc(self):
71-
self.build(
72-
dictionary={
73-
"C_SOURCES": "incomplete_sequence_without_sc.c",
74-
"EXE": "incomplete_sc.x",
75-
}
76-
)
77-
(target, process, cur_thread, bkpt) = lldbutil.run_to_name_breakpoint(
78-
self, "incomplete_cas", exe_name="incomplete_sc.x"
79-
)
80-
entry_pc = cur_thread.GetFrameAtIndex(0).GetPC()
81-
82-
self.runCmd("thread step-inst")
83-
84-
self.expect(
85-
"thread list",
86-
substrs=["stopped", "stop reason = instruction step into"],
87-
)
88-
89-
pc = cur_thread.GetFrameAtIndex(0).GetPC()
90-
self.assertTrue((pc - entry_pc) == 0x4)
68+
"""
69+
This test checks the behavior of a standalone lr instruction without a subsequent sc. Since the lr
70+
lacks its required sc counterpart, LLDB should treat it as a non-atomic load rather than part of an
71+
atomic sequence.
72+
"""
73+
difference = do_sequence_test("incomplete_sequence_without_sc", "incomplete_cas")
74+
self.assertTrue(difference == 0x4)

0 commit comments

Comments
 (0)