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/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"
15 
16 using namespace llvm;
17 using namespace llvm::ELFAttrs;
18 
19 static constexpr EnumEntry<unsigned> tagNames[] = {
20     {"Tag_File", ELFAttrs::File},
21     {"Tag_Section", ELFAttrs::Section},
22     {"Tag_Symbol", ELFAttrs::Symbol},
23 };
24 
parseStringAttribute(const char * name,unsigned tag,ArrayRef<const char * > strings)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));
33   }
34   printAttribute(tag, value, strings[value]);
35   return Error::success();
36 }
37 
integerAttribute(unsigned tag)38 Error ELFAttributeParser::integerAttribute(unsigned tag) {
39   StringRef tagName =
40       ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
41   uint64_t value = de.getULEB128(cursor);
42   attributes.insert(std::make_pair(tag, value));
43 
44   if (sw) {
45     DictScope scope(*sw, "Attribute");
46     sw->printNumber("Tag", tag);
47     if (!tagName.empty())
48       sw->printString("TagName", tagName);
49     sw->printNumber("Value", value);
50   }
51   return Error::success();
52 }
53 
stringAttribute(unsigned tag)54 Error ELFAttributeParser::stringAttribute(unsigned tag) {
55   StringRef tagName =
56       ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
57   StringRef desc = de.getCStrRef(cursor);
58   attributesStr.insert(std::make_pair(tag, desc));
59 
60   if (sw) {
61     DictScope scope(*sw, "Attribute");
62     sw->printNumber("Tag", tag);
63     if (!tagName.empty())
64       sw->printString("TagName", tagName);
65     sw->printString("Value", desc);
66   }
67   return Error::success();
68 }
69 
printAttribute(unsigned tag,unsigned value,StringRef valueDesc)70 void ELFAttributeParser::printAttribute(unsigned tag, unsigned value,
71                                         StringRef valueDesc) {
72   attributes.insert(std::make_pair(tag, value));
73 
74   if (sw) {
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);
80     if (!tagName.empty())
81       sw->printString("TagName", tagName);
82     if (!valueDesc.empty())
83       sw->printString("Description", valueDesc);
84   }
85 }
86 
parseIndexList(SmallVectorImpl<uint8_t> & indexList)87 void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
88   for (;;) {
89     uint64_t value = de.getULEB128(cursor);
90     if (!cursor || !value)
91       break;
92     indexList.push_back(value);
93   }
94 }
95 
parseAttributeList(uint32_t length)96 Error ELFAttributeParser::parseAttributeList(uint32_t length) {
97   uint64_t pos;
98   uint64_t end = cursor.tell() + length;
99   while ((pos = cursor.tell()) < end) {
100     uint64_t tag = de.getULEB128(cursor);
101     bool handled;
102     if (Error e = handler(tag, handled))
103       return e;
104 
105     if (!handled) {
106       if (tag < 32) {
107         return createStringError(errc::invalid_argument,
108                                  "invalid tag 0x" + Twine::utohexstr(tag) +
109                                      " at offset 0x" + Twine::utohexstr(pos));
110       }
111 
112       if (tag % 2 == 0) {
113         if (Error e = integerAttribute(tag))
114           return e;
115       } else {
116         if (Error e = stringAttribute(tag))
117           return e;
118       }
119     }
120   }
121   return Error::success();
122 }
123 
parseSubsection(uint32_t length)124 Error ELFAttributeParser::parseSubsection(uint32_t length) {
125   uint64_t end = cursor.tell() - sizeof(length) + length;
126   StringRef vendorName = de.getCStrRef(cursor);
127   if (sw) {
128     sw->printNumber("SectionLength", length);
129     sw->printString("Vendor", vendorName);
130   }
131 
132   // Ignore unrecognized vendor-name.
133   if (vendorName.lower() != vendor)
134     return createStringError(errc::invalid_argument,
135                              "unrecognized vendor-name: " + vendorName);
136 
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);
141     if (!cursor)
142       return cursor.takeError();
143 
144     if (sw) {
145       sw->printEnum("Tag", tag, makeArrayRef(tagNames));
146       sw->printNumber("Size", size);
147     }
148     if (size < 5)
149       return createStringError(errc::invalid_argument,
150                                "invalid attribute size " + Twine(size) +
151                                    " at offset 0x" +
152                                    Twine::utohexstr(cursor.tell() - 5));
153 
154     StringRef scopeName, indexName;
155     SmallVector<uint8_t, 8> indicies;
156     switch (tag) {
157     case ELFAttrs::File:
158       scopeName = "FileAttributes";
159       break;
160     case ELFAttrs::Section:
161       scopeName = "SectionAttributes";
162       indexName = "Sections";
163       parseIndexList(indicies);
164       break;
165     case ELFAttrs::Symbol:
166       scopeName = "SymbolAttributes";
167       indexName = "Symbols";
168       parseIndexList(indicies);
169       break;
170     default:
171       return createStringError(errc::invalid_argument,
172                                "unrecognized tag 0x" + Twine::utohexstr(tag) +
173                                    " at offset 0x" +
174                                    Twine::utohexstr(cursor.tell() - 5));
175     }
176 
177     if (sw) {
178       DictScope scope(*sw, scopeName);
179       if (!indicies.empty())
180         sw->printList(indexName, indicies);
181       if (Error e = parseAttributeList(size - 5))
182         return e;
183     } else if (Error e = parseAttributeList(size - 5))
184       return e;
185   }
186   return Error::success();
187 }
188 
parse(ArrayRef<uint8_t> section,support::endianness endian)189 Error ELFAttributeParser::parse(ArrayRef<uint8_t> section,
190                                 support::endianness endian) {
191   unsigned sectionNumber = 0;
192   de = DataExtractor(section, endian == support::little, 0);
193 
194   // For early returns, we have more specific errors, consume the Error in
195   // cursor.
196   struct ClearCursorError {
197     DataExtractor::Cursor &cursor;
198     ~ClearCursorError() { consumeError(cursor.takeError()); }
199   } clear{cursor};
200 
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));
207 
208   while (!de.eof(cursor)) {
209     uint32_t sectionLength = de.getU32(cursor);
210     if (!cursor)
211       return cursor.takeError();
212 
213     if (sw) {
214       sw->startLine() << "Section " << ++sectionNumber << " {\n";
215       sw->indent();
216     }
217 
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));
223 
224     if (Error e = parseSubsection(sectionLength))
225       return e;
226     if (sw) {
227       sw->unindent();
228       sw->startLine() << "}\n";
229     }
230   }
231 
232   return cursor.takeError();
233 }
234