[llvm] [readobj][AArch64] Parse AArch64 build attributes (PR #124276)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 24 06:37:07 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support
Author: SivanShani-Arm (sivan-shani)
<details>
<summary>Changes</summary>
Add support for parsing AArch64 build attributes in llvm-readobj
---
Full diff: https://github.com/llvm/llvm-project/pull/124276.diff
11 Files Affected:
- (modified) llvm/include/llvm/Object/ELFObjectFile.h (+3-2)
- (added) llvm/include/llvm/Support/AArch64AttributeParser.h (+33)
- (modified) llvm/include/llvm/Support/ELFAttributeParser.h (+3-2)
- (added) llvm/lib/Support/AArch64AttributeParser.cpp (+153)
- (modified) llvm/lib/Support/CMakeLists.txt (+1)
- (modified) llvm/lib/Support/ELFAttributeParser.cpp (+2-3)
- (added) llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-comprehensive.s (+56)
- (added) llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-err.s (+5)
- (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+7)
- (modified) llvm/unittests/Support/ELFAttributeParserTest.cpp (+3)
- (modified) llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn (+1)
``````````diff
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",
``````````
</details>
https://github.com/llvm/llvm-project/pull/124276
More information about the llvm-commits
mailing list