Skip to content

Commit c924bb0

Browse files
committed
[readobj][AArch64] Support Parsing AArch64 Build Attributes
Added support for parsing AArch64 build attributes in llvm-readobj.
1 parent e453ae0 commit c924bb0

17 files changed

+373
-113
lines changed

llvm/include/llvm/Object/ELFObjectFile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,9 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
410410
case ELF::EM_ARM:
411411
Type = ELF::SHT_ARM_ATTRIBUTES;
412412
break;
413+
case ELF::EM_AARCH64:
414+
Type = ELF::SHT_AARCH64_ATTRIBUTES;
415+
break;
413416
case ELF::EM_RISCV:
414417
Type = ELF::SHT_RISCV_ATTRIBUTES;
415418
break;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//=== - AArch64AttributeParser.h-AArch64 Attribute Information Printer - ===//
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+
#ifndef LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
10+
#define LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
11+
12+
#include "ELFAttributeParser.h"
13+
#include "llvm/Support/Error.h"
14+
15+
namespace llvm {
16+
17+
class ScopedPrinter;
18+
19+
class AArch64AttributeParser : public ELFAttributeParser {
20+
Error handler(uint64_t Tag, bool &Handled) override {
21+
return Error::success();
22+
}
23+
24+
public:
25+
Error parse(ArrayRef<uint8_t> Section, llvm::endianness Endian) override;
26+
27+
AArch64AttributeParser(ScopedPrinter *Sw) : ELFAttributeParser(Sw) {}
28+
AArch64AttributeParser() {}
29+
};
30+
} // namespace llvm
31+
32+
#endif // LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H

