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