1 //===--- ELFAttributeParser.cpp - ELF Attribute Parser --------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/ELFAttributeParser.h"
10 #include "llvm/ADT/StringExtras.h"
11 #include "llvm/Support/Errc.h"
12 #include "llvm/Support/ScopedPrinter.h"
15 using namespace llvm::ELFAttrs
;
17 static constexpr EnumEntry
<unsigned> tagNames
[] = {
18 {"Tag_File", ELFAttrs::File
},
19 {"Tag_Section", ELFAttrs::Section
},
20 {"Tag_Symbol", ELFAttrs::Symbol
},
23 Error
ELFAttributeParser::parseStringAttribute(const char *name
, unsigned tag
,
24 ArrayRef
<const char *> strings
) {
25 uint64_t value
= de
.getULEB128(cursor
);
26 if (value
>= strings
.size()) {
27 printAttribute(tag
, value
, "");
28 return createStringError(errc::invalid_argument
,
29 "unknown " + Twine(name
) +
30 " value: " + Twine(value
));
32 printAttribute(tag
, value
, strings
[value
]);
33 return Error::success();
36 Error
ELFAttributeParser::integerAttribute(unsigned tag
) {
38 ELFAttrs::attrTypeAsString(tag
, tagToStringMap
, /*hasTagPrefix=*/false);
39 uint64_t value
= de
.getULEB128(cursor
);
40 attributes
.insert(std::make_pair(tag
, value
));
43 DictScope
scope(*sw
, "Attribute");
44 sw
->printNumber("Tag", tag
);
46 sw
->printString("TagName", tagName
);
47 sw
->printNumber("Value", value
);
49 return Error::success();
52 Error
ELFAttributeParser::stringAttribute(unsigned tag
) {
54 ELFAttrs::attrTypeAsString(tag
, tagToStringMap
, /*hasTagPrefix=*/false);
55 StringRef desc
= de
.getCStrRef(cursor
);
56 setAttributeString(tag
, desc
);
59 DictScope
scope(*sw
, "Attribute");
60 sw
->printNumber("Tag", tag
);
62 sw
->printString("TagName", tagName
);
63 sw
->printString("Value", desc
);
65 return Error::success();
68 void ELFAttributeParser::printAttribute(unsigned tag
, unsigned value
,
69 StringRef valueDesc
) {
70 attributes
.insert(std::make_pair(tag
, value
));
73 StringRef tagName
= ELFAttrs::attrTypeAsString(tag
, tagToStringMap
,
74 /*hasTagPrefix=*/false);
75 DictScope
as(*sw
, "Attribute");
76 sw
->printNumber("Tag", tag
);
77 sw
->printNumber("Value", value
);
79 sw
->printString("TagName", tagName
);
80 if (!valueDesc
.empty())
81 sw
->printString("Description", valueDesc
);
85 void ELFAttributeParser::parseIndexList(SmallVectorImpl
<uint8_t> &indexList
) {
87 uint64_t value
= de
.getULEB128(cursor
);
88 if (!cursor
|| !value
)
90 indexList
.push_back(value
);
94 Error
ELFAttributeParser::parseAttributeList(uint32_t length
) {
96 uint64_t end
= cursor
.tell() + length
;
97 while ((pos
= cursor
.tell()) < end
) {
98 uint64_t tag
= de
.getULEB128(cursor
);
100 if (Error e
= handler(tag
, handled
))
105 return createStringError(errc::invalid_argument
,
106 "invalid tag 0x" + Twine::utohexstr(tag
) +
107 " at offset 0x" + Twine::utohexstr(pos
));
111 if (Error e
= integerAttribute(tag
))
114 if (Error e
= stringAttribute(tag
))
119 return Error::success();
122 Error
ELFAttributeParser::parseSubsection(uint32_t length
) {
123 uint64_t end
= cursor
.tell() - sizeof(length
) + length
;
124 StringRef vendorName
= de
.getCStrRef(cursor
);
126 sw
->printNumber("SectionLength", length
);
127 sw
->printString("Vendor", vendorName
);
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
) {
136 return Error::success();
139 while (cursor
.tell() < end
) {
140 /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
141 uint8_t tag
= de
.getU8(cursor
);
142 uint32_t size
= de
.getU32(cursor
);
144 return cursor
.takeError();
147 sw
->printEnum("Tag", tag
, ArrayRef(tagNames
));
148 sw
->printNumber("Size", size
);
151 return createStringError(errc::invalid_argument
,
152 "invalid attribute size " + Twine(size
) +
154 Twine::utohexstr(cursor
.tell() - 5));
156 StringRef scopeName
, indexName
;
157 SmallVector
<uint8_t, 8> indicies
;
160 scopeName
= "FileAttributes";
162 case ELFAttrs::Section
:
163 scopeName
= "SectionAttributes";
164 indexName
= "Sections";
165 parseIndexList(indicies
);
167 case ELFAttrs::Symbol
:
168 scopeName
= "SymbolAttributes";
169 indexName
= "Symbols";
170 parseIndexList(indicies
);
173 return createStringError(errc::invalid_argument
,
174 "unrecognized tag 0x" + Twine::utohexstr(tag
) +
176 Twine::utohexstr(cursor
.tell() - 5));
180 DictScope
scope(*sw
, scopeName
);
181 if (!indicies
.empty())
182 sw
->printList(indexName
, indicies
);
183 if (Error e
= parseAttributeList(size
- 5))
185 } else if (Error e
= parseAttributeList(size
- 5))
188 return Error::success();
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);
196 // For early returns, we have more specific errors, consume the Error in
198 struct ClearCursorError
{
199 DataExtractor::Cursor
&cursor
;
200 ~ClearCursorError() { consumeError(cursor
.takeError()); }
203 // Unrecognized format-version.
204 uint8_t formatVersion
= de
.getU8(cursor
);
205 if (formatVersion
!= ELFAttrs::Format_Version
)
206 return createStringError(errc::invalid_argument
,
207 "unrecognized format-version: 0x" +
208 utohexstr(formatVersion
));
210 while (!de
.eof(cursor
)) {
211 uint32_t sectionLength
= de
.getU32(cursor
);
213 return cursor
.takeError();
216 sw
->startLine() << "Section " << ++sectionNumber
<< " {\n";
220 if (sectionLength
< 4 || cursor
.tell() - 4 + sectionLength
> section
.size())
221 return createStringError(errc::invalid_argument
,
222 "invalid section length " +
223 Twine(sectionLength
) + " at offset 0x" +
224 utohexstr(cursor
.tell() - 4));
226 if (Error e
= parseSubsection(sectionLength
))
230 sw
->startLine() << "}\n";
234 return cursor
.takeError();