439 lines · cpp
1//===-- ELFDump.cpp - ELF-specific dumper -----------------------*- C++ -*-===//2//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file implements the ELF-specific dumper for llvm-objdump.11///12//===----------------------------------------------------------------------===//13 14#include "ELFDump.h"15 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"21 22using namespace llvm;23using namespace llvm::object;24using namespace llvm::objdump;25 26namespace {27template <typename ELFT> class ELFDumper : public Dumper {28public:29 ELFDumper(const ELFObjectFile<ELFT> &O) : Dumper(O), Obj(O) {}30 void printPrivateHeaders() override;31 void printDynamicRelocations() override;32 33private:34 const ELFObjectFile<ELFT> &Obj;35 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);41};42} // namespace43 44template <class ELFT>45static std::unique_ptr<Dumper> createDumper(const ELFObjectFile<ELFT> &Obj) {46 return std::make_unique<ELFDumper<ELFT>>(Obj);47}48 49std::unique_ptr<Dumper>50objdump::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));58}59 60template <class ELFT>61static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> &Elf) {62 auto DynamicEntriesOrError = Elf.dynamicEntries();63 if (!DynamicEntriesOrError)64 return DynamicEntriesOrError.takeError();65 66 typename ELFT::Xword StringTableSize{0};67 const uint8_t *MappedAddr = nullptr;68 for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {69 if (Dyn.d_tag == ELF::DT_STRTAB) {70 auto MappedAddrOrError = Elf.toMappedAddr(Dyn.getPtr());71 if (!MappedAddrOrError)72 return MappedAddrOrError.takeError();73 MappedAddr = *MappedAddrOrError;74 }75 if (Dyn.d_tag == ELF::DT_STRSZ)76 StringTableSize = Dyn.getVal();77 }78 if (MappedAddr && StringTableSize)79 return StringRef(reinterpret_cast<const char *>(MappedAddr),80 StringTableSize);81 82 // If the dynamic segment is not present, or is missing the important tags, we83 // fall back on the sections.84 auto SectionsOrError = Elf.sections();85 if (!SectionsOrError)86 return SectionsOrError.takeError();87 88 for (const typename ELFT::Shdr &Sec : *SectionsOrError) {89 if (Sec.sh_type == ELF::SHT_DYNAMIC)90 return Elf.getLinkAsStrtab(Sec);91 }92 93 return createError("dynamic string table not found");94}95 96template <class ELFT>97static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj,98 const RelocationRef &RelRef,99 SmallVectorImpl<char> &Result) {100 const ELFFile<ELFT> &EF = Obj->getELFFile();101 DataRefImpl Rel = RelRef.getRawDataRefImpl();102 auto SecOrErr = EF.getSection(Rel.d.a);103 if (!SecOrErr)104 return SecOrErr.takeError();105 106 int64_t Addend = 0;107 // If there is no Symbol associated with the relocation, we set the undef108 // boolean value to 'true'. This will prevent us from calling functions that109 // requires the relocation to be associated with a symbol.110 //111 // In SHT_REL case we would need to read the addend from section data.112 // GNU objdump does not do that and we just follow for simplicity atm.113 bool Undef = false;114 if ((*SecOrErr)->sh_type == ELF::SHT_CREL) {115 auto ERela = Obj->getCrel(Rel);116 Addend = ERela.r_addend;117 Undef = ERela.getSymbol(false) == 0;118 } else if ((*SecOrErr)->sh_type == ELF::SHT_RELA) {119 const typename ELFT::Rela *ERela = Obj->getRela(Rel);120 Addend = ERela->r_addend;121 Undef = ERela->getSymbol(false) == 0;122 } else if ((*SecOrErr)->sh_type == ELF::SHT_REL) {123 const typename ELFT::Rel *ERel = Obj->getRel(Rel);124 Undef = ERel->getSymbol(false) == 0;125 } else {126 return make_error<BinaryError>();127 }128 129 // Default scheme is to print Target, as well as "+ <addend>" for nonzero130 // addend. Should be acceptable for all normal purposes.131 std::string FmtBuf;132 raw_string_ostream Fmt(FmtBuf);133 134 if (!Undef) {135 symbol_iterator SI = RelRef.getSymbol();136 Expected<const typename ELFT::Sym *> SymOrErr =137 Obj->getSymbol(SI->getRawDataRefImpl());138 // TODO: test this error.139 if (!SymOrErr)140 return SymOrErr.takeError();141 142 if ((*SymOrErr)->getType() == ELF::STT_SECTION) {143 Expected<section_iterator> SymSI = SI->getSection();144 if (!SymSI)145 return SymSI.takeError();146 const typename ELFT::Shdr *SymSec =147 Obj->getSection((*SymSI)->getRawDataRefImpl());148 auto SecName = EF.getSectionName(*SymSec);149 if (!SecName)150 return SecName.takeError();151 Fmt << *SecName;152 } else {153 Expected<StringRef> SymName = SI->getName();154 if (!SymName)155 return SymName.takeError();156 Fmt << (Demangle ? demangle(*SymName) : *SymName);157 }158 } else {159 Fmt << "*ABS*";160 }161 if (Addend != 0) {162 Fmt << (Addend < 0163 ? "-"164 : "+") << format("0x%" PRIx64,165 (Addend < 0 ? -(uint64_t)Addend : (uint64_t)Addend));166 }167 Fmt.flush();168 Result.append(FmtBuf.begin(), FmtBuf.end());169 return Error::success();170}171 172Error objdump::getELFRelocationValueString(const ELFObjectFileBase *Obj,173 const RelocationRef &Rel,174 SmallVectorImpl<char> &Result) {175 if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))176 return getRelocationValueString(ELF32LE, Rel, Result);177 if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))178 return getRelocationValueString(ELF64LE, Rel, Result);179 if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))180 return getRelocationValueString(ELF32BE, Rel, Result);181 auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);182 return getRelocationValueString(ELF64BE, Rel, Result);183}184 185template <class ELFT>186static uint64_t getSectionLMA(const ELFFile<ELFT> &Obj,187 const object::ELFSectionRef &Sec) {188 auto PhdrRangeOrErr = Obj.program_headers();189 if (!PhdrRangeOrErr)190 report_fatal_error(Twine(toString(PhdrRangeOrErr.takeError())));191 192 // Search for a PT_LOAD segment containing the requested section. Use this193 // segment's p_addr to calculate the section's LMA.194 for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)195 if ((Phdr.p_type == ELF::PT_LOAD) &&196 (isSectionInSegment<ELFT>(197 Phdr, *cast<const ELFObjectFile<ELFT>>(Sec.getObject())198 ->getSection(Sec.getRawDataRefImpl()))))199 return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr;200 201 // Return section's VMA if it isn't in a PT_LOAD segment.202 return Sec.getAddress();203}204 205uint64_t objdump::getELFSectionLMA(const object::ELFSectionRef &Sec) {206 if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Sec.getObject()))207 return getSectionLMA(ELFObj->getELFFile(), Sec);208 else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Sec.getObject()))209 return getSectionLMA(ELFObj->getELFFile(), Sec);210 else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Sec.getObject()))211 return getSectionLMA(ELFObj->getELFFile(), Sec);212 const auto *ELFObj = cast<ELF64BEObjectFile>(Sec.getObject());213 return getSectionLMA(ELFObj->getELFFile(), Sec);214}215 216template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() {217 const ELFFile<ELFT> &Elf = getELFFile();218 auto DynamicEntriesOrErr = Elf.dynamicEntries();219 if (!DynamicEntriesOrErr) {220 reportWarning(toString(DynamicEntriesOrErr.takeError()), Obj.getFileName());221 return;222 }223 ArrayRef<typename ELFT::Dyn> DynamicEntries = *DynamicEntriesOrErr;224 225 // Find the maximum tag name length to format the value column properly.226 size_t MaxLen = 0;227 for (const typename ELFT::Dyn &Dyn : DynamicEntries)228 MaxLen = std::max(MaxLen, Elf.getDynamicTagAsString(Dyn.d_tag).size());229 std::string TagFmt = " %-" + std::to_string(MaxLen) + "s ";230 231 outs() << "\nDynamic Section:\n";232 233 for (const typename ELFT::Dyn &Dyn : DynamicEntries) {234 if (Dyn.d_tag == ELF::DT_NULL)235 continue;236 237 std::string Str = Elf.getDynamicTagAsString(Dyn.d_tag);238 239 const char *Fmt =240 ELFT::Is64Bits ? "0x%016" PRIx64 "\n" : "0x%08" PRIx64 "\n";241 if (Dyn.d_tag == ELF::DT_NEEDED || Dyn.d_tag == ELF::DT_RPATH ||242 Dyn.d_tag == ELF::DT_RUNPATH || Dyn.d_tag == ELF::DT_SONAME ||243 Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER) {244 Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf);245 if (StrTabOrErr) {246 const char *Data = StrTabOrErr->data();247 if (Dyn.getVal() >= StrTabOrErr->size()) {248 reportWarning("invalid string table offset, string table size: 0x" +249 Twine::utohexstr(StrTabOrErr->size()),250 Obj.getFileName());251 outs() << format(TagFmt.c_str(), Str.c_str())252 << format(Fmt, (uint64_t)Dyn.getVal());253 continue;254 }255 outs() << format(TagFmt.c_str(), Str.c_str()) << Data + Dyn.getVal()256 << "\n";257 continue;258 }259 reportWarning(toString(StrTabOrErr.takeError()), Obj.getFileName());260 consumeError(StrTabOrErr.takeError());261 }262 outs() << format(TagFmt.c_str(), Str.c_str())263 << format(Fmt, (uint64_t)Dyn.getVal());264 }265}266 267template <class ELFT> void ELFDumper<ELFT>::printProgramHeaders() {268 outs() << "\nProgram Header:\n";269 auto ProgramHeaderOrError = getELFFile().program_headers();270 if (!ProgramHeaderOrError) {271 reportWarning("unable to read program headers: " +272 toString(ProgramHeaderOrError.takeError()),273 Obj.getFileName());274 return;275 }276 277 for (const typename ELFT::Phdr &Phdr : *ProgramHeaderOrError) {278 switch (Phdr.p_type) {279 case ELF::PT_DYNAMIC:280 outs() << " DYNAMIC ";281 break;282 case ELF::PT_GNU_EH_FRAME:283 outs() << "EH_FRAME ";284 break;285 case ELF::PT_GNU_RELRO:286 outs() << " RELRO ";287 break;288 case ELF::PT_GNU_PROPERTY:289 outs() << "PROPERTY ";290 break;291 case ELF::PT_GNU_STACK:292 outs() << " STACK ";293 break;294 case ELF::PT_GNU_SFRAME:295 outs() << " SFRAME ";296 break;297 case ELF::PT_INTERP:298 outs() << " INTERP ";299 break;300 case ELF::PT_LOAD:301 outs() << " LOAD ";302 break;303 case ELF::PT_NOTE:304 outs() << " NOTE ";305 break;306 case ELF::PT_OPENBSD_BOOTDATA:307 outs() << "OPENBSD_BOOTDATA ";308 break;309 case ELF::PT_OPENBSD_MUTABLE:310 outs() << "OPENBSD_MUTABLE ";311 break;312 case ELF::PT_OPENBSD_NOBTCFI:313 outs() << "OPENBSD_NOBTCFI ";314 break;315 case ELF::PT_OPENBSD_RANDOMIZE:316 outs() << "OPENBSD_RANDOMIZE ";317 break;318 case ELF::PT_OPENBSD_SYSCALLS:319 outs() << "OPENBSD_SYSCALLS ";320 break;321 case ELF::PT_OPENBSD_WXNEEDED:322 outs() << "OPENBSD_WXNEEDED ";323 break;324 case ELF::PT_PHDR:325 outs() << " PHDR ";326 break;327 case ELF::PT_TLS:328 outs() << " TLS ";329 break;330 default:331 outs() << " UNKNOWN ";332 }333 334 const char *Fmt = ELFT::Is64Bits ? "0x%016" PRIx64 " " : "0x%08" PRIx64 " ";335 336 outs() << "off " << format(Fmt, (uint64_t)Phdr.p_offset) << "vaddr "337 << format(Fmt, (uint64_t)Phdr.p_vaddr) << "paddr "338 << format(Fmt, (uint64_t)Phdr.p_paddr)339 << format("align 2**%u\n", llvm::countr_zero<uint64_t>(Phdr.p_align))340 << " filesz " << format(Fmt, (uint64_t)Phdr.p_filesz)341 << "memsz " << format(Fmt, (uint64_t)Phdr.p_memsz) << "flags "342 << ((Phdr.p_flags & ELF::PF_R) ? "r" : "-")343 << ((Phdr.p_flags & ELF::PF_W) ? "w" : "-")344 << ((Phdr.p_flags & ELF::PF_X) ? "x" : "-") << "\n";345 }346}347 348template <typename ELFT> void ELFDumper<ELFT>::printDynamicRelocations() {349 if (!any_of(Obj.sections(), [](const ELFSectionRef Sec) {350 return Sec.getType() == ELF::SHT_DYNAMIC;351 })) {352 reportError(Obj.getFileName(), "not a dynamic object");353 return;354 }355 356 std::vector<SectionRef> DynRelSec =357 cast<ObjectFile>(Obj).dynamic_relocation_sections();358 if (DynRelSec.empty())359 return;360 361 outs() << "\nDYNAMIC RELOCATION RECORDS\n";362 const uint32_t OffsetPadding = (Obj.getBytesInAddress() > 4 ? 16 : 8);363 const uint32_t TypePadding = 24;364 outs() << left_justify("OFFSET", OffsetPadding) << ' '365 << left_justify("TYPE", TypePadding) << " VALUE\n";366 367 StringRef Fmt = Obj.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;368 for (const SectionRef &Section : DynRelSec)369 for (const RelocationRef &Reloc : Section.relocations()) {370 uint64_t Address = Reloc.getOffset();371 SmallString<32> RelocName;372 SmallString<32> ValueStr;373 Reloc.getTypeName(RelocName);374 if (Error E = getELFRelocationValueString(&Obj, Reloc, ValueStr))375 reportError(std::move(E), Obj.getFileName());376 outs() << format(Fmt.data(), Address) << ' '377 << left_justify(RelocName, TypePadding) << ' ' << ValueStr << '\n';378 }379}380 381template <class ELFT>382void ELFDumper<ELFT>::printSymbolVersionDependency(383 const typename ELFT::Shdr &Sec) {384 outs() << "\nVersion References:\n";385 Expected<std::vector<VerNeed>> V =386 getELFFile().getVersionDependencies(Sec, this->WarningHandler);387 if (!V) {388 reportWarning(toString(V.takeError()), Obj.getFileName());389 return;390 }391 392 raw_fd_ostream &OS = outs();393 for (const VerNeed &VN : *V) {394 OS << " required from " << VN.File << ":\n";395 for (const VernAux &Aux : VN.AuxV)396 OS << format(" 0x%08x 0x%02x %02u %s\n", Aux.Hash, Aux.Flags,397 Aux.Other, Aux.Name.c_str());398 }399}400 401template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() {402 const ELFFile<ELFT> &Elf = getELFFile();403 StringRef FileName = Obj.getFileName();404 ArrayRef<typename ELFT::Shdr> Sections =405 unwrapOrError(Elf.sections(), FileName);406 for (const typename ELFT::Shdr &Shdr : Sections) {407 if (Shdr.sh_type != ELF::SHT_GNU_verneed &&408 Shdr.sh_type != ELF::SHT_GNU_verdef)409 continue;410 411 if (Shdr.sh_type == ELF::SHT_GNU_verneed) {412 printSymbolVersionDependency(Shdr);413 } else {414 OS << "\nVersion definitions:\n";415 Expected<std::vector<VerDef>> V =416 getELFFile().getVersionDefinitions(Shdr);417 if (!V) {418 this->reportUniqueWarning(V.takeError());419 continue;420 }421 for (const VerDef &Def : *V) {422 OS << Def.Ndx << ' ' << format_hex(Def.Flags, 4) << ' '423 << format_hex(Def.Hash, 10) << ' ' << Def.Name << '\n';424 if (!Def.AuxV.empty()) {425 for (auto [I, Aux] : enumerate(Def.AuxV))426 OS << (I ? ' ' : '\t') << Aux.Name;427 OS << '\n';428 }429 }430 }431 }432}433 434template <class ELFT> void ELFDumper<ELFT>::printPrivateHeaders() {435 printProgramHeaders();436 printDynamicSection();437 printSymbolVersion();438}439