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_WXNEEDED: 295 outs() << "OPENBSD_WXNEEDED "; 296 break; 297 case ELF::PT_PHDR: 298 outs() << " PHDR "; 299 break; 300 case ELF::PT_TLS: 301 outs() << " TLS "; 302 break; 303 default: 304 outs() << " UNKNOWN "; 305 } 306 307 const char *Fmt = ELFT::Is64Bits ? "0x%016" PRIx64 " " : "0x%08" PRIx64 " "; 308 309 outs() << "off " << format(Fmt, (uint64_t)Phdr.p_offset) << "vaddr " 310 << format(Fmt, (uint64_t)Phdr.p_vaddr) << "paddr " 311 << format(Fmt, (uint64_t)Phdr.p_paddr) 312 << format("align 2**%u\n", llvm::countr_zero<uint64_t>(Phdr.p_align)) 313 << " filesz " << format(Fmt, (uint64_t)Phdr.p_filesz) 314 << "memsz " << format(Fmt, (uint64_t)Phdr.p_memsz) << "flags " 315 << ((Phdr.p_flags & ELF::PF_R) ? "r" : "-") 316 << ((Phdr.p_flags & ELF::PF_W) ? "w" : "-") 317 << ((Phdr.p_flags & ELF::PF_X) ? "x" : "-") << "\n"; 318 } 319 } 320 321 template <typename ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { 322 if (!any_of(Obj.sections(), [](const ELFSectionRef Sec) { 323 return Sec.getType() == ELF::SHT_DYNAMIC; 324 })) { 325 reportError(Obj.getFileName(), "not a dynamic object"); 326 return; 327 } 328 329 std::vector<SectionRef> DynRelSec = 330 cast<ObjectFile>(Obj).dynamic_relocation_sections(); 331 if (DynRelSec.empty()) 332 return; 333 334 outs() << "\nDYNAMIC RELOCATION RECORDS\n"; 335 const uint32_t OffsetPadding = (Obj.getBytesInAddress() > 4 ? 16 : 8); 336 const uint32_t TypePadding = 24; 337 outs() << left_justify("OFFSET", OffsetPadding) << ' ' 338 << left_justify("TYPE", TypePadding) << " VALUE\n"; 339 340 StringRef Fmt = Obj.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; 341 for (const SectionRef &Section : DynRelSec) 342 for (const RelocationRef &Reloc : Section.relocations()) { 343 uint64_t Address = Reloc.getOffset(); 344 SmallString<32> RelocName; 345 SmallString<32> ValueStr; 346 Reloc.getTypeName(RelocName); 347 if (Error E = getELFRelocationValueString(&Obj, Reloc, ValueStr)) 348 reportError(std::move(E), Obj.getFileName()); 349 outs() << format(Fmt.data(), Address) << ' ' 350 << left_justify(RelocName, TypePadding) << ' ' << ValueStr << '\n'; 351 } 352 } 353 354 template <class ELFT> 355 void ELFDumper<ELFT>::printSymbolVersionDependency( 356 const typename ELFT::Shdr &Sec) { 357 outs() << "\nVersion References:\n"; 358 Expected<std::vector<VerNeed>> V = 359 getELFFile().getVersionDependencies(Sec, this->WarningHandler); 360 if (!V) { 361 reportWarning(toString(V.takeError()), Obj.getFileName()); 362 return; 363 } 364 365 raw_fd_ostream &OS = outs(); 366 for (const VerNeed &VN : *V) { 367 OS << " required from " << VN.File << ":\n"; 368 for (const VernAux &Aux : VN.AuxV) 369 OS << format(" 0x%08x 0x%02x %02u %s\n", Aux.Hash, Aux.Flags, 370 Aux.Other, Aux.Name.c_str()); 371 } 372 } 373 374 template <class ELFT> 375 static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr, 376 ArrayRef<uint8_t> Contents, 377 StringRef StrTab) { 378 outs() << "\nVersion definitions:\n"; 379 380 const uint8_t *Buf = Contents.data(); 381 uint32_t VerdefIndex = 1; 382 // sh_info contains the number of entries in the SHT_GNU_verdef section. To 383 // make the index column have consistent width, we should insert blank spaces 384 // according to sh_info. 385 uint16_t VerdefIndexWidth = std::to_string(Shdr.sh_info).size(); 386 while (Buf) { 387 auto *Verdef = reinterpret_cast<const typename ELFT::Verdef *>(Buf); 388 outs() << format_decimal(VerdefIndex++, VerdefIndexWidth) << " " 389 << format("0x%02" PRIx16 " ", (uint16_t)Verdef->vd_flags) 390 << format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash); 391 392 const uint8_t *BufAux = Buf + Verdef->vd_aux; 393 uint16_t VerdauxIndex = 0; 394 while (BufAux) { 395 auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux); 396 if (VerdauxIndex) 397 outs() << std::string(VerdefIndexWidth + 17, ' '); 398 outs() << StringRef(StrTab.drop_front(Verdaux->vda_name).data()) << '\n'; 399 BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr; 400 ++VerdauxIndex; 401 } 402 Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr; 403 } 404 } 405 406 template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() { 407 const ELFFile<ELFT> &Elf = getELFFile(); 408 StringRef FileName = Obj.getFileName(); 409 ArrayRef<typename ELFT::Shdr> Sections = 410 unwrapOrError(Elf.sections(), FileName); 411 for (const typename ELFT::Shdr &Shdr : Sections) { 412 if (Shdr.sh_type != ELF::SHT_GNU_verneed && 413 Shdr.sh_type != ELF::SHT_GNU_verdef) 414 continue; 415 416 ArrayRef<uint8_t> Contents = 417 unwrapOrError(Elf.getSectionContents(Shdr), FileName); 418 const typename ELFT::Shdr *StrTabSec = 419 unwrapOrError(Elf.getSection(Shdr.sh_link), FileName); 420 StringRef StrTab = unwrapOrError(Elf.getStringTable(*StrTabSec), FileName); 421 422 if (Shdr.sh_type == ELF::SHT_GNU_verneed) 423 printSymbolVersionDependency(Shdr); 424 else 425 printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab); 426 } 427 } 428 429 template <class ELFT> void ELFDumper<ELFT>::printPrivateHeaders() { 430 printProgramHeaders(); 431 printDynamicSection(); 432 printSymbolVersion(); 433 } 434