Skip to content

Commit 535b284

Browse files
authored
[Symbolize] Always use filename:line from debug info when debug info for the given address is available. (llvm#128619)
To reland llvm#124846, we need to make symbolizer consistent with the case when line number is 0. Always using filename and line from debug info even if the line number is 0 sounds like the reasonable path to go.
1 parent aacc4e9 commit 535b284

File tree

3 files changed

+252
-8
lines changed

3 files changed

+252
-8
lines changed

llvm/lib/DebugInfo/DWARF/DWARFContext.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,11 +1733,11 @@ DWARFContext::getLocalsForAddress(object::SectionedAddress Address) {
17331733
std::optional<DILineInfo>
17341734
DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
17351735
DILineInfoSpecifier Spec) {
1736-
DILineInfo Result;
17371736
DWARFCompileUnit *CU = getCompileUnitForCodeAddress(Address.Address);
17381737
if (!CU)
1739-
return Result;
1738+
return std::nullopt;
17401739

1740+
DILineInfo Result;
17411741
getFunctionNameAndStartLineForAddress(
17421742
CU, Address.Address, Spec.FNKind, Spec.FLIKind, Result.FunctionName,
17431743
Result.StartFileName, Result.StartLine, Result.StartAddress);

llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,9 @@ SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
277277
ModuleOffset.SectionIndex =
278278
getModuleSectionIndexForAddress(ModuleOffset.Address);
279279
DILineInfo LineInfo;
280-
if (std::optional<DILineInfo> DBGLineInfo =
281-
DebugInfoContext->getLineInfoForAddress(ModuleOffset,
282-
LineInfoSpecifier))
280+
std::optional<DILineInfo> DBGLineInfo =
281+
DebugInfoContext->getLineInfoForAddress(ModuleOffset, LineInfoSpecifier);
282+
if (DBGLineInfo)
283283
LineInfo = *DBGLineInfo;
284284

285285
// Override function name from symbol table if necessary.
@@ -290,7 +290,9 @@ SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
290290
FileName)) {
291291
LineInfo.FunctionName = FunctionName;
292292
LineInfo.StartAddress = Start;
293-
if (LineInfo.FileName == DILineInfo::BadString && !FileName.empty())
293+
// Only use the filename from symbol table if the debug info for the
294+
// address is missing.
295+
if (!DBGLineInfo && !FileName.empty())
294296
LineInfo.FileName = FileName;
295297
}
296298
}
@@ -307,8 +309,11 @@ DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
307309
ModuleOffset, LineInfoSpecifier);
308310

309311
// Make sure there is at least one frame in context.
310-
if (InlinedContext.getNumberOfFrames() == 0)
312+
bool EmptyFrameAdded = false;
313+
if (InlinedContext.getNumberOfFrames() == 0) {
314+
EmptyFrameAdded = true;
311315
InlinedContext.addFrame(DILineInfo());
316+
}
312317

