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