Skip to content

Commit b169e7f

Browse files
authored
[ELF] Improve undefined symbol message w/ DW_TAG_variable of the enclosing symbol but w/o line number information (#70854)
The undefined symbol message suggests the source line when line number information is available (see https://reviews.llvm.org/D31481). When the undefined symbol is from a global variable, we won't get the line information. ``` extern int undef; namespace ns { int *var[] = { &undef }; // DW_TAG_variable(DW_AT_decl_file/DW_AT_decl_line) is available while // line number information is unavailable. } ld.lld: error: undefined symbol: undef >>> referenced by undef-debug2.cc >>> undef-debug2.o:(ns::var) ``` This patch utilizes `getEnclosingSymbol` to locate `var` and find DW_TAG_variable for `var`: ``` ld.lld: error: undefined symbol: undef >>> referenced by undef-debug2.cc:3 (/tmp/c/undef-debug2.cc:3) >>> undef-debug2.o:(ns::var) ```
1 parent 888742a commit b169e7f

File tree

4 files changed

+212
-3
lines changed

4 files changed

+212
-3
lines changed

lld/ELF/Relocations.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,10 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
739739
uint64_t offset = l.offset;
740740

741741
msg += "\n>>> referenced by ";
742-
std::string src = sec.getSrcMsg(sym, offset);
742+
// In the absence of line number information, utilize DW_TAG_variable (if
743+
// present) for the enclosing symbol (e.g. var in `int *a[] = {&undef};`).
744+
Symbol *enclosing = sec.getEnclosingSymbol(offset);
745+
std::string src = sec.getSrcMsg(enclosing ? *enclosing : sym, offset);
743746
if (!src.empty())
744747
msg += src + "\n>>> ";
745748
msg += sec.getObjMsg(offset);

lld/test/ELF/Inputs/undef-debug.s

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
## Variables with line number information
12
.file 1 "dir/undef-debug.s"
23
.loc 1 3
34
.quad zed3

lld/test/ELF/Inputs/undef-debug2.s

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
## Generate from:
2+
##
3+
## extern int zed9;
4+
## namespace ns {
5+
## int *var[] = {
6+
## &zed9
7+
## };
8+
## }
9+
.text
10+
.file "undef-debug2.cc"
11+
.file 0 "dir" "undef-debug2.cc" md5 0xd7caefb836c47f6c56303f19e96f2587
12+
.type _ZN2ns3varE,@object # @_ZN2ns3varE
13+
.data
14+
.globl _ZN2ns3varE
15+
.p2align 3, 0x0
16+
_ZN2ns3varE:
17+
.quad zed9
18+
.size _ZN2ns3varE, 8
19+
20+
.section .debug_abbrev,"",@progbits
21+
.byte 1 # Abbreviation Code
22+
.byte 17 # DW_TAG_compile_unit
23+
.byte 1 # DW_CHILDREN_yes
24+
.byte 37 # DW_AT_producer
25+
.byte 37 # DW_FORM_strx1
26+
.byte 19 # DW_AT_language
27+
.byte 5 # DW_FORM_data2
28+
.byte 3 # DW_AT_name
29+
.byte 37 # DW_FORM_strx1
30+
.byte 114 # DW_AT_str_offsets_base
31+
.byte 23 # DW_FORM_sec_offset
32+
.byte 16 # DW_AT_stmt_list
33+
.byte 23 # DW_FORM_sec_offset
34+
.byte 27 # DW_AT_comp_dir
35+
.byte 37 # DW_FORM_strx1
36+
.byte 115 # DW_AT_addr_base
37+
.byte 23 # DW_FORM_sec_offset
38+
.byte 0 # EOM(1)
39+
.byte 0 # EOM(2)
40+
.byte 2 # Abbreviation Code
41+
.byte 57 # DW_TAG_namespace
42+
.byte 1 # DW_CHILDREN_yes
43+
.byte 3 # DW_AT_name
44+
.byte 37 # DW_FORM_strx1
45+
.byte 0 # EOM(1)
46+
.byte 0 # EOM(2)
47+
.byte 3 # Abbreviation Code
48+
.byte 52 # DW_TAG_variable
49+
.byte 0 # DW_CHILDREN_no
50+
.byte 3 # DW_AT_name
51+
.byte 37 # DW_FORM_strx1
52+
.byte 73 # DW_AT_type
53+
.byte 19 # DW_FORM_ref4
54+
.byte 63 # DW_AT_external
55+
.byte 25 # DW_FORM_flag_present
56+
.byte 58 # DW_AT_decl_file
57+
.byte 11 # DW_FORM_data1
58+
.byte 59 # DW_AT_decl_line
59+
.byte 11 # DW_FORM_data1
60+
.byte 2 # DW_AT_location
61+
.byte 24 # DW_FORM_exprloc
62+
.byte 110 # DW_AT_linkage_name
63+
.byte 37 # DW_FORM_strx1
64+
.byte 0 # EOM(1)
65+
.byte 0 # EOM(2)
66+
.byte 4 # Abbreviation Code
67+
.byte 1 # DW_TAG_array_type
68+
.byte 1 # DW_CHILDREN_yes
69+
.byte 73 # DW_AT_type
70+
.byte 19 # DW_FORM_ref4
71+
.byte 0 # EOM(1)
72+
.byte 0 # EOM(2)
73+
.byte 5 # Abbreviation Code
74+
.byte 33 # DW_TAG_subrange_type
75+
.byte 0 # DW_CHILDREN_no
76+
.byte 73 # DW_AT_type
77+
.byte 19 # DW_FORM_ref4
78+
.byte 55 # DW_AT_count
79+
.byte 11 # DW_FORM_data1
80+
.byte 0 # EOM(1)
81+
.byte 0 # EOM(2)
82+
.byte 6 # Abbreviation Code
83+
.byte 15 # DW_TAG_pointer_type
84+
.byte 0 # DW_CHILDREN_no
85+
.byte 73 # DW_AT_type
86+
.byte 19 # DW_FORM_ref4
87+
.byte 0 # EOM(1)
88+
.byte 0 # EOM(2)
89+
.byte 7 # Abbreviation Code
90+
.byte 36 # DW_TAG_base_type
91+
.byte 0 # DW_CHILDREN_no
92+
.byte 3 # DW_AT_name
93+
.byte 37 # DW_FORM_strx1
94+
.byte 62 # DW_AT_encoding
95+
.byte 11 # DW_FORM_data1
96+
.byte 11 # DW_AT_byte_size
97+
.byte 11 # DW_FORM_data1
98+
.byte 0 # EOM(1)
99+
.byte 0 # EOM(2)
100+
.byte 8 # Abbreviation Code
101+
.byte 36 # DW_TAG_base_type
102+
.byte 0 # DW_CHILDREN_no
103+
.byte 3 # DW_AT_name
104+
.byte 37 # DW_FORM_strx1
105+
.byte 11 # DW_AT_byte_size
106+
.byte 11 # DW_FORM_data1
107+
.byte 62 # DW_AT_encoding
108+
.byte 11 # DW_FORM_data1
109+
.byte 0 # EOM(1)
110+
.byte 0 # EOM(2)
111+
.byte 0 # EOM(3)
112+
.section .debug_info,"",@progbits
113+
.Lcu_begin0:
114+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
115+
.Ldebug_info_start0:
116+
.short 5 # DWARF version number
117+
.byte 1 # DWARF Unit Type
118+
.byte 8 # Address Size (in bytes)
119+
.long .debug_abbrev # Offset Into Abbrev. Section
120+
.byte 1 # Abbrev [1] 0xc:0x3b DW_TAG_compile_unit
121+
.byte 0 # DW_AT_producer
122+
.short 33 # DW_AT_language
123+
.byte 1 # DW_AT_name
124+
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
125+
.long .Lline_table_start0 # DW_AT_stmt_list
126+
.byte 2 # DW_AT_comp_dir
127+
.long .Laddr_table_base0 # DW_AT_addr_base
128+
.byte 2 # Abbrev [2] 0x1e:0xf DW_TAG_namespace
129+
.byte 3 # DW_AT_name
130+
.byte 3 # Abbrev [3] 0x20:0xc DW_TAG_variable
131+
.byte 4 # DW_AT_name
132+
.long 45 # DW_AT_type
133+
# DW_AT_external
134+
.byte 0 # DW_AT_decl_file
135+
.byte 3 # DW_AT_decl_line
136+
.byte 2 # DW_AT_location
137+
.byte 161
138+
.byte 0
139+
.byte 7 # DW_AT_linkage_name
140+
.byte 0 # End Of Children Mark
141+
.byte 4 # Abbrev [4] 0x2d:0xc DW_TAG_array_type
142+
.long 57 # DW_AT_type
143+
.byte 5 # Abbrev [5] 0x32:0x6 DW_TAG_subrange_type
144+
.long 66 # DW_AT_type
145+
.byte 1 # DW_AT_count
146+
.byte 0 # End Of Children Mark
147+
.byte 6 # Abbrev [6] 0x39:0x5 DW_TAG_pointer_type
148+
.long 62 # DW_AT_type
149+
.byte 7 # Abbrev [7] 0x3e:0x4 DW_TAG_base_type
150+
.byte 5 # DW_AT_name
151+
.byte 5 # DW_AT_encoding
152+
.byte 4 # DW_AT_byte_size
153+
.byte 8 # Abbrev [8] 0x42:0x4 DW_TAG_base_type
154+
.byte 6 # DW_AT_name
155+
.byte 8 # DW_AT_byte_size
156+
.byte 7 # DW_AT_encoding
157+
.byte 0 # End Of Children Mark
158+
.Ldebug_info_end0:
159+
.section .debug_str_offsets,"",@progbits
160+
.long 36 # Length of String Offsets Set
161+
.short 5
162+
.short 0
163+
.Lstr_offsets_base0:
164+
.section .debug_str,"MS",@progbits,1
165+
.Linfo_string0:
166+
.asciz "clang version 18.0.0" # string offset=0
167+
.Linfo_string1:
168+
.asciz "undef-debug2.cc" # string offset=21
169+
.Linfo_string2:
170+
.asciz "dir" # string offset=37
171+
.Linfo_string3:
172+
.asciz "ns" # string offset=44
173+
.Linfo_string4:
174+
.asciz "var" # string offset=47
175+
.Linfo_string5:
176+
.asciz "int" # string offset=51
177+
.Linfo_string6:
178+
.asciz "__ARRAY_SIZE_TYPE__" # string offset=55
179+
.Linfo_string7:
180+
.asciz "_ZN2ns3varE" # string offset=75
181+
.section .debug_str_offsets,"",@progbits
182+
.long .Linfo_string0
183+
.long .Linfo_string1
184+
.long .Linfo_string2
185+
.long .Linfo_string3
186+
.long .Linfo_string4
187+
.long .Linfo_string5
188+
.long .Linfo_string6
189+
.long .Linfo_string7
190+
.section .debug_addr,"",@progbits
191+
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
192+
.Ldebug_addr_start0:
193+
.short 5 # DWARF version number
194+
.byte 8 # Address size
195+
.byte 0 # Segment selector size
196+
.Laddr_table_base0:
197+
.quad _ZN2ns3varE
198+
.Ldebug_addr_end0:
199+
.section .debug_line,"",@progbits
200+
.Lline_table_start0:

lld/test/ELF/undef.s

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o
44
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-debug.s -o %t3.o
55
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-bad-debug.s -o %t4.o
6+
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-debug2.s -o %t5.o
67
# RUN: rm -f %t2.a
78
# RUN: llvm-ar rc %t2.a %t2.o
8-
# RUN: not ld.lld --threads=1 %t.o %t2.a %t3.o %t4.o -o /dev/null 2>&1 \
9+
# RUN: not ld.lld --threads=1 %t.o %t2.a %t3.o %t4.o %t5.o -o /dev/null 2>&1 \
910
# RUN: | FileCheck %s --implicit-check-not="error:" --implicit-check-not="warning:"
10-
# RUN: not ld.lld --threads=1 -pie %t.o %t2.a %t3.o %t4.o -o /dev/null 2>&1 \
11+
# RUN: not ld.lld --threads=1 -pie %t.o %t2.a %t3.o %t4.o %t5.o -o /dev/null 2>&1 \
1112
# RUN: | FileCheck %s --implicit-check-not="error:" --implicit-check-not="warning:"
1213

1314
# CHECK: error: undefined symbol: foo
@@ -82,6 +83,10 @@
8283
# CHECK-NEXT: >>> referenced by undef-bad-debug2.s:11 (dir2{{/|\\}}undef-bad-debug2.s:11)
8384
# CHECK-NEXT: >>> {{.*}}tmp4.o:(.text+0x18)
8485

86+
# CHECK: error: undefined symbol: zed9
87+
# CHECK-NEXT: >>> referenced by undef-debug2.cc:3 (dir{{/|\\}}undef-debug2.cc:3)
88+
# CHECK-NEXT: >>> {{.*}}tmp5.o:(ns::var)
89+
8590
# RUN: not ld.lld %t.o %t2.a -o /dev/null -no-demangle 2>&1 | \
8691
# RUN: FileCheck -check-prefix=NO-DEMANGLE %s
8792
# NO-DEMANGLE: error: undefined symbol: _Z3fooi

0 commit comments

Comments
 (0)