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
17using namespace llvm;
18using namespace llvm::ELFAttrs;
19
20static constexpr EnumEntry<unsigned> tagNames[] = {
21 {"Tag_File", ELFAttrs::File},
22 {"Tag_Section", ELFAttrs::Section},
23 {"Tag_Symbol", ELFAttrs::Symbol},
24};
25
26Error 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
39Error 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
55Error 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
71void 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
88void 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
97Error 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
125Error 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
194Error 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