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/STLExtras.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/LEB128.h"
14 #include "llvm/Support/ScopedPrinter.h"
17 using namespace llvm::ELFAttrs
;
19 static constexpr EnumEntry
<unsigned> tagNames
[] = {
20 {"Tag_File", ELFAttrs::File
},
21 {"Tag_Section", ELFAttrs::Section
},
22 {"Tag_Symbol", ELFAttrs::Symbol
},
25 Error
ELFAttributeParser::parseStringAttribute(const char *name
, unsigned tag
,
26 ArrayRef
<const char *> strings
) {
27 uint64_t value
= de
.getULEB128(cursor
);
28 if (value
>= strings
.size()) {
29 printAttribute(tag
, value
, "");
30 return createStringError(errc::invalid_argument
,
31 "unknown " + Twine(name
) +
32 " value: " + Twine(value
));
34 printAttribute(tag
, value
, strings
[value
]);
35 return Error::success();
38 Error
ELFAttributeParser::integerAttribute(unsigned tag
) {
40 ELFAttrs::attrTypeAsString(tag
, tagToStringMap
, /*hasTagPrefix=*/false);
41 uint64_t value
= de
.getULEB128(cursor
);
42 attributes
.insert(std::make_pair(tag
, value
));
45 DictScope
scope(*sw
, "Attribute");
46 sw
->printNumber("Tag", tag
);
48 sw
->printString("TagName", tagName
);
49 sw
->printNumber("Value", value
);
51 return Error::success();
54 Error
ELFAttributeParser::stringAttribute(unsigned tag
) {
56 ELFAttrs::attrTypeAsString(tag
, tagToStringMap
, /*hasTagPrefix=*/false);
57 StringRef desc
= de
.getCStrRef(cursor
);
58 attributesStr
.insert(std::make_pair(tag
, desc
));
61 DictScope
scope(*sw
, "Attribute");
62 sw
->printNumber("Tag", tag
);
64 sw
->printString("TagName", tagName
);
65 sw
->printString("Value", desc
);
67 return Error::success();
70 void ELFAttributeParser::printAttribute(unsigned tag
, unsigned value
,
71 StringRef valueDesc
) {
72 attributes
.insert(std::make_pair(tag
, value
));
75 StringRef tagName
= ELFAttrs::attrTypeAsString(tag
, tagToStringMap
,
76 /*hasTagPrefix=*/false);
77 DictScope
as(*sw
, "Attribute");
78 sw
->printNumber("Tag", tag
);
79 sw
->printNumber("Value", value
);
81 sw
->printString("TagName", tagName
);
82 if (!valueDesc
.empty())
83 sw
->printString("Description", valueDesc
);
87 void ELFAttributeParser::parseIndexList(SmallVectorImpl
<uint8_t> &indexList
) {
89 uint64_t value
= de
.getULEB128(cursor
);
90 if (!cursor
|| !value
)
92 indexList
.push_back(value
);
96 Error
ELFAttributeParser::parseAttributeList(uint32_t length
) {
98 uint64_t end
= cursor
.tell() + length
;
99 while ((pos
= cursor
.tell()) < end
) {
100 uint64_t tag
= de
.getULEB128(cursor
);
102 if (Error e
= handler(tag
, handled
))
107 return createStringError(errc::invalid_argument
,
108 "invalid tag 0x" + Twine::utohexstr(tag
) +
109 " at offset 0x" + Twine::utohexstr(pos
));
113 if (Error e
= integerAttribute(tag
))
116 if (Error e
= stringAttribute(tag
))
121 return Error::success();
124 Error
ELFAttributeParser::parseSubsection(uint32_t length
) {
125 uint64_t end
= cursor
.tell() - sizeof(length
) + length
;
126 StringRef vendorName
= de
.getCStrRef(cursor
);
128 sw
->printNumber("SectionLength", length
);
129 sw
->printString("Vendor", vendorName
);
132 // Ignore unrecognized vendor-name.
133 if (vendorName
.lower() != vendor
)
134 return createStringError(errc::invalid_argument
,
135 "unrecognized vendor-name: " + vendorName
);
137 while (cursor
.tell() < end
) {
138 /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
139 uint8_t tag
= de
.getU8(cursor
);
140 uint32_t size
= de
.getU32(cursor
);
142 return cursor
.takeError();
145 sw
->printEnum("Tag", tag
, makeArrayRef(tagNames
));
146 sw
->printNumber("Size", size
);
149 return createStringError(errc::invalid_argument
,
150 "invalid attribute size " + Twine(size
) +
152 Twine::utohexstr(cursor
.tell() - 5));
154 StringRef scopeName
, indexName
;
155 SmallVector
<uint8_t, 8> indicies
;
158 scopeName
= "FileAttributes";
160 case ELFAttrs::Section
:
161 scopeName
= "SectionAttributes";
162 indexName
= "Sections";
163 parseIndexList(indicies
);
165 case ELFAttrs::Symbol
:
166 scopeName
= "SymbolAttributes";
167 indexName
= "Symbols";
168 parseIndexList(indicies
);
171 return createStringError(errc::invalid_argument
,
172 "unrecognized tag 0x" + Twine::utohexstr(tag
) +
174 Twine::utohexstr(cursor
.tell() - 5));
178 DictScope
scope(*sw
, scopeName
);
179 if (!indicies
.empty())
180 sw
->printList(indexName
, indicies
);
181 if (Error e
= parseAttributeList(size
- 5))
183 } else if (Error e
= parseAttributeList(size
- 5))
186 return Error::success();
189 Error
ELFAttributeParser::parse(ArrayRef
<uint8_t> section
,
190 support::endianness endian
) {
191 unsigned sectionNumber
= 0;
192 de
= DataExtractor(section
, endian
== support::little
, 0);
194 // For early returns, we have more specific errors, consume the Error in
196 struct ClearCursorError
{
197 DataExtractor::Cursor
&cursor
;
198 ~ClearCursorError() { consumeError(cursor
.takeError()); }
201 // Unrecognized format-version.
202 uint8_t formatVersion
= de
.getU8(cursor
);
203 if (formatVersion
!= ELFAttrs::Format_Version
)
204 return createStringError(errc::invalid_argument
,
205 "unrecognized format-version: 0x" +
206 utohexstr(formatVersion
));
208 while (!de
.eof(cursor
)) {
209 uint32_t sectionLength
= de
.getU32(cursor
);
211 return cursor
.takeError();
214 sw
->startLine() << "Section " << ++sectionNumber
<< " {\n";
218 if (sectionLength
< 4 || cursor
.tell() - 4 + sectionLength
> section
.size())
219 return createStringError(errc::invalid_argument
,
220 "invalid section length " +
221 Twine(sectionLength
) + " at offset 0x" +
222 utohexstr(cursor
.tell() - 4));
224 if (Error e
= parseSubsection(sectionLength
))
228 sw
->startLine() << "}\n";
232 return cursor
.takeError();