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
);
111 : "+") << format("0x%" PRIx64
,
112 (Addend
< 0 ? -(uint64_t)Addend
: (uint64_t)Addend
));
115 Result
.append(FmtBuf
.begin(), FmtBuf
.end());
116 return Error::success();
119 Error
getELFRelocationValueString(const ELFObjectFileBase
*Obj
,
120 const RelocationRef
&Rel
,
121 SmallVectorImpl
<char> &Result
) {
122 if (auto *ELF32LE
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
123 return getRelocationValueString(ELF32LE
, Rel
, Result
);
124 if (auto *ELF64LE
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
125 return getRelocationValueString(ELF64LE
, Rel
, Result
);
126 if (auto *ELF32BE
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
127 return getRelocationValueString(ELF32BE
, Rel
, Result
);
128 auto *ELF64BE
= cast
<ELF64BEObjectFile
>(Obj
);
129 return getRelocationValueString(ELF64BE
, Rel
, Result
);
132 template <class ELFT
>
133 static uint64_t getSectionLMA(const ELFFile
<ELFT
> *Obj
,
134 const object::ELFSectionRef
&Sec
) {
135 auto PhdrRangeOrErr
= Obj
->program_headers();
137 report_fatal_error(toString(PhdrRangeOrErr
.takeError()));
139 // Search for a PT_LOAD segment containing the requested section. Use this
140 // segment's p_addr to calculate the section's LMA.
141 for (const typename
ELFT::Phdr
&Phdr
: *PhdrRangeOrErr
)
142 if ((Phdr
.p_type
== ELF::PT_LOAD
) && (Phdr
.p_vaddr
<= Sec
.getAddress()) &&
143 (Phdr
.p_vaddr
+ Phdr
.p_memsz
> Sec
.getAddress()))
144 return Sec
.getAddress() - Phdr
.p_vaddr
+ Phdr
.p_paddr
;
146 // Return section's VMA if it isn't in a PT_LOAD segment.
147 return Sec
.getAddress();
150 uint64_t getELFSectionLMA(const object::ELFSectionRef
&Sec
) {
151 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Sec
.getObject()))
152 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
153 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Sec
.getObject()))
154 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
155 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Sec
.getObject()))
156 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
157 const auto *ELFObj
= cast
<ELF64BEObjectFile
>(Sec
.getObject());
158 return getSectionLMA(ELFObj
->getELFFile(), Sec
);
161 template <class ELFT
>
162 void printDynamicSection(const ELFFile
<ELFT
> *Elf
, StringRef Filename
) {
163 ArrayRef
<typename
ELFT::Dyn
> DynamicEntries
=
164 unwrapOrError(Elf
->dynamicEntries(), Filename
);
166 // Find the maximum tag name length to format the value column properly.
168 for (const typename
ELFT::Dyn
&Dyn
: DynamicEntries
)
169 MaxLen
= std::max(MaxLen
, Elf
->getDynamicTagAsString(Dyn
.d_tag
).size());
170 std::string TagFmt
= " %-" + std::to_string(MaxLen
) + "s ";
172 outs() << "Dynamic Section:\n";
173 for (const typename
ELFT::Dyn
&Dyn
: DynamicEntries
) {
174 if (Dyn
.d_tag
== ELF::DT_NULL
)
177 std::string Str
= Elf
->getDynamicTagAsString(Dyn
.d_tag
);
178 outs() << format(TagFmt
.c_str(), Str
.c_str());
181 ELFT::Is64Bits
? "0x%016" PRIx64
"\n" : "0x%08" PRIx64
"\n";
182 if (Dyn
.d_tag
== ELF::DT_NEEDED
|| Dyn
.d_tag
== ELF::DT_RPATH
||
183 Dyn
.d_tag
== ELF::DT_RUNPATH
|| Dyn
.d_tag
== ELF::DT_SONAME
||
184 Dyn
.d_tag
== ELF::DT_AUXILIARY
|| Dyn
.d_tag
== ELF::DT_FILTER
) {
185 Expected
<StringRef
> StrTabOrErr
= getDynamicStrTab(Elf
);
187 const char *Data
= StrTabOrErr
.get().data();
188 outs() << (Data
+ Dyn
.d_un
.d_val
) << "\n";
191 reportWarning(toString(StrTabOrErr
.takeError()), Filename
);
192 consumeError(StrTabOrErr
.takeError());
194 outs() << format(Fmt
, (uint64_t)Dyn
.d_un
.d_val
);
198 template <class ELFT
> void printProgramHeaders(const ELFFile
<ELFT
> *o
) {
199 outs() << "Program Header:\n";
200 auto ProgramHeaderOrError
= o
->program_headers();
201 if (!ProgramHeaderOrError
)
202 report_fatal_error(toString(ProgramHeaderOrError
.takeError()));
203 for (const typename
ELFT::Phdr
&Phdr
: *ProgramHeaderOrError
) {
204 switch (Phdr
.p_type
) {
205 case ELF::PT_DYNAMIC
:
206 outs() << " DYNAMIC ";
208 case ELF::PT_GNU_EH_FRAME
:
209 outs() << "EH_FRAME ";
211 case ELF::PT_GNU_RELRO
:
214 case ELF::PT_GNU_PROPERTY
:
215 outs() << " PROPERTY ";
217 case ELF::PT_GNU_STACK
:
221 outs() << " INTERP ";
229 case ELF::PT_OPENBSD_BOOTDATA
:
230 outs() << " OPENBSD_BOOTDATA ";
232 case ELF::PT_OPENBSD_RANDOMIZE
:
233 outs() << " OPENBSD_RANDOMIZE ";
235 case ELF::PT_OPENBSD_WXNEEDED
:
236 outs() << " OPENBSD_WXNEEDED ";
245 outs() << " UNKNOWN ";
248 const char *Fmt
= ELFT::Is64Bits
? "0x%016" PRIx64
" " : "0x%08" PRIx64
" ";
250 outs() << "off " << format(Fmt
, (uint64_t)Phdr
.p_offset
) << "vaddr "
251 << format(Fmt
, (uint64_t)Phdr
.p_vaddr
) << "paddr "
252 << format(Fmt
, (uint64_t)Phdr
.p_paddr
)
253 << format("align 2**%u\n",
254 countTrailingZeros
<uint64_t>(Phdr
.p_align
))
255 << " filesz " << format(Fmt
, (uint64_t)Phdr
.p_filesz
)
256 << "memsz " << format(Fmt
, (uint64_t)Phdr
.p_memsz
) << "flags "
257 << ((Phdr
.p_flags
& ELF::PF_R
) ? "r" : "-")
258 << ((Phdr
.p_flags
& ELF::PF_W
) ? "w" : "-")
259 << ((Phdr
.p_flags
& ELF::PF_X
) ? "x" : "-") << "\n";
264 template <class ELFT
>
265 void printSymbolVersionDependency(ArrayRef
<uint8_t> Contents
,
267 outs() << "Version References:\n";
269 const uint8_t *Buf
= Contents
.data();
271 auto *Verneed
= reinterpret_cast<const typename
ELFT::Verneed
*>(Buf
);
272 outs() << " required from "
273 << StringRef(StrTab
.drop_front(Verneed
->vn_file
).data()) << ":\n";
275 const uint8_t *BufAux
= Buf
+ Verneed
->vn_aux
;
277 auto *Vernaux
= reinterpret_cast<const typename
ELFT::Vernaux
*>(BufAux
);
279 << format("0x%08" PRIx32
" ", (uint32_t)Vernaux
->vna_hash
)
280 << format("0x%02" PRIx16
" ", (uint16_t)Vernaux
->vna_flags
)
281 << format("%02" PRIu16
" ", (uint16_t)Vernaux
->vna_other
)
282 << StringRef(StrTab
.drop_front(Vernaux
->vna_name
).data()) << '\n';
283 BufAux
= Vernaux
->vna_next
? BufAux
+ Vernaux
->vna_next
: nullptr;
285 Buf
= Verneed
->vn_next
? Buf
+ Verneed
->vn_next
: nullptr;
289 template <class ELFT
>
290 void printSymbolVersionDefinition(const typename
ELFT::Shdr
&Shdr
,
291 ArrayRef
<uint8_t> Contents
,
293 outs() << "Version definitions:\n";
295 const uint8_t *Buf
= Contents
.data();
296 uint32_t VerdefIndex
= 1;
297 // sh_info contains the number of entries in the SHT_GNU_verdef section. To
298 // make the index column have consistent width, we should insert blank spaces
299 // according to sh_info.
300 uint16_t VerdefIndexWidth
= std::to_string(Shdr
.sh_info
).size();
302 auto *Verdef
= reinterpret_cast<const typename
ELFT::Verdef
*>(Buf
);
303 outs() << format_decimal(VerdefIndex
++, VerdefIndexWidth
) << " "
304 << format("0x%02" PRIx16
" ", (uint16_t)Verdef
->vd_flags
)
305 << format("0x%08" PRIx32
" ", (uint32_t)Verdef
->vd_hash
);
307 const uint8_t *BufAux
= Buf
+ Verdef
->vd_aux
;
308 uint16_t VerdauxIndex
= 0;
310 auto *Verdaux
= reinterpret_cast<const typename
ELFT::Verdaux
*>(BufAux
);
312 outs() << std::string(VerdefIndexWidth
+ 17, ' ');
313 outs() << StringRef(StrTab
.drop_front(Verdaux
->vda_name
).data()) << '\n';
314 BufAux
= Verdaux
->vda_next
? BufAux
+ Verdaux
->vda_next
: nullptr;
317 Buf
= Verdef
->vd_next
? Buf
+ Verdef
->vd_next
: nullptr;
321 template <class ELFT
>
322 void printSymbolVersionInfo(const ELFFile
<ELFT
> *Elf
, StringRef FileName
) {
323 ArrayRef
<typename
ELFT::Shdr
> Sections
=
324 unwrapOrError(Elf
->sections(), FileName
);
325 for (const typename
ELFT::Shdr
&Shdr
: Sections
) {
326 if (Shdr
.sh_type
!= ELF::SHT_GNU_verneed
&&
327 Shdr
.sh_type
!= ELF::SHT_GNU_verdef
)
330 ArrayRef
<uint8_t> Contents
=
331 unwrapOrError(Elf
->getSectionContents(&Shdr
), FileName
);
332 const typename
ELFT::Shdr
*StrTabSec
=
333 unwrapOrError(Elf
->getSection(Shdr
.sh_link
), FileName
);
334 StringRef StrTab
= unwrapOrError(Elf
->getStringTable(StrTabSec
), FileName
);
336 if (Shdr
.sh_type
== ELF::SHT_GNU_verneed
)
337 printSymbolVersionDependency
<ELFT
>(Contents
, StrTab
);
339 printSymbolVersionDefinition
<ELFT
>(Shdr
, Contents
, StrTab
);
343 void printELFFileHeader(const object::ObjectFile
*Obj
) {
344 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
345 printProgramHeaders(ELFObj
->getELFFile());
346 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
347 printProgramHeaders(ELFObj
->getELFFile());
348 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
349 printProgramHeaders(ELFObj
->getELFFile());
350 else if (const auto *ELFObj
= dyn_cast
<ELF64BEObjectFile
>(Obj
))
351 printProgramHeaders(ELFObj
->getELFFile());
354 void printELFDynamicSection(const object::ObjectFile
*Obj
) {
355 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
356 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
357 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
358 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
359 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
360 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
361 else if (const auto *ELFObj
= dyn_cast
<ELF64BEObjectFile
>(Obj
))
362 printDynamicSection(ELFObj
->getELFFile(), Obj
->getFileName());
365 void printELFSymbolVersionInfo(const object::ObjectFile
*Obj
) {
366 if (const auto *ELFObj
= dyn_cast
<ELF32LEObjectFile
>(Obj
))
367 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());
368 else if (const auto *ELFObj
= dyn_cast
<ELF32BEObjectFile
>(Obj
))
369 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());
370 else if (const auto *ELFObj
= dyn_cast
<ELF64LEObjectFile
>(Obj
))
371 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());
372 else if (const auto *ELFObj
= dyn_cast
<ELF64BEObjectFile
>(Obj
))
373 printSymbolVersionInfo(ELFObj
->getELFFile(), Obj
->getFileName());