Skip to content

Commit 7c26356

Browse files
authored
[llvm-objdump] Rework .gnu.version_d dumping
and fix crash when vd_aux is invalid (#86611). vd_version, vd_flags, vd_ndx, and vd_cnt in Elf{32,64}_Verdef are 16-bit. Change VerDef to use uint16_t instead. vda_name specifies a NUL-terminated string. Update getVersionDefinitions to remove some `.c_str()`. Pull Request: #128434
1 parent 1b25c0c commit 7c26356

File tree

9 files changed

+160
-53
lines changed

9 files changed

+160
-53
lines changed

llvm/include/llvm/Object/ELF.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ struct VerdAux {
4141

4242
struct VerDef {
4343
unsigned Offset;
44-
unsigned Version;
45-
unsigned Flags;
46-
unsigned Ndx;
47-
unsigned Cnt;
44+
uint16_t Version;
45+
uint16_t Flags;
46+
uint16_t Ndx;
47+
uint16_t Cnt;
4848
unsigned Hash;
4949
std::string Name;
5050
std::vector<VerdAux> AuxV;
@@ -1057,8 +1057,8 @@ ELFFile<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const {
10571057

10581058
VerdAux Aux;
10591059
Aux.Offset = VerdauxBuf - Start;
1060-
if (Verdaux->vda_name <= StrTabOrErr->size())
1061-
Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name));
1060+
if (Verdaux->vda_name < StrTabOrErr->size())
1061+
Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name).data());
10621062
else
10631063
Aux.Name = ("<invalid vda_name: " + Twine(Verdaux->vda_name) + ">").str();
10641064
return Aux;

llvm/test/tools/llvm-objdump/ELF/private-headers.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Sections:
3838
Value: 0x0
3939
- Name: .gnu.version_d
4040
Type: SHT_GNU_verdef
41+
AddressAlign: 4
4142
Entries:
4243
- Version: 1
4344
Flags: 1
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
## Adapted from test/llvm-readobj/ELF/verdef-invalid.test
2+
## Check that we report a warning when a SHT_GNU_verdef section contains a version definition
3+
## that refers to an auxiliary entry that goes past the end of the section.
4+
5+
# RUN: yaml2obj %s -o %t
6+
# RUN: llvm-objdump -p %t 2>&1 | FileCheck %s --check-prefix=AUX-PAST-END -DFILE=%t
7+
8+
# AUX-PAST-END: warning: '[[FILE]]': invalid SHT_GNU_verdef section with index 1: version definition 1 refers to an auxiliary entry that goes past the end of the section
9+
10+
--- !ELF
11+
FileHeader:
12+
Class: ELFCLASS64
13+
Data: ELFDATA2LSB
14+
Type: ET_DYN
15+
Sections:
16+
- Name: .gnu.version_d
17+
Type: SHT_GNU_verdef
18+
Entries:
19+
- Names:
20+
- FOO
21+
## The correct sh_size is 28.
22+
ShSize: 27
23+
DynamicSymbols:
24+
- Name: foo
25+
26+
## Check we report a warning when a version definition is not correctly aligned in memory.
27+
28+
# RUN: yaml2obj %s --docnum=2 -o %t2
29+
# RUN: llvm-objdump -p %t2 2>&1 | FileCheck %s --check-prefix=MISALIGNED-DEF -DFILE=%t2
30+
31+
# MISALIGNED-DEF: warning: '[[FILE]]': invalid SHT_GNU_verdef section with index 1: found a misaligned version definition entry at offset 0x0
32+
33+
--- !ELF
34+
FileHeader:
35+
Class: ELFCLASS64
36+
Data: ELFDATA2LSB
37+
Type: ET_DYN
38+
Sections:
39+
- Type: Fill
40+
Size: 0x1
41+
- Name: .gnu.version_d
42+
Type: SHT_GNU_verdef
43+
Link: .dynstr
44+
Info: 0x1
45+
Entries:
46+
- Names:
47+
- FOO
48+
DynamicSymbols:
49+
- Name: foo
50+
51+
## Check we report "invalid vda_name" when vda_name = size(.dynstr)
52+
53+
# RUN: yaml2obj %s --docnum=3 -o %t3
54+
# RUN: llvm-objdump -p %t3 2>&1 | FileCheck %s --check-prefix=VDANAME-PAST-END --implicit-check-not=warning:
55+
56+
# VDANAME-PAST-END: Version definitions:
57+
# VDANAME-PAST-END-NEXT: 0 0x00 0x00000000 V0
58+
# VDANAME-PAST-END-NEXT: <invalid vda_name: 7>
59+
60+
--- !ELF
61+
FileHeader:
62+
Class: ELFCLASS64
63+
Data: ELFDATA2LSB
64+
Type: ET_DYN
65+
Sections:
66+
- Name: .gnu.version_d
67+
Type: SHT_GNU_verdef
68+
Flags: [ SHF_ALLOC ]
69+
Link: .dynstr
70+
Info: 0x1
71+
## The byte offset to the auxiliary entry is 0x13, i.e. it is not correctly aligned in memory.
72+
Content: "010000000000020000000000140000000000000004000000080000000700000000000000"
73+
DynamicSymbols:
74+
- Name: V1
75+
Binding: STB_GLOBAL
76+
- Name: V0
77+
Binding: STB_GLOBAL

