[llvm] [readobj][AArch64] Parse AArch64 build attributes (PR #124276)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 24 06:42:48 PST 2025
https://github.com/sivan-shani updated https://github.com/llvm/llvm-project/pull/124276
>From ba91667361d0d6d2841634930d191c5b4920aba3 Mon Sep 17 00:00:00 2001
From: Sivan Shani <sivan.shani at arm.com>
Date: Thu, 23 Jan 2025 18:00:32 +0000
Subject: [PATCH] [readobj][AArch64] Parse AArch64 build attributes
Add support for parsing AArch64 build attributes in llvm-readobj
---
llvm/include/llvm/Object/ELFObjectFile.h | 3 +
.../llvm/Support/AArch64AttributeParser.h | 32 ++++
.../include/llvm/Support/ELFAttributeParser.h | 4 +-
llvm/lib/Support/AArch64AttributeParser.cpp | 153 ++++++++++++++++++
llvm/lib/Support/CMakeLists.txt | 1 +
llvm/lib/Support/ELFAttributeParser.cpp | 5 +-
.../aarch64-build-attributes-comprehensive.s | 56 +++++++
.../AArch64/aarch64-build-attributes-err.s | 5 +
llvm/tools/llvm-readobj/ELFDumper.cpp | 7 +
.../Support/ELFAttributeParserTest.cpp | 3 +
.../gn/secondary/llvm/lib/Support/BUILD.gn | 1 +
11 files changed, 266 insertions(+), 4 deletions(-)
create mode 100644 llvm/include/llvm/Support/AArch64AttributeParser.h
create mode 100644 llvm/lib/Support/AArch64AttributeParser.cpp
create mode 100644 llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-comprehensive.s
create mode 100644 llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-build-attributes-err.s
diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 60c72062a3f6a1..bafc92cafe5395 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -410,6 +410,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;
diff --git a/llvm/include/llvm/Support/AArch64AttributeParser.h b/llvm/include/llvm/Support/AArch64AttributeParser.h
new file mode 100644
index 00000000000000..655cf749d22d27
--- /dev/null
+++ b/llvm/include/llvm/Support/AArch64AttributeParser.h
@@ -0,0 +1,32 @@
+//=== - AArch64AttributeParser.h-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
+//
+//===--------------------------------------------------------------------===//
+
+#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..25f4fd49042826 100644
--- a/llvm/include/llvm/Support/ELFAttributeParser.h
+++ b/llvm/include/llvm/Support/ELFAttributeParser.h
@@ -56,8 +56,10 @@ class ELFAttributeParser {
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",
More information about the llvm-commits
mailing list