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