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(Err: Cursor.takeError()); } |
86 | } Clear{.Cursor: 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(C&: Cursor); |
105 | if (!Cursor) |
106 | return Cursor.takeError(); |
107 | if (ELFAttrs::Format_Version != FormatVersion) |
108 | return createStringError(EC: errc::invalid_argument, |
109 | S: "unrecognized format-version: 0x" + |
110 | utohexstr(X: FormatVersion)); |
111 | |
112 | while (!De.eof(C: Cursor)) { |
113 | uint32_t ExtBASubsectionLength = De.getU32(C&: 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 | EC: errc::invalid_argument, |
124 | S: "invalid Extended Build Attributes subsection size at offset: " + |
125 | utohexstr(X: Cursor.tell() - 4)); |
126 | |
127 | StringRef VendorName = De.getCStrRef(C&: Cursor); |
128 | if (!Cursor) |
129 | return Cursor.takeError(); |
130 | uint8_t IsOptional = De.getU8(C&: Cursor); |
131 | if (!Cursor) |
132 | return Cursor.takeError(); |
133 | if (!(0 == IsOptional || 1 == IsOptional)) |
134 | return createStringError( |
135 | EC: errc::invalid_argument, |
136 | S: "\ninvalid Optionality at offset " + utohexstr(X: Cursor.tell() - 4) + |
137 | ": " + utohexstr(X: IsOptional) + " (Options are 1|0)" ); |
138 | StringRef IsOptionalStr = IsOptional ? "optional" : "required" ; |
139 | uint8_t Type = De.getU8(C&: Cursor); |
140 | if (!Cursor) |
141 | return Cursor.takeError(); |
142 | if (!(0 == Type || 1 == Type)) |
143 | return createStringError(EC: errc::invalid_argument, |
144 | S: "\ninvalid Type at offset " + |
145 | utohexstr(X: Cursor.tell() - 4) + ": " + |
146 | utohexstr(X: 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(Label: "SectionLength" , Value: 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(C&: Cursor); |
174 | if (!Cursor) |
175 | return Cursor.takeError(); |
176 | |
177 | StringRef TagName = getTagName(BuildAttrSubsectionName: VendorName, Tag); |
178 | |
179 | uint64_t ValueInt = 0; |
180 | std::string ValueStr = "" ; |
181 | if (Type) { // type==1 --> ntbs |
182 | ValueStr = De.getCStrRef(C&: Cursor); |
183 | if (!Cursor) |
184 | return Cursor.takeError(); |
185 | if (Sw) |
186 | Sw->printString(Label: "" != TagName ? TagName : utostr(X: Tag), Value: ValueStr); |
187 | } else { // type==0 --> uleb128 |
188 | ValueInt = De.getULEB128(C&: Cursor); |
189 | if (!Cursor) |
190 | return Cursor.takeError(); |
191 | if (Sw) |
192 | Sw->printNumber(Label: "" != TagName ? TagName : utostr(X: Tag), Value: ValueInt); |
193 | } |
194 | |
195 | // populate data structure |
196 | BuildAttributeItem BAItem(static_cast<BuildAttributeItem::Types>(Type), |
197 | Tag, ValueInt, ValueStr); |
198 | BASubSection.Content.push_back(Elt: 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(Elt: BASubSection); |
211 | } |
212 | |
213 | return Cursor.takeError(); |
214 | } |
215 | |