llvm/test/tools/llvm-objdump/ELF/verdef.test

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# RUN: yaml2obj %s -o %t
2-
# RUN: llvm-objdump -p %t | FileCheck --strict-whitespace %s
2+
# RUN: llvm-objdump -p %t | FileCheck --match-full-lines --strict-whitespace %s
33

4-
# CHECK: Dynamic Section:
5-
# CHECK-EMPTY:
6-
# CHECK-NEXT: Version definitions:
7-
# CHECK-NEXT: 1 0x01 0x075bcd15 foo
8-
# CHECK-NEXT: 2 0x02 0x3ade68b1 VERSION_1
9-
# CHECK-NEXT: VERSION_2
4+
# CHECK:Dynamic Section:
5+
#CHECK-EMPTY:
6+
# CHECK-NEXT:Version definitions:
7+
# CHECK-NEXT:2 0x01 0x075bcd15 foo
8+
# CHECK-NEXT:3 0x02 0x3ade68b1 VERSION_1
9+
# CHECK-NEXT: VERSION_2
10+
# CHECK-NEXT:4 0x00 0x0000007b VERSION_3
11+
# CHECK-NEXT: VERSION_4 VERSION_5
1012

1113
--- !ELF
1214
FileHeader:
@@ -24,17 +26,25 @@ Sections:
2426
Entries:
2527
- Version: 1
2628
Flags: 1
27-
VersionNdx: 1
29+
VersionNdx: 2
2830
Hash: 123456789
2931
Names:
3032
- foo
3133
- Version: 1
3234
Flags: 2
33-
VersionNdx: 2
35+
VersionNdx: 3
3436
Hash: 987654321
3537
Names:
3638
- VERSION_1
3739
- VERSION_2
40+
- Version: 1
41+
Flags: 0
42+
VersionNdx: 4
43+
Hash: 123
44+
Names:
45+
- VERSION_3
46+
- VERSION_4
47+
- VERSION_5
3848
DynamicSymbols:
3949
- Name: bar
4050
Binding: STB_GLOBAL

llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ Sections:
128128
Entries:
129129
- Names:
130130
- FOO
131-
ShSize: 21
131+
## The correct sh_size is 28.
132+
ShSize: 27
132133
DynamicSymbols:
133134
- Name: foo
134135

@@ -290,3 +291,36 @@ Sections:
290291
DynamicSymbols:
291292
- Name: foo
292293
Binding: STB_GLOBAL
294+
295+
## Check we report "invalid vda_name" when vda_name = size(.dynstr)
296+
297+
# RUN: yaml2obj %s --docnum=10 -o %t11
298+
# RUN: llvm-readobj -V %t11 2>&1 | FileCheck %s --check-prefix=VDANAME-PAST-END-LLVM -DFILE=%t11 --implicit-check-not=warning:
299+
# RUN: llvm-readelf -V %t11 2>&1 | FileCheck %s --check-prefix=VDANAME-PAST-END-GNU -DFILE=%t11 --implicit-check-not=warning:
300+
301+
# VDANAME-PAST-END-LLVM: Name: V0
302+
# VDANAME-PAST-END-LLVM-NEXT: Predecessors: [<invalid vda_name: 7>]
303+
304+
# VDANAME-PAST-END-GNU: Version definition section '.gnu.version_d' contains 1 entries:
305+
# VDANAME-PAST-END-GNU-NEXT: Addr: 0000000000000000 Offset: 0x000040 Link: 3 (.dynstr)
306+
# VDANAME-PAST-END-GNU-NEXT: 0x0000: Rev: 1 Flags: none Index: 0 Cnt: 2 Name: V0
307+
# VDANAME-PAST-END-GNU-NEXT: 0x001c: Parent 1: <invalid vda_name: 7>
308+
309+
--- !ELF
310+
FileHeader:
311+
Class: ELFCLASS64
312+
Data: ELFDATA2LSB
313+
Type: ET_DYN
314+
Sections:
315+
- Name: .gnu.version_d
316+
Type: SHT_GNU_verdef
317+
Flags: [ SHF_ALLOC ]
318+
Link: .dynstr
319+
Info: 0x1
320+
## The byte offset to the auxiliary entry is 0x13, i.e. it is not correctly aligned in memory.
321+
Content: "010000000000020000000000140000000000000004000000080000000700000000000000"
322+
DynamicSymbols:
323+
- Name: V1
324+
Binding: STB_GLOBAL
325+
- Name: V0
326+
Binding: STB_GLOBAL