313318
// Override the function name in lower frame with name from symbol table.
314319
if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {
@@ -320,7 +325,9 @@ DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
320325
InlinedContext.getNumberOfFrames() - 1);
321326
LI->FunctionName = FunctionName;
322327
LI->StartAddress = Start;
323-
if (LI->FileName == DILineInfo::BadString && !FileName.empty())
328+
// Only use the filename from symbol table if the debug info for the
329+
// address is missing.
330+
if (EmptyFrameAdded && !FileName.empty())
324331
LI->FileName = FileName;
325332
}
326333
}
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# Test llvm-symbolizer always uses line info from debug info if present.
2+
3+
# It's produced by the following steps.
4+
# 1. Compile with "clang++ test.ll -S -o test.s".
5+
# 2. Replace all "test.ll" with "<invalid>"" except the "test.ll" in first line.
6+
# 3. Replace "/" in Linfo_string2 with "".
7+
# source:
8+
# ; ModuleID = 'test.ll'
9+
# source_filename = "test.ll"
10+
# ; Function Attrs: nounwind
11+
# define void @foo(i32 %i) local_unnamed_addr #0 !dbg !5 {
12+
# entry:
13+
# #dbg_value(i32 0, !9, !DIExpression(), !11)
14+
# switch i32 %i, label %if.end3 [
15+
# i32 5, label %if.end3.sink.split
16+
# i32 7, label %if.end3.sink.split
17+
# ], !dbg !11
18+
# if.end3.sink.split: ; preds = %entry, %entry
19+
# tail call void @bar() #0, !dbg !12
20+
# br label %if.end3, !dbg !13
21+
# if.end3: ; preds = %if.end3.sink.split, %entry
22+
# tail call void @bar() #0, !dbg !13
23+
# ret void, !dbg !14
24+
# }
25+
# declare dso_local void @bar()
26+
# attributes #0 = { nounwind }
27+
# !llvm.dbg.cu = !{!0}
28+
# !llvm.debugify = !{!2, !3}
29+
# !llvm.module.flags = !{!4}
30+
# !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
31+
# !1 = !DIFile(filename: "test.ll", directory: "/")
32+
# !2 = !{i32 7}
33+
# !3 = !{i32 1}
34+
# !4 = !{i32 2, !"Debug Info Version", i32 3}
35+
# !5 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
36+
# !6 = !DISubroutineType(types: !7)
37+
# !7 = !{}
38+
# !8 = !{!9}
39+
# !9 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !10)
40+
# !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
41+
# !11 = !DILocation(line: 1, column: 1, scope: !5)
42+
# !12 = !DILocation(line: 0, scope: !5)
43+
# !13 = !DILocation(line: 6, column: 1, scope: !5)
44+
# !14 = !DILocation(line: 7, column: 1, scope: !5)
45+
46+
47+
# RUN: llvm-mc -filetype=obj %s -o %t
48+
# RUN: llvm-symbolizer --obj=%t 0xd | FileCheck %s
49+
# RUN: llvm-symbolizer --inlining=false --obj=%t 0xd | FileCheck %s
50+
# CHECK: foo
51+
# CHECK-NEXT: ??:0:0
52+
53+
.file "test.ll"
54+
.text
55+
.p2align 4
56+
.type foo,@function
57+
foo: # @foo
58+
.Lfunc_begin0:
59+
.file 1 "<invalid>"
60+
.loc 1 1 0 # <invalid>:1:0
61+
.cfi_sections .debug_frame
62+
.cfi_startproc
63+
# %bb.0: # %entry
64+
pushq %rax
65+
.cfi_def_cfa_offset 16
66+
movl %edi, %eax
67+
.Ltmp0:
68+
#DEBUG_VALUE: foo:1 <- 0
69+
.loc 1 1 1 prologue_end # <invalid>:1:1
70+
orl $2, %eax
71+
subl $7, %eax
72+
je .LBB0_1
73+
jmp .LBB0_2
74+
.Ltmp1:
75+
.LBB0_1: # %if.end3.sink.split
76+
#DEBUG_VALUE: foo:1 <- 0
77+
.loc 1 0 0 is_stmt 0 # <invalid>:0
78+
callq bar
79+
.Ltmp2:
80+
.LBB0_2: # %if.end3
81+
#DEBUG_VALUE: foo:1 <- 0
82+
.loc 1 6 1 epilogue_begin is_stmt 1 # <invalid>:6:1
83+
popq %rax
84+
.cfi_def_cfa_offset 8
85+
jmp bar # TAILCALL
86+
.Ltmp3:
87+
.Lfunc_end0:
88+
.size foo, .Lfunc_end0-foo
89+
.cfi_endproc
90+
# -- End function
91+
.section .debug_abbrev,"",@progbits
92+
.byte 1 # Abbreviation Code
93+
.byte 17 # DW_TAG_compile_unit
94+
.byte 1 # DW_CHILDREN_yes
95+
.byte 37 # DW_AT_producer
96+
.byte 14 # DW_FORM_strp
97+
.byte 19 # DW_AT_language
98+
.byte 5 # DW_FORM_data2
99+
.byte 3 # DW_AT_name
100+
.byte 14 # DW_FORM_strp
101+
.byte 16 # DW_AT_stmt_list
102+
.byte 23 # DW_FORM_sec_offset
103+
.byte 27 # DW_AT_comp_dir
104+
.byte 14 # DW_FORM_strp
105+
.ascii "\264B" # DW_AT_GNU_pubnames
106+
.byte 25 # DW_FORM_flag_present
107+
.byte 17 # DW_AT_low_pc
108+
.byte 1 # DW_FORM_addr
109+
.byte 18 # DW_AT_high_pc
110+
.byte 6 # DW_FORM_data4
111+
.byte 0 # EOM(1)
112+
.byte 0 # EOM(2)
113+
.byte 2 # Abbreviation Code
114+
.byte 46 # DW_TAG_subprogram
115+
.byte 1 # DW_CHILDREN_yes
116+
.byte 17 # DW_AT_low_pc
117+
.byte 1 # DW_FORM_addr
118+
.byte 18 # DW_AT_high_pc
119+
.byte 6 # DW_FORM_data4
120+
.byte 64 # DW_AT_frame_base
121+
.byte 24 # DW_FORM_exprloc
122+
.byte 110 # DW_AT_linkage_name
123+
.byte 14 # DW_FORM_strp
124+
.byte 3 # DW_AT_name
125+
.byte 14 # DW_FORM_strp
126+
.byte 58 # DW_AT_decl_file
127+
.byte 11 # DW_FORM_data1
128+
.byte 59 # DW_AT_decl_line
129+
.byte 11 # DW_FORM_data1
130+
.byte 63 # DW_AT_external
131+
.byte 25 # DW_FORM_flag_present
132+
.byte 0 # EOM(1)
133+
.byte 0 # EOM(2)
134+
.byte 3 # Abbreviation Code
135+
.byte 52 # DW_TAG_variable
136+
.byte 0 # DW_CHILDREN_no
137+
.byte 28 # DW_AT_const_value
138+
.byte 15 # DW_FORM_udata
139+
.byte 3 # DW_AT_name
140+
.byte 14 # DW_FORM_strp
141+
.byte 58 # DW_AT_decl_file
142+
.byte 11 # DW_FORM_data1
143+
.byte 59 # DW_AT_decl_line
144+
.byte 11 # DW_FORM_data1
145+
.byte 73 # DW_AT_type
146+
.byte 19 # DW_FORM_ref4
147+
.byte 0 # EOM(1)
148+
.byte 0 # EOM(2)
149+
.byte 4 # Abbreviation Code
150+
.byte 36 # DW_TAG_base_type
151+
.byte 0 # DW_CHILDREN_no
152+
.byte 3 # DW_AT_name
153+
.byte 14 # DW_FORM_strp
154+
.byte 62 # DW_AT_encoding
155+
.byte 11 # DW_FORM_data1
156+
.byte 11 # DW_AT_byte_size
157+
.byte 11 # DW_FORM_data1
158+
.byte 0 # EOM(1)
159+
.byte 0 # EOM(2)
160+
.byte 0 # EOM(3)
161+
.section .debug_info,"",@progbits
162+
.Lcu_begin0:
163+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
164+
.Ldebug_info_start0:
165+
.short 4 # DWARF version number
166+
.long .debug_abbrev # Offset Into Abbrev. Section
167+
.byte 8 # Address Size (in bytes)
168+
.byte 1 # Abbrev [1] 0xb:0x4d DW_TAG_compile_unit
169+
.long .Linfo_string0 # DW_AT_producer
170+
.short 2 # DW_AT_language
171+
.long .Linfo_string1 # DW_AT_name
172+
.long .Lline_table_start0 # DW_AT_stmt_list
173+
.long .Linfo_string2 # DW_AT_comp_dir
174+
# DW_AT_GNU_pubnames
175+
.quad .Lfunc_begin0 # DW_AT_low_pc
176+
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
177+
.byte 2 # Abbrev [2] 0x2a:0x26 DW_TAG_subprogram
178+
.quad .Lfunc_begin0 # DW_AT_low_pc
179+
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
180+
.byte 1 # DW_AT_frame_base
181+
.byte 87
182+
.long .Linfo_string3 # DW_AT_linkage_name
183+
.long .Linfo_string3 # DW_AT_name
184+
.byte 1 # DW_AT_decl_file
185+
.byte 1 # DW_AT_decl_line
186+
# DW_AT_external
187+
.byte 3 # Abbrev [3] 0x43:0xc DW_TAG_variable
188+
.byte 0 # DW_AT_const_value
189+
.long .Linfo_string4 # DW_AT_name
190+
.byte 1 # DW_AT_decl_file
191+
.byte 1 # DW_AT_decl_line
192+
.long 80 # DW_AT_type
193+
.byte 0 # End Of Children Mark
194+
.byte 4 # Abbrev [4] 0x50:0x7 DW_TAG_base_type
195+
.long .Linfo_string5 # DW_AT_name
196+
.byte 7 # DW_AT_encoding
197+
.byte 4 # DW_AT_byte_size
198+
.byte 0 # End Of Children Mark
199+
.Ldebug_info_end0:
200+
.section .debug_str,"MS",@progbits,1
201+
.Linfo_string0:
202+
.asciz "debugify" # string offset=0
203+
.Linfo_string1:
204+
.asciz "<invalid>" # string offset=9
205+
.Linfo_string2:
206+
.asciz "" # string offset=17
207+
.Linfo_string3:
208+
.asciz "foo" # string offset=19
209+
.Linfo_string4:
210+
.asciz "1" # string offset=23
211+
.Linfo_string5:
212+
.asciz "ty32" # string offset=25
213+
.section .debug_pubnames,"",@progbits
214+
.long .LpubNames_end0-.LpubNames_start0 # Length of Public Names Info
215+
.LpubNames_start0:
216+
.short 2 # DWARF Version
217+
.long .Lcu_begin0 # Offset of Compilation Unit Info
218+
.long 88 # Compilation Unit Length
219+
.long 42 # DIE offset
220+
.asciz "foo" # External Name
221+
.long 0 # End Mark
222+
.LpubNames_end0:
223+
.section .debug_pubtypes,"",@progbits
224+
.long .LpubTypes_end0-.LpubTypes_start0 # Length of Public Types Info
225+
.LpubTypes_start0:
226+
.short 2 # DWARF Version
227+
.long .Lcu_begin0 # Offset of Compilation Unit Info
228+
.long 88 # Compilation Unit Length
229+
.long 80 # DIE offset
230+
.asciz "ty32" # External Name
231+
.long 0 # End Mark
232+
.LpubTypes_end0:
233+
.section ".note.GNU-stack","",@progbits
234+
.addrsig
235+
.addrsig_sym bar
236+
.section .debug_line,"",@progbits
237+
.Lline_table_start0:

0 commit comments

Comments
 (0)