1 //===-ELFAttrParserExtended.cpp-ELF Extended Attribute Information Printer-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 4 // Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===------------------------------------------------------------------===// 9 10 #include "llvm/Support/ELFAttrParserExtended.h" 11 #include "llvm/ADT/StringExtras.h" 12 #include "llvm/ADT/StringRef.h" 13 #include "llvm/Support/ELFAttributes.h" 14 #include "llvm/Support/Errc.h" 15 #include "llvm/Support/Error.h" 16 #include "llvm/Support/ScopedPrinter.h" 17 #include "llvm/Support/raw_ostream.h" 18 #include <cstdint> 19 20 using namespace llvm; 21 using namespace ELFAttrs; 22 23 std::optional<unsigned> 24 ELFExtendedAttrParser::getAttributeValue(unsigned Tag) const { 25 assert( 26 0 && 27 "use getAttributeValue overloaded version accepting Stringref, unsigned"); 28 return std::nullopt; 29 } 30 31 std::optional<unsigned> 32 ELFExtendedAttrParser::getAttributeValue(StringRef BuildAttrSubsectionName, 33 unsigned Tag) const { 34 for (const auto &SubSection : SubSectionVec) { 35 if (BuildAttrSubsectionName == SubSection.Name) 36 for (const auto &BAItem : SubSection.Content) { 37 if (Tag == BAItem.Tag) 38 return std::optional<unsigned>(BAItem.IntValue); 39 } 40 } 41 return std::nullopt; 42 } 43 44 std::optional<StringRef> 45 ELFExtendedAttrParser::getAttributeString(unsigned Tag) const { 46 assert( 47 0 && 48 "use getAttributeValue overloaded version accepting Stringref, unsigned"); 49 return std::nullopt; 50 } 51 52 std::optional<StringRef> 53 ELFExtendedAttrParser::getAttributeString(StringRef BuildAttrSubsectionName, 54 unsigned Tag) const { 55 for (const auto &SubSection : SubSectionVec) { 56 if (BuildAttrSubsectionName == SubSection.Name) 57 for (const auto &BAItem : SubSection.Content) { 58 if (Tag == BAItem.Tag) 59 return std::optional<StringRef>(BAItem.StringValue); 60 } 61 } 62 return std::nullopt; 63 } 64 65 StringRef 66 ELFExtendedAttrParser::getTagName(const StringRef &BuildAttrSubsectionName, 67 const unsigned Tag) { 68 for (const auto &Entry : TagsNamesMap) { 69 if (BuildAttrSubsectionName == Entry.SubsectionName) 70 if (Tag == Entry.Tag) 71 return Entry.TagName; 72 } 73 return ""; 74 } 75 76 Error ELFExtendedAttrParser::parse(ArrayRef<uint8_t> Section, 77 llvm::endianness Endian) { 78 79 unsigned SectionNumber = 0; 80 De = DataExtractor(Section, Endian == llvm::endianness::little, 0); 81 82 // Early returns have specific errors. Consume the Error in Cursor. 83 struct ClearCursorError { 84 DataExtractor::Cursor &Cursor; 85 ~ClearCursorError() { consumeError(Cursor.takeError()); } 86 } Clear{Cursor}; 87 88 /* 89 ELF Extended Build Attributes Layout: 90 <format-version: ‘A’> --> Currently, there is only one version: 'A' (0x41) 91 [ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ] 92 --> subsection-length: Offset from the start of this subsection to the 93 start of the next one. 94 --> vendor-name: Null-terminated byte string. 95 --> vendor-data expands to: 96 [ <uint8: optional> <uint8: parameter type> <attribute>* ] 97 --> optional: 0 = required, 1 = optional. 98 --> parameter type: 0 = ULEB128, 1 = NTBS. 99 --> attribute: <tag, value>* pair. Tag is ULEB128, value is of 100 <parameter type>. 101 */ 102 103 // Get format-version 104 uint8_t FormatVersion = De.getU8(Cursor); 105 if (!Cursor) 106 return Cursor.takeError(); 107 if (ELFAttrs::Format_Version != FormatVersion) 108 return createStringError(errc::invalid_argument, 109 "unrecognized format-version: 0x" + 110 utohexstr(FormatVersion)); 111 112 while (!De.eof(Cursor)) { 113 uint32_t ExtBASubsectionLength = De.getU32(Cursor); 114 if (!Cursor) 115 return Cursor.takeError(); 116 // Minimal valid Extended Build Attributes subsection size is at 117 // least 8: length(4) name(at least a single char + null) optionality(1) and 118 // type(1) 119 // Extended Build Attributes subsection has to fit inside the section. 120 if (ExtBASubsectionLength < 8 || 121 ExtBASubsectionLength > (Section.size() - Cursor.tell() + 4)) 122 return createStringError( 123 errc::invalid_argument, 124 "invalid Extended Build Attributes subsection size at offset: " + 125 utohexstr(Cursor.tell() - 4)); 126 127 StringRef VendorName = De.getCStrRef(Cursor); 128 if (!Cursor) 129 return Cursor.takeError(); 130 uint8_t IsOptional = De.getU8(Cursor); 131 if (!Cursor) 132 return Cursor.takeError(); 133 if (!(0 == IsOptional || 1 == IsOptional)) 134 return createStringError( 135 errc::invalid_argument, 136 "\ninvalid Optionality at offset " + utohexstr(Cursor.tell() - 4) + 137 ": " + utohexstr(IsOptional) + " (Options are 1|0)"); 138 StringRef IsOptionalStr = IsOptional ? "optional" : "required"; 139 uint8_t Type = De.getU8(Cursor); 140 if (!Cursor) 141 return Cursor.takeError(); 142 if (!(0 == Type || 1 == Type)) 143 return createStringError(errc::invalid_argument, 144 "\ninvalid Type at offset " + 145 utohexstr(Cursor.tell() - 4) + ": " + 146 utohexstr(Type) + " (Options are 1|0)"); 147 StringRef TypeStr = Type ? "ntbs" : "uleb128"; 148 149 BuildAttributeSubSection BASubSection; 150 BASubSection.Name = VendorName; 151 BASubSection.IsOptional = IsOptional; 152 BASubSection.ParameterType = Type; 153 154 if (Sw) { 155 Sw->startLine() << "Section " << ++SectionNumber << " {\n"; 156 Sw->indent(); 157 Sw->printNumber("SectionLength", ExtBASubsectionLength); 158 Sw->startLine() << "VendorName" << ": " << VendorName 159 << " Optionality: " << IsOptionalStr 160 << " Type: " << TypeStr << "\n"; 161 Sw->startLine() << "Attributes {\n"; 162 Sw->indent(); 163 } 164 165 // Offset in Section 166 uint64_t OffsetInSection = Cursor.tell(); 167 // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination), 168 // optionality: 1, type: 1 169 uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1; 170 while (Cursor.tell() < 171 (OffsetInSection + ExtBASubsectionLength - BytesAllButAttributes)) { 172 173 uint64_t Tag = De.getULEB128(Cursor); 174 if (!Cursor) 175 return Cursor.takeError(); 176 177 StringRef TagName = getTagName(VendorName, Tag); 178 179 uint64_t ValueInt = 0; 180 std::string ValueStr = ""; 181 if (Type) { // type==1 --> ntbs 182 ValueStr = De.getCStrRef(Cursor); 183 if (!Cursor) 184 return Cursor.takeError(); 185 if (Sw) 186 Sw->printString("" != TagName ? TagName : utostr(Tag), ValueStr); 187 } else { // type==0 --> uleb128 188 ValueInt = De.getULEB128(Cursor); 189 if (!Cursor) 190 return Cursor.takeError(); 191 if (Sw) 192 Sw->printNumber("" != TagName ? TagName : utostr(Tag), ValueInt); 193 } 194 195 // populate data structure 196 BuildAttributeItem BAItem(static_cast<BuildAttributeItem::Types>(Type), 197 Tag, ValueInt, ValueStr); 198 BASubSection.Content.push_back(BAItem); 199 } 200 if (Sw) { 201 // Close 'Attributes' 202 Sw->unindent(); 203 Sw->startLine() << "}\n"; 204 // Close 'Section' 205 Sw->unindent(); 206 Sw->startLine() << "}\n"; 207 } 208 209 // populate data structure 210 SubSectionVec.push_back(BASubSection); 211 } 212 213 return Cursor.takeError(); 214 } 215