llvm/include/llvm/Support/AArch64BuildAttributes.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
namespace llvm {
2424

25-
namespace AArch64BuildAttrs {
25+
namespace AArch64BuildAttributes {
2626

2727
/// AArch64 build attributes vendors IDs (a.k.a subsection name)
2828
enum VendorID : unsigned {
@@ -69,7 +69,7 @@ enum FeatureAndBitsFlag : unsigned {
6969
Feature_PAC_Flag = 1 << 1,
7070
Feature_GCS_Flag = 1 << 2
7171
};
72-
} // namespace AArch64BuildAttrs
72+
} // namespace AArch64BuildAttributes
7373
} // namespace llvm
7474

7575
#endif // LLVM_SUPPORT_AARCH64BUILDATTRIBUTES_H

llvm/include/llvm/Support/ELFAttributeParser.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ class ELFAttributeParser {
5656

5757
ELFAttributeParser(TagNameMap tagNameMap, StringRef vendor)
5858
: vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {}
59+
ELFAttributeParser(ScopedPrinter *sw) : sw(sw) {}
60+
ELFAttributeParser() : sw(nullptr) {}
5961

60-
Error parse(ArrayRef<uint8_t> section, llvm::endianness endian);
62+
virtual Error parse(ArrayRef<uint8_t> section, llvm::endianness endian);
6163

6264
std::optional<unsigned> getAttributeValue(unsigned tag) const {
6365
auto I = attributes.find(tag);
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
//===-AArch64AttributeParser.cpp-AArch64 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/AArch64AttributeParser.h"
11+
#include "llvm/ADT/StringExtras.h"
12+
#include "llvm/ADT/StringRef.h"
13+
#include "llvm/Support/AArch64BuildAttributes.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+
22+
Error AArch64AttributeParser::parse(ArrayRef<uint8_t> Section,
23+
llvm::endianness Endian) {
24+
25+
unsigned SectionNumber = 0;
26+
de = DataExtractor(Section, Endian == llvm::endianness::little, 0);
27+
28+
// Early returns have specific errors. Consume the Error in cursor.
29+
struct ClearCursorError {
30+
DataExtractor::Cursor &Cursor;
31+
~ClearCursorError() { consumeError(Cursor.takeError()); }
32+
} Clear{cursor};
33+
34+
/*
35+
AArch64 build attributes layout:
36+
<format-version: ‘A’> --> There is only one version, 'A' (0x41)
37+
[ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ]
38+
--> subsection-length: the offset from the start of this subsection to the
39+
start of the next one.
40+
--> vendor-name: NUL-terminated byte string.
41+
--> vendor-data expands to:
42+
[ <uint8: optional> <uint8: parameter type> <attribute>*]
43+
--> optional: 0- required, 1- optional
44+
--> type: 0- ULEB128, 1- NTBS
45+
--> attribute: <tag, value>* pair. Tag is ULEB128, value is <parameter
46+
type> type.
47+
*/
48+
49+
// Get format-version
50+
uint8_t FormatVersion = de.getU8(cursor);
51+
if (ELFAttrs::Format_Version != FormatVersion)
52+
return createStringError(errc::invalid_argument,
53+
"unrecognized format-version: 0x" +
54+
utohexstr(FormatVersion));
55+
56+
while (!de.eof(cursor)) {
57+
uint32_t BASubsectionLength = de.getU32(cursor);
58+
// Minimal valid BA subsection header size is at least 8: length(4) name(at
59+
// least a single char + null) optionality(1) and type(1)
60+
if (BASubsectionLength < 8)
61+
return createStringError(
62+
errc::invalid_argument,
63+
"invalid AArch64 build attribute subsection size at offset: " +
64+
utohexstr(cursor.tell() - 4));
65+
66+
StringRef VendorName = de.getCStrRef(cursor);
67+
// The layout of a private subsection (--> vendor name does not starts with
68+
// 'aeabi') is unknown, skip)
69+
if (!VendorName.starts_with("aeabi")) {
70+
sw->startLine()
71+
<< "** Skipping private AArch64 build attributes subsection: "
72+
<< VendorName << "\n";
73+
// Offset in Section
74+
uint64_t OffsetInSection = cursor.tell();
75+
// Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination)
76+
uint32_t BytesForLengthName = 4 + (VendorName.size() + 1);
77+
cursor.seek(OffsetInSection + BASubsectionLength - BytesForLengthName);
78+
continue;
79+
}
80+
// All public subsections names must be known
81+
if (VendorName.starts_with("aeabi")) {
82+
if (!("aeabi_feature_and_bits" == VendorName ||
83+
"aeabi_pauthabi" == VendorName)) {
84+
return createStringError(
85+
errc::invalid_argument,
86+
"unknown public AArch64 build attribute subsection name at "
87+
"offset: " +
88+
utohexstr(cursor.tell() - (VendorName.size() + 1)));
89+
}
90+
}
91+
92+
uint8_t IsOptional = de.getU8(cursor);
93+
StringRef IsOptionalStr = IsOptional ? "optional" : "required";
94+
uint8_t Type = de.getU8(cursor);
95+
StringRef TypeStr = Type ? "ntbs" : "uleb128";
96+
97+
if (sw) {
98+
sw->startLine() << "Section " << ++SectionNumber << " {\n";
99+
sw->indent();
100+
sw->printNumber("SectionLength", BASubsectionLength);
101+
sw->startLine() << "VendorName" << ": " << VendorName
102+
<< " Optionality: " << IsOptionalStr
103+
<< " Type: " << TypeStr << "\n";
104+
sw->startLine() << "Attributes {\n";
105+
sw->indent();
106+
}
107+
108+
// Offset in Section
109+
uint64_t OffsetInSection = cursor.tell();
110+
// Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination),
111+
// optionality: 1, size: 1
112+
uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1;
113+
while (cursor.tell() <
114+
(OffsetInSection + BASubsectionLength - BytesAllButAttributes)) {
115+
116+
uint64_t Tag = de.getULEB128(cursor);
117+
std::string Str = utostr(Tag);
118+
StringRef TagStr(Str);
119+
if ("aeabi_feature_and_bits" == VendorName) {
120+
StringRef TagAsString =
121+
AArch64BuildAttributes::getFeatureAndBitsTagsStr(Tag);
122+
if ("" != TagAsString)
123+
TagStr = TagAsString;
124+
}
125+
if ("aeabi_pauthabi" == VendorName) {
126+
StringRef TagAsString = AArch64BuildAttributes::getPauthABITagsStr(Tag);
127+
if ("" != TagAsString)
128+
TagStr = TagAsString;
129+
}
130+
131+
if (Type) { // type==1 --> ntbs
132+
StringRef Value = de.getCStrRef(cursor);
133+
if (sw)
134+
sw->printString(TagStr, Value);
135+
} else { // type==0 --> uleb128
136+
uint64_t Value = de.getULEB128(cursor);
137+
if (sw)
138+
sw->printNumber(TagStr, Value);
139+
}
140+
}
141+
if (sw) {
142+
// Close 'Attributes'
143+
sw->unindent();
144+
sw->startLine() << "}\n";
145+
// Close 'Section'
146+
sw->unindent();
147+
sw->startLine() << "}\n";
148+
}
149+
}
150+
151+
return cursor.takeError();
152+
}

llvm/lib/Support/AArch64BuildAttributes.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
#include "llvm/ADT/StringSwitch.h"
1111

1212
using namespace llvm;
13-
using namespace llvm::AArch64BuildAttrs;
13+
using namespace llvm::AArch64BuildAttributes;
1414

15-
StringRef AArch64BuildAttrs::getVendorName(unsigned Vendor) {
15+
StringRef AArch64BuildAttributes::getVendorName(unsigned Vendor) {
1616
switch (Vendor) {
1717
case AEABI_FEATURE_AND_BITS:
1818
return "aeabi_feature_and_bits";
@@ -25,14 +25,14 @@ StringRef AArch64BuildAttrs::getVendorName(unsigned Vendor) {
2525
return "";
2626
}
2727
}
28-
VendorID AArch64BuildAttrs::getVendorID(StringRef Vendor) {
28+
VendorID AArch64BuildAttributes::getVendorID(StringRef Vendor) {
2929
return StringSwitch<VendorID>(Vendor)
3030
.Case("aeabi_feature_and_bits", AEABI_FEATURE_AND_BITS)
3131
.Case("aeabi_pauthabi", AEABI_PAUTHABI)
3232
.Default(VENDOR_UNKNOWN);
3333
}
3434

35-
StringRef AArch64BuildAttrs::getOptionalStr(unsigned Optional) {
35+
StringRef AArch64BuildAttributes::getOptionalStr(unsigned Optional) {
3636
switch (Optional) {
3737
case REQUIRED:
3838
return "required";
@@ -43,18 +43,18 @@ StringRef AArch64BuildAttrs::getOptionalStr(unsigned Optional) {
4343
return "";
4444
}
4545
}
46-
SubsectionOptional AArch64BuildAttrs::getOptionalID(StringRef Optional) {
46+
SubsectionOptional AArch64BuildAttributes::getOptionalID(StringRef Optional) {
4747
return StringSwitch<SubsectionOptional>(Optional)
4848
.Case("required", REQUIRED)
4949
.Case("optional", OPTIONAL)
5050
.Default(OPTIONAL_NOT_FOUND);
5151
}
52-
StringRef AArch64BuildAttrs::getSubsectionOptionalUnknownError() {
52+
StringRef AArch64BuildAttributes::getSubsectionOptionalUnknownError() {
5353
return "unknown AArch64 build attributes optionality, expected "
5454
"required|optional";
5555
}
5656

57-
StringRef AArch64BuildAttrs::getTypeStr(unsigned Type) {
57+
StringRef AArch64BuildAttributes::getTypeStr(unsigned Type) {
5858
switch (Type) {
5959
case ULEB128:
6060
return "uleb128";
@@ -65,17 +65,17 @@ StringRef AArch64BuildAttrs::getTypeStr(unsigned Type) {
6565
return "";
6666
}
6767
}
68-
SubsectionType AArch64BuildAttrs::getTypeID(StringRef Type) {
68+
SubsectionType AArch64BuildAttributes::getTypeID(StringRef Type) {
6969
return StringSwitch<SubsectionType>(Type)
7070
.Cases("uleb128", "ULEB128", ULEB128)
7171
.Cases("ntbs", "NTBS", NTBS)
7272
.Default(TYPE_NOT_FOUND);
7373
}
74-
StringRef AArch64BuildAttrs::getSubsectionTypeUnknownError() {
74+
StringRef AArch64BuildAttributes::getSubsectionTypeUnknownError() {
7575
return "unknown AArch64 build attributes type, expected uleb128|ntbs";
7676
}
7777

78-
StringRef AArch64BuildAttrs::getPauthABITagsStr(unsigned PauthABITag) {
78+
StringRef AArch64BuildAttributes::getPauthABITagsStr(unsigned PauthABITag) {
7979
switch (PauthABITag) {
8080
case TAG_PAUTH_PLATFORM:
8181
return "Tag_PAuth_Platform";
@@ -87,15 +87,15 @@ StringRef AArch64BuildAttrs::getPauthABITagsStr(unsigned PauthABITag) {
8787
}
8888
}
8989

90-
PauthABITags AArch64BuildAttrs::getPauthABITagsID(StringRef PauthABITag) {
90+
PauthABITags AArch64BuildAttributes::getPauthABITagsID(StringRef PauthABITag) {
9191
return StringSwitch<PauthABITags>(PauthABITag)
9292
.Case("Tag_PAuth_Platform", TAG_PAUTH_PLATFORM)
9393
.Case("Tag_PAuth_Schema", TAG_PAUTH_SCHEMA)
9494
.Default(PAUTHABI_TAG_NOT_FOUND);
9595
}
9696

9797
StringRef
98-
AArch64BuildAttrs::getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag) {
98+
AArch64BuildAttributes::getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag) {
9999
switch (FeatureAndBitsTag) {
100100
case TAG_FEATURE_BTI:
101101
return "Tag_Feature_BTI";
@@ -110,7 +110,7 @@ AArch64BuildAttrs::getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag) {
110110
}
111111

112112
FeatureAndBitsTags
113-
AArch64BuildAttrs::getFeatureAndBitsTagsID(StringRef FeatureAndBitsTag) {
113+
AArch64BuildAttributes::getFeatureAndBitsTagsID(StringRef FeatureAndBitsTag) {
114114
return StringSwitch<FeatureAndBitsTags>(FeatureAndBitsTag)
115115
.Case("Tag_Feature_BTI", TAG_FEATURE_BTI)
116116
.Case("Tag_Feature_PAC", TAG_FEATURE_PAC)

llvm/lib/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ add_llvm_component_library(LLVMSupport
146146
ARMBuildAttributes.cpp
147147
AArch64BuildAttributes.cpp
148148
ARMAttributeParser.cpp
149+
AArch64AttributeParser.cpp
149150
ARMWinEH.cpp
150151
Allocator.cpp
151152
AutoConvert.cpp

llvm/lib/Support/ELFAttributeParser.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,8 @@ Error ELFAttributeParser::parseSubsection(uint32_t length) {
128128
}
129129

130130
// 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.
131+
// over it to the next subsection. vendor attribute sections must not
132+
// affect compatibility, so this should always be safe.
134133
if (vendorName.lower() != vendor) {
135134
cursor.seek(end);
136135
return Error::success();

0 commit comments

Comments
 (0)