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/MathExtras.h"
21 #include "llvm/Support/raw_ostream.h"
24 using namespace llvm::object
;
25 using namespace llvm::objdump
;
28 template <typename ELFT
> class ELFDumper
: public Dumper
{
30 ELFDumper(const ELFObjectFile
<ELFT
> &O
) : Dumper(O
), Obj(O
) {}
31 void printPrivateHeaders() override
;
32 void printDynamicRelocations() override
;
35 const ELFObjectFile
<ELFT
> &Obj
;
37 const ELFFile
<ELFT
> &getELFFile() const { return Obj
.getELFFile(); }
38 void printDynamicSection();
39 void printProgramHeaders();
40 void printSymbolVersion();
41 void printSymbolVersionDependency(const typename
ELFT::Shdr
&Sec
);
46 static std::unique_ptr
<Dumper
> createDumper(const ELFObjectFile
<ELFT
> &Obj
) {
47 return std::make_unique
<ELFDumper
<ELFT
>>(Obj
);
50 std::unique_ptr
<Dumper
>
51 objdump::createELFDumper(const object::ELFObjectFileBase
&Obj
) {
52 if (const auto *O
= dyn_cast
<ELF32LEObjectFile
>(&Obj
))
53 return createDumper(*O
);
54 if (const auto *O
= dyn_cast
<ELF32BEObjectFile
>(&Obj
))
55 return createDumper(*O
);
56 if (const auto *O
= dyn_cast
<ELF64LEObjectFile
>(&Obj
))
57 return createDumper(*O
);
58 return createDumper(cast
<ELF64BEObjectFile
>(Obj
));
62 static Expected
<StringRef
> getDynamicStrTab(const ELFFile
<ELFT
> &Elf
) {
63 auto DynamicEntriesOrError
= Elf
.dynamicEntries();
64 if (!DynamicEntriesOrError
)
65 return DynamicEntriesOrError
.takeError();
67 for (const typename
ELFT::Dyn
&Dyn
: *DynamicEntriesOrError
) {
68 if (Dyn
.d_tag
== ELF::DT_STRTAB
) {
69 auto MappedAddrOrError
= Elf
.toMappedAddr(Dyn
.getPtr());
70 if (!MappedAddrOrError
)
71 consumeError(MappedAddrOrError
.takeError());
72 return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError
));
76 // If the dynamic segment is not present, we fall back on the sections.
77 auto SectionsOrError
= Elf
.sections();
79 return SectionsOrError
.takeError();
81 for (const typename
ELFT::Shdr
&Sec
: *SectionsOrError
) {
82 if (Sec
.sh_type
== ELF::SHT_DYNSYM
)
83 return Elf
.getStringTableForSymtab(Sec
);
86 return createError("dynamic string table not found");
90 static Error
getRelocationValueString(const ELFObjectFile
<ELFT
> *Obj
,
91 const RelocationRef
&RelRef
,
92 SmallVectorImpl
<char> &Result
) {
93 const ELFFile
<ELFT
> &EF
= Obj
->getELFFile();
94 DataRefImpl Rel
= RelRef
.getRawDataRefImpl();
95 auto SecOrErr
= EF
.getSection(Rel
.d
.a
);
97 return SecOrErr
.takeError();
100 // If there is no Symbol associated with the relocation, we set the undef
101 // boolean value to 'true'. This will prevent us from calling functions that
102 // requires the relocation to be associated with a symbol.
104 // In SHT_REL case we would need to read the addend from section data.
105 // GNU objdump does not do that and we just follow for simplicity atm.
107 if ((*SecOrErr
)->sh_type
== ELF::SHT_RELA
) {
108 const typename
ELFT::Rela
*ERela
= Obj
->getRela(Rel
);
109 Addend
= ERela
->r_addend
;
110 Undef
= ERela
->getSymbol(false) == 0;
111 } else if ((*SecOrErr
)->sh_type
== ELF::SHT_REL
) {
112 const typename
ELFT::Rel
*ERel
= Obj
->getRel(Rel
);
113 Undef
= ERel
->getSymbol(false) == 0;
115 return make_error
<BinaryError
>();
118 // Default scheme is to print Target, as well as "+ <addend>" for nonzero
119 // addend. Should be acceptable for all normal purposes.
121 raw_string_ostream
Fmt(FmtBuf
);
124 symbol_iterator SI
= RelRef
.getSymbol();
125 Expected
<const typename
ELFT::Sym
*> SymOrErr
=
126 Obj
->getSymbol(SI
->getRawDataRefImpl());
127 // TODO: test this error.
129 return SymOrErr
.takeError();
131 if ((*SymOrErr
)->getType() == ELF::STT_SECTION
) {
132 Expected
<section_iterator
> SymSI
= SI
->getSection();
134 return SymSI
.takeError();
135 const typename
ELFT::Shdr
*SymSec
=
136 Obj
->getSection((*SymSI
)->getRawDataRefImpl());
137 auto SecName
= EF
.getSectionName(*SymSec
);
139 return SecName
.takeError();
142 Expected
<StringRef
> SymName
= SI
->getName();
144 return SymName
.takeError();
145 Fmt
<< (Demangle
? demangle(*SymName
) : *SymName
);
153 : "+") << format("0x%" PRIx64
,
154 (Addend
< 0 ? -(uint64_t)Addend
: (uint64_t)Addend
));
157 Result
.append(FmtBuf
.begin(), FmtBuf
.end());
158 return Error::success();
161 Error
objdump::getELFRelocationValueString(const ELFObjectFileBase
*Obj
,
162 const RelocationRef
&Rel
,
163 SmallVectorImpl
<char> &Result
) {
164 if (auto *ELF32LE
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
165 return getRelocationValueString(ELF32LE
, Rel
, Result
);
166 if (auto *ELF64LE
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
167 return getRelocationValueString(ELF64LE
, Rel
, Result
);
168 if (auto *ELF32BE
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
169 return getRelocationValueString(ELF32BE
, Rel
, Result
);
170 auto *ELF64BE
= cast
<ELF64BEObjectFile
>(Obj
);
171 return getRelocationValueString(ELF64BE
, Rel
, Result
);
174 template <class ELFT
>
175 static uint64_t getSectionLMA(const ELFFile
<ELFT
> &Obj
,
176 const object::ELFSectionRef
&Sec
) {
177 auto PhdrRangeOrErr
= Obj
.program_headers();
179 report_fatal_error(Twine(toString(PhdrRangeOrErr
.takeError())));
181 // Search for a PT_LOAD segment containing the requested section. Use this
182 // segment's p_addr to calculate the section's LMA.
183 for (const typename
ELFT::Phdr
&Phdr
: *PhdrRangeOrErr
)
184 if ((Phdr
.p_type
== ELF::PT_LOAD
) && (Phdr
.p_vaddr
<= Sec
.getAddress()) &&
185 (Phdr
.p_vaddr
+ Phdr
.p_memsz
> Sec
.getAddress()))
186 return Sec
.getAddress() - Phdr
.p_vaddr
+ Phdr
.p_paddr
;
188 // Return section's VMA if it isn't in a PT_LOAD segment.
189 return Sec
.getAddress();
192 uint64_t objdump::getELFSectionLMA(const object::ELFSectionRef
&Sec
) {
193 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Sec
.getObject()))
194 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
195 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Sec
.getObject()))
196 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
197 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Sec
.getObject()))
198 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
199 const auto *ELFObj
= cast
<ELF64BEObjectFile
>(Sec
.getObject());
200 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
203 template <class ELFT
> void ELFDumper
<ELFT
>::printDynamicSection() {
204 const ELFFile
<ELFT
> &Elf
= getELFFile();
205 auto DynamicEntriesOrErr
= Elf
.dynamicEntries();
206 if (!DynamicEntriesOrErr
) {
207 reportWarning(toString(DynamicEntriesOrErr
.takeError()), Obj
.getFileName());
210 ArrayRef
<typename
ELFT::Dyn
> DynamicEntries
= *DynamicEntriesOrErr
;
212 // Find the maximum tag name length to format the value column properly.
214 for (const typename
ELFT::Dyn
&Dyn
: DynamicEntries
)
215 MaxLen
= std::max(MaxLen
, Elf
.getDynamicTagAsString(Dyn
.d_tag
).size());
216 std::string TagFmt
= " %-" + std::to_string(MaxLen
) + "s ";
218 outs() << "\nDynamic Section:\n";
219 for (const typename
ELFT::Dyn
&Dyn
: DynamicEntries
) {
220 if (Dyn
.d_tag
== ELF::DT_NULL
)
223 std::string Str
= Elf
.getDynamicTagAsString(Dyn
.d_tag
);
224 outs() << format(TagFmt
.c_str(), Str
.c_str());
227 ELFT::Is64Bits
? "0x%016" PRIx64
"\n" : "0x%08" PRIx64
"\n";
228 if (Dyn
.d_tag
== ELF::DT_NEEDED
|| Dyn
.d_tag
== ELF::DT_RPATH
||
229 Dyn
.d_tag
== ELF::DT_RUNPATH
|| Dyn
.d_tag
== ELF::DT_SONAME
||
230 Dyn
.d_tag
== ELF::DT_AUXILIARY
|| Dyn
.d_tag
== ELF::DT_FILTER
) {
231 Expected
<StringRef
> StrTabOrErr
= getDynamicStrTab(Elf
);
233 const char *Data
= StrTabOrErr
.get().data();
234 outs() << (Data
+ Dyn
.d_un
.d_val
) << "\n";
237 reportWarning(toString(StrTabOrErr
.takeError()), Obj
.getFileName());
238 consumeError(StrTabOrErr
.takeError());
240 outs() << format(Fmt
, (uint64_t)Dyn
.d_un
.d_val
);
244 template <class ELFT
> void ELFDumper
<ELFT
>::printProgramHeaders() {
245 outs() << "\nProgram Header:\n";
246 auto ProgramHeaderOrError
= getELFFile().program_headers();
247 if (!ProgramHeaderOrError
) {
248 reportWarning("unable to read program headers: " +
249 toString(ProgramHeaderOrError
.takeError()),
254 for (const typename
ELFT::Phdr
&Phdr
: *ProgramHeaderOrError
) {
255 switch (Phdr
.p_type
) {
256 case ELF::PT_DYNAMIC
:
257 outs() << " DYNAMIC ";
259 case ELF::PT_GNU_EH_FRAME
:
260 outs() << "EH_FRAME ";
262 case ELF::PT_GNU_RELRO
:
265 case ELF::PT_GNU_PROPERTY
:
266 outs() << " PROPERTY ";
268 case ELF::PT_GNU_STACK
:
272 outs() << " INTERP ";
280 case ELF::PT_OPENBSD_BOOTDATA
:
281 outs() << "OPENBSD_BOOTDATA ";
283 case ELF::PT_OPENBSD_MUTABLE
:
284 outs() << "OPENBSD_MUTABLE ";
286 case ELF::PT_OPENBSD_NOBTCFI
:
287 outs() << "OPENBSD_NOBTCFI ";
289 case ELF::PT_OPENBSD_RANDOMIZE
:
290 outs() << "OPENBSD_RANDOMIZE ";
292 case ELF::PT_OPENBSD_WXNEEDED
:
293 outs() << "OPENBSD_WXNEEDED ";
302 outs() << " UNKNOWN ";
305 const char *Fmt
= ELFT::Is64Bits
? "0x%016" PRIx64
" " : "0x%08" PRIx64
" ";
307 outs() << "off " << format(Fmt
, (uint64_t)Phdr
.p_offset
) << "vaddr "
308 << format(Fmt
, (uint64_t)Phdr
.p_vaddr
) << "paddr "
309 << format(Fmt
, (uint64_t)Phdr
.p_paddr
)
310 << format("align 2**%u\n", llvm::countr_zero
<uint64_t>(Phdr
.p_align
))
311 << " filesz " << format(Fmt
, (uint64_t)Phdr
.p_filesz
)
312 << "memsz " << format(Fmt
, (uint64_t)Phdr
.p_memsz
) << "flags "
313 << ((Phdr
.p_flags
& ELF::PF_R
) ? "r" : "-")
314 << ((Phdr
.p_flags
& ELF::PF_W
) ? "w" : "-")
315 << ((Phdr
.p_flags
& ELF::PF_X
) ? "x" : "-") << "\n";
319 template <typename ELFT
> void ELFDumper
<ELFT
>::printDynamicRelocations() {
320 if (!any_of(Obj
.sections(), [](const ELFSectionRef Sec
) {
321 return Sec
.getType() == ELF::SHT_DYNAMIC
;
323 reportError(Obj
.getFileName(), "not a dynamic object");
327 std::vector
<SectionRef
> DynRelSec
=
328 cast
<ObjectFile
>(Obj
).dynamic_relocation_sections();
329 if (DynRelSec
.empty())
332 outs() << "\nDYNAMIC RELOCATION RECORDS\n";
333 const uint32_t OffsetPadding
= (Obj
.getBytesInAddress() > 4 ? 16 : 8);
334 const uint32_t TypePadding
= 24;
335 outs() << left_justify("OFFSET", OffsetPadding
) << ' '
336 << left_justify("TYPE", TypePadding
) << " VALUE\n";
338 StringRef Fmt
= Obj
.getBytesInAddress() > 4 ? "%016" PRIx64
: "%08" PRIx64
;
339 for (const SectionRef
&Section
: DynRelSec
)
340 for (const RelocationRef
&Reloc
: Section
.relocations()) {
341 uint64_t Address
= Reloc
.getOffset();
342 SmallString
<32> RelocName
;
343 SmallString
<32> ValueStr
;
344 Reloc
.getTypeName(RelocName
);
345 if (Error E
= getELFRelocationValueString(&Obj
, Reloc
, ValueStr
))
346 reportError(std::move(E
), Obj
.getFileName());
347 outs() << format(Fmt
.data(), Address
) << ' '
348 << left_justify(RelocName
, TypePadding
) << ' ' << ValueStr
<< '\n';
352 template <class ELFT
>
353 void ELFDumper
<ELFT
>::printSymbolVersionDependency(
354 const typename
ELFT::Shdr
&Sec
) {
355 outs() << "\nVersion References:\n";
356 Expected
<std::vector
<VerNeed
>> V
=
357 getELFFile().getVersionDependencies(Sec
, this->WarningHandler
);
359 reportWarning(toString(V
.takeError()), Obj
.getFileName());
363 raw_fd_ostream
&OS
= outs();
364 for (const VerNeed
&VN
: *V
) {
365 OS
<< " required from " << VN
.File
<< ":\n";
366 for (const VernAux
&Aux
: VN
.AuxV
)
367 OS
<< format(" 0x%08x 0x%02x %02u %s\n", Aux
.Hash
, Aux
.Flags
,
368 Aux
.Other
, Aux
.Name
.c_str());
372 template <class ELFT
>
373 static void printSymbolVersionDefinition(const typename
ELFT::Shdr
&Shdr
,
374 ArrayRef
<uint8_t> Contents
,
376 outs() << "\nVersion definitions:\n";
378 const uint8_t *Buf
= Contents
.data();
379 uint32_t VerdefIndex
= 1;
380 // sh_info contains the number of entries in the SHT_GNU_verdef section. To
381 // make the index column have consistent width, we should insert blank spaces
382 // according to sh_info.
383 uint16_t VerdefIndexWidth
= std::to_string(Shdr
.sh_info
).size();
385 auto *Verdef
= reinterpret_cast<const typename
ELFT::Verdef
*>(Buf
);
386 outs() << format_decimal(VerdefIndex
++, VerdefIndexWidth
) << " "
387 << format("0x%02" PRIx16
" ", (uint16_t)Verdef
->vd_flags
)
388 << format("0x%08" PRIx32
" ", (uint32_t)Verdef
->vd_hash
);
390 const uint8_t *BufAux
= Buf
+ Verdef
->vd_aux
;
391 uint16_t VerdauxIndex
= 0;
393 auto *Verdaux
= reinterpret_cast<const typename
ELFT::Verdaux
*>(BufAux
);
395 outs() << std::string(VerdefIndexWidth
+ 17, ' ');
396 outs() << StringRef(StrTab
.drop_front(Verdaux
->vda_name
).data()) << '\n';
397 BufAux
= Verdaux
->vda_next
? BufAux
+ Verdaux
->vda_next
: nullptr;
400 Buf
= Verdef
->vd_next
? Buf
+ Verdef
->vd_next
: nullptr;
404 template <class ELFT
> void ELFDumper
<ELFT
>::printSymbolVersion() {
405 const ELFFile
<ELFT
> &Elf
= getELFFile();
406 StringRef FileName
= Obj
.getFileName();
407 ArrayRef
<typename
ELFT::Shdr
> Sections
=
408 unwrapOrError(Elf
.sections(), FileName
);
409 for (const typename
ELFT::Shdr
&Shdr
: Sections
) {
410 if (Shdr
.sh_type
!= ELF::SHT_GNU_verneed
&&
411 Shdr
.sh_type
!= ELF::SHT_GNU_verdef
)
414 ArrayRef
<uint8_t> Contents
=
415 unwrapOrError(Elf
.getSectionContents(Shdr
), FileName
);
416 const typename
ELFT::Shdr
*StrTabSec
=
417 unwrapOrError(Elf
.getSection(Shdr
.sh_link
), FileName
);
418 StringRef StrTab
= unwrapOrError(Elf
.getStringTable(*StrTabSec
), FileName
);
420 if (Shdr
.sh_type
== ELF::SHT_GNU_verneed
)
421 printSymbolVersionDependency(Shdr
);
423 printSymbolVersionDefinition
<ELFT
>(Shdr
, Contents
, StrTab
);
427 template <class ELFT
> void ELFDumper
<ELFT
>::printPrivateHeaders() {
428 printProgramHeaders();
429 printDynamicSection();
430 printSymbolVersion();