-
Notifications
You must be signed in to change notification settings - Fork 14.3k
WIP [readobj][AArch64] Parse AArch64 build attributes #124276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-llvm-support Author: SivanShani-Arm (sivan-shani) ChangesAdd support for parsing AArch64 build attributes in llvm-readobj Full diff: https://github.com/llvm/llvm-project/pull/124276.diff 11 Files Affected:
diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 60c72062a3f6a1..e76c92c526aa01 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -58,7 +58,6 @@ class ELFObjectFileBase : public ObjectFile {
friend class ELFRelocationRef;
friend class ELFSectionRef;
friend class ELFSymbolRef;
-
SubtargetFeatures getMIPSFeatures() const;
SubtargetFeatures getARMFeatures() const;
SubtargetFeatures getHexagonFeatures() const;
@@ -410,6 +409,9 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
case ELF::EM_ARM:
Type = ELF::SHT_ARM_ATTRIBUTES;
break;
+ case ELF::EM_AARCH64:
+ Type = ELF::SHT_AARCH64_ATTRIBUTES;
+ break;
case ELF::EM_RISCV:
Type = ELF::SHT_RISCV_ATTRIBUTES;
break;
@@ -433,7 +435,6 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
auto Contents = ErrorOrContents.get();
if (Contents[0] != ELFAttrs::Format_Version || Contents.size() == 1)
return Error::success();
-
if (Error E = Attributes.parse(Contents, ELFT::Endianness))
return E;
break;
diff --git a/llvm/include/llvm/Support/AArch64AttributeParser.h b/llvm/include/llvm/Support/AArch64AttributeParser.h
new file mode 100644
index 00000000000000..5a6e6ed92eda5a
--- /dev/null
+++ b/llvm/include/llvm/Support/AArch64AttributeParser.h
@@ -0,0 +1,33 @@
+//===- AArch64AttributeParser.h - AArch64 Attribute Information Printer -*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===------------------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
+
+#include "ELFAttributeParser.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+class ScopedPrinter;
+
+class AArch64AttributeParser : public ELFAttributeParser {
+ Error handler(uint64_t Tag, bool &Handled) override {
+ return Error::success();
+ }
+
+public:
+ Error parse(ArrayRef<uint8_t> Section, llvm::endianness Endian) override;
+
+ AArch64AttributeParser(ScopedPrinter *Sw) : ELFAttributeParser(Sw) {}
+ AArch64AttributeParser() {}
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
diff --git a/llvm/include/llvm/Support/ELFAttributeParser.h b/llvm/include/llvm/Support/ELFAttributeParser.h
index ffb92468fb37eb..b132e6d144b18e 100644
--- a/llvm/include/llvm/Support/ELFAttributeParser.h
+++ b/llvm/include/llvm/Support/ELFAttributeParser.h
@@ -53,11 +53,12 @@ class ELFAttributeParser {
ELFAttributeParser(ScopedPrinter *sw, TagNameMap tagNameMap, StringRef vendor)
: vendor(vendor), sw(sw), tagToStringMap(tagNameMap) {}
-
ELFAttributeParser(TagNameMap tagNameMap, StringRef vendor)
: vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {}
+ ELFAttributeParser(ScopedPrinter *sw) : sw(sw) {}
+ ELFAttributeParser() {}
- Error parse(ArrayRef<uint8_t> section, llvm::endianness endian);
+ virtual Error parse(ArrayRef<uint8_t> section, llvm::endianness endian);
std::optional<unsigned> getAttributeValue(unsigned tag) const {
auto I = attributes.find(tag);
diff --git a/llvm/lib/Support/AArch64AttributeParser.cpp b/llvm/lib/Support/AArch64AttributeParser.cpp
new file mode 100644
index 00000000000000..03e03e9f2af880
--- /dev/null
+++ b/llvm/lib/Support/AArch64AttributeParser.cpp
@@ -0,0 +1,153 @@
+//===-AArch64AttributeParser.cpp-AArch64 Attribute Information Printer-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===------------------------------------------------------------------===//
+
+#include "llvm/Support/AArch64AttributeParser.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/AArch64BuildAttributes.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+namespace llvm {
+
+Error AArch64AttributeParser::parse(ArrayRef<uint8_t> Section,
+ llvm::endianness Endian) {
+
+ unsigned SectionNumber = 0;
+ de = DataExtractor(Section, Endian == llvm::endianness::little, 0);
+
+ // Early returns have specific errors. Consume the Error in cursor.
+ struct ClearCursorError {
+ DataExtractor::Cursor &Cursor;
+ ~ClearCursorError() { consumeError(Cursor.takeError()); }
+ } Clear{cursor};
+
+ /*
+ AArch64 build attributes layout:
+ <format-version: ‘A’> --> There is only one version, 'A' (0x41)
+ [ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ]
+ --> subsection-length: the offset from the start of this subsection to the
+ start of the next one.
+ --> vendor-name: NUL-terminated byte string.
+ --> vendor-data expands to:
+ [ <uint8: optional> <uint8: parameter type> <attribute>*]
+ --> optional: 0- required, 1- optional
+ --> type: 0- ULEB128, 1- NTBS
+ --> attribute: <tag, value>* pair. Tag is ULEB128, value is <parameter
+ type> type.
+ */
+
+ // Get format-version
+ uint8_t FormatVersion = de.getU8(cursor);
+ if (ELFAttrs::Format_Version != FormatVersion)
+ return createStringError(errc::invalid_argument,
+ "unrecognized format-version: 0x" +
+ utohexstr(FormatVersion));
+
+ while (!de.eof(cursor)) {
+ uint32_t BASubsectionLength = de.getU32(cursor);
+ // Minimal valid BA subsection header size is at least 8: length(4) name(at
+ // least a single char + null) optionality(1) and type(1)
+ if (BASubsectionLength < 8)
+ return createStringError(
+ errc::invalid_argument,
+ "invalid AArch64 build attribute subsection size at offset: " +
+ utohexstr(cursor.tell() - 4));
+
+ StringRef VendorName = de.getCStrRef(cursor);
+ // The layout of a private subsection (--> vendor name does not starts with
+ // 'aeabi') is unknown, skip)
+ if (!VendorName.starts_with("aeabi")) {
+ sw->startLine()
+ << "** Skipping private AArch64 build attributes subsection: "
+ << VendorName << "\n";
+ // Offset in Section
+ uint64_t OffsetInSection = cursor.tell();
+ // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination)
+ uint32_t BytesForLengthName = 4 + (VendorName.size() + 1);
+ cursor.seek(OffsetInSection + BASubsectionLength - BytesForLengthName);
+ continue;
+ }
+ // All public subsections names must be known
+ if (VendorName.starts_with("aeabi")) {
+ if (!("aeabi_feature_and_bits" == VendorName ||
+ "aeabi_pauthabi" == VendorName)) {
+ return createStringError(
+ errc::invalid_argument,
+ "unknown public AArch64 build attribute subsection name at "
+ "offset: " +
+ utohexstr(cursor.tell() - (VendorName.size() + 1)));
+ }
+ }
+
+ uint8_t IsOptional = de.getU8(cursor);
+ StringRef IsOptionalStr = IsOptional ? "optional" : "required";
+ uint8_t Type = de.getU8(cursor);
+ StringRef TypeStr = Type ? "ntbs" : "uleb128";
+
+ if (sw) {
+ sw->startLine() << "Section " << ++SectionNumber << " {\n";
+ sw->indent();
+ sw->printNumber("SectionLength", BASubsectionLength);
+ sw->startLine() << "VendorName" << ": " << VendorName
+ << " Optionality: " << IsOptionalStr
+ << " Type: " << TypeStr << "\n";
+ sw->startLine() << "Attributes {\n";
+ sw->indent();
+ }
+
+ // Offset in Section
+ uint64_t OffsetInSection = cursor.tell();
+ // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination),
+ // optionality: 1, size: 1
+ uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1;
+ while (cursor.tell() <
+ (OffsetInSection + BASubsectionLength - BytesAllButAttributes)) {
+
+ uint64_t Tag = de.getULEB128(cursor);
+ std::string Str = utostr(Tag);
+ StringRef TagStr(Str);
+ if ("aeabi_feature_and_bits" == VendorName) {
+ StringRef TagAsString =
+ AArch64BuildAttributes::getFeatureAndBitsTagsStr(Tag);
+ if ("" != TagAsString)
+ TagStr = TagAsString;
+ }
+ if ("aeabi_pauthabi" == VendorName) {
+ StringRef TagAsString = AArch64BuildAttributes::getPauthABITagsStr(Tag);
+ if ("" != TagAsString)
+ TagStr = TagAsString;
+ }
+
+ if (Type) { // type==1 --> ntbs
+ StringRef Value = de.getCStrRef(cursor);
+ if (sw)
+ sw->printString(TagStr, Value);
+ } else { // type==0 --> uleb128
+ uint64_t Value = de.getULEB128(cursor);
+ if (sw)
+ sw->printNumber(TagStr, Value);
+ }
+ }
+ if (sw) {
+ // Close 'Attributes'
+ sw->unindent();
+ sw->startLine() << "}\n";
+ // Close 'Section'
+ sw->unindent();
+ sw->startLine() << "}\n";
+ }
+ }
+
+ return cursor.takeError();
+}
+} // namespace llvm
\ No newline at end of file
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 122240c27b1fcd..0be9f62c810a65 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -146,6 +146,7 @@ add_llvm_component_library(LLVMSupport
ARMBuildAttrs.cpp
AArch64BuildAttributes.cpp
ARMAttributeParser.cpp
+ AArch64AttributeParser.cpp
ARMWinEH.cpp
Allocator.cpp
AutoConvert.cpp
diff --git a/llvm/lib/Support/ELFAttributeParser.cpp b/llvm/lib/Support/ELFAttributeParser.cpp
index 26c3d54e17ade8..47055b6fda2f80 100644
--- a/llvm/lib/Support/ELFAttributeParser.cpp
+++ b/llvm/lib/Support/ELFAttributeParser.cpp
@@ -128,9 +128,8 @@ Error ELFAttributeParser::parseSubsection(uint32_t length) {
}
// Handle a subsection with an unrecognized vendor-name by skipping
- // over it to the next subsection. ADDENDA32 in the Arm ABI defines
- // that vendor attribute sections must not affect compatibility, so
- // this should always be safe.
+ // over it to the next subsection. vendor attribute sections must not
+ // affect compatibility, so this should always be safe.
if (vendorName.lower() != vendor) {
cursor.seek(end);
return Error::success();
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-comprehensive.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-comprehensive.s
new file mode 100644
index 00000000000000..253148ba93ca71
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-comprehensive.s
@@ -0,0 +1,56 @@
+# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --arch-specific - | FileCheck %s --check-prefix=ATTR
+
+# ATTR: BuildAttributes {
+# ATTR-NEXT: FormatVersion: 0x41
+# ATTR-NEXT: ** Skipping private AArch64 build attributes subsection: private_subsection_1
+# ATTR-NEXT: Section 1 {
+# ATTR-NEXT: SectionLength: 37
+# ATTR-NEXT: VendorName: aeabi_feature_and_bits Optionality: optional Type: uleb128
+# ATTR-NEXT: Attributes {
+# ATTR-NEXT: Tag_Feature_BTI: 1
+# ATTR-NEXT: Tag_Feature_PAC: 1
+# ATTR-NEXT: Tag_Feature_GCS: 1
+# ATTR-NEXT: 3: 1
+# ATTR-NEXT: }
+# ATTR-NEXT: }
+# ATTR-NEXT: ** Skipping private AArch64 build attributes subsection: private_subsection_3
+# ATTR-NEXT: Section 2 {
+# ATTR-NEXT: SectionLength: 35
+# ATTR-NEXT: VendorName: aeabi_pauthabi Optionality: required Type: uleb128
+# ATTR-NEXT: Attributes {
+# ATTR-NEXT: Tag_PAuth_Schema: 1
+# ATTR-NEXT: Tag_PAuth_Platform: 1
+# ATTR-NEXT: 5: 1
+# ATTR-NEXT: 6: 1
+# ATTR-NEXT: 7: 1
+# ATTR-NEXT: 8: 1
+# ATTR-NEXT: 9: 1
+# ATTR-NEXT: }
+# ATTR-NEXT: }
+# ATTR-NEXT: ** Skipping private AArch64 build attributes subsection: private_subsection_4
+# ATTR-NEXT: ** Skipping private AArch64 build attributes subsection: private_subsection_2
+# ATTR-NEXT: }
+
+
+.aeabi_subsection private_subsection_1, optional, uleb128
+.aeabi_attribute 1, 1
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute 1, 1
+.aeabi_attribute 2, 1
+.aeabi_attribute 3, 1
+.aeabi_subsection private_subsection_3, optional, ntbs
+.aeabi_attribute 1, "1"
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Schema, 1
+.aeabi_attribute Tag_PAuth_Platform, 1
+.aeabi_attribute 5, 1
+.aeabi_attribute 6, 1
+.aeabi_attribute 7, 1
+.aeabi_attribute 8, 1
+.aeabi_attribute 9, 1
+.aeabi_subsection private_subsection_4, required, ntbs
+.aeabi_attribute 1, "1"
+.aeabi_subsection private_subsection_2, required, uleb128
+.aeabi_attribute 1, 1
+.aeabi_attribute 2, 1
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-err.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-err.s
new file mode 100644
index 00000000000000..30502c79cf7a37
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-err.s
@@ -0,0 +1,5 @@
+# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --arch-specific - 2>&1 | FileCheck %s --check-prefix=ERR
+
+# ERR: unable to dump attributes from the Unknown section with index 3: unknown public AArch64 build attribute subsection name at offset: 5
+
+.aeabi_subsection aeabi_a, optional, uleb128
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index bfca65aad52b44..3ee9a15eb8b4a9 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -39,6 +39,7 @@
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/RelocationResolver.h"
#include "llvm/Object/StackMapParser.h"
+#include "llvm/Support/AArch64AttributeParser.h"
#include "llvm/Support/AMDGPUMetadata.h"
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
@@ -2872,6 +2873,12 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
ELF::SHT_ARM_ATTRIBUTES, std::make_unique<ARMAttributeParser>(&W),
Obj.isLE() ? llvm::endianness::little : llvm::endianness::big);
break;
+ case EM_AARCH64:
+ printAttributes(ELF::SHT_AARCH64_ATTRIBUTES,
+ std::make_unique<AArch64AttributeParser>(&W),
+ Obj.isLE() ? llvm::endianness::little
+ : llvm::endianness::big);
+ break;
case EM_RISCV:
if (Obj.isLE())
printAttributes(ELF::SHT_RISCV_ATTRIBUTES,
diff --git a/llvm/unittests/Support/ELFAttributeParserTest.cpp b/llvm/unittests/Support/ELFAttributeParserTest.cpp
index 38e7b09cc3c7d5..0e034814c4d856 100644
--- a/llvm/unittests/Support/ELFAttributeParserTest.cpp
+++ b/llvm/unittests/Support/ELFAttributeParserTest.cpp
@@ -27,6 +27,9 @@ class AttributeHeaderParser : public ELFAttributeParser {
AttributeHeaderParser(ScopedPrinter *printer)
: ELFAttributeParser(printer, emptyTagNameMap, "test") {}
AttributeHeaderParser() : ELFAttributeParser(emptyTagNameMap, "test") {}
+ Error parse(ArrayRef<uint8_t> section, llvm::endianness endian) override {
+ return ELFAttributeParser::parse(section, endian);
+ }
};
static void testParseError(ArrayRef<uint8_t> bytes, const char *msg) {
diff --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
index 5146d4141f29b6..b6b67b830fe761 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
@@ -41,6 +41,7 @@ static_library("Support") {
"APInt.cpp",
"APSInt.cpp",
"ARMAttributeParser.cpp",
+ "AArch64AttributeParser.cpp",
"ARMBuildAttrs.cpp",
"ARMWinEH.cpp",
"Allocator.cpp",
|
0d63207
to
e2d9486
Compare
|
||
using namespace llvm; | ||
|
||
Error AArch64AttributeParser::parse(ArrayRef<uint8_t> Section, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is completely replacing the parse
function in the base class, which I think makes the design more complicated because there is lots of code now in the base class which is only sometimes used.
I think it would be better to split out parsing of the two sub-classes to parse the ARM-style (also used by other architectures) and AArch64-style (currently AArch64 only, but not guaranteed to remain AArch64-specific). This would leave the base class as an abstract class without an implementation of the parse
function. The architecture-specific classes can then derive from one of the new classes, depending on which format it uses.
The new AArch64AttributeParser
implementation also only implements some of the behaviour of ELFAttributeParser
, for example it does not populate the attributes
map, so the getAttributeValue
and getAttributeString
functions will fail. This should either implement all of the functionality provided by the base class, or the parts not needed for the AArch64-style attributes should be moved to the ARM-style class.
} | ||
// All public subsections names must be known | ||
if (VendorName.starts_with("aeabi")) { | ||
if (!("aeabi_feature_and_bits" == VendorName || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be able to print any "aeabi*" subsection, because the format is known, even if the tag names aren't.
…les) This commit deletes previous tests files, following commits adding new test files.
Parsing error message should not print the symbol triggering error. (Only point to it with the symbol '^')
Print Tags as numbers followed by comments instead of using string representations. For example: .aeabi_attribute 0, 1 @ Tag_Feature_BTI instead of: .aeabi_attribute Tag_Feature_BTI, 1 This reduces dependencies between compiler and assembler versions.
- Reject strings for unknown tags. - Allow any value for Tag_PAuth_Platform and Tag_PAuth_Schema.
Adding the same value twice is valid, so the assertion has been removed.
Add test files
326394e
to
c924bb0
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
Added support for parsing AArch64 build attributes in llvm-readobj.
c924bb0
to
b57cce1
Compare
Changes submitted here: |
Add support for parsing AArch64 build attributes in llvm-readobj