1 //===-- ELFDump.cpp - ELF-specific dumper -----------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file implements the ELF-specific dumper for llvm-objdump.
12 //===----------------------------------------------------------------------===//
16 #include "llvm-objdump.h"
17 #include "llvm/Demangle/Demangle.h"
18 #include "llvm/Object/ELFObjectFile.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/raw_ostream.h"
23 using namespace llvm::object
;
24 using namespace llvm::objdump
;
27 template <typename ELFT
> class ELFDumper
: public Dumper
{
29 ELFDumper(const ELFObjectFile
<ELFT
> &O
) : Dumper(O
), Obj(O
) {}
30 void printPrivateHeaders() override
;
31 void printDynamicRelocations() override
;
34 const ELFObjectFile
<ELFT
> &Obj
;
36 const ELFFile
<ELFT
> &getELFFile() const { return Obj
.getELFFile(); }
37 void printDynamicSection();
38 void printProgramHeaders();
39 void printSymbolVersion();
40 void printSymbolVersionDependency(const typename
ELFT::Shdr
&Sec
);
45 static std::unique_ptr
<Dumper
> createDumper(const ELFObjectFile
<ELFT
> &Obj
) {
46 return std::make_unique
<ELFDumper
<ELFT
>>(Obj
);
49 std::unique_ptr
<Dumper
>
50 objdump::createELFDumper(const object::ELFObjectFileBase
&Obj
) {
51 if (const auto *O
= dyn_cast
<ELF32LEObjectFile
>(&Obj
))
52 return createDumper(*O
);
53 if (const auto *O
= dyn_cast
<ELF32BEObjectFile
>(&Obj
))
54 return createDumper(*O
);
55 if (const auto *O
= dyn_cast
<ELF64LEObjectFile
>(&Obj
))
56 return createDumper(*O
);
57 return createDumper(cast
<ELF64BEObjectFile
>(Obj
));
61 static Expected
<StringRef
> getDynamicStrTab(const ELFFile
<ELFT
> &Elf
) {
62 auto DynamicEntriesOrError
= Elf
.dynamicEntries();
63 if (!DynamicEntriesOrError
)
64 return DynamicEntriesOrError
.takeError();
66 for (const typename
ELFT::Dyn
&Dyn
: *DynamicEntriesOrError
) {
67 if (Dyn
.d_tag
== ELF::DT_STRTAB
) {
68 auto MappedAddrOrError
= Elf
.toMappedAddr(Dyn
.getPtr());
69 if (!MappedAddrOrError
)
70 return MappedAddrOrError
.takeError();
71 return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError
));
75 // If the dynamic segment is not present, we fall back on the sections.
76 auto SectionsOrError
= Elf
.sections();
78 return SectionsOrError
.takeError();
80 for (const typename
ELFT::Shdr
&Sec
: *SectionsOrError
) {
81 if (Sec
.sh_type
== ELF::SHT_DYNSYM
)
82 return Elf
.getStringTableForSymtab(Sec
);
85 return createError("dynamic string table not found");
89 static Error
getRelocationValueString(const ELFObjectFile
<ELFT
> *Obj
,
90 const RelocationRef
&RelRef
,
91 SmallVectorImpl
<char> &Result
) {
92 const ELFFile
<ELFT
> &EF
= Obj
->getELFFile();
93 DataRefImpl Rel
= RelRef
.getRawDataRefImpl();
94 auto SecOrErr
= EF
.getSection(Rel
.d
.a
);
96 return SecOrErr
.takeError();
99 // If there is no Symbol associated with the relocation, we set the undef
100 // boolean value to 'true'. This will prevent us from calling functions that
101 // requires the relocation to be associated with a symbol.
103 // In SHT_REL case we would need to read the addend from section data.
104 // GNU objdump does not do that and we just follow for simplicity atm.
106 if ((*SecOrErr
)->sh_type
== ELF::SHT_CREL
) {
107 auto ERela
= Obj
->getCrel(Rel
);
108 Addend
= ERela
.r_addend
;
109 Undef
= ERela
.getSymbol(false) == 0;
110 } else if ((*SecOrErr
)->sh_type
== ELF::SHT_RELA
) {
111 const typename
ELFT::Rela
*ERela
= Obj
->getRela(Rel
);
112 Addend
= ERela
->r_addend
;
113 Undef
= ERela
->getSymbol(false) == 0;
114 } else if ((*SecOrErr
)->sh_type
== ELF::SHT_REL
) {
115 const typename
ELFT::Rel
*ERel
= Obj
->getRel(Rel
);
116 Undef
= ERel
->getSymbol(false) == 0;
118 return make_error
<BinaryError
>();
121 // Default scheme is to print Target, as well as "+ <addend>" for nonzero
122 // addend. Should be acceptable for all normal purposes.
124 raw_string_ostream
Fmt(FmtBuf
);
127 symbol_iterator SI
= RelRef
.getSymbol();
128 Expected
<const typename
ELFT::Sym
*> SymOrErr
=
129 Obj
->getSymbol(SI
->getRawDataRefImpl());
130 // TODO: test this error.
132 return SymOrErr
.takeError();
134 if ((*SymOrErr
)->getType() == ELF::STT_SECTION
) {
135 Expected
<section_iterator
> SymSI
= SI
->getSection();
137 return SymSI
.takeError();
138 const typename
ELFT::Shdr
*SymSec
=
139 Obj
->getSection((*SymSI
)->getRawDataRefImpl());
140 auto SecName
= EF
.getSectionName(*SymSec
);
142 return SecName
.takeError();
145 Expected
<StringRef
> SymName
= SI
->getName();
147 return SymName
.takeError();
148 Fmt
<< (Demangle
? demangle(*SymName
) : *SymName
);
156 : "+") << format("0x%" PRIx64
,
157 (Addend
< 0 ? -(uint64_t)Addend
: (uint64_t)Addend
));
160 Result
.append(FmtBuf
.begin(), FmtBuf
.end());
161 return Error::success();
164 Error
objdump::getELFRelocationValueString(const ELFObjectFileBase
*Obj
,
165 const RelocationRef
&Rel
,
166 SmallVectorImpl
<char> &Result
) {
167 if (auto *ELF32LE
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
168 return getRelocationValueString(ELF32LE
, Rel
, Result
);
169 if (auto *ELF64LE
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
170 return getRelocationValueString(ELF64LE
, Rel
, Result
);
171 if (auto *ELF32BE
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
172 return getRelocationValueString(ELF32BE
, Rel
, Result
);
173 auto *ELF64BE
= cast
<ELF64BEObjectFile
>(Obj
);
174 return getRelocationValueString(ELF64BE
, Rel
, Result
);
177 template <class ELFT
>
178 static uint64_t getSectionLMA(const ELFFile
<ELFT
> &Obj
,
179 const object::ELFSectionRef
&Sec
) {
180 auto PhdrRangeOrErr
= Obj
.program_headers();
182 report_fatal_error(Twine(toString(PhdrRangeOrErr
.takeError())));
184 // Search for a PT_LOAD segment containing the requested section. Use this
185 // segment's p_addr to calculate the section's LMA.
186 for (const typename
ELFT::Phdr
&Phdr
: *PhdrRangeOrErr
)
187 if ((Phdr
.p_type
== ELF::PT_LOAD
) &&
188 (isSectionInSegment
<ELFT
>(
189 Phdr
, *cast
<const ELFObjectFile
<ELFT
>>(Sec
.getObject())
190 ->getSection(Sec
.getRawDataRefImpl()))))
191 return Sec
.getAddress() - Phdr
.p_vaddr
+ Phdr
.p_paddr
;
193 // Return section's VMA if it isn't in a PT_LOAD segment.
194 return Sec
.getAddress();
197 uint64_t objdump::getELFSectionLMA(const object::ELFSectionRef
&Sec
) {
198 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Sec
.getObject()))
199 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
200 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Sec
.getObject()))
201 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
202 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Sec
.getObject()))
203 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
204 const auto *ELFObj
= cast
<ELF64BEObjectFile
>(Sec
.getObject());
205 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
208 template <class ELFT
> void ELFDumper
<ELFT
>::printDynamicSection() {
209 const ELFFile
<ELFT
> &Elf
= getELFFile();
210 auto DynamicEntriesOrErr
= Elf
.dynamicEntries();
211 if (!DynamicEntriesOrErr
) {
212 reportWarning(toString(DynamicEntriesOrErr
.takeError()), Obj
.getFileName());
215 ArrayRef
<typename
ELFT::Dyn
> DynamicEntries
= *DynamicEntriesOrErr
;
217 // Find the maximum tag name length to format the value column properly.
219 for (const typename
ELFT::Dyn
&Dyn
: DynamicEntries
)
220 MaxLen
= std::max(MaxLen
, Elf
.getDynamicTagAsString(Dyn
.d_tag
).size());
221 std::string TagFmt
= " %-" + std::to_string(MaxLen
) + "s ";
223 outs() << "\nDynamic Section:\n";
224 for (const typename
ELFT::Dyn
&Dyn
: DynamicEntries
) {
225 if (Dyn
.d_tag
== ELF::DT_NULL
)
228 std::string Str
= Elf
.getDynamicTagAsString(Dyn
.d_tag
);
231 ELFT::Is64Bits
? "0x%016" PRIx64
"\n" : "0x%08" PRIx64
"\n";
232 if (Dyn
.d_tag
== ELF::DT_NEEDED
|| Dyn
.d_tag
== ELF::DT_RPATH
||
233 Dyn
.d_tag
== ELF::DT_RUNPATH
|| Dyn
.d_tag
== ELF::DT_SONAME
||
234 Dyn
.d_tag
== ELF::DT_AUXILIARY
|| Dyn
.d_tag
== ELF::DT_FILTER
) {
235 Expected
<StringRef
> StrTabOrErr
= getDynamicStrTab(Elf
);
237 const char *Data
= StrTabOrErr
->data();
238 outs() << format(TagFmt
.c_str(), Str
.c_str()) << Data
+ Dyn
.getVal()
242 reportWarning(toString(StrTabOrErr
.takeError()), Obj
.getFileName());
243 consumeError(StrTabOrErr
.takeError());
245 outs() << format(TagFmt
.c_str(), Str
.c_str())
246 << format(Fmt
, (uint64_t)Dyn
.getVal());
250 template <class ELFT
> void ELFDumper
<ELFT
>::printProgramHeaders() {
251 outs() << "\nProgram Header:\n";
252 auto ProgramHeaderOrError
= getELFFile().program_headers();
253 if (!ProgramHeaderOrError
) {
254 reportWarning("unable to read program headers: " +
255 toString(ProgramHeaderOrError
.takeError()),
260 for (const typename
ELFT::Phdr
&Phdr
: *ProgramHeaderOrError
) {
261 switch (Phdr
.p_type
) {
262 case ELF::PT_DYNAMIC
:
263 outs() << " DYNAMIC ";
265 case ELF::PT_GNU_EH_FRAME
:
266 outs() << "EH_FRAME ";
268 case ELF::PT_GNU_RELRO
:
271 case ELF::PT_GNU_PROPERTY
:
272 outs() << " PROPERTY ";
274 case ELF::PT_GNU_STACK
:
278 outs() << " INTERP ";
286 case ELF::PT_OPENBSD_BOOTDATA
:
287 outs() << "OPENBSD_BOOTDATA ";
289 case ELF::PT_OPENBSD_MUTABLE
:
290 outs() << "OPENBSD_MUTABLE ";
292 case ELF::PT_OPENBSD_NOBTCFI
:
293 outs() << "OPENBSD_NOBTCFI ";
295 case ELF::PT_OPENBSD_RANDOMIZE
:
296 outs() << "OPENBSD_RANDOMIZE ";
298 case ELF::PT_OPENBSD_SYSCALLS
:
299 outs() << "OPENBSD_SYSCALLS ";
301 case ELF::PT_OPENBSD_WXNEEDED
:
302 outs() << "OPENBSD_WXNEEDED ";
311 outs() << " UNKNOWN ";
314 const char *Fmt
= ELFT::Is64Bits
? "0x%016" PRIx64
" " : "0x%08" PRIx64
" ";
316 outs() << "off " << format(Fmt
, (uint64_t)Phdr
.p_offset
) << "vaddr "
317 << format(Fmt
, (uint64_t)Phdr
.p_vaddr
) << "paddr "
318 << format(Fmt
, (uint64_t)Phdr
.p_paddr
)
319 << format("align 2**%u\n", llvm::countr_zero
<uint64_t>(Phdr
.p_align
))
320 << " filesz " << format(Fmt
, (uint64_t)Phdr
.p_filesz
)
321 << "memsz " << format(Fmt
, (uint64_t)Phdr
.p_memsz
) << "flags "
322 << ((Phdr
.p_flags
& ELF::PF_R
) ? "r" : "-")
323 << ((Phdr
.p_flags
& ELF::PF_W
) ? "w" : "-")
324 << ((Phdr
.p_flags
& ELF::PF_X
) ? "x" : "-") << "\n";
328 template <typename ELFT
> void ELFDumper
<ELFT
>::printDynamicRelocations() {
329 if (!any_of(Obj
.sections(), [](const ELFSectionRef Sec
) {
330 return Sec
.getType() == ELF::SHT_DYNAMIC
;
332 reportError(Obj
.getFileName(), "not a dynamic object");
336 std::vector
<SectionRef
> DynRelSec
=
337 cast
<ObjectFile
>(Obj
).dynamic_relocation_sections();
338 if (DynRelSec
.empty())
341 outs() << "\nDYNAMIC RELOCATION RECORDS\n";
342 const uint32_t OffsetPadding
= (Obj
.getBytesInAddress() > 4 ? 16 : 8);
343 const uint32_t TypePadding
= 24;
344 outs() << left_justify("OFFSET", OffsetPadding
) << ' '
345 << left_justify("TYPE", TypePadding
) << " VALUE\n";
347 StringRef Fmt
= Obj
.getBytesInAddress() > 4 ? "%016" PRIx64
: "%08" PRIx64
;
348 for (const SectionRef
&Section
: DynRelSec
)
349 for (const RelocationRef
&Reloc
: Section
.relocations()) {
350 uint64_t Address
= Reloc
.getOffset();
351 SmallString
<32> RelocName
;
352 SmallString
<32> ValueStr
;
353 Reloc
.getTypeName(RelocName
);
354 if (Error E
= getELFRelocationValueString(&Obj
, Reloc
, ValueStr
))
355 reportError(std::move(E
), Obj
.getFileName());
356 outs() << format(Fmt
.data(), Address
) << ' '
357 << left_justify(RelocName
, TypePadding
) << ' ' << ValueStr
<< '\n';
361 template <class ELFT
>
362 void ELFDumper
<ELFT
>::printSymbolVersionDependency(
363 const typename
ELFT::Shdr
&Sec
) {
364 outs() << "\nVersion References:\n";
365 Expected
<std::vector
<VerNeed
>> V
=
366 getELFFile().getVersionDependencies(Sec
, this->WarningHandler
);
368 reportWarning(toString(V
.takeError()), Obj
.getFileName());
372 raw_fd_ostream
&OS
= outs();
373 for (const VerNeed
&VN
: *V
) {
374 OS
<< " required from " << VN
.File
<< ":\n";
375 for (const VernAux
&Aux
: VN
.AuxV
)
376 OS
<< format(" 0x%08x 0x%02x %02u %s\n", Aux
.Hash
, Aux
.Flags
,
377 Aux
.Other
, Aux
.Name
.c_str());
381 template <class ELFT
>
382 static void printSymbolVersionDefinition(const typename
ELFT::Shdr
&Shdr
,
383 ArrayRef
<uint8_t> Contents
,
385 outs() << "\nVersion definitions:\n";
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();
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
);
399 const uint8_t *BufAux
= Buf
+ Verdef
->vd_aux
;
400 uint16_t VerdauxIndex
= 0;
402 auto *Verdaux
= reinterpret_cast<const typename
ELFT::Verdaux
*>(BufAux
);
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;
409 Buf
= Verdef
->vd_next
? Buf
+ Verdef
->vd_next
: nullptr;
413 template <class ELFT
> void ELFDumper
<ELFT
>::printSymbolVersion() {
414 const ELFFile
<ELFT
> &Elf
= getELFFile();
415 StringRef FileName
= Obj
.getFileName();
416 ArrayRef
<typename
ELFT::Shdr
> Sections
=
417 unwrapOrError(Elf
.sections(), FileName
);
418 for (const typename
ELFT::Shdr
&Shdr
: Sections
) {
419 if (Shdr
.sh_type
!= ELF::SHT_GNU_verneed
&&
420 Shdr
.sh_type
!= ELF::SHT_GNU_verdef
)
423 ArrayRef
<uint8_t> Contents
=
424 unwrapOrError(Elf
.getSectionContents(Shdr
), FileName
);
425 const typename
ELFT::Shdr
*StrTabSec
=
426 unwrapOrError(Elf
.getSection(Shdr
.sh_link
), FileName
);
427 StringRef StrTab
= unwrapOrError(Elf
.getStringTable(*StrTabSec
), FileName
);
429 if (Shdr
.sh_type
== ELF::SHT_GNU_verneed
)
430 printSymbolVersionDependency(Shdr
);
432 printSymbolVersionDefinition
<ELFT
>(Shdr
, Contents
, StrTab
);
436 template <class ELFT
> void ELFDumper
<ELFT
>::printPrivateHeaders() {
437 printProgramHeaders();
438 printDynamicSection();
439 printSymbolVersion();