Skip to content

Commit 480f1a4

Browse files
authored
[lldb-dap] fix wrong assembly line number x64 (#136486)
Fix wrong assembly line number calculation that assumes the instruction size is `GetAddressByteSize() / 2` Fixes #136495
1 parent 51dc0cc commit 480f1a4

File tree

4 files changed

+103
-4
lines changed

4 files changed

+103
-4
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c
2+
3+
include Makefile.rules
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Test lldb-dap stack trace containing x86 assembly
3+
"""
4+
5+
import lldbdap_testcase
6+
from lldbsuite.test import lldbplatformutil
7+
from lldbsuite.test.decorators import skipUnlessArch, skipUnlessPlatform
8+
from lldbsuite.test.lldbtest import line_number
9+
10+
11+
class TestDAP_stacktrace_x86(lldbdap_testcase.DAPTestCaseBase):
12+
@skipUnlessArch("x86_64")
13+
@skipUnlessPlatform(["linux"] + lldbplatformutil.getDarwinOSTriples())
14+
def test_stacktrace_x86(self):
15+
"""
16+
Tests that lldb-dap steps through correctly and the source lines are correct in x86 assembly.
17+
"""
18+
program = self.getBuildArtifact("a.out")
19+
self.build_and_launch(
20+
program,
21+
initCommands=[
22+
"settings set target.process.thread.step-in-avoid-nodebug false"
23+
],
24+
)
25+
26+
source = "main.c"
27+
breakpoint_ids = self.set_source_breakpoints(
28+
source,
29+
[line_number(source, "// Break here")],
30+
)
31+
self.continue_to_breakpoints(breakpoint_ids)
32+
self.stepIn()
33+
34+
frame = self.get_stackFrames()[0]
35+
self.assertEqual(
36+
frame["name"],
37+
"no_branch_func",
38+
"verify we are in the no_branch_func function",
39+
)
40+
41+
self.assertEqual(frame["line"], 1, "verify we are at the start of the function")
42+
minimum_assembly_lines = (
43+
line_number(source, "Assembly end")
44+
- line_number(source, "Assembly start")
45+
+ 1
46+
)
47+
self.assertLessEqual(
48+
10,
49+
minimum_assembly_lines,
50+
"verify we have a reasonable number of assembly lines",
51+
)
52+
53+
for i in range(2, minimum_assembly_lines):
54+
self.stepIn()
55+
frame = self.get_stackFrames()[0]
56+
self.assertEqual(
57+
frame["name"],
58+
"no_branch_func",
59+
"verify we are still in the no_branch_func function",
60+
)
61+
self.assertEqual(
62+
frame["line"],
63+
i,
64+
f"step in should advance a single line in the function to {i}",
65+
)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <stdio.h>
2+
3+
__attribute__((nodebug)) int no_branch_func(void) {
4+
int result = 0;
5+
6+
__asm__ __volatile__("movl $0, %%eax;" // Assembly start
7+
"incl %%eax;"
8+
"incl %%eax;"
9+
"incl %%eax;"
10+
"incl %%eax;"
11+
"incl %%eax;"
12+
"incl %%eax;"
13+
"incl %%eax;"
14+
"incl %%eax;"
15+
"incl %%eax;"
16+
"incl %%eax;"
17+
"movl %%eax, %0;" // Assembly end
18+
: "=r"(result)
19+
:
20+
: "%eax");
21+
22+
return result;
23+
}
24+
25+
int main(void) {
26+
int result = no_branch_func(); // Break here
27+
printf("Result: %d\n", result);
28+
return 0;
29+
}

lldb/tools/lldb-dap/JSONUtils.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "lldb/API/SBFileSpec.h"
2020
#include "lldb/API/SBFrame.h"
2121
#include "lldb/API/SBFunction.h"
22+
#include "lldb/API/SBInstructionList.h"
2223
#include "lldb/API/SBLineEntry.h"
2324
#include "lldb/API/SBModule.h"
2425
#include "lldb/API/SBQueue.h"
@@ -776,10 +777,11 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
776777

777778
// Calculate the line of the current PC from the start of the current
778779
// symbol.
779-
lldb::addr_t inst_offset = frame.GetPCAddress().GetOffset() -
780-
frame.GetSymbol().GetStartAddress().GetOffset();
781-
lldb::addr_t inst_line =
782-
inst_offset / (frame.GetThread().GetProcess().GetAddressByteSize() / 2);
780+
lldb::SBTarget target = frame.GetThread().GetProcess().GetTarget();
781+
lldb::SBInstructionList inst_list = target.ReadInstructions(
782+
frame.GetSymbol().GetStartAddress(), frame.GetPCAddress(), nullptr);
783+
size_t inst_line = inst_list.GetSize();
784+
783785
// Line numbers are 1-based.
784786
object.try_emplace("line", inst_line + 1);
785787
object.try_emplace("column", 1);

0 commit comments

Comments
 (0)