diff options
Diffstat (limited to 'tools/llvm-readobj/ELFDumper.cpp')
| -rw-r--r-- | tools/llvm-readobj/ELFDumper.cpp | 476 |
1 files changed, 324 insertions, 152 deletions
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 5698420bbcc2..9678667abffe 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -18,6 +18,7 @@ #include "StackMapPrinter.h" #include "llvm-readobj.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallString.h" @@ -33,6 +34,7 @@ #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/StackMapParser.h" +#include "llvm/Support/AMDGPUMetadata.h" #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Casting.h" @@ -155,8 +157,6 @@ public: void printMipsReginfo() override; void printMipsOptions() override; - void printAMDGPUCodeObjectMetadata() override; - void printStackMap() const override; void printHashHistogram() override; @@ -820,12 +820,24 @@ static const EnumEntry<unsigned> ElfOSABI[] = { {"AROS", "AROS", ELF::ELFOSABI_AROS}, {"FenixOS", "FenixOS", ELF::ELFOSABI_FENIXOS}, {"CloudABI", "CloudABI", ELF::ELFOSABI_CLOUDABI}, - {"C6000_ELFABI", "Bare-metal C6000", ELF::ELFOSABI_C6000_ELFABI}, - {"C6000_LINUX", "Linux C6000", ELF::ELFOSABI_C6000_LINUX}, - {"ARM", "ARM", ELF::ELFOSABI_ARM}, {"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE} }; +static const EnumEntry<unsigned> AMDGPUElfOSABI[] = { + {"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA}, + {"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL}, + {"AMDGPU_MESA3D", "AMDGPU - MESA3D", ELF::ELFOSABI_AMDGPU_MESA3D} +}; + +static const EnumEntry<unsigned> ARMElfOSABI[] = { + {"ARM", "ARM", ELF::ELFOSABI_ARM} +}; + +static const EnumEntry<unsigned> C6000ElfOSABI[] = { + {"C6000_ELFABI", "Bare-metal C6000", ELF::ELFOSABI_C6000_ELFABI}, + {"C6000_LINUX", "Linux C6000", ELF::ELFOSABI_C6000_LINUX} +}; + static const EnumEntry<unsigned> ElfMachineType[] = { ENUM_ENT(EM_NONE, "None"), ENUM_ENT(EM_M32, "WE32100"), @@ -967,7 +979,7 @@ static const EnumEntry<unsigned> ElfMachineType[] = { ENUM_ENT(EM_L10M, "EM_L10M"), ENUM_ENT(EM_K10M, "EM_K10M"), ENUM_ENT(EM_AARCH64, "AArch64"), - ENUM_ENT(EM_AVR32, "Atmel AVR 8-bit microcontroller"), + ENUM_ENT(EM_AVR32, "Atmel Corporation 32-bit microprocessor family"), ENUM_ENT(EM_STM8, "STMicroeletronics STM8 8-bit microcontroller"), ENUM_ENT(EM_TILE64, "Tilera TILE64 multicore architecture family"), ENUM_ENT(EM_TILEPRO, "Tilera TILEPro multicore architecture family"), @@ -1231,6 +1243,20 @@ static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) }; +static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_NONE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_R600), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_GCN) +}; + +static const EnumEntry<unsigned> ElfHeaderRISCVFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_RVC), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_FLOAT_ABI_SINGLE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_FLOAT_ABI_DOUBLE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_FLOAT_ABI_QUAD), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_RVE) +}; + static const EnumEntry<unsigned> ElfSymOtherFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, STV_INTERNAL), LLVM_READOBJ_ENUM_ENT(ELF, STV_HIDDEN), @@ -1287,15 +1313,16 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, ScopedPrinter &Writer) switch (Sec.sh_type) { case ELF::SHT_SYMTAB: if (DotSymtabSec != nullptr) - reportError("Multilpe SHT_SYMTAB"); + reportError("Multiple SHT_SYMTAB"); DotSymtabSec = &Sec; break; case ELF::SHT_DYNSYM: if (DynSymRegion.Size) - reportError("Multilpe SHT_DYNSYM"); + reportError("Multiple SHT_DYNSYM"); DynSymRegion = createDRIFrom(&Sec); // This is only used (if Elf_Shdr present)for naming section in GNU style DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec)); + DynamicStringTable = unwrapOrError(Obj->getStringTableForSymtab(Sec)); break; case ELF::SHT_SYMTAB_SHNDX: ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec)); @@ -1312,7 +1339,7 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, ScopedPrinter &Writer) break; case ELF::SHT_GNU_verneed: if (dot_gnu_version_r_sec != nullptr) - reportError("Multilpe SHT_GNU_verneed"); + reportError("Multiple SHT_GNU_verneed"); dot_gnu_version_r_sec = &Sec; break; } @@ -1330,8 +1357,11 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable( ArrayRef<const Elf_Phdr *> LoadSegments) { auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { - const Elf_Phdr *const *I = std::upper_bound( - LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr<ELFT>); + const Elf_Phdr *const *I = + std::upper_bound(LoadSegments.begin(), LoadSegments.end(), VAddr, + [](uint64_t VAddr, const Elf_Phdr_Impl<ELFT> *Phdr) { + return VAddr < Phdr->p_vaddr; + }); if (I == LoadSegments.begin()) report_fatal_error("Virtual address is not in any segment"); --I; @@ -1487,6 +1517,10 @@ static const char *getTypeString(unsigned Arch, uint64_t Type) { } } switch (Type) { + LLVM_READOBJ_TYPE_CASE(ANDROID_REL); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELSZ); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELA); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELASZ); LLVM_READOBJ_TYPE_CASE(BIND_NOW); LLVM_READOBJ_TYPE_CASE(DEBUG); LLVM_READOBJ_TYPE_CASE(FINI); @@ -1689,6 +1723,8 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_PREINIT_ARRAYSZ: + case DT_ANDROID_RELSZ: + case DT_ANDROID_RELASZ: OS << Value << " (bytes)"; break; case DT_NEEDED: @@ -1874,6 +1910,7 @@ public: MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, Elf_Dyn_Range DynTable, ScopedPrinter &W); + void parseStaticGOT(); void parseGOT(); void parsePLT(); @@ -1890,11 +1927,12 @@ private: std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); + void printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num); void printGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It); void printGlobalGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It, const Elf_Sym *Sym, - StringRef StrTable, bool IsDynamic); + StringRef StrTable); void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, const GOTEntry *It, StringRef Purpose); void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, @@ -1929,6 +1967,50 @@ MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, } } +template <class ELFT> +void MipsGOTParser<ELFT>::printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num) { + ArrayRef<uint8_t> GOT = unwrapOrError(Obj->getSectionContents(GOTShdr)); + + const GOTEntry *GotBegin = makeGOTIter(GOT, 0); + const GOTEntry *GotEnd = makeGOTIter(GOT, Num); + const GOTEntry *It = GotBegin; + + W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0); + { + ListScope RS(W, "Reserved entries"); + + { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Lazy resolver")); + } + + if (It != GotEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Module pointer (GNU extension)")); + } + } + { + ListScope LS(W, "Local entries"); + for (; It != GotEnd; ++It) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It); + } + } +} + +template <class ELFT> void MipsGOTParser<ELFT>::parseStaticGOT() { + const Elf_Shdr *GOTShdr = findSectionByName(*Obj, ".got"); + if (!GOTShdr) { + W.startLine() << "Cannot find .got section.\n"; + return; + } + + DictScope GS(W, "Static GOT"); + printLocalGOT(GOTShdr, GOTShdr->sh_size / sizeof(GOTEntry)); +} + template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { // See "Global Offset Table" in Chapter 5 in the following document // for detailed GOT description. @@ -1946,10 +2028,7 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - StringRef StrTable = Dumper->getDynamicStringTable(); - const Elf_Sym *DynSymBegin = Dumper->dynamic_symbols().begin(); - const Elf_Sym *DynSymEnd = Dumper->dynamic_symbols().end(); - std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); + std::size_t DynSymTotal = Dumper->dynamic_symbols().size(); if (*DtGotSym > DynSymTotal) report_fatal_error("MIPS_GOTSYM exceeds a number of dynamic symbols"); @@ -1971,45 +2050,19 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { if (*DtLocalGotNum + GlobalGotNum > getGOTTotal(GOT)) report_fatal_error("Number of GOT entries exceeds the size of GOT section"); - const GOTEntry *GotBegin = makeGOTIter(GOT, 0); - const GOTEntry *GotLocalEnd = makeGOTIter(GOT, *DtLocalGotNum); - const GOTEntry *It = GotBegin; - DictScope GS(W, "Primary GOT"); + printLocalGOT(GOTShdr, *DtLocalGotNum); - W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0); - { - ListScope RS(W, "Reserved entries"); - - { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It++); - W.printString("Purpose", StringRef("Lazy resolver")); - } - - if (It != GotLocalEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It++); - W.printString("Purpose", StringRef("Module pointer (GNU extension)")); - } - } - { - ListScope LS(W, "Local entries"); - for (; It != GotLocalEnd; ++It) { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It); - } - } { ListScope GS(W, "Global entries"); - const GOTEntry *GotGlobalEnd = - makeGOTIter(GOT, *DtLocalGotNum + GlobalGotNum); - const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym; - for (; It != GotGlobalEnd; ++It) { + const GOTEntry *GotBegin = makeGOTIter(GOT, 0); + const GOTEntry *GotEnd = makeGOTIter(GOT, *DtLocalGotNum + GlobalGotNum); + const Elf_Sym *GotDynSym = Dumper->dynamic_symbols().begin() + *DtGotSym; + for (auto It = makeGOTIter(GOT, *DtLocalGotNum); It != GotEnd; ++It) { DictScope D(W, "Entry"); - printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, StrTable, - true); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, + Dumper->getDynamicStringTable()); } } @@ -2101,9 +2154,11 @@ void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, } template <class ELFT> -void MipsGOTParser<ELFT>::printGlobalGotEntry( - uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It, - const Elf_Sym *Sym, StringRef StrTable, bool IsDynamic) { +void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, + const GOTEntry *BeginIt, + const GOTEntry *It, + const Elf_Sym *Sym, + StringRef StrTable) { printGotEntry(GotAddr, BeginIt, It); W.printHex("Value", Sym->st_value); @@ -2115,8 +2170,7 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry( Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = - Dumper->getFullSymbolName(Sym, StrTable, IsDynamic); + std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true); W.printNumber("Name", FullSymbolName, Sym->st_name); } @@ -2160,8 +2214,12 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { } MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W); - GOTParser.parseGOT(); - GOTParser.parsePLT(); + if (dynamic_table().empty()) + GOTParser.parseStaticGOT(); + else { + GOTParser.parseGOT(); + GOTParser.parsePLT(); + } } static const EnumEntry<unsigned> ElfMipsISAExtType[] = { @@ -2326,36 +2384,6 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() { } } -template <class ELFT> void ELFDumper<ELFT>::printAMDGPUCodeObjectMetadata() { - const Elf_Shdr *Shdr = findSectionByName(*Obj, ".note"); - if (!Shdr) { - W.startLine() << "There is no .note section in the file.\n"; - return; - } - ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); - - const uint32_t CodeObjectMetadataNoteType = 10; - for (auto I = reinterpret_cast<const Elf_Word *>(&Sec[0]), - E = I + Sec.size()/4; I != E;) { - uint32_t NameSZ = I[0]; - uint32_t DescSZ = I[1]; - uint32_t Type = I[2]; - I += 3; - - StringRef Name; - if (NameSZ) { - Name = StringRef(reinterpret_cast<const char *>(I), NameSZ - 1); - I += alignTo<4>(NameSZ)/4; - } - - if (Name == "AMD" && Type == CodeObjectMetadataNoteType) { - StringRef Desc(reinterpret_cast<const char *>(I), DescSZ); - W.printString(Desc); - } - I += alignTo<4>(DescSZ)/4; - } -} - template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { const Elf_Shdr *StackMapSection = nullptr; for (const auto &Sec : unwrapOrError(Obj->sections())) { @@ -2369,7 +2397,6 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { if (!StackMapSection) return; - StringRef StackMapContents; ArrayRef<uint8_t> StackMapContentsArray = unwrapOrError(Obj->getSectionContents(StackMapSection)); @@ -2441,34 +2468,91 @@ template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { printFields(OS, "Section header string table index:", Str); } -template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { - uint32_t SectionIndex = 0; - bool HasGroups = false; +namespace { +struct GroupMember { + StringRef Name; + uint64_t Index; +}; + +struct GroupSection { + StringRef Name; + StringRef Signature; + uint64_t ShName; + uint64_t Index; + uint32_t Type; + std::vector<GroupMember> Members; +}; + +template <class ELFT> +std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) { + using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr; + using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym; + using Elf_Word = typename ELFFile<ELFT>::Elf_Word; + + std::vector<GroupSection> Ret; + uint64_t I = 0; for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - if (Sec.sh_type == ELF::SHT_GROUP) { - HasGroups = true; - const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); - const Elf_Sym *Signature = - unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); - ArrayRef<Elf_Word> Data = unwrapOrError( - Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); - OS << "\n" << getGroupType(Data[0]) << " group section [" - << format_decimal(SectionIndex, 5) << "] `" << Name << "' [" - << StrTable.data() + Signature->st_name << "] contains " - << (Data.size() - 1) << " sections:\n" - << " [Index] Name\n"; - for (auto &Ndx : Data.slice(1)) { - auto Sec = unwrapOrError(Obj->getSection(Ndx)); - const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); - OS << " [" << format_decimal(Ndx, 5) << "] " << Name - << "\n"; + ++I; + if (Sec.sh_type != ELF::SHT_GROUP) + continue; + + const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); + StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); + const Elf_Sym *Sym = + unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); + auto Data = + unwrapOrError(Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); + + StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + StringRef Signature = StrTable.data() + Sym->st_name; + Ret.push_back({Name, Signature, Sec.sh_name, I - 1, Data[0], {}}); + + std::vector<GroupMember> &GM = Ret.back().Members; + for (uint32_t Ndx : Data.slice(1)) { + auto Sec = unwrapOrError(Obj->getSection(Ndx)); + const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); + GM.push_back({Name, Ndx}); + } + } + return Ret; +} + +DenseMap<uint64_t, const GroupSection *> +mapSectionsToGroups(ArrayRef<GroupSection> Groups) { + DenseMap<uint64_t, const GroupSection *> Ret; + for (const GroupSection &G : Groups) + for (const GroupMember &GM : G.Members) + Ret.insert({GM.Index, &G}); + return Ret; +} + +} // namespace + +template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { + std::vector<GroupSection> V = getGroups<ELFT>(Obj); + DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); + for (const GroupSection &G : V) { + OS << "\n" + << getGroupType(G.Type) << " group section [" + << format_decimal(G.Index, 5) << "] `" << G.Name << "' [" << G.Signature + << "] contains " << G.Members.size() << " sections:\n" + << " [Index] Name\n"; + for (const GroupMember &GM : G.Members) { + const GroupSection *MainGroup = Map[GM.Index]; + if (MainGroup != &G) { + OS.flush(); + errs() << "Error: section [" << format_decimal(GM.Index, 5) + << "] in group section [" << format_decimal(G.Index, 5) + << "] already in group section [" + << format_decimal(MainGroup->Index, 5) << "]"; + errs().flush(); + continue; } + OS << " [" << format_decimal(GM.Index, 5) << "] " << GM.Name << "\n"; } - ++SectionIndex; } - if (!HasGroups) + + if (V.empty()) OS << "There are no section groups in this file.\n"; } @@ -2539,7 +2623,9 @@ static inline void printRelocHeader(raw_ostream &OS, bool Is64, bool IsRela) { template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { bool HasRelocSections = false; for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && + Sec.sh_type != ELF::SHT_ANDROID_REL && + Sec.sh_type != ELF::SHT_ANDROID_RELA) continue; HasRelocSections = true; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); @@ -2548,9 +2634,12 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { OS << "\nRelocation section '" << Name << "' at offset 0x" << to_hexString(Offset, false) << " contains " << Entries << " entries:\n"; - printRelocHeader(OS, ELFT::Is64Bits, (Sec.sh_type == ELF::SHT_RELA)); + printRelocHeader(OS, ELFT::Is64Bits, + Sec.sh_type == ELF::SHT_RELA || + Sec.sh_type == ELF::SHT_ANDROID_RELA); const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); - if (Sec.sh_type == ELF::SHT_REL) { + switch (Sec.sh_type) { + case ELF::SHT_REL: for (const auto &R : unwrapOrError(Obj->rels(&Sec))) { Elf_Rela Rela; Rela.r_offset = R.r_offset; @@ -2558,9 +2647,16 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { Rela.r_addend = 0; printRelocation(Obj, SymTab, Rela, false); } - } else { + break; + case ELF::SHT_RELA: for (const auto &R : unwrapOrError(Obj->relas(&Sec))) printRelocation(Obj, SymTab, R, true); + break; + case ELF::SHT_ANDROID_REL: + case ELF::SHT_ANDROID_RELA: + for (const auto &R : unwrapOrError(Obj->android_relas(&Sec))) + printRelocation(Obj, SymTab, R, Sec.sh_type == ELF::SHT_ANDROID_RELA); + break; } } if (!HasRelocSections) @@ -3310,7 +3406,7 @@ static std::string getGNUNoteTypeName(const uint32_t NT) { std::string string; raw_string_ostream OS(string); OS << format("Unknown note type (0x%08x)", NT); - return string; + return OS.str(); } static std::string getFreeBSDNoteTypeName(const uint32_t NT) { @@ -3338,7 +3434,30 @@ static std::string getFreeBSDNoteTypeName(const uint32_t NT) { std::string string; raw_string_ostream OS(string); OS << format("Unknown note type (0x%08x)", NT); - return string; + return OS.str(); +} + +static std::string getAMDGPUNoteTypeName(const uint32_t NT) { + static const struct { + uint32_t ID; + const char *Name; + } Notes[] = { + {ELF::NT_AMD_AMDGPU_HSA_METADATA, + "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"}, + {ELF::NT_AMD_AMDGPU_ISA, + "NT_AMD_AMDGPU_ISA (ISA Version)"}, + {ELF::NT_AMD_AMDGPU_PAL_METADATA, + "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"} + }; + + for (const auto &Note : Notes) + if (Note.ID == NT) + return std::string(Note.Name); + + std::string string; + raw_string_ostream OS(string); + OS << format("Unknown note type (0x%08x)", NT); + return OS.str(); } template <typename ELFT> @@ -3381,6 +3500,39 @@ static void printGNUNote(raw_ostream &OS, uint32_t NoteType, OS << '\n'; } +template <typename ELFT> +static void printAMDGPUNote(raw_ostream &OS, uint32_t NoteType, + ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words, + size_t Size) { + switch (NoteType) { + default: + return; + case ELF::NT_AMD_AMDGPU_HSA_METADATA: + OS << " HSA Metadata:\n" + << StringRef(reinterpret_cast<const char *>(Words.data()), Size); + break; + case ELF::NT_AMD_AMDGPU_ISA: + OS << " ISA Version:\n" + << " " + << StringRef(reinterpret_cast<const char *>(Words.data()), Size); + break; + case ELF::NT_AMD_AMDGPU_PAL_METADATA: + const uint32_t *PALMetadataBegin = reinterpret_cast<const uint32_t *>(Words.data()); + const uint32_t *PALMetadataEnd = PALMetadataBegin + Size; + std::vector<uint32_t> PALMetadata(PALMetadataBegin, PALMetadataEnd); + std::string PALMetadataString; + auto Error = AMDGPU::PALMD::toString(PALMetadata, PALMetadataString); + OS << " PAL Metadata:\n"; + if (Error) { + OS << " Invalid"; + return; + } + OS << PALMetadataString; + break; + } + OS.flush(); +} + template <class ELFT> void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { const Elf_Ehdr *e = Obj->getHeader(); @@ -3421,6 +3573,9 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { printGNUNote<ELFT>(OS, Type, Descriptor, DescriptorSize); } else if (Name == "FreeBSD") { OS << getFreeBSDNoteTypeName(Type) << '\n'; + } else if (Name == "AMD") { + OS << getAMDGPUNoteTypeName(Type) << '\n'; + printAMDGPUNote<ELFT>(OS, Type, Descriptor, DescriptorSize); } else { OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; } @@ -3454,13 +3609,22 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { makeArrayRef(ElfDataEncoding)); W.printNumber("FileVersion", e->e_ident[ELF::EI_VERSION]); - // Handle architecture specific OS/ABI values. - if (e->e_machine == ELF::EM_AMDGPU && - e->e_ident[ELF::EI_OSABI] == ELF::ELFOSABI_AMDGPU_HSA) - W.printHex("OS/ABI", "AMDGPU_HSA", ELF::ELFOSABI_AMDGPU_HSA); - else - W.printEnum("OS/ABI", e->e_ident[ELF::EI_OSABI], - makeArrayRef(ElfOSABI)); + auto OSABI = makeArrayRef(ElfOSABI); + if (e->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH && + e->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) { + switch (e->e_machine) { + case ELF::EM_AMDGPU: + OSABI = makeArrayRef(AMDGPUElfOSABI); + break; + case ELF::EM_ARM: + OSABI = makeArrayRef(ARMElfOSABI); + break; + case ELF::EM_TI_C6000: + OSABI = makeArrayRef(C6000ElfOSABI); + break; + } + } + W.printEnum("OS/ABI", e->e_ident[ELF::EI_OSABI], OSABI); W.printNumber("ABIVersion", e->e_ident[ELF::EI_ABIVERSION]); W.printBinary("Unused", makeArrayRef(e->e_ident).slice(ELF::EI_PAD)); } @@ -3475,6 +3639,11 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderMipsFlags), unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI), unsigned(ELF::EF_MIPS_MACH)); + else if (e->e_machine == EM_AMDGPU) + W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags), + unsigned(ELF::EF_AMDGPU_ARCH)); + else if (e->e_machine == EM_RISCV) + W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderRISCVFlags)); else W.printFlags("Flags", e->e_flags); W.printNumber("HeaderSize", e->e_ehsize); @@ -3489,36 +3658,32 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { template <class ELFT> void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) { DictScope Lists(W, "Groups"); - uint32_t SectionIndex = 0; - bool HasGroups = false; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - if (Sec.sh_type == ELF::SHT_GROUP) { - HasGroups = true; - const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); - const Elf_Sym *Sym = - unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); - auto Data = unwrapOrError( - Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); - DictScope D(W, "Group"); - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); - W.printNumber("Name", Name, Sec.sh_name); - W.printNumber("Index", SectionIndex); - W.printHex("Type", getGroupType(Data[0]), Data[0]); - W.startLine() << "Signature: " << StrTable.data() + Sym->st_name << "\n"; - { - ListScope L(W, "Section(s) in group"); - size_t Member = 1; - while (Member < Data.size()) { - auto Sec = unwrapOrError(Obj->getSection(Data[Member])); - const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); - W.startLine() << Name << " (" << Data[Member++] << ")\n"; - } + std::vector<GroupSection> V = getGroups<ELFT>(Obj); + DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); + for (const GroupSection &G : V) { + DictScope D(W, "Group"); + W.printNumber("Name", G.Name, G.ShName); + W.printNumber("Index", G.Index); + W.printHex("Type", getGroupType(G.Type), G.Type); + W.startLine() << "Signature: " << G.Signature << "\n"; + + ListScope L(W, "Section(s) in group"); + for (const GroupMember &GM : G.Members) { + const GroupSection *MainGroup = Map[GM.Index]; + if (MainGroup != &G) { + W.flush(); + errs() << "Error: " << GM.Name << " (" << GM.Index + << ") in a group " + G.Name + " (" << G.Index + << ") is already in a group " + MainGroup->Name + " (" + << MainGroup->Index << ")\n"; + errs().flush(); + continue; } + W.startLine() << GM.Name << " (" << GM.Index << ")\n"; } - ++SectionIndex; } - if (!HasGroups) + + if (V.empty()) W.startLine() << "There are no group sections in the file.\n"; } @@ -3529,7 +3694,9 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) { for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { ++SectionNumber; - if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && + Sec.sh_type != ELF::SHT_ANDROID_REL && + Sec.sh_type != ELF::SHT_ANDROID_RELA) continue; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); @@ -3562,6 +3729,11 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { for (const Elf_Rela &R : unwrapOrError(Obj->relas(Sec))) printRelocation(Obj, R, SymTab); break; + case ELF::SHT_ANDROID_REL: + case ELF::SHT_ANDROID_RELA: + for (const Elf_Rela &R : unwrapOrError(Obj->android_relas(Sec))) + printRelocation(Obj, R, SymTab); + break; } } |
