Skip to content

Commit 9d0614e

Browse files
authored
[lldb-dap] fix disassembly request instruction offset handling (#140486)
Fix the handling of the `instructionOffset` parameter, which resulted in always returning the wrong disassembly because VSCode always uses `instructionOffset = -50` and expects 50 instructions before the given address, instead of 50 bytes before
1 parent 1fd2436 commit 9d0614e

File tree

8 files changed

+282
-105
lines changed

8 files changed

+282
-105
lines changed

lldb/include/lldb/API/SBTarget.h

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

350350
SBError SetLabel(const char *label);
351351

352+
/// Architecture opcode byte size width accessor
353+
///
354+
/// \return
355+
/// The minimum size in 8-bit (host) bytes of an opcode.
356+
uint32_t GetMinimumOpcodeByteSize() const;
357+
358+
/// Architecture opcode byte size width accessor
359+
///
360+
/// \return
361+
/// The maximum size in 8-bit (host) bytes of an opcode.
362+
uint32_t GetMaximumOpcodeByteSize() const;
363+
352364
/// Architecture data byte width accessor
353365
///
354366
/// \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=-50, 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: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,56 @@ 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 = 200
50+
instructions_count = 400
51+
instructions = self.dap_server.request_disassemble(
52+
memoryReference=instruction_pointer_reference,
53+
instructionOffset=-backwards_instructions,
54+
instructionCount=instructions_count,
55+
)
56+
57+
self.assertEqual(
58+
len(instructions),
59+
instructions_count,
60+
"Disassemble request should return the exact requested number of instructions.",
61+
)
62+
63+
frame_instruction_index = next(
64+
(
65+
i
66+
for i, instruction in enumerate(instructions)
67+
if instruction["address"] == instruction_pointer_reference
68+
),
69+
-1,
70+
)
71+
self.assertEqual(
72+
frame_instruction_index,
73+
backwards_instructions,
74+
f"requested instruction should be preceeded by {backwards_instructions} instructions. Actual index: {frame_instruction_index}",
75+
)

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]

0 commit comments

Comments
 (0)