1 | //===--- ELFCompactAttrParser.cpp - ELF Compact Attribute Parser ------ ===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | // ELF Compact Attribute Parser parse ELF build atrributes that are held |
8 | // in a single Build Attributes Subsection. |
9 | // |
10 | //===--------------------------------------------------------------------===// |
11 | |
12 | #include "llvm/Support/ELFAttrParserCompact.h" |
13 | #include "llvm/ADT/StringExtras.h" |
14 | #include "llvm/Support/Errc.h" |
15 | #include "llvm/Support/ScopedPrinter.h" |
16 | |
17 | using namespace llvm; |
18 | using namespace llvm::ELFAttrs; |
19 | |
20 | static constexpr EnumEntry<unsigned> tagNames[] = { |
21 | {"Tag_File" , ELFAttrs::File}, |
22 | {"Tag_Section" , ELFAttrs::Section}, |
23 | {"Tag_Symbol" , ELFAttrs::Symbol}, |
24 | }; |
25 | |
26 | Error ELFCompactAttrParser::parseStringAttribute( |
27 | const char *name, unsigned tag, ArrayRef<const char *> strings) { |
28 | uint64_t value = de.getULEB128(C&: cursor); |
29 | if (value >= strings.size()) { |
30 | printAttribute(tag, value, valueDesc: "" ); |
31 | return createStringError(EC: errc::invalid_argument, |
32 | S: "unknown " + Twine(name) + |
33 | " value: " + Twine(value)); |
34 | } |
35 | printAttribute(tag, value, valueDesc: strings[value]); |
36 | return Error::success(); |
37 | } |
38 | |
39 | Error ELFCompactAttrParser::integerAttribute(unsigned tag) { |
40 | StringRef tagName = |
41 | ELFAttrs::attrTypeAsString(attr: tag, tagNameMap: tagToStringMap, /*hasTagPrefix=*/false); |
42 | uint64_t value = de.getULEB128(C&: cursor); |
43 | attributes.insert(x: std::make_pair(x&: tag, y&: value)); |
44 | |
45 | if (sw) { |
46 | DictScope scope(*sw, "Attribute" ); |
47 | sw->printNumber(Label: "Tag" , Value: tag); |
48 | if (!tagName.empty()) |
49 | sw->printString(Label: "TagName" , Value: tagName); |
50 | sw->printNumber(Label: "Value" , Value: value); |
51 | } |
52 | return Error::success(); |
53 | } |
54 | |
55 | Error ELFCompactAttrParser::stringAttribute(unsigned tag) { |
56 | StringRef tagName = |
57 | ELFAttrs::attrTypeAsString(attr: tag, tagNameMap: tagToStringMap, /*hasTagPrefix=*/false); |
58 | StringRef desc = de.getCStrRef(C&: cursor); |
59 | setAttributeString(tag, value: desc); |
60 | |
61 | if (sw) { |
62 | DictScope scope(*sw, "Attribute" ); |
63 | sw->printNumber(Label: "Tag" , Value: tag); |
64 | if (!tagName.empty()) |
65 | sw->printString(Label: "TagName" , Value: tagName); |
66 | sw->printString(Label: "Value" , Value: desc); |
67 | } |
68 | return Error::success(); |
69 | } |
70 | |
71 | void ELFCompactAttrParser::printAttribute(unsigned tag, unsigned value, |
72 | StringRef valueDesc) { |
73 | attributes.insert(x: std::make_pair(x&: tag, y&: value)); |
74 | |
75 | if (sw) { |
76 | StringRef tagName = ELFAttrs::attrTypeAsString(attr: tag, tagNameMap: tagToStringMap, |
77 | /*hasTagPrefix=*/false); |
78 | DictScope as(*sw, "Attribute" ); |
79 | sw->printNumber(Label: "Tag" , Value: tag); |
80 | sw->printNumber(Label: "Value" , Value: value); |
81 | if (!tagName.empty()) |
82 | sw->printString(Label: "TagName" , Value: tagName); |
83 | if (!valueDesc.empty()) |
84 | sw->printString(Label: "Description" , Value: valueDesc); |
85 | } |
86 | } |
87 | |
88 | void ELFCompactAttrParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) { |
89 | for (;;) { |
90 | uint64_t value = de.getULEB128(C&: cursor); |
91 | if (!cursor || !value) |
92 | break; |
93 | indexList.push_back(Elt: value); |
94 | } |
95 | } |
96 | |
97 | Error ELFCompactAttrParser::parseAttributeList(uint32_t length) { |
98 | uint64_t pos; |
99 | uint64_t end = cursor.tell() + length; |
100 | while ((pos = cursor.tell()) < end) { |
101 | uint64_t tag = de.getULEB128(C&: cursor); |
102 | bool handled; |
103 | if (Error e = handler(tag, handled)) |
104 | return e; |
105 | |
106 | if (!handled) { |
107 | if (tag < 32) { |
108 | return createStringError(EC: errc::invalid_argument, |
109 | S: "invalid tag 0x" + Twine::utohexstr(Val: tag) + |
110 | " at offset 0x" + Twine::utohexstr(Val: pos)); |
111 | } |
112 | |
113 | if (tag % 2 == 0) { |
114 | if (Error e = integerAttribute(tag)) |
115 | return e; |
116 | } else { |
117 | if (Error e = stringAttribute(tag)) |
118 | return e; |
119 | } |
120 | } |
121 | } |
122 | return Error::success(); |
123 | } |
124 | |
125 | Error ELFCompactAttrParser::parseSubsection(uint32_t length) { |
126 | uint64_t end = cursor.tell() - sizeof(length) + length; |
127 | StringRef vendorName = de.getCStrRef(C&: cursor); |
128 | if (sw) { |
129 | sw->printNumber(Label: "SectionLength" , Value: length); |
130 | sw->printString(Label: "Vendor" , Value: vendorName); |
131 | } |
132 | |
133 | // Handle a subsection with an unrecognized vendor-name by skipping |
134 | // over it to the next subsection. ADDENDA32 in the Arm ABI defines |
135 | // that vendor attribute sections must not affect compatibility, so |
136 | // this should always be safe. |
137 | if (vendorName.lower() != vendor) { |
138 | cursor.seek(NewOffSet: end); |
139 | return Error::success(); |
140 | } |
141 | |
142 | while (cursor.tell() < end) { |
143 | /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size |
144 | uint8_t tag = de.getU8(C&: cursor); |
145 | uint32_t size = de.getU32(C&: cursor); |
146 | if (!cursor) |
147 | return cursor.takeError(); |
148 | |
149 | if (sw) { |
150 | sw->printEnum(Label: "Tag" , Value: tag, EnumValues: ArrayRef(tagNames)); |
151 | sw->printNumber(Label: "Size" , Value: size); |
152 | } |
153 | if (size < 5) |
154 | return createStringError(EC: errc::invalid_argument, |
155 | S: "invalid attribute size " + Twine(size) + |
156 | " at offset 0x" + |
157 | Twine::utohexstr(Val: cursor.tell() - 5)); |
158 | |
159 | StringRef scopeName, indexName; |
160 | SmallVector<uint8_t, 8> indices; |
161 | switch (tag) { |
162 | case ELFAttrs::File: |
163 | scopeName = "FileAttributes" ; |
164 | break; |
165 | case ELFAttrs::Section: |
166 | scopeName = "SectionAttributes" ; |
167 | indexName = "Sections" ; |
168 | parseIndexList(indexList&: indices); |
169 | break; |
170 | case ELFAttrs::Symbol: |
171 | scopeName = "SymbolAttributes" ; |
172 | indexName = "Symbols" ; |
173 | parseIndexList(indexList&: indices); |
174 | break; |
175 | default: |
176 | return createStringError(EC: errc::invalid_argument, |
177 | S: "unrecognized tag 0x" + Twine::utohexstr(Val: tag) + |
178 | " at offset 0x" + |
179 | Twine::utohexstr(Val: cursor.tell() - 5)); |
180 | } |
181 | |
182 | if (sw) { |
183 | DictScope scope(*sw, scopeName); |
184 | if (!indices.empty()) |
185 | sw->printList(Label: indexName, List: indices); |
186 | if (Error e = parseAttributeList(length: size - 5)) |
187 | return e; |
188 | } else if (Error e = parseAttributeList(length: size - 5)) |
189 | return e; |
190 | } |
191 | return Error::success(); |
192 | } |
193 | |
194 | Error ELFCompactAttrParser::parse(ArrayRef<uint8_t> section, |
195 | llvm::endianness endian) { |
196 | unsigned sectionNumber = 0; |
197 | de = DataExtractor(section, endian == llvm::endianness::little, 0); |
198 | |
199 | // For early returns, we have more specific errors, consume the Error in |
200 | // cursor. |
201 | struct ClearCursorError { |
202 | DataExtractor::Cursor &cursor; |
203 | ~ClearCursorError() { consumeError(Err: cursor.takeError()); } |
204 | } clear{.cursor: cursor}; |
205 | |
206 | // Unrecognized format-version. |
207 | uint8_t formatVersion = de.getU8(C&: cursor); |
208 | if (formatVersion != ELFAttrs::Format_Version) |
209 | return createStringError(EC: errc::invalid_argument, |
210 | S: "unrecognized format-version: 0x" + |
211 | utohexstr(X: formatVersion)); |
212 | |
213 | while (!de.eof(C: cursor)) { |
214 | uint32_t sectionLength = de.getU32(C&: cursor); |
215 | if (!cursor) |
216 | return cursor.takeError(); |
217 | |
218 | if (sw) { |
219 | sw->startLine() << "Section " << ++sectionNumber << " {\n" ; |
220 | sw->indent(); |
221 | } |
222 | |
223 | if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size()) |
224 | return createStringError(EC: errc::invalid_argument, |
225 | S: "invalid section length " + |
226 | Twine(sectionLength) + " at offset 0x" + |
227 | utohexstr(X: cursor.tell() - 4)); |
228 | |
229 | if (Error e = parseSubsection(length: sectionLength)) |
230 | return e; |
231 | if (sw) { |
232 | sw->unindent(); |
233 | sw->startLine() << "}\n" ; |
234 | } |
235 | } |
236 | |
237 | return cursor.takeError(); |
238 | } |
239 | |