1//===-ELFAttrParserExtended.cpp-ELF Extended Attribute Information Printer-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM
4// Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===------------------------------------------------------------------===//
9
10#include "llvm/Support/ELFAttrParserExtended.h"
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/Support/ELFAttributes.h"
14#include "llvm/Support/Errc.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/ScopedPrinter.h"
17#include "llvm/Support/raw_ostream.h"
18#include <cstdint>
19
20using namespace llvm;
21using namespace ELFAttrs;
22
23std::optional<unsigned>
24ELFExtendedAttrParser::getAttributeValue(unsigned Tag) const {
25 assert(
26 0 &&
27 "use getAttributeValue overloaded version accepting Stringref, unsigned");
28 return std::nullopt;
29}
30
31std::optional<unsigned>
32ELFExtendedAttrParser::getAttributeValue(StringRef BuildAttrSubsectionName,
33 unsigned Tag) const {
34 for (const auto &SubSection : SubSectionVec) {
35 if (BuildAttrSubsectionName == SubSection.Name)
36 for (const auto &BAItem : SubSection.Content) {
37 if (Tag == BAItem.Tag)
38 return std::optional<unsigned>(BAItem.IntValue);
39 }
40 }
41 return std::nullopt;
42}
43
44std::optional<StringRef>
45ELFExtendedAttrParser::getAttributeString(unsigned Tag) const {
46 assert(
47 0 &&
48 "use getAttributeValue overloaded version accepting Stringref, unsigned");
49 return std::nullopt;
50}
51
52std::optional<StringRef>
53ELFExtendedAttrParser::getAttributeString(StringRef BuildAttrSubsectionName,
54 unsigned Tag) const {
55 for (const auto &SubSection : SubSectionVec) {
56 if (BuildAttrSubsectionName == SubSection.Name)
57 for (const auto &BAItem : SubSection.Content) {
58 if (Tag == BAItem.Tag)
59 return std::optional<StringRef>(BAItem.StringValue);
60 }
61 }
62 return std::nullopt;
63}
64
65StringRef
66ELFExtendedAttrParser::getTagName(const StringRef &BuildAttrSubsectionName,
67 const unsigned Tag) {
68 for (const auto &Entry : TagsNamesMap) {
69 if (BuildAttrSubsectionName == Entry.SubsectionName)
70 if (Tag == Entry.Tag)
71 return Entry.TagName;
72 }
73 return "";
74}
75
76Error ELFExtendedAttrParser::parse(ArrayRef<uint8_t> Section,
77 llvm::endianness Endian) {
78
79 unsigned SectionNumber = 0;
80 De = DataExtractor(Section, Endian == llvm::endianness::little, 0);
81
82 // Early returns have specific errors. Consume the Error in Cursor.
83 struct ClearCursorError {
84 DataExtractor::Cursor &Cursor;
85 ~ClearCursorError() { consumeError(Err: Cursor.takeError()); }
86 } Clear{.Cursor: Cursor};
87
88 /*
89 ELF Extended Build Attributes Layout:
90 <format-version: ‘A’> --> Currently, there is only one version: 'A' (0x41)
91 [ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ]
92 --> subsection-length: Offset from the start of this subsection to the
93 start of the next one.
94 --> vendor-name: Null-terminated byte string.
95 --> vendor-data expands to:
96 [ <uint8: optional> <uint8: parameter type> <attribute>* ]
97 --> optional: 0 = required, 1 = optional.
98 --> parameter type: 0 = ULEB128, 1 = NTBS.
99 --> attribute: <tag, value>* pair. Tag is ULEB128, value is of
100 <parameter type>.
101 */
102
103 // Get format-version
104 uint8_t FormatVersion = De.getU8(C&: Cursor);
105 if (!Cursor)
106 return Cursor.takeError();
107 if (ELFAttrs::Format_Version != FormatVersion)
108 return createStringError(EC: errc::invalid_argument,
109 S: "unrecognized format-version: 0x" +
110 utohexstr(X: FormatVersion));
111
112 while (!De.eof(C: Cursor)) {
113 uint32_t ExtBASubsectionLength = De.getU32(C&: Cursor);
114 if (!Cursor)
115 return Cursor.takeError();
116 // Minimal valid Extended Build Attributes subsection size is at
117 // least 8: length(4) name(at least a single char + null) optionality(1) and
118 // type(1)
119 // Extended Build Attributes subsection has to fit inside the section.
120 if (ExtBASubsectionLength < 8 ||
121 ExtBASubsectionLength > (Section.size() - Cursor.tell() + 4))
122 return createStringError(
123 EC: errc::invalid_argument,
124 S: "invalid Extended Build Attributes subsection size at offset: " +
125 utohexstr(X: Cursor.tell() - 4));
126
127 StringRef VendorName = De.getCStrRef(C&: Cursor);
128 if (!Cursor)
129 return Cursor.takeError();
130 uint8_t IsOptional = De.getU8(C&: Cursor);
131 if (!Cursor)
132 return Cursor.takeError();
133 if (!(0 == IsOptional || 1 == IsOptional))
134 return createStringError(
135 EC: errc::invalid_argument,
136 S: "\ninvalid Optionality at offset " + utohexstr(X: Cursor.tell() - 4) +
137 ": " + utohexstr(X: IsOptional) + " (Options are 1|0)");
138 StringRef IsOptionalStr = IsOptional ? "optional" : "required";
139 uint8_t Type = De.getU8(C&: Cursor);
140 if (!Cursor)
141 return Cursor.takeError();
142 if (!(0 == Type || 1 == Type))
143 return createStringError(EC: errc::invalid_argument,
144 S: "\ninvalid Type at offset " +
145 utohexstr(X: Cursor.tell() - 4) + ": " +
146 utohexstr(X: Type) + " (Options are 1|0)");
147 StringRef TypeStr = Type ? "ntbs" : "uleb128";
148
149 BuildAttributeSubSection BASubSection;
150 BASubSection.Name = VendorName;
151 BASubSection.IsOptional = IsOptional;
152 BASubSection.ParameterType = Type;
153
154 if (Sw) {
155 Sw->startLine() << "Section " << ++SectionNumber << " {\n";
156 Sw->indent();
157 Sw->printNumber(Label: "SectionLength", Value: ExtBASubsectionLength);
158 Sw->startLine() << "VendorName" << ": " << VendorName
159 << " Optionality: " << IsOptionalStr
160 << " Type: " << TypeStr << "\n";
161 Sw->startLine() << "Attributes {\n";
162 Sw->indent();
163 }
164
165 // Offset in Section
166 uint64_t OffsetInSection = Cursor.tell();
167 // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination),
168 // optionality: 1, type: 1
169 uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1;
170 while (Cursor.tell() <
171 (OffsetInSection + ExtBASubsectionLength - BytesAllButAttributes)) {
172
173 uint64_t Tag = De.getULEB128(C&: Cursor);
174 if (!Cursor)
175 return Cursor.takeError();
176
177 StringRef TagName = getTagName(BuildAttrSubsectionName: VendorName, Tag);
178
179 uint64_t ValueInt = 0;
180 std::string ValueStr = "";
181 if (Type) { // type==1 --> ntbs
182 ValueStr = De.getCStrRef(C&: Cursor);
183 if (!Cursor)
184 return Cursor.takeError();
185 if (Sw)
186 Sw->printString(Label: "" != TagName ? TagName : utostr(X: Tag), Value: ValueStr);
187 } else { // type==0 --> uleb128
188 ValueInt = De.getULEB128(C&: Cursor);
189 if (!Cursor)
190 return Cursor.takeError();
191 if (Sw)
192 Sw->printNumber(Label: "" != TagName ? TagName : utostr(X: Tag), Value: ValueInt);
193 }
194
195 // populate data structure
196 BuildAttributeItem BAItem(static_cast<BuildAttributeItem::Types>(Type),
197 Tag, ValueInt, ValueStr);
198 BASubSection.Content.push_back(Elt: BAItem);
199 }
200 if (Sw) {
201 // Close 'Attributes'
202 Sw->unindent();
203 Sw->startLine() << "}\n";
204 // Close 'Section'
205 Sw->unindent();
206 Sw->startLine() << "}\n";
207 }
208
209 // populate data structure
210 SubSectionVec.push_back(Elt: BASubSection);
211 }
212
213 return Cursor.takeError();
214}
215