Index: include/llvm/Object/ELFObjectFile.h =================================================================== --- include/llvm/Object/ELFObjectFile.h +++ include/llvm/Object/ELFObjectFile.h @@ -26,6 +26,7 @@ #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" @@ -72,6 +73,8 @@ static inline bool classof(const Binary *v) { return v->isELF(); } SubtargetFeatures getFeatures() const override; + + void setARMSubArch(Triple &TheTriple) const override; }; class ELFSectionRef : public SectionRef { @@ -356,6 +359,28 @@ return std::error_code(); } + std::error_code getBuildAttributes(ARMAttributeParser &Attributes) const override { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return errorToErrorCode(SectionsOrErr.takeError()); + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { + auto ErrorOrContents = EF.getSectionContents(&Sec); + if (!ErrorOrContents) + return errorToErrorCode(ErrorOrContents.takeError()); + + auto Contents = ErrorOrContents.get(); + if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1) + return std::error_code(); + + Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); + break; + } + } + return std::error_code(); + } + const ELFFile *getELFFile() const { return &EF; } bool isDyldType() const { return isDyldELFObject; } Index: include/llvm/Object/ObjectFile.h =================================================================== --- include/llvm/Object/ObjectFile.h +++ include/llvm/Object/ObjectFile.h @@ -24,6 +24,8 @@ #include namespace llvm { +class ARMAttributeParser; + namespace object { class ObjectFile; @@ -265,6 +267,7 @@ virtual StringRef getFileFormatName() const = 0; virtual /* Triple::ArchType */ unsigned getArch() const = 0; virtual SubtargetFeatures getFeatures() const = 0; + virtual void setARMSubArch(Triple &TheTriple) const { } /// Returns platform-specific object flags, if any. virtual std::error_code getPlatformFlags(unsigned &Result) const { @@ -272,6 +275,11 @@ return object_error::invalid_file_type; } + virtual std::error_code + getBuildAttributes(ARMAttributeParser &Attributes) const { + return std::error_code(); + } + /// True if this is a relocatable object (.o/.obj). virtual bool isRelocatableObject() const = 0; Index: include/llvm/Support/ARMAttributeParser.h =================================================================== --- include/llvm/Support/ARMAttributeParser.h +++ include/llvm/Support/ARMAttributeParser.h @@ -13,11 +13,15 @@ #include "ARMBuildAttributes.h" #include "ScopedPrinter.h" +#include + namespace llvm { class StringRef; class ARMAttributeParser { - ScopedPrinter &SW; + ScopedPrinter *SW; + + std::map> Attributes; struct DisplayHandler { ARMBuildAttrs::AttrType Attribute; @@ -115,9 +119,15 @@ SmallVectorImpl &IndexList); void ParseSubsection(const uint8_t *Data, uint32_t Length); public: - ARMAttributeParser(ScopedPrinter &SW) : SW(SW) {} + ARMAttributeParser(ScopedPrinter *SW) : SW(SW) {} + + ARMAttributeParser() : SW(nullptr) { } + + void Parse(ArrayRef Section, bool isLittle); - void Parse(ArrayRef Section); + unsigned getAttributeValue(unsigned Tag) const { + return Attributes.find(Tag)->second.first; + } }; } Index: lib/Object/ELFObjectFile.cpp =================================================================== --- lib/Object/ELFObjectFile.cpp +++ lib/Object/ELFObjectFile.cpp @@ -122,4 +122,60 @@ } } +void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { + if (TheTriple.getSubArch() != Triple::NoSubArch) + return; + + ARMAttributeParser Attributes; + std::error_code EC = getBuildAttributes(Attributes); + + std::string Triple; + // Default to ARM, but use the triple if it's been set. + if (TheTriple.getArch() == Triple::thumb || + TheTriple.getArch() == Triple::thumbeb) + Triple = "thumb"; + else + Triple = "arm"; + + switch(Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch)) { + case ARMBuildAttrs::v4: + Triple += "v4"; + break; + case ARMBuildAttrs::v4T: + Triple += "v4t"; + break; + case ARMBuildAttrs::v5T: + Triple += "v5t"; + break; + case ARMBuildAttrs::v5TE: + Triple += "v5te"; + break; + case ARMBuildAttrs::v5TEJ: + Triple += "v5tej"; + break; + case ARMBuildAttrs::v6: + Triple += "v6"; + break; + case ARMBuildAttrs::v6K: + Triple += "v6k"; + break; + case ARMBuildAttrs::v6T2: + Triple += "v6t2"; + break; + case ARMBuildAttrs::v6_M: + Triple += "v6m"; + break; + case ARMBuildAttrs::v7: + Triple += "v7"; + break; + case ARMBuildAttrs::v7E_M: + Triple += "v7em"; + break; + } + if (!isLittleEndian()) + Triple += "eb"; + + TheTriple.setArchName(Triple); +} + } // end namespace llvm Index: lib/Support/ARMAttributeParser.cpp =================================================================== --- lib/Support/ARMAttributeParser.cpp +++ lib/Support/ARMAttributeParser.cpp @@ -89,32 +89,47 @@ void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - SW.printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), - ParseInteger(Data, Offset)); + + uint64_t Value = ParseInteger(Data, Offset); + Attributes.insert(std::make_pair(Tag, std::make_pair(Value, ""))); + + if (SW) + SW->printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), Value); } void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false); + StringRef ValueDesc = ParseString(Data, Offset); - DictScope AS(SW, "Attribute"); - SW.printNumber("Tag", Tag); - if (!TagName.empty()) - SW.printString("TagName", TagName); - SW.printString("Value", ParseString(Data, Offset)); + Attributes.insert( + std::make_pair(Tag, std::make_pair(1, std::string(ValueDesc.str())))); + + if (SW) { + DictScope AS(*SW, "Attribute"); + SW->printNumber("Tag", Tag); + if (!TagName.empty()) + SW->printString("TagName", TagName); + SW->printString("Value", ValueDesc); + } } void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc) { - StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false); - - DictScope AS(SW, "Attribute"); - SW.printNumber("Tag", Tag); - SW.printNumber("Value", Value); - if (!TagName.empty()) - SW.printString("TagName", TagName); - if (!ValueDesc.empty()) - SW.printString("Description", ValueDesc); + Attributes.insert( + std::make_pair(Tag, std::make_pair(Value, std::string(ValueDesc.str())))); + + if (SW) { + StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, + /*TagPrefix*/false); + DictScope AS(*SW, "Attribute"); + SW->printNumber("Tag", Tag); + SW->printNumber("Value", Value); + if (!TagName.empty()) + SW->printString("TagName", TagName); + if (!ValueDesc.empty()) + SW->printString("Description", ValueDesc); + } } void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data, @@ -449,20 +464,22 @@ uint64_t Integer = ParseInteger(Data, Offset); StringRef String = ParseString(Data, Offset); - DictScope AS(SW, "Attribute"); - SW.printNumber("Tag", Tag); - SW.startLine() << "Value: " << Integer << ", " << String << '\n'; - SW.printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false)); - switch (Integer) { - case 0: - SW.printString("Description", StringRef("No Specific Requirements")); - break; - case 1: - SW.printString("Description", StringRef("AEABI Conformant")); - break; - default: - SW.printString("Description", StringRef("AEABI Non-Conformant")); - break; + if (SW) { + DictScope AS(*SW, "Attribute"); + SW->printNumber("Tag", Tag); + SW->startLine() << "Value: " << Integer << ", " << String << '\n'; + SW->printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false)); + switch (Integer) { + case 0: + SW->printString("Description", StringRef("No Specific Requirements")); + break; + case 1: + SW->printString("Description", StringRef("AEABI Conformant")); + break; + default: + SW->printString("Description", StringRef("AEABI Non-Conformant")); + break; + } } } @@ -604,27 +621,33 @@ void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { uint32_t Offset = sizeof(uint32_t); /* SectionLength */ - SW.printNumber("SectionLength", Length); const char *VendorName = reinterpret_cast(Data + Offset); size_t VendorNameLength = std::strlen(VendorName); - SW.printString("Vendor", StringRef(VendorName, VendorNameLength)); Offset = Offset + VendorNameLength + 1; + if (SW) { + SW->printNumber("SectionLength", Length); + SW->printString("Vendor", StringRef(VendorName, VendorNameLength)); + } + if (StringRef(VendorName, VendorNameLength).lower() != "aeabi") return; while (Offset < Length) { /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size uint8_t Tag = Data[Offset]; - SW.printEnum("Tag", Tag, makeArrayRef(TagNames)); Offset = Offset + sizeof(Tag); uint32_t Size = *reinterpret_cast(Data + Offset); - SW.printNumber("Size", Size); Offset = Offset + sizeof(Size); + if (SW) { + SW->printEnum("Tag", Tag, makeArrayRef(TagNames)); + SW->printNumber("Size", Size); + } + if (Size > Length) { errs() << "subsection length greater than section length\n"; return; @@ -651,31 +674,37 @@ return; } - DictScope ASS(SW, ScopeName); - - if (!Indicies.empty()) - SW.printList(IndexName, Indicies); + if (SW) { + DictScope ASS(*SW, ScopeName); + if (!Indicies.empty()) + SW->printList(IndexName, Indicies); + } ParseAttributeList(Data, Offset, Length); } } -void ARMAttributeParser::Parse(ArrayRef Section) { +void ARMAttributeParser::Parse(ArrayRef Section, bool isLittle) { size_t Offset = 1; unsigned SectionNumber = 0; while (Offset < Section.size()) { - uint32_t SectionLength = - *reinterpret_cast(Section.data() + Offset); + uint32_t SectionLength = isLittle ? + *reinterpret_cast(Section.data() + Offset) : + *reinterpret_cast(Section.data() + Offset); - SW.startLine() << "Section " << ++SectionNumber << " {\n"; - SW.indent(); + if (SW) { + SW->startLine() << "Section " << ++SectionNumber << " {\n"; + SW->indent(); + } ParseSubsection(Section.data() + Offset, SectionLength); Offset = Offset + SectionLength; - SW.unindent(); - SW.startLine() << "}\n"; + if (SW) { + SW->unindent(); + SW->startLine() << "}\n"; + } } } } Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -357,7 +357,16 @@ llvm::Triple TheTriple("unknown-unknown-unknown"); if (TripleName.empty()) { if (Obj) { - TheTriple.setArch(Triple::ArchType(Obj->getArch())); + auto Arch = Obj->getArch(); + TheTriple.setArch(Triple::ArchType(Arch)); + + // For ARM targets, try to use the build attributes to build determine + // the build target. Target features are also added, but later during + // disassembly. + if (Arch == Triple::arm || Arch == Triple::armeb) { + Obj->setARMSubArch(TheTriple); + } + // TheTriple defaults to ELF, and COFF doesn't have an environment: // the best we can do here is indicate that it is mach-o. if (Obj->isMachO()) @@ -369,8 +378,16 @@ TheTriple.setTriple("thumbv7-windows"); } } - } else + } else { TheTriple.setTriple(Triple::normalize(TripleName)); + // Use the triple, but also try to combine with ARM build attributes. + if (Obj) { + auto Arch = Obj->getArch(); + if (Arch == Triple::arm || Arch == Triple::armeb) { + Obj->setARMSubArch(TheTriple); + } + } + } // Get the target specific parser. std::string Error; Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -1892,7 +1892,7 @@ if (Contents.size() == 1) continue; - ARMAttributeParser(W).Parse(Contents); + ARMAttributeParser(&W).Parse(Contents, true); } } }