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 //===----------------------------------------------------------------------===//
14 #include "llvm-objdump.h"
15 #include "llvm/Demangle/Demangle.h"
16 #include "llvm/Object/ELFObjectFile.h"
17 #include "llvm/Support/Format.h"
18 #include "llvm/Support/MathExtras.h"
19 #include "llvm/Support/raw_ostream.h"
21 using namespace llvm::object
;
25 static Expected
<StringRef
> getDynamicStrTab(const ELFFile
<ELFT
> *Elf
) {
26 auto DynamicEntriesOrError
= Elf
->dynamicEntries();
27 if (!DynamicEntriesOrError
)
28 return DynamicEntriesOrError
.takeError();
30 for (const typename
ELFT::Dyn
&Dyn
: *DynamicEntriesOrError
) {
31 if (Dyn
.d_tag
== ELF::DT_STRTAB
) {
32 auto MappedAddrOrError
= Elf
->toMappedAddr(Dyn
.getPtr());
33 if (!MappedAddrOrError
)
34 consumeError(MappedAddrOrError
.takeError());
35 return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError
));
39 // If the dynamic segment is not present, we fall back on the sections.
40 auto SectionsOrError
= Elf
->sections();
42 return SectionsOrError
.takeError();
44 for (const typename
ELFT::Shdr
&Sec
: *SectionsOrError
) {
45 if (Sec
.sh_type
== ELF::SHT_DYNSYM
)
46 return Elf
->getStringTableForSymtab(Sec
);
49 return createError("dynamic string table not found");
53 static Error
getRelocationValueString(const ELFObjectFile
<ELFT
> *Obj
,
54 const RelocationRef
&RelRef
,
55 SmallVectorImpl
<char> &Result
) {
56 const ELFFile
<ELFT
> &EF
= *Obj
->getELFFile();
57 DataRefImpl Rel
= RelRef
.getRawDataRefImpl();
58 auto SecOrErr
= EF
.getSection(Rel
.d
.a
);
60 return SecOrErr
.takeError();
63 // If there is no Symbol associated with the relocation, we set the undef
64 // boolean value to 'true'. This will prevent us from calling functions that
65 // requires the relocation to be associated with a symbol.
67 // In SHT_REL case we would need to read the addend from section data.
68 // GNU objdump does not do that and we just follow for simplicity atm.
70 if ((*SecOrErr
)->sh_type
== ELF::SHT_RELA
) {
71 const typename
ELFT::Rela
*ERela
= Obj
->getRela(Rel
);
72 Addend
= ERela
->r_addend
;
73 Undef
= ERela
->getSymbol(false) == 0;
74 } else if ((*SecOrErr
)->sh_type
!= ELF::SHT_REL
) {
75 return make_error
<BinaryError
>();
78 // Default scheme is to print Target, as well as "+ <addend>" for nonzero
79 // addend. Should be acceptable for all normal purposes.
81 raw_string_ostream
Fmt(FmtBuf
);
84 symbol_iterator SI
= RelRef
.getSymbol();
85 const typename
ELFT::Sym
*Sym
= Obj
->getSymbol(SI
->getRawDataRefImpl());
86 if (Sym
->getType() == ELF::STT_SECTION
) {
87 Expected
<section_iterator
> SymSI
= SI
->getSection();
89 return SymSI
.takeError();
90 const typename
ELFT::Shdr
*SymSec
=
91 Obj
->getSection((*SymSI
)->getRawDataRefImpl());
92 auto SecName
= EF
.getSectionName(SymSec
);
94 return SecName
.takeError();
97 Expected
<StringRef
> SymName
= SI
->getName();
99 return SymName
.takeError();
101 Fmt
<< demangle(*SymName
);
110 Fmt
<< (Addend
< 0 ? "" : "+") << Addend
;
112 Result
.append(FmtBuf
.begin(), FmtBuf
.end());
113 return Error::success();
116 Error
getELFRelocationValueString(const ELFObjectFileBase
*Obj
,
117 const RelocationRef
&Rel
,
118 SmallVectorImpl
<char> &Result
) {
119 if (auto *ELF32LE
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
120 return getRelocationValueString(ELF32LE
, Rel
, Result
);
121 if (auto *ELF64LE
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
122 return getRelocationValueString(ELF64LE
, Rel
, Result
);
123 if (auto *ELF32BE
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
124 return getRelocationValueString(ELF32BE
, Rel
, Result
);
125 auto *ELF64BE
= cast
<ELF64BEObjectFile
>(Obj
);
126 return getRelocationValueString(ELF64BE
, Rel
, Result
);
129 template <class ELFT
>
130 static uint64_t getSectionLMA(const ELFFile
<ELFT
> *Obj
,
131 const object::ELFSectionRef
&Sec
) {
132 auto PhdrRangeOrErr
= Obj
->program_headers();
134 report_fatal_error(toString(PhdrRangeOrErr
.takeError()));
136 // Search for a PT_LOAD segment containing the requested section. Use this
137 // segment's p_addr to calculate the section's LMA.
138 for (const typename
ELFT::Phdr
&Phdr
: *PhdrRangeOrErr
)
139 if ((Phdr
.p_type
== ELF::PT_LOAD
) && (Phdr
.p_vaddr
<= Sec
.getAddress()) &&
140 (Phdr
.p_vaddr
+ Phdr
.p_memsz
> Sec
.getAddress()))
141 return Sec
.getAddress() - Phdr
.p_vaddr
+ Phdr
.p_paddr
;
143 // Return section's VMA if it isn't in a PT_LOAD segment.
144 return Sec
.getAddress();
147 uint64_t getELFSectionLMA(const object::ELFSectionRef
&Sec
) {
148 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Sec
.getObject()))
149 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
150 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Sec
.getObject()))
151 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
152 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Sec
.getObject()))
153 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
154 const auto *ELFObj
= cast
<ELF64BEObjectFile
>(Sec
.getObject());
155 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
158 template <class ELFT
>
159 void printDynamicSection(const ELFFile
<ELFT
> *Elf
, StringRef Filename
) {
160 ArrayRef
<typename
ELFT::Dyn
> DynamicEntries
=
161 unwrapOrError(Elf
->dynamicEntries(), Filename
);
162 outs() << "Dynamic Section:\n";
163 for (const typename
ELFT::Dyn
&Dyn
: DynamicEntries
) {
164 if (Dyn
.d_tag
== ELF::DT_NULL
)
167 std::string Str
= Elf
->getDynamicTagAsString(Dyn
.d_tag
);
168 outs() << format(" %-21s", Str
.c_str());
171 ELFT::Is64Bits
? "0x%016" PRIx64
"\n" : "0x%08" PRIx64
"\n";
172 if (Dyn
.d_tag
== ELF::DT_NEEDED
|| Dyn
.d_tag
== ELF::DT_RPATH
||
173 Dyn
.d_tag
== ELF::DT_RUNPATH
|| Dyn
.d_tag
== ELF::DT_SONAME
||
174 Dyn
.d_tag
== ELF::DT_AUXILIARY
|| Dyn
.d_tag
== ELF::DT_FILTER
) {
175 Expected
<StringRef
> StrTabOrErr
= getDynamicStrTab(Elf
);
177 const char *Data
= StrTabOrErr
.get().data();
178 outs() << (Data
+ Dyn
.d_un
.d_val
) << "\n";
181 reportWarning(toString(StrTabOrErr
.takeError()), Filename
);
182 consumeError(StrTabOrErr
.takeError());
184 outs() << format(Fmt
, (uint64_t)Dyn
.d_un
.d_val
);
188 template <class ELFT
> void printProgramHeaders(const ELFFile
<ELFT
> *o
) {
189 outs() << "Program Header:\n";
190 auto ProgramHeaderOrError
= o
->program_headers();
191 if (!ProgramHeaderOrError
)
192 report_fatal_error(toString(ProgramHeaderOrError
.takeError()));
193 for (const typename
ELFT::Phdr
&Phdr
: *ProgramHeaderOrError
) {
194 switch (Phdr
.p_type
) {
195 case ELF::PT_DYNAMIC
:
196 outs() << " DYNAMIC ";
198 case ELF::PT_GNU_EH_FRAME
:
199 outs() << "EH_FRAME ";
201 case ELF::PT_GNU_RELRO
:
204 case ELF::PT_GNU_STACK
:
208 outs() << " INTERP ";
216 case ELF::PT_OPENBSD_BOOTDATA
:
217 outs() << " OPENBSD_BOOTDATA ";
219 case ELF::PT_OPENBSD_RANDOMIZE
:
220 outs() << " OPENBSD_RANDOMIZE ";
222 case ELF::PT_OPENBSD_WXNEEDED
:
223 outs() << " OPENBSD_WXNEEDED ";
232 outs() << " UNKNOWN ";
235 const char *Fmt
= ELFT::Is64Bits
? "0x%016" PRIx64
" " : "0x%08" PRIx64
" ";
237 outs() << "off " << format(Fmt
, (uint64_t)Phdr
.p_offset
) << "vaddr "
238 << format(Fmt
, (uint64_t)Phdr
.p_vaddr
) << "paddr "
239 << format(Fmt
, (uint64_t)Phdr
.p_paddr
)
240 << format("align 2**%u\n",
241 countTrailingZeros
<uint64_t>(Phdr
.p_align
))
242 << " filesz " << format(Fmt
, (uint64_t)Phdr
.p_filesz
)
243 << "memsz " << format(Fmt
, (uint64_t)Phdr
.p_memsz
) << "flags "
244 << ((Phdr
.p_flags
& ELF::PF_R
) ? "r" : "-")
245 << ((Phdr
.p_flags
& ELF::PF_W
) ? "w" : "-")
246 << ((Phdr
.p_flags
& ELF::PF_X
) ? "x" : "-") << "\n";
251 template <class ELFT
>
252 void printSymbolVersionDependency(ArrayRef
<uint8_t> Contents
,
254 outs() << "Version References:\n";
256 const uint8_t *Buf
= Contents
.data();
258 auto *Verneed
= reinterpret_cast<const typename
ELFT::Verneed
*>(Buf
);
259 outs() << " required from "
260 << StringRef(StrTab
.drop_front(Verneed
->vn_file
).data()) << ":\n";
262 const uint8_t *BufAux
= Buf
+ Verneed
->vn_aux
;
264 auto *Vernaux
= reinterpret_cast<const typename
ELFT::Vernaux
*>(BufAux
);
266 << format("0x%08" PRIx32
" ", (uint32_t)Vernaux
->vna_hash
)
267 << format("0x%02" PRIx16
" ", (uint16_t)Vernaux
->vna_flags
)
268 << format("%02" PRIu16
" ", (uint16_t)Vernaux
->vna_other
)
269 << StringRef(StrTab
.drop_front(Vernaux
->vna_name
).data()) << '\n';
270 BufAux
= Vernaux
->vna_next
? BufAux
+ Vernaux
->vna_next
: nullptr;
272 Buf
= Verneed
->vn_next
? Buf
+ Verneed
->vn_next
: nullptr;
276 template <class ELFT
>
277 void printSymbolVersionDefinition(const typename
ELFT::Shdr
&Shdr
,
278 ArrayRef
<uint8_t> Contents
,
280 outs() << "Version definitions:\n";
282 const uint8_t *Buf
= Contents
.data();
283 uint32_t VerdefIndex
= 1;
284 // sh_info contains the number of entries in the SHT_GNU_verdef section. To
285 // make the index column have consistent width, we should insert blank spaces
286 // according to sh_info.
287 uint16_t VerdefIndexWidth
= std::to_string(Shdr
.sh_info
).size();
289 auto *Verdef
= reinterpret_cast<const typename
ELFT::Verdef
*>(Buf
);
290 outs() << format_decimal(VerdefIndex
++, VerdefIndexWidth
) << " "
291 << format("0x%02" PRIx16
" ", (uint16_t)Verdef
->vd_flags
)
292 << format("0x%08" PRIx32
" ", (uint32_t)Verdef
->vd_hash
);
294 const uint8_t *BufAux
= Buf
+ Verdef
->vd_aux
;
295 uint16_t VerdauxIndex
= 0;
297 auto *Verdaux
= reinterpret_cast<const typename
ELFT::Verdaux
*>(BufAux
);
299 outs() << std::string(VerdefIndexWidth
+ 17, ' ');
300 outs() << StringRef(StrTab
.drop_front(Verdaux
->vda_name
).data()) << '\n';
301 BufAux
= Verdaux
->vda_next
? BufAux
+ Verdaux
->vda_next
: nullptr;
304 Buf
= Verdef
->vd_next
? Buf
+ Verdef
->vd_next
: nullptr;
308 template <class ELFT
>
309 void printSymbolVersionInfo(const ELFFile
<ELFT
> *Elf
, StringRef FileName
) {
310 ArrayRef
<typename
ELFT::Shdr
> Sections
=
311 unwrapOrError(Elf
->sections(), FileName
);
312 for (const typename
ELFT::Shdr
&Shdr
: Sections
) {
313 if (Shdr
.sh_type
!= ELF::SHT_GNU_verneed
&&
314 Shdr
.sh_type
!= ELF::SHT_GNU_verdef
)
317 ArrayRef
<uint8_t> Contents
=
318 unwrapOrError(Elf
->getSectionContents(&Shdr
), FileName
);
319 const typename
ELFT::Shdr
*StrTabSec
=
320 unwrapOrError(Elf
->getSection(Shdr
.sh_link
), FileName
);
321 StringRef StrTab
= unwrapOrError(Elf
->getStringTable(StrTabSec
), FileName
);
323 if (Shdr
.sh_type
== ELF::SHT_GNU_verneed
)
324 printSymbolVersionDependency
<ELFT
>(Contents
, StrTab
);
326 printSymbolVersionDefinition
<ELFT
>(Shdr
, Contents
, StrTab
);
330 void printELFFileHeader(const object::ObjectFile
*Obj
) {
331 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
332 printProgramHeaders(ELFObj
->getELFFile());
333 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
334 printProgramHeaders(ELFObj
->getELFFile());
335 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
336 printProgramHeaders(ELFObj
->getELFFile());
337 else if (const auto *ELFObj
= dyn_cast
<ELF64BEObjectFile
>(Obj
))
338 printProgramHeaders(ELFObj
->getELFFile());
341 void printELFDynamicSection(const object::ObjectFile
*Obj
) {
342 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
343 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
344 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
345 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
346 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
347 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
348 else if (const auto *ELFObj
= dyn_cast
<ELF64BEObjectFile
>(Obj
))
349 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
352 void printELFSymbolVersionInfo(const object::ObjectFile
*Obj
) {
353 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
354 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());
355 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
356 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());
357 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
358 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());
359 else if (const auto *ELFObj
= dyn_cast
<ELF64BEObjectFile
>(Obj
))
360 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());