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