xref: /freebsd/contrib/llvm-project/llvm/lib/Support/ELFAttrParserExtended.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
20 using namespace llvm;
21 using namespace ELFAttrs;
22 
23 std::optional<unsigned>
getAttributeValue(unsigned Tag) const24 ELFExtendedAttrParser::getAttributeValue(unsigned Tag) const {
25   assert(
26       0 &&
27       "use getAttributeValue overloaded version accepting Stringref, unsigned");
28   return std::nullopt;
29 }
30 
31 std::optional<unsigned>
getAttributeValue(StringRef BuildAttrSubsectionName,unsigned Tag) const32 ELFExtendedAttrParser::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 
44 std::optional<StringRef>
getAttributeString(unsigned Tag) const45 ELFExtendedAttrParser::getAttributeString(unsigned Tag) const {
46   assert(
47       0 &&
48       "use getAttributeValue overloaded version accepting Stringref, unsigned");
49   return std::nullopt;
50 }
51 
52 std::optional<StringRef>
getAttributeString(StringRef BuildAttrSubsectionName,unsigned Tag) const53 ELFExtendedAttrParser::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 
65 StringRef
getTagName(const StringRef & BuildAttrSubsectionName,const unsigned Tag)66 ELFExtendedAttrParser::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 
parse(ArrayRef<uint8_t> Section,llvm::endianness Endian)76 Error 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(Cursor.takeError()); }
86   } Clear{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(Cursor);
105   if (!Cursor)
106     return Cursor.takeError();
107   if (ELFAttrs::Format_Version != FormatVersion)
108     return createStringError(errc::invalid_argument,
109                              "unrecognized format-version: 0x" +
110                                  utohexstr(FormatVersion));
111 
112   while (!De.eof(Cursor)) {
113     uint32_t ExtBASubsectionLength = De.getU32(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           errc::invalid_argument,
124           "invalid Extended Build Attributes subsection size at offset: " +
125               utohexstr(Cursor.tell() - 4));
126 
127     StringRef VendorName = De.getCStrRef(Cursor);
128     if (!Cursor)
129       return Cursor.takeError();
130     uint8_t IsOptional = De.getU8(Cursor);
131     if (!Cursor)
132       return Cursor.takeError();
133     if (!(0 == IsOptional || 1 == IsOptional))
134       return createStringError(
135           errc::invalid_argument,
136           "\ninvalid Optionality at offset " + utohexstr(Cursor.tell() - 4) +
137               ": " + utohexstr(IsOptional) + " (Options are 1|0)");
138     StringRef IsOptionalStr = IsOptional ? "optional" : "required";
139     uint8_t Type = De.getU8(Cursor);
140     if (!Cursor)
141       return Cursor.takeError();
142     if (!(0 == Type || 1 == Type))
143       return createStringError(errc::invalid_argument,
144                                "\ninvalid Type at offset " +
145                                    utohexstr(Cursor.tell() - 4) + ": " +
146                                    utohexstr(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("SectionLength", 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(Cursor);
174       if (!Cursor)
175         return Cursor.takeError();
176 
177       StringRef TagName = getTagName(VendorName, Tag);
178 
179       uint64_t ValueInt = 0;
180       std::string ValueStr = "";
181       if (Type) { // type==1 --> ntbs
182         ValueStr = De.getCStrRef(Cursor);
183         if (!Cursor)
184           return Cursor.takeError();
185         if (Sw)
186           Sw->printString("" != TagName ? TagName : utostr(Tag), ValueStr);
187       } else { // type==0 --> uleb128
188         ValueInt = De.getULEB128(Cursor);
189         if (!Cursor)
190           return Cursor.takeError();
191         if (Sw)
192           Sw->printNumber("" != TagName ? TagName : utostr(Tag), ValueInt);
193       }
194 
195       // populate data structure
196       BuildAttributeItem BAItem(static_cast<BuildAttributeItem::Types>(Type),
197                                 Tag, ValueInt, ValueStr);
198       BASubSection.Content.push_back(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(BASubSection);
211   }
212 
213   return Cursor.takeError();
214 }
215