brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.2 KiB · 1e7bb00 Raw
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