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(cursor);
26  if (value >= strings.size()) {
27    printAttribute(tag, value, "");
28    return createStringError(errc::invalid_argument,
29                             "unknown " + Twine(name) +
30                                 " value: " + Twine(value));
31  }
32  printAttribute(tag, value, strings[value]);
33  return Error::success();
34}
35
36Error ELFAttributeParser::integerAttribute(unsigned tag) {
37  StringRef tagName =
38      ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
39  uint64_t value = de.getULEB128(cursor);
40  attributes.insert(std::make_pair(tag, value));
41
42  if (sw) {
43    DictScope scope(*sw, "Attribute");
44    sw->printNumber("Tag", tag);
45    if (!tagName.empty())
46      sw->printString("TagName", tagName);
47    sw->printNumber("Value", value);
48  }
49  return Error::success();
50}
51
52Error ELFAttributeParser::stringAttribute(unsigned tag) {
53  StringRef tagName =
54      ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
55  StringRef desc = de.getCStrRef(cursor);
56  setAttributeString(tag, desc);
57
58  if (sw) {
59    DictScope scope(*sw, "Attribute");
60    sw->printNumber("Tag", tag);
61    if (!tagName.empty())
62      sw->printString("TagName", tagName);
63    sw->printString("Value", desc);
64  }
65  return Error::success();
66}
67
68void ELFAttributeParser::printAttribute(unsigned tag, unsigned value,
69                                        StringRef valueDesc) {
70  attributes.insert(std::make_pair(tag, value));
71
72  if (sw) {
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);
78    if (!tagName.empty())
79      sw->printString("TagName", tagName);
80    if (!valueDesc.empty())
81      sw->printString("Description", valueDesc);
82  }
83}
84
85void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
86  for (;;) {
87    uint64_t value = de.getULEB128(cursor);
88    if (!cursor || !value)
89      break;
90    indexList.push_back(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(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(errc::invalid_argument,
106                                 "invalid tag 0x" + Twine::utohexstr(tag) +
107                                     " at offset 0x" + Twine::utohexstr(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(cursor);
125  if (sw) {
126    sw->printNumber("SectionLength", length);
127    sw->printString("Vendor", 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(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(cursor);
142    uint32_t size = de.getU32(cursor);
143    if (!cursor)
144      return cursor.takeError();
145
146    if (sw) {
147      sw->printEnum("Tag", tag, ArrayRef(tagNames));
148      sw->printNumber("Size", size);
149    }
150    if (size < 5)
151      return createStringError(errc::invalid_argument,
152                               "invalid attribute size " + Twine(size) +
153                                   " at offset 0x" +
154                                   Twine::utohexstr(cursor.tell() - 5));
155
156    StringRef scopeName, indexName;
157    SmallVector<uint8_t, 8> indicies;
158    switch (tag) {
159    case ELFAttrs::File:
160      scopeName = "FileAttributes";
161      break;
162    case ELFAttrs::Section:
163      scopeName = "SectionAttributes";
164      indexName = "Sections";
165      parseIndexList(indicies);
166      break;
167    case ELFAttrs::Symbol:
168      scopeName = "SymbolAttributes";
169      indexName = "Symbols";
170      parseIndexList(indicies);
171      break;
172    default:
173      return createStringError(errc::invalid_argument,
174                               "unrecognized tag 0x" + Twine::utohexstr(tag) +
175                                   " at offset 0x" +
176                                   Twine::utohexstr(cursor.tell() - 5));
177    }
178
179    if (sw) {
180      DictScope scope(*sw, scopeName);
181      if (!indicies.empty())
182        sw->printList(indexName, indicies);
183      if (Error e = parseAttributeList(size - 5))
184        return e;
185    } else if (Error e = parseAttributeList(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(cursor.takeError()); }
201  } clear{cursor};
202
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));
209
210  while (!de.eof(cursor)) {
211    uint32_t sectionLength = de.getU32(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(errc::invalid_argument,
222                               "invalid section length " +
223                                   Twine(sectionLength) + " at offset 0x" +
224                                   utohexstr(cursor.tell() - 4));
225
226    if (Error e = parseSubsection(sectionLength))
227      return e;
228    if (sw) {
229      sw->unindent();
230      sw->startLine() << "}\n";
231    }
232  }
233
234  return cursor.takeError();
235}
236