Skip to content

Commit b9465b5

Browse files
committed
optimize for architectures with a fixed opcode size, add backwards disassembly test
1 parent 3cfe849 commit b9465b5

File tree

8 files changed

+116
-42
lines changed

8 files changed

+116
-42
lines changed

lldb/include/lldb/API/SBTarget.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ class LLDB_API SBTarget {
349349

350350
SBError SetLabel(const char *label);
351351

352+
uint32_t GetMinimumOpcodeByteSize() const;
353+
354+
uint32_t GetMaximumOpcodeByteSize() const;
355+
352356
/// Architecture data byte width accessor
353357
///
354358
/// \return

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ def __init__(
136136
self.initialized = False
137137
self.frame_scopes = {}
138138
self.init_commands = init_commands
139-
self.disassembled_instructions = {}
140139

141140
@classmethod
142141
def encode_content(cls, s: str) -> bytes:
@@ -735,11 +734,15 @@ def request_disconnect(self, terminateDebuggee=None):
735734
return self.send_recv(command_dict)
736735

737736
def request_disassemble(
738-
self, memoryReference, offset=0, instructionCount=200, resolveSymbols=True
737+
self,
738+
memoryReference,
739+
instructionOffset=-50,
740+
instructionCount=200,
741+
resolveSymbols=True,
739742
):
740743
args_dict = {
741744
"memoryReference": memoryReference,
742-
"offset": offset,
745+
"instructionOffset": instructionOffset,
743746
"instructionCount": instructionCount,
744747
"resolveSymbols": resolveSymbols,
745748
}
@@ -748,9 +751,7 @@ def request_disassemble(
748751
"type": "request",
749752
"arguments": args_dict,
750753
}
751-
instructions = self.send_recv(command_dict)["body"]["instructions"]
752-
for inst in instructions:
753-
self.disassembled_instructions[inst["address"]] = inst
754+
return self.send_recv(command_dict)["body"]["instructions"]
754755

755756
def request_readMemory(self, memoryReference, offset, count):
756757
args_dict = {

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,14 @@ def disassemble(self, threadId=None, frameIndex=None):
346346
memoryReference = stackFrames[0]["instructionPointerReference"]
347347
self.assertIsNotNone(memoryReference)
348348

349-
if memoryReference not in self.dap_server.disassembled_instructions:
350-
self.dap_server.request_disassemble(memoryReference=memoryReference)
349+
instructions = self.dap_server.request_disassemble(
350+
memoryReference=memoryReference
351+
)
352+
disassembled_instructions = {}
353+
for inst in instructions:
354+
disassembled_instructions[inst["address"]] = inst
351355

352-
return self.dap_server.disassembled_instructions[memoryReference]
356+
return disassembled_instructions, disassembled_instructions[memoryReference]
353357

354358
def attach(
355359
self,

lldb/source/API/SBTarget.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,6 +1668,26 @@ SBError SBTarget::SetLabel(const char *label) {
16681668
return Status::FromError(target_sp->SetLabel(label));
16691669
}
16701670

1671+
uint32_t SBTarget::GetMinimumOpcodeByteSize() const {
1672+
LLDB_INSTRUMENT_VA(this);
1673+
1674+
TargetSP target_sp(GetSP());
1675+
if (target_sp) {
1676+
return target_sp->GetArchitecture().GetMinimumOpcodeByteSize();
1677+
}
1678+
return 0;
1679+
}
1680+
1681+
uint32_t SBTarget::GetMaximumOpcodeByteSize() const {
1682+
LLDB_INSTRUMENT_VA(this);
1683+
1684+
TargetSP target_sp(GetSP());
1685+
if (target_sp) {
1686+
return target_sp->GetArchitecture().GetMaximumOpcodeByteSize();
1687+
}
1688+
return 0;
1689+
}
1690+
16711691
uint32_t SBTarget::GetDataByteSize() {
16721692
LLDB_INSTRUMENT_VA(this);
16731693

lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,48 @@ def test_disassemble(self):
2020
program = self.getBuildArtifact("a.out")
2121
self.build_and_launch(program)
2222
source = "main.c"
23-
self.source_path = os.path.join(os.getcwd(), source)
24-
self.set_source_breakpoints(
25-
source,
26-
[
27-
line_number(source, "// breakpoint 1"),
28-
],
29-
)
23+
self.set_source_breakpoints(source, [line_number(source, "// breakpoint 1")])
3024
self.continue_to_next_stop()
3125

32-
pc_assembly = self.disassemble(frameIndex=0)
26+
_, pc_assembly = self.disassemble(frameIndex=0)
3327
self.assertIn("location", pc_assembly, "Source location missing.")
3428
self.assertIn("instruction", pc_assembly, "Assembly instruction missing.")
3529

3630
# The calling frame (qsort) is coming from a system library, as a result
3731
# we should not have a source location.
38-
qsort_assembly = self.disassemble(frameIndex=1)
32+
_, qsort_assembly = self.disassemble(frameIndex=1)
3933
self.assertNotIn("location", qsort_assembly, "Source location not expected.")
4034
self.assertIn("instruction", pc_assembly, "Assembly instruction missing.")
35+
36+
def test_disassemble_backwards(self):
37+
"""
38+
Tests the 'disassemble' request with a backwards disassembly range.
39+
"""
40+
program = self.getBuildArtifact("a.out")
41+
self.build_and_launch(program)
42+
source = "main.c"
43+
self.set_source_breakpoints(source, [line_number(source, "// breakpoint 1")])
44+
self.continue_to_next_stop()
45+
46+
instruction_pointer_reference = self.get_stackFrames()[1][
47+
"instructionPointerReference"
48+
]
49+
backwards_instructions = 50
50+
instructions = self.dap_server.request_disassemble(
51+
memoryReference=instruction_pointer_reference,
52+
instructionOffset=-backwards_instructions,
53+
)
54+
55+
frame_instruction_index = next(
56+
(
57+
i
58+
for i, instruction in enumerate(instructions)
59+
if instruction["address"] == instruction_pointer_reference
60+
),
61+
-1,
62+
)
63+
self.assertEqual(
64+
frame_instruction_index,
65+
backwards_instructions,
66+
f"requested instruction should be preceeded by {backwards_instructions} instructions. Actual index: {frame_instruction_index}",
67+
)

lldb/test/API/tools/lldb-dap/disassemble/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ int main(void) {
2727

2828
printf("\n");
2929
return 0;
30-
}
30+
}

lldb/test/API/tools/lldb-dap/instruction-breakpoint/TestDAP_instruction_breakpoint.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,15 @@ def instruction_breakpoint_test(self):
6666
)
6767

6868
# Check disassembly view
69-
instruction = self.disassemble(frameIndex=0)
69+
disassembled_instructions, instruction = self.disassemble(frameIndex=0)
7070
self.assertEqual(
7171
instruction["address"],
7272
intstructionPointerReference[0],
7373
"current breakpoint reference is not in the disaasembly view",
7474
)
7575

7676
# Get next instruction address to set instruction breakpoint
77-
disassembled_instruction_list = self.dap_server.disassembled_instructions
78-
instruction_addr_list = list(disassembled_instruction_list.keys())
77+
instruction_addr_list = list(disassembled_instructions.keys())
7978
index = instruction_addr_list.index(intstructionPointerReference[0])
8079
if len(instruction_addr_list) >= (index + 1):
8180
next_inst_addr = instruction_addr_list[index + 1]

lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -105,29 +105,48 @@ DisassembleRequestHandler::disassembleBackwards(
105105
const char *flavor_string, bool resolve_symbols) const {
106106
std::vector<DisassembledInstruction> instructions;
107107

108-
// TODO: Simply disassemble from `addr` - `instruction_count` *
109-
// `instruction_size` in architectures with a fixed instruction size.
110-
111-
// need to disassemble backwards, let's try from the start of the symbol if
112-
// available.
113-
auto symbol = addr.GetSymbol();
114-
if (symbol.IsValid()) {
115-
// add valid instructions before the current instruction using the symbol.
116-
lldb::SBInstructionList symbol_insts = dap.target.ReadInstructions(
117-
symbol.GetStartAddress(), addr, flavor_string);
118-
if (symbol_insts.IsValid()) {
119-
size_t backwards_insts_start =
120-
symbol_insts.GetSize() >= instruction_count
121-
? symbol_insts.GetSize() - instruction_count
122-
: 0;
123-
for (size_t i = backwards_insts_start;
124-
i < symbol_insts.GetSize() &&
125-
instructions.size() < instruction_count;
126-
++i) {
127-
lldb::SBInstruction inst = symbol_insts.GetInstructionAtIndex(i);
108+
if (dap.target.GetMinimumOpcodeByteSize() ==
109+
dap.target.GetMaximumOpcodeByteSize()) {
110+
// If the target has a fixed opcode size, we can disassemble backwards
111+
// directly.
112+
lldb::addr_t disassemble_start_load_addr =
113+
addr.GetLoadAddress(dap.target) -
114+
(instruction_count * dap.target.GetMinimumOpcodeByteSize());
115+
lldb::SBAddress disassemble_start_addr(disassemble_start_load_addr,
116+
dap.target);
117+
lldb::SBInstructionList backwards_insts =
118+
dap.target.ReadInstructions(addr, instruction_count, flavor_string);
119+
if (backwards_insts.IsValid()) {
120+
for (size_t i = 0; i < backwards_insts.GetSize(); ++i) {
121+
lldb::SBInstruction inst = backwards_insts.GetInstructionAtIndex(i);
128122
instructions.push_back(
129123
SBInstructionToDisassembledInstruction(inst, resolve_symbols));
130124
}
125+
return instructions;
126+
}
127+
} else {
128+
// There is no opcode fixed size so we have no idea where are the valid
129+
// instructions before the current address. let's try from the start of the
130+
// symbol if available.
131+
auto symbol = addr.GetSymbol();
132+
if (symbol.IsValid()) {
133+
// add valid instructions before the current instruction using the symbol.
134+
lldb::SBInstructionList symbol_insts = dap.target.ReadInstructions(
135+
symbol.GetStartAddress(), addr, flavor_string);
136+
if (symbol_insts.IsValid()) {
137+
size_t backwards_insts_start =
138+
symbol_insts.GetSize() >= instruction_count
139+
? symbol_insts.GetSize() - instruction_count
140+
: 0;
141+
for (size_t i = backwards_insts_start;
142+
i < symbol_insts.GetSize() &&
143+
instructions.size() < instruction_count;
144+
++i) {
145+
lldb::SBInstruction inst = symbol_insts.GetInstructionAtIndex(i);
146+
instructions.push_back(
147+
SBInstructionToDisassembledInstruction(inst, resolve_symbols));
148+
}
149+
}
131150
}
132151
}
133152

0 commit comments

Comments
 (0)