| //===-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 <cstdint> | |
| using namespace llvm; | |
| using namespace ELFAttrs; | |
| std::optional<unsigned> | |
| ELFExtendedAttrParser::getAttributeValue(unsigned Tag) const { | |
| assert( | |
| 0 && | |
| "use getAttributeValue overloaded version accepting Stringref, unsigned"); | |
| return std::nullopt; | |
| } | |
| std::optional<unsigned> | |
| 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<unsigned>(BAItem.IntValue); | |
| } | |
| } | |
| return std::nullopt; | |
| } | |
| std::optional<StringRef> | |
| ELFExtendedAttrParser::getAttributeString(unsigned Tag) const { | |
| assert( | |
| 0 && | |
| "use getAttributeValue overloaded version accepting Stringref, unsigned"); | |
| return std::nullopt; | |
| } | |
| std::optional<StringRef> | |
| 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<StringRef>(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<uint8_t> Section, | |
| llvm::endianness Endian) { | |
| unsigned SectionNumber = 0; | |
| De = DataExtractor(Section, Endian == llvm::endianness::little); | |
| // 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: | |
| <format-version: ‘A’> --> Currently, there is only one version: 'A' (0x41) | |
| [ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ] | |
| --> 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: | |
| [ <uint8: optional> <uint8: parameter type> <attribute>* ] | |
| --> optional: 0 = required, 1 = optional. | |
| --> parameter type: 0 = ULEB128, 1 = NTBS. | |
| --> attribute: <tag, value>* pair. Tag is ULEB128, value is of | |
| <parameter type>. | |
| */ | |
| // 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<BuildAttributeItem::Types>(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(); | |
| } |