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
14using namespace llvm;
15using namespace llvm::ELFAttrs;
16
17static constexpr EnumEntry<unsigned> tagNames[] = {
18 {"Tag_File", ELFAttrs::File},
19 {"Tag_Section", ELFAttrs::Section},
20 {"Tag_Symbol", ELFAttrs::Symbol},
21};
22
23Error 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
36Error 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
52Error 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
68void 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
85void 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
94Error 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
122Error 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
191Error 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