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