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