llvm/tools/llvm-objdump/ELFDump.cpp

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -378,38 +378,6 @@ void ELFDumper<ELFT>::printSymbolVersionDependency(
378378
}
379379
}
380380

381-
template <class ELFT>
382-
static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
383-
ArrayRef<uint8_t> Contents,
384-
StringRef StrTab) {
385-
outs() << "\nVersion definitions:\n";
386-
387-
const uint8_t *Buf = Contents.data();
388-
uint32_t VerdefIndex = 1;
389-
// sh_info contains the number of entries in the SHT_GNU_verdef section. To
390-
// make the index column have consistent width, we should insert blank spaces
391-
// according to sh_info.
392-
uint16_t VerdefIndexWidth = std::to_string(Shdr.sh_info).size();
393-
while (Buf) {
394-
auto *Verdef = reinterpret_cast<const typename ELFT::Verdef *>(Buf);
395-
outs() << format_decimal(VerdefIndex++, VerdefIndexWidth) << " "
396-
<< format("0x%02" PRIx16 " ", (uint16_t)Verdef->vd_flags)
397-
<< format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash);
398-
399-
const uint8_t *BufAux = Buf + Verdef->vd_aux;
400-
uint16_t VerdauxIndex = 0;
401-
while (BufAux) {
402-
auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux);
403-
if (VerdauxIndex)
404-
outs() << std::string(VerdefIndexWidth + 17, ' ');
405-
outs() << StringRef(StrTab.drop_front(Verdaux->vda_name).data()) << '\n';
406-
BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr;
407-
++VerdauxIndex;
408-
}
409-
Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr;
410-
}
411-
}
412-
413381
template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() {
414382
const ELFFile<ELFT> &Elf = getELFFile();
415383
StringRef FileName = Obj.getFileName();
@@ -426,10 +394,26 @@ template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() {
426394
unwrapOrError(Elf.getSection(Shdr.sh_link), FileName);
427395
StringRef StrTab = unwrapOrError(Elf.getStringTable(*StrTabSec), FileName);
428396

429-
if (Shdr.sh_type == ELF::SHT_GNU_verneed)
397+
if (Shdr.sh_type == ELF::SHT_GNU_verneed) {
430398
printSymbolVersionDependency(Shdr);
431-
else
432-
printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab);
399+
} else {
400+
OS << "\nVersion definitions:\n";
401+
Expected<std::vector<VerDef>> V =
402+
getELFFile().getVersionDefinitions(Shdr);
403+
if (!V) {
404+
this->reportUniqueWarning(V.takeError());
405+
continue;
406+
}
407+
for (const VerDef &Def : *V) {
408+
OS << Def.Ndx << ' ' << format_hex(Def.Flags, 4) << ' '
409+
<< format_hex(Def.Hash, 10) << ' ' << Def.Name << '\n';
410+
if (!Def.AuxV.empty()) {
411+
for (auto [I, Aux] : enumerate(Def.AuxV))
412+
OS << (I ? ' ' : '\t') << Aux.Name;
413+
OS << '\n';
414+
}
415+
}
416+
}
433417
}
434418
}
435419

llvm/tools/llvm-objdump/llvm-objdump.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ static StringRef ToolName;
360360

361361
std::unique_ptr<BuildIDFetcher> BIDFetcher;
362362

363-
Dumper::Dumper(const object::ObjectFile &O) : O(O) {
363+
Dumper::Dumper(const object::ObjectFile &O) : O(O), OS(outs()) {
364364
WarningHandler = [this](const Twine &Msg) {
365365
if (Warnings.insert(Msg.str()).second)
366366
reportWarning(Msg, this->O.getFileName());

llvm/tools/llvm-objdump/llvm-objdump.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class Dumper {
7777
StringSet<> Warnings;
7878

7979
protected:
80+
llvm::raw_ostream &OS;
8081
std::function<Error(const Twine &Msg)> WarningHandler;
8182

8283
public:

llvm/tools/llvm-readobj/ELFDumper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7668,7 +7668,7 @@ void LLVMELFDumper<ELFT>::printVersionDefinitionSection(const Elf_Shdr *Sec) {
76687668
W.printFlags("Flags", D.Flags, ArrayRef(SymVersionFlags));
76697669
W.printNumber("Index", D.Ndx);
76707670
W.printNumber("Hash", D.Hash);
7671-
W.printString("Name", D.Name.c_str());
7671+
W.printString("Name", D.Name);
76727672
W.printList(
76737673
"Predecessors", D.AuxV,
76747674
[](raw_ostream &OS, const VerdAux &Aux) { OS << Aux.Name.c_str(); });

0 commit comments

Comments
 (0)