Skip to content

Commit 6d766c8

Browse files
committed
DebugInfo/Symbolize: Allow STT_NOTYPE/STT_GNU_IFUNC symbols for .symtab symbolization
In assembly files, omitting `.type foo,@function` is common. Such functions have type `STT_NOTYPE` and llvm-symbolizer reports `??` for them. An ifunc symbol usually has an associated resolver symbol which is defined at the same address. Returning either one is fine for symbolization. The resolver symbol may not end up in the symbol table if (object file) `.L` is used (linked image) .symtab is stripped while .dynsym is retained. This patch allows ELF STT_NOTYPE/STT_GNU_IFUNC symbols for .symtab symbolization. I have left TODO in the test files for an unimplemented STT_FILE heuristic. Differential Revision: https://reviews.llvm.org/D95916
1 parent 4c9adbb commit 6d766c8

File tree

5 files changed

+154
-8
lines changed

5 files changed

+154
-8
lines changed

llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,27 @@ Error SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
149149
DataExtractor *OpdExtractor,
150150
uint64_t OpdAddress) {
151151
// Avoid adding symbols from an unknown/undefined section.
152-
const ObjectFile *Obj = Symbol.getObject();
152+
const ObjectFile &Obj = *Symbol.getObject();
153153
Expected<section_iterator> Sec = Symbol.getSection();
154-
if (!Sec || (Obj && Obj->section_end() == *Sec))
154+
if (!Sec || Obj.section_end() == *Sec)
155155
return Error::success();
156+
156157
Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
157158
if (!SymbolTypeOrErr)
158159
return SymbolTypeOrErr.takeError();
159160
SymbolRef::Type SymbolType = *SymbolTypeOrErr;
160-
if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
161+
if (Obj.isELF()) {
162+
// Allow function and data symbols. Additionally allow STT_NONE, which are
163+
// common for functions defined in assembly.
164+
uint8_t Type = ELFSymbolRef(Symbol).getELFType();
165+
if (Type != ELF::STT_NOTYPE && Type != ELF::STT_FUNC &&
166+
Type != ELF::STT_OBJECT && Type != ELF::STT_GNU_IFUNC)
167+
return Error::success();
168+
} else if (SymbolType != SymbolRef::ST_Function &&
169+
SymbolType != SymbolRef::ST_Data) {
161170
return Error::success();
171+
}
172+
162173
Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
163174
if (!SymbolAddressOrErr)
164175
return SymbolAddressOrErr.takeError();
@@ -186,11 +197,17 @@ Error SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
186197
// Mach-O symbol table names have leading underscore, skip it.
187198
if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
188199
SymbolName = SymbolName.drop_front();
189-
// FIXME: If a function has alias, there are two entries in symbol table
190-
// with same address size. Make sure we choose the correct one.
191-
auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
192-
SymbolDesc SD = { SymbolAddress, SymbolSize };
193-
M.emplace_back(SD, SymbolName);
200+
201+
SymbolDesc SD = {SymbolAddress, SymbolSize};
202+
203+
// DATA command symbolizes just ST_Data (ELF STT_OBJECT) symbols as an
204+
// optimization. Treat everything else (e.g. ELF STT_NOTYPE, STT_FUNC and
205+
// STT_GNU_IFUNC) as function symbols which can be used to symbolize
206+
// addresses.
207+
if (SymbolType == SymbolRef::ST_Data)
208+
Objects.emplace_back(SD, SymbolName);
209+
else
210+
Functions.emplace_back(SD, SymbolName);
194211
return Error::success();
195212
}
196213

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
## When locating a local symbol, we can obtain the filename according to the
2+
## preceding STT_FILE symbol.
3+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
4+
# RUN: llvm-symbolizer --obj=%t 0 1 2 | FileCheck %s
5+
6+
## TODO Find the preceding STT_FILE symbol as the filename of a local symbol.
7+
# CHECK: local1
8+
# CHECK-NEXT: ??:0:0
9+
# CHECK-EMPTY:
10+
# CHECK-NEXT: local2
11+
# CHECK-NEXT: ??:0:0
12+
# CHECK-EMPTY:
13+
# CHECK-NEXT: local3
14+
# CHECK-NEXT: ??:0:0
15+
# CHECK-EMPTY:
16+
17+
.file "1.c"
18+
local1:
19+
nop
20+
21+
.file "2.c"
22+
local2:
23+
nop
24+
25+
.file "3.c"
26+
local3:
27+
nop
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## Test we can symbolize STT_GNU_IFUNC symbols.
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
3+
# RUN: llvm-symbolizer --obj=%t 0 1
4+
5+
# CHECK: g_ifunc
6+
# CHECK-NEXT: ??:0:0
7+
# CHECK-EMPTY:
8+
# CHECK-NEXT: l_ifunc
9+
# CHECK-NEXT: ??:0:0
10+
# CHECK-EMPTY:
11+
12+
## TODO Find the preceding STT_FILE symbol as the filename of l_ifunc.
13+
.file "symtab-ifunc.s"
14+
15+
.Lg_resolver:
16+
ret
17+
.size .Lg_resolver, 1
18+
19+
.globl g_ifunc
20+
.set g_ifunc, .Lg_resolver
21+
.type g_ifunc, @gnu_indirect_function
22+
23+
.Ll_resolver:
24+
ret
25+
.size .Ll_resolver, 1
26+
27+
.set l_ifunc, .Ll_resolver
28+
.type l_ifunc, @gnu_indirect_function
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## Ignore STT_SECTION and STT_TLS symbols for .symtab symbolization.
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
3+
# RUN: llvm-symbolizer --obj=%t 0 | FileCheck %s
4+
5+
# CHECK: b
6+
# CHECK-NEXT: ??:0:0
7+
# CHECK-EMPTY:
8+
9+
.file "1.c"
10+
11+
.section a,"a",@progbits
12+
b:
13+
.reloc ., R_X86_64_NONE, a
14+
.section c,"a",@progbits
15+
.reloc ., R_X86_64_NONE, c
16+
17+
.section .tbss,"awT",@nobits
18+
.globl tls
19+
tls:
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
## STT_NOTYPE symbols are common in assembly files. Test we can symbolize them.
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
3+
# RUN: llvm-symbolizer --obj=%t --inlines 0 1 2 3 4 5 6 7 | FileCheck %s
4+
# RUN: llvm-symbolizer --obj=%t --no-inlines 0 1 2 3 4 5 6 7 | FileCheck %s
5+
6+
# CHECK: _start
7+
# CHECK-NEXT: ??:0:0
8+
# CHECK-EMPTY:
9+
# CHECK-NEXT: g_notype
10+
# CHECK-NEXT: ??:0:0
11+
# CHECK-EMPTY:
12+
# CHECK-NEXT: g_notype
13+
# CHECK-NEXT: ??:0:0
14+
# CHECK-EMPTY:
15+
16+
## This is a gap.
17+
# CHECK-NEXT: ??
18+
# CHECK-NEXT: ??:0:0
19+
# CHECK-EMPTY:
20+
21+
# CHECK-NEXT: l_notype
22+
# CHECK-NEXT: ??:0:0
23+
# CHECK-EMPTY:
24+
25+
## TODO addr2line does not symbolize the last two out-of-bounds addresses.
26+
# CHECK-NEXT: l_notype_nosize
27+
# CHECK-NEXT: ??:0:0
28+
# CHECK-EMPTY:
29+
# CHECK-NEXT: l_notype_nosize
30+
# CHECK-NEXT: ??:0:0
31+
# CHECK-EMPTY:
32+
# CHECK-NEXT: l_notype_nosize
33+
# CHECK-NEXT: ??:0:0
34+
# CHECK-EMPTY:
35+
36+
## TODO Find the preceding STT_FILE symbol as the filename of a local symbol.
37+
.file "symtab-notype.s"
38+
39+
.globl _start, g_notype
40+
_start:
41+
retq
42+
43+
g_notype:
44+
nop
45+
nop
46+
.size g_notype, . - g_notype
47+
48+
nop
49+
50+
l_notype:
51+
nop
52+
.size l_notype, . - l_notype
53+
54+
l_notype_nosize:
55+
nop

0 commit comments

Comments
 (0)