[llvm] [llvm-readobj][ELF][RISCV] Dump .note.gnu.property section contents (PR #125642)
Ming-Yi Lai via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 6 19:40:22 PST 2025
https://github.com/mylai-mtk updated https://github.com/llvm/llvm-project/pull/125642
>From 5e850a228e41578f50e5d181d0068878a0ffe1c3 Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Fri, 24 Jan 2025 17:53:35 +0800
Subject: [PATCH] [llvm-readobj][ELF][RISCV] Dump .note.gnu.property section
contents
RISCV Zicfilp/Zicfiss extensions uses the `.note.gnu.property` section to store
flags indicating the adoption of features based on these extensions. This
patch enables the llvm-readobj/llvm-readelf tools to dump these flags with the
`--notes` flag
---
llvm/include/llvm/BinaryFormat/ELF.h | 8 +++
.../ELF/RISCV/note-gnu-property.yaml | 45 +++++++++++++++
llvm/tools/llvm-readobj/ELFDumper.cpp | 55 ++++++++++++++-----
3 files changed, 95 insertions(+), 13 deletions(-)
create mode 100644 llvm/test/tools/llvm-readobj/ELF/RISCV/note-gnu-property.yaml
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 8853c4a88b0b593..4b826bbf58f177d 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1798,6 +1798,7 @@ enum : unsigned {
GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000,
GNU_PROPERTY_AARCH64_FEATURE_PAUTH = 0xc0000001,
GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002,
+ GNU_PROPERTY_RISCV_FEATURE_1_AND = 0xc0000000,
GNU_PROPERTY_X86_UINT32_OR_LO = 0xc0008000,
GNU_PROPERTY_X86_FEATURE_2_NEEDED = GNU_PROPERTY_X86_UINT32_OR_LO + 1,
@@ -1862,6 +1863,13 @@ enum : unsigned {
GNU_PROPERTY_X86_ISA_1_V4 = 1 << 3,
};
+// RISC-V processor feature bits.
+enum : unsigned {
+ GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED = 1 << 0,
+ GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS = 1 << 1,
+ GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG = 1 << 2,
+};
+
// FreeBSD note types.
enum {
NT_FREEBSD_ABI_TAG = 1,
diff --git a/llvm/test/tools/llvm-readobj/ELF/RISCV/note-gnu-property.yaml b/llvm/test/tools/llvm-readobj/ELF/RISCV/note-gnu-property.yaml
new file mode 100644
index 000000000000000..f87ed762038c111
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/RISCV/note-gnu-property.yaml
@@ -0,0 +1,45 @@
+# RUN: yaml2obj %s -DBITS=32 -DPR_PADDING= -o %t1
+# RUN: llvm-readelf --notes %t1 | FileCheck %s --check-prefix=GNU
+# RUN: llvm-readobj --notes %t1 | FileCheck %s --check-prefix=LLVM
+
+# RUN: yaml2obj %s -DBITS=64 -DPR_PADDING=00000000 -o %t2
+# RUN: llvm-readelf --notes %t2 | FileCheck %s --check-prefix=GNU
+# RUN: llvm-readobj --notes %t2 | FileCheck %s --check-prefix=LLVM
+
+# GNU: Displaying notes found in: .note.gnu.property
+# GNU-NEXT: Owner Data size Description
+# GNU-NEXT: GNU 0x{{([0-9a-z]{8})}} NT_GNU_PROPERTY_TYPE_0 (property note)
+# GNU-NEXT: Properties: RISC-V feature: ZICFILP-unlabeled, ZICFISS, ZICFILP-func-sig
+
+# LLVM: NoteSections [
+# LLVM-NEXT: NoteSection {
+# LLVM-NEXT: Name: .note.gnu.property
+# LLVM-NEXT: Offset:
+# LLVM-NEXT: Size:
+# LLVM-NEXT: Notes [
+# LLVM-NEXT: {
+# LLVM-NEXT: Owner: GNU
+# LLVM-NEXT: Data size:
+# LLVM-NEXT: Type: NT_GNU_PROPERTY_TYPE_0 (property note)
+# LLVM-NEXT: Property [
+# LLVM-NEXT: RISC-V feature: ZICFILP-unlabeled, ZICFISS, ZICFILP-func-sig
+# LLVM-NEXT: ]
+# LLVM-NEXT: }
+# LLVM-NEXT: ]
+# LLVM-NEXT: }
+# LLVM-NEXT: ]
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS[[BITS]]
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+Sections:
+ - Name: .note.gnu.property
+ Type: SHT_NOTE
+ Flags: [ SHF_ALLOC ]
+ Notes:
+ - Name: 'GNU'
+ Desc: '000000c00400000007000000[[PR_PADDING]]'
+ Type: 5 # NT_GNU_PROPERTY_TYPE_0
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index bfca65aad52b443..7806eea6a0c52df 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -5333,7 +5333,8 @@ static bool printAArch64PAuthABICoreInfo(raw_ostream &OS, uint32_t DataSize,
template <typename ELFT>
static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
- ArrayRef<uint8_t> Data) {
+ ArrayRef<uint8_t> Data,
+ typename ELFT::Half EMachine) {
std::string str;
raw_string_ostream OS(str);
uint32_t PrData;
@@ -5366,8 +5367,25 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
return str;
case GNU_PROPERTY_AARCH64_FEATURE_1_AND:
case GNU_PROPERTY_X86_FEATURE_1_AND:
- OS << ((Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) ? "aarch64 feature: "
- : "x86 feature: ");
+ static_assert(GNU_PROPERTY_AARCH64_FEATURE_1_AND ==
+ GNU_PROPERTY_RISCV_FEATURE_1_AND,
+ "GNU_PROPERTY_RISCV_FEATURE_1_AND should equal "
+ "GNU_PROPERTY_AARCH64_FEATURE_1_AND, otherwise "
+ "GNU_PROPERTY_RISCV_FEATURE_1_AND would be skipped!");
+
+ if (EMachine == EM_AARCH64 && Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
+ OS << "aarch64 feature: ";
+ } else if (EMachine == EM_RISCV &&
+ Type == GNU_PROPERTY_RISCV_FEATURE_1_AND) {
+ OS << "RISC-V feature: ";
+ } else if ((EMachine == EM_386 || EMachine == EM_X86_64) &&
+ Type == GNU_PROPERTY_X86_FEATURE_1_AND) {
+ OS << "x86 feature: ";
+ } else {
+ OS << format("<application-specific type 0x%x>", Type);
+ return str;
+ }
+
if (DataSize != 4) {
OS << format("<corrupt length: 0x%x>", DataSize);
return str;
@@ -5377,10 +5395,16 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
OS << "<None>";
return str;
}
- if (Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
+
+ if (EMachine == EM_AARCH64) {
DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI");
DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC");
DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_GCS, "GCS");
+ } else if (EMachine == EM_RISCV) {
+ DumpBit(GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED,
+ "ZICFILP-unlabeled");
+ DumpBit(GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS, "ZICFISS");
+ DumpBit(GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG, "ZICFILP-func-sig");
} else {
DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT");
DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK");
@@ -5441,7 +5465,8 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
}
template <typename ELFT>
-static SmallVector<std::string, 4> getGNUPropertyList(ArrayRef<uint8_t> Arr) {
+static SmallVector<std::string, 4>
+getGNUPropertyList(ArrayRef<uint8_t> Arr, typename ELFT::Half EMachine) {
using Elf_Word = typename ELFT::Word;
SmallVector<std::string, 4> Properties;
@@ -5459,8 +5484,8 @@ static SmallVector<std::string, 4> getGNUPropertyList(ArrayRef<uint8_t> Arr) {
Properties.push_back(str);
break;
}
- Properties.push_back(
- getGNUProperty<ELFT>(Type, DataSize, Arr.take_front(PaddedSize)));
+ Properties.push_back(getGNUProperty<ELFT>(
+ Type, DataSize, Arr.take_front(PaddedSize), EMachine));
Arr = Arr.drop_front(PaddedSize);
}
@@ -5512,7 +5537,7 @@ static StringRef getDescAsStringRef(ArrayRef<uint8_t> Desc) {
template <typename ELFT>
static bool printGNUNote(raw_ostream &OS, uint32_t NoteType,
- ArrayRef<uint8_t> Desc) {
+ ArrayRef<uint8_t> Desc, typename ELFT::Half EMachine) {
// Return true if we were able to pretty-print the note, false otherwise.
switch (NoteType) {
default:
@@ -5534,7 +5559,7 @@ static bool printGNUNote(raw_ostream &OS, uint32_t NoteType,
break;
case ELF::NT_GNU_PROPERTY_TYPE_0:
OS << " Properties:";
- for (const std::string &Property : getGNUPropertyList<ELFT>(Desc))
+ for (const std::string &Property : getGNUPropertyList<ELFT>(Desc, EMachine))
OS << " " << Property << "\n";
break;
}
@@ -6223,10 +6248,12 @@ template <class ELFT> void GNUELFDumper<ELFT>::printNotes() {
else
OS << "Unknown note type: (" << format_hex(Type, 10) << ")\n";
+ const typename ELFT::Half EMachine = this->Obj.getHeader().e_machine;
+
// Print the description, or fallback to printing raw bytes for unknown
// owners/if we fail to pretty-print the contents.
if (Name == "GNU") {
- if (printGNUNote<ELFT>(OS, Type, Descriptor))
+ if (printGNUNote<ELFT>(OS, Type, Descriptor, EMachine))
return Error::success();
} else if (Name == "FreeBSD") {
if (std::optional<FreeBSDNote> N =
@@ -7913,7 +7940,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printAddrsig() {
template <typename ELFT>
static bool printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
- ScopedPrinter &W) {
+ ScopedPrinter &W,
+ typename ELFT::Half EMachine) {
// Return true if we were able to pretty-print the note, false otherwise.
switch (NoteType) {
default:
@@ -7938,7 +7966,7 @@ static bool printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
break;
case ELF::NT_GNU_PROPERTY_TYPE_0:
ListScope D(W, "Property");
- for (const std::string &Property : getGNUPropertyList<ELFT>(Desc))
+ for (const std::string &Property : getGNUPropertyList<ELFT>(Desc, EMachine))
W.printString(Property);
break;
}
@@ -8057,10 +8085,11 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() {
W.printString("Type",
"Unknown (" + to_string(format_hex(Type, 10)) + ")");
+ const typename ELFT::Half EMachine = this->Obj.getHeader().e_machine;
// Print the description, or fallback to printing raw bytes for unknown
// owners/if we fail to pretty-print the contents.
if (Name == "GNU") {
- if (printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W))
+ if (printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W, EMachine))
return Error::success();
} else if (Name == "FreeBSD") {
if (std::optional<FreeBSDNote> N =
More information about the llvm-commits
mailing list