//===-ELFAttrParserExtended.cpp-ELF Extended Attribute Information Printer-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM // Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===------------------------------------------------------------------===// #include "llvm/Support/ELFAttrParserExtended.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ELFAttributes.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace ELFAttrs; std::optional ELFExtendedAttrParser::getAttributeValue(unsigned Tag) const { assert( 0 && "use getAttributeValue overloaded version accepting Stringref, unsigned"); return std::nullopt; } std::optional ELFExtendedAttrParser::getAttributeValue(StringRef BuildAttrSubsectionName, unsigned Tag) const { for (const auto &SubSection : SubSectionVec) { if (BuildAttrSubsectionName == SubSection.Name) for (const auto &BAItem : SubSection.Content) { if (Tag == BAItem.Tag) return std::optional(BAItem.IntValue); } } return std::nullopt; } std::optional ELFExtendedAttrParser::getAttributeString(unsigned Tag) const { assert( 0 && "use getAttributeValue overloaded version accepting Stringref, unsigned"); return std::nullopt; } std::optional ELFExtendedAttrParser::getAttributeString(StringRef BuildAttrSubsectionName, unsigned Tag) const { for (const auto &SubSection : SubSectionVec) { if (BuildAttrSubsectionName == SubSection.Name) for (const auto &BAItem : SubSection.Content) { if (Tag == BAItem.Tag) return std::optional(BAItem.StringValue); } } return std::nullopt; } StringRef ELFExtendedAttrParser::getTagName(const StringRef &BuildAttrSubsectionName, const unsigned Tag) { for (const auto &Entry : TagsNamesMap) { if (BuildAttrSubsectionName == Entry.SubsectionName) if (Tag == Entry.Tag) return Entry.TagName; } return ""; } Error ELFExtendedAttrParser::parse(ArrayRef Section, llvm::endianness Endian) { unsigned SectionNumber = 0; De = DataExtractor(Section, Endian == llvm::endianness::little, 0); // Early returns have specific errors. Consume the Error in Cursor. struct ClearCursorError { DataExtractor::Cursor &Cursor; ~ClearCursorError() { consumeError(Cursor.takeError()); } } Clear{Cursor}; /* ELF Extended Build Attributes Layout: --> Currently, there is only one version: 'A' (0x41) [ ] --> subsection-length: Offset from the start of this subsection to the start of the next one. --> vendor-name: Null-terminated byte string. --> vendor-data expands to: [ * ] --> optional: 0 = required, 1 = optional. --> parameter type: 0 = ULEB128, 1 = NTBS. --> attribute: * pair. Tag is ULEB128, value is of . */ // Get format-version uint8_t FormatVersion = De.getU8(Cursor); if (!Cursor) return Cursor.takeError(); if (ELFAttrs::Format_Version != FormatVersion) return createStringError(errc::invalid_argument, "unrecognized format-version: 0x" + utohexstr(FormatVersion)); while (!De.eof(Cursor)) { uint32_t ExtBASubsectionLength = De.getU32(Cursor); if (!Cursor) return Cursor.takeError(); // Minimal valid Extended Build Attributes subsection size is at // least 8: length(4) name(at least a single char + null) optionality(1) and // type(1) // Extended Build Attributes subsection has to fit inside the section. if (ExtBASubsectionLength < 8 || ExtBASubsectionLength > (Section.size() - Cursor.tell() + 4)) return createStringError( errc::invalid_argument, "invalid Extended Build Attributes subsection size at offset: " + utohexstr(Cursor.tell() - 4)); StringRef VendorName = De.getCStrRef(Cursor); if (!Cursor) return Cursor.takeError(); uint8_t IsOptional = De.getU8(Cursor); if (!Cursor) return Cursor.takeError(); if (!(0 == IsOptional || 1 == IsOptional)) return createStringError( errc::invalid_argument, "\ninvalid Optionality at offset " + utohexstr(Cursor.tell() - 4) + ": " + utohexstr(IsOptional) + " (Options are 1|0)"); StringRef IsOptionalStr = IsOptional ? "optional" : "required"; uint8_t Type = De.getU8(Cursor); if (!Cursor) return Cursor.takeError(); if (!(0 == Type || 1 == Type)) return createStringError(errc::invalid_argument, "\ninvalid Type at offset " + utohexstr(Cursor.tell() - 4) + ": " + utohexstr(Type) + " (Options are 1|0)"); StringRef TypeStr = Type ? "ntbs" : "uleb128"; BuildAttributeSubSection BASubSection; BASubSection.Name = VendorName; BASubSection.IsOptional = IsOptional; BASubSection.ParameterType = Type; if (Sw) { Sw->startLine() << "Section " << ++SectionNumber << " {\n"; Sw->indent(); Sw->printNumber("SectionLength", ExtBASubsectionLength); Sw->startLine() << "VendorName" << ": " << VendorName << " Optionality: " << IsOptionalStr << " Type: " << TypeStr << "\n"; Sw->startLine() << "Attributes {\n"; Sw->indent(); } // Offset in Section uint64_t OffsetInSection = Cursor.tell(); // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination), // optionality: 1, type: 1 uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1; while (Cursor.tell() < (OffsetInSection + ExtBASubsectionLength - BytesAllButAttributes)) { uint64_t Tag = De.getULEB128(Cursor); if (!Cursor) return Cursor.takeError(); StringRef TagName = getTagName(VendorName, Tag); uint64_t ValueInt = 0; std::string ValueStr = ""; if (Type) { // type==1 --> ntbs ValueStr = De.getCStrRef(Cursor); if (!Cursor) return Cursor.takeError(); if (Sw) Sw->printString("" != TagName ? TagName : utostr(Tag), ValueStr); } else { // type==0 --> uleb128 ValueInt = De.getULEB128(Cursor); if (!Cursor) return Cursor.takeError(); if (Sw) Sw->printNumber("" != TagName ? TagName : utostr(Tag), ValueInt); } // populate data structure BuildAttributeItem BAItem(static_cast(Type), Tag, ValueInt, ValueStr); BASubSection.Content.push_back(BAItem); } if (Sw) { // Close 'Attributes' Sw->unindent(); Sw->startLine() << "}\n"; // Close 'Section' Sw->unindent(); Sw->startLine() << "}\n"; } // populate data structure SubSectionVec.push_back(BASubSection); } return Cursor.takeError(); }