[llvm] a4d39d4 - [llvm-readobj] Add --memtag
Mitch Phillips via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 1 11:00:20 PST 2023
Author: Mitch Phillips
Date: 2023-03-01T10:59:59-08:00
New Revision: a4d39d4b69b265ee41b08cd04f5292e3ddb31aeb
URL: https://github.com/llvm/llvm-project/commit/a4d39d4b69b265ee41b08cd04f5292e3ddb31aeb
DIFF: https://github.com/llvm/llvm-project/commit/a4d39d4b69b265ee41b08cd04f5292e3ddb31aeb.diff
LOG: [llvm-readobj] Add --memtag
This adds functionality to readelf/readobj to specifically handle
MTE-related bits, like the AARCH64_MEMTAG_* dynamic entries, and a
decoder for the Android-specific ELF note.
Reviewed By: jhenderson, MaskRay
Differential Revision: https://reviews.llvm.org/D143693
Added:
llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test
Modified:
llvm/docs/CommandGuide/llvm-readelf.rst
llvm/docs/CommandGuide/llvm-readobj.rst
llvm/include/llvm/BinaryFormat/DynamicTags.def
llvm/tools/llvm-readobj/ELFDumper.cpp
llvm/tools/llvm-readobj/ObjDumper.h
llvm/tools/llvm-readobj/Opts.td
llvm/tools/llvm-readobj/llvm-readobj.cpp
Removed:
llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test
################################################################################
diff --git a/llvm/docs/CommandGuide/llvm-readelf.rst b/llvm/docs/CommandGuide/llvm-readelf.rst
index dd4d82190eb55..2ad217cec7ace 100644
--- a/llvm/docs/CommandGuide/llvm-readelf.rst
+++ b/llvm/docs/CommandGuide/llvm-readelf.rst
@@ -116,6 +116,12 @@ OPTIONS
Display the specified section(s) as hexadecimal bytes. ``section`` may be a
section index or section name.
+.. option:: --memtag
+
+ Display information about memory tagging present in the binary. This includes
+ various memtag-specific dynamic entries, decoded global descriptor sections,
+ and decoded Android-specific ELF notes.
+
.. option:: --needed-libs
Display the needed libraries.
diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst
index 6167190f0fa05..cb9232ef5e560 100644
--- a/llvm/docs/CommandGuide/llvm-readobj.rst
+++ b/llvm/docs/CommandGuide/llvm-readobj.rst
@@ -79,6 +79,12 @@ file formats.
Display the specified section(s) as hexadecimal bytes. ``section`` may be a
section index or section name.
+ .. option:: --memtag
+
+ Display information about memory tagging present in the binary. This includes
+ various memtag-specific dynamic entries, decoded global descriptor sections,
+ and decoded Android-specific ELF notes.
+
.. option:: --needed-libs
Display the needed libraries.
@@ -208,6 +214,12 @@ The following options are implemented only for the ELF file format.
Display the hash table for dynamic symbols.
+.. option:: --memtag
+
+ Display information about memory tagging present in the binary. This includes
+ various dynamic entries, decoded global descriptor sections, and decoded
+ Android-specific ELF notes.
+
.. option:: --notes, -n
Display all notes.
diff --git a/llvm/include/llvm/BinaryFormat/DynamicTags.def b/llvm/include/llvm/BinaryFormat/DynamicTags.def
index ae25ec53813c7..7bb248c006c14 100644
--- a/llvm/include/llvm/BinaryFormat/DynamicTags.def
+++ b/llvm/include/llvm/BinaryFormat/DynamicTags.def
@@ -126,6 +126,11 @@ DYNAMIC_TAG(VERNEEDNUM, 0X6FFFFFFF) // The number of entries in DT_VERNEED.
AARCH64_DYNAMIC_TAG(AARCH64_BTI_PLT, 0x70000001)
AARCH64_DYNAMIC_TAG(AARCH64_PAC_PLT, 0x70000003)
AARCH64_DYNAMIC_TAG(AARCH64_VARIANT_PCS, 0x70000005)
+AARCH64_DYNAMIC_TAG(AARCH64_MEMTAG_MODE, 0x70000009)
+AARCH64_DYNAMIC_TAG(AARCH64_MEMTAG_HEAP, 0x7000000b)
+AARCH64_DYNAMIC_TAG(AARCH64_MEMTAG_STACK, 0x7000000c)
+AARCH64_DYNAMIC_TAG(AARCH64_MEMTAG_GLOBALS, 0x7000000d)
+AARCH64_DYNAMIC_TAG(AARCH64_MEMTAG_GLOBALSSZ, 0x7000000f)
// Hexagon specific dynamic table entries
HEXAGON_DYNAMIC_TAG(HEXAGON_SYMSZ, 0x70000000)
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test
new file mode 100644
index 0000000000000..107aafc571b01
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test
@@ -0,0 +1,220 @@
+# RUN: yaml2obj -D DESC='0d000000' -D MODE=1 -D HEAP=1 -D STACK=1 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,HEAP,STACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,HEAP,STACK
+
+# RUN: yaml2obj -D DESC='0e000000' -D MODE=0 -D HEAP=1 -D STACK=1 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,HEAP,STACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,HEAP,STACK
+
+# RUN: yaml2obj -D DESC='05000000' -D MODE=1 -D HEAP=1 -D STACK=0 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,HEAP,NOSTACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,HEAP,NOSTACK
+
+# RUN: yaml2obj -D DESC='06000000' -D MODE=0 -D HEAP=1 -D STACK=0 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,HEAP,NOSTACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,HEAP,NOSTACK
+
+# RUN: yaml2obj -D DESC='09000000' -D MODE=1 -D HEAP=0 -D STACK=1 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,NOHEAP,STACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,NOHEAP,STACK
+
+# RUN: yaml2obj -D DESC='0a000000' -D MODE=0 -D HEAP=0 -D STACK=1 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,NOHEAP,STACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,NOHEAP,STACK
+
+# RUN: yaml2obj -D DESC='03000000' -D MODE=2 -D HEAP=0 -D STACK=0 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,UNKNOWN,NOHEAP,NOSTACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,UNKNOWN,NOHEAP,NOSTACK
+
+# RUN: yaml2obj -D DESC='00000000' -D MODE=2 -D HEAP=0 -D STACK=0 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-OK,NONE,NOHEAP,NOSTACK
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,NONE,NOHEAP,NOSTACK
+
+# RUN: yaml2obj -D DESC='""' -D MODE=2 -D HEAP=2 -D STACK=2 %s -o %t
+# RUN: llvm-readelf --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=GNU,GNU-BAD,INVALID
+# RUN: llvm-readobj --notes --dynamic --memtag %t | FileCheck %s --check-prefixes=LLVM,LLVM-BAD,INVALID
+
+# LLVM: DynamicSection [ (6 entries)
+# LLVM: Tag Type Name/Value
+# GNU: Dynamic section
+# GNU-SAME: contains 6 entries
+
+# ASYNC: 0x0000000070000009
+# ASYNC-SAME: AARCH64_MEMTAG_MODE
+# ASYNC-SAME: Asynchronous (1)
+
+# SYNC: 0x0000000070000009
+# SYNC-SAME: AARCH64_MEMTAG_MODE
+# SYNC-SAME: Synchronous (0)
+
+# UNKNOWN: 0x0000000070000009
+# UNKNOWN-SAME: AARCH64_MEMTAG_MODE
+# UNKNOWN-SAME: Unknown (2)
+
+# INVALID: 0x0000000070000009
+# INVALID-SAME: AARCH64_MEMTAG_MODE
+# INVALID-SAME: Unknown (2)
+
+# HEAP: 0x000000007000000{{[bB]}}
+# HEAP-SAME: AARCH64_MEMTAG_HEAP
+# HEAP-SAME: Enabled (1)
+
+# NOHEAP: 0x000000007000000{{[bB]}}
+# NOHEAP-SAME: AARCH64_MEMTAG_HEAP
+# NOHEAP-SAME: Disabled (0)
+
+# INVALID: 0x000000007000000{{[bB]}}
+# INVALID-SAME: AARCH64_MEMTAG_HEAP
+# INVALID-SAME: Unknown (2)
+
+# STACK: 0x000000007000000{{[cC]}}
+# STACK-SAME: AARCH64_MEMTAG_STACK
+# STACK-SAME: Enabled (1)
+
+# NOSTACK: 0x000000007000000{{[cC]}}
+# NOSTACK-SAME: AARCH64_MEMTAG_STACK
+# NOSTACK-SAME: Disabled (0)
+
+# INVALID: 0x000000007000000{{[cC]}}
+# INVALID-SAME: AARCH64_MEMTAG_STACK
+# INVALID-SAME: Unknown (2)
+
+# LLVM: 0x000000007000000D AARCH64_MEMTAG_GLOBALS 0xdeadbeef
+# LLVM: 0x000000007000000F AARCH64_MEMTAG_GLOBALSSZ 1234
+
+# GNU: 0x000000007000000d (AARCH64_MEMTAG_GLOBALS) 0xdeadbeef0
+# GNU: 0x000000007000000f (AARCH64_MEMTAG_GLOBALSSZ) 1234
+
+# GNU: Displaying notes found in: .note.android.memtag
+# GNU-NEXT: Owner Data size Description
+# GNU-OK-NEXT: Android 0x00000004 NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
+# GNU-BAD-NEXT: Android 0x00000000 NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
+
+# LLVM: Notes [
+# LLVM-NEXT: NoteSection {
+# LLVM-NEXT: Name: .note.android.memtag
+# LLVM-NEXT: Offset: 0x40
+# LLVM-OK-NEXT: Size: 0x18
+# LLVM-BAD-NEXT: Size: 0x14
+# LLVM-NEXT: Note {
+# LLVM-NEXT: Owner: Android
+# LLVM-OK-NEXT: Data size: 0x4
+# LLVM-BAD-NEXT: Data size: 0x0
+# LLVM-NEXT: Type: NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
+
+## Hint: Also used for the GNU tests.
+# INVALID-NEXT: Invalid .note.android.memtag
+# NONE-NEXT: Tagging Mode: NONE
+# ASYNC-NEXT: Tagging Mode: ASYNC
+# SYNC-NEXT: Tagging Mode: SYNC
+# UNKNOWN-NEXT: Tagging Mode: Unknown (3)
+# HEAP-NEXT: Heap: Enabled
+# NOHEAP-NEXT: Heap: Disabled
+# STACK-NEXT: Stack: Enabled
+# NOSTACK-NEXT: Stack: Disabled
+
+# LLVM-NEXT: }
+# LLVM-NEXT: }
+# LLVM-NEXT: ]
+
+# LLVM: Memtag Dynamic Entries
+# GNU: Memtag Dynamic Entries
+
+## Ensure that for --memtag, we don't print irrelevant dynamic entries.
+# LLVM-NOT: DT_INIT_ARRAY
+# GNU-NOT: DT_INIT_ARRAY
+
+# SYNC: AARCH64_MEMTAG_MODE: Synchronous (0)
+# ASYNC: AARCH64_MEMTAG_MODE: Asynchronous (1)
+# HEAP: AARCH64_MEMTAG_HEAP: Enabled (1)
+# NOHEAP: AARCH64_MEMTAG_HEAP: Disabled (0)
+# STACK: AARCH64_MEMTAG_STACK: Enabled (1)
+# NOSTACK: AARCH64_MEMTAG_STACK: Disabled (0)
+# LLVM: AARCH64_MEMTAG_GLOBALS: 0xdeadbeef0
+# GNU: AARCH64_MEMTAG_GLOBALS: 0xdeadbeef0
+# LLVM: AARCH64_MEMTAG_GLOBALSSZ: 1234
+# GNU: AARCH64_MEMTAG_GLOBALSSZ: 1234
+
+# LLVM-OK: Memtag Android Note
+# GNU-OK: Memtag Android Note
+
+# SYNC: Tagging Mode: SYNC
+# ASYNC: Tagging Mode: ASYNC
+# UNKNOWN: Tagging Mode: Unknown (3)
+# HEAP: Heap: Enabled
+# NOHEAP: Heap: Disabled
+# STACK: Stack: Enabled
+# NOSTACK: Stack: Disabled
+
+#########################################
+## --docnum=1 (default)
+#########################################
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_AARCH64
+Sections:
+ - Name: .note.android.memtag
+ Type: SHT_NOTE
+ Notes:
+ - Name: Android
+ Type: NT_ANDROID_TYPE_MEMTAG
+ Desc: [[DESC]]
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Entries:
+ - Tag: DT_AARCH64_MEMTAG_MODE
+ Value: [[MODE]]
+ - Tag: DT_AARCH64_MEMTAG_HEAP
+ Value: [[HEAP]]
+ - Tag: DT_AARCH64_MEMTAG_STACK
+ Value: [[STACK]]
+ - Tag: DT_AARCH64_MEMTAG_GLOBALS
+ Value: 0xdeadbeef0
+ - Tag: DT_AARCH64_MEMTAG_GLOBALSSZ
+ Value: 1234
+ - Tag: DT_INIT_ARRAY
+ Value: 0x1000
+
+# RUN: yaml2obj --docnum=2 %s -o %t
+# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=MISSING-GNU
+# RUN: llvm-readobj --memtag %t | FileCheck %s --check-prefixes=MISSING-LLVM
+
+## Ensure the header is printed, even if there's no relevant dynamic entries,
+## and that nothing else is printed.
+
+# MISSING-GNU-NOT: {{.}}
+# MISSING-GNU: Memtag Dynamic Entries:
+# MISSING-GNU-NEXT: < none found >
+# MISSING-GNU-NOT: {{.}}
+
+# MISSING-LLVM-NOT: {{.}}
+# MISSING-LLVM: File: {{.*}}memtag.test
+# MISSING-LLVM-NEXT: Format: elf64-littleaarch64
+# MISSING-LLVM-NEXT: Arch: aarch64
+# MISSING-LLVM-NEXT: AddressSize: 64bit
+# MISSING-LLVM-NEXT: LoadName:
+# MISSING-LLVM-NEXT: Memtag Dynamic Entries: [
+# MISSING-LLVM-NEXT: < none found >
+# MISSING-LLVM-NEXT: ]
+# MISSING-LLVM-NOT: {{.}}
+
+#########################################
+## --docnum=2
+#########################################
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_AARCH64
+Sections:
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Entries:
+ - Tag: DT_INIT_ARRAY
+ Value: 0x1000
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test b/llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test
deleted file mode 100644
index c500e7d8179a5..0000000000000
--- a/llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test
+++ /dev/null
@@ -1,80 +0,0 @@
-# RUN: yaml2obj -D DESC='0d000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,HEAP,STACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,HEAP,STACK
-
-# RUN: yaml2obj -D DESC='0e000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,HEAP,STACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,HEAP,STACK
-
-# RUN: yaml2obj -D DESC='05000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,HEAP,NOSTACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,HEAP,NOSTACK
-
-# RUN: yaml2obj -D DESC='06000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,HEAP,NOSTACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,HEAP,NOSTACK
-
-# RUN: yaml2obj -D DESC='09000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,ASYNC,NOHEAP,STACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,ASYNC,NOHEAP,STACK
-
-# RUN: yaml2obj -D DESC='0a000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,SYNC,NOHEAP,STACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,SYNC,NOHEAP,STACK
-
-# RUN: yaml2obj -D DESC='03000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,UNKNOWN,NOHEAP,NOSTACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,UNKNOWN,NOHEAP,NOSTACK
-
-# RUN: yaml2obj -D DESC='00000000' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-OK,NONE,NOHEAP,NOSTACK
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-OK,NONE,NOHEAP,NOSTACK
-
-# RUN: yaml2obj -D DESC='""' %s -o %t
-# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU,GNU-BAD,INVALID
-# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM,LLVM-BAD,INVALID
-
-# GNU: Displaying notes found in: .note.android.memtag
-# GNU-NEXT: Owner Data size Description
-# GNU-OK-NEXT: Android 0x00000004 NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
-# GNU-BAD-NEXT: Android 0x00000000 NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
-
-# LLVM: Notes [
-# LLVM-NEXT: NoteSection {
-# LLVM-NEXT: Name: .note.android.memtag
-# LLVM-NEXT: Offset: 0x40
-# LLVM-OK-NEXT: Size: 0x18
-# LLVM-BAD-NEXT: Size: 0x14
-# LLVM-NEXT: Note {
-# LLVM-NEXT: Owner: Android
-# LLVM-OK-NEXT: Data size: 0x4
-# LLVM-BAD-NEXT: Data size: 0x0
-# LLVM-NEXT: Type: NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)
-
-## Hint: Also used for the GNU tests.
-# INVALID-NEXT: Invalid .note.android.memtag
-# NONE-NEXT: Tagging Mode: NONE
-# ASYNC-NEXT: Tagging Mode: ASYNC
-# SYNC-NEXT: Tagging Mode: SYNC
-# UNKNOWN-NEXT: Tagging Mode: Unknown (3)
-# HEAP-NEXT: Heap: Enabled
-# NOHEAP-NEXT: Heap: Disabled
-# STACK-NEXT: Stack: Enabled
-# NOSTACK-NEXT: Stack: Disabled
-
-# LLVM-NEXT: }
-# LLVM-NEXT: }
-# LLVM-NEXT: ]
-
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_DYN
-Sections:
- - Name: .note.android.memtag
- Type: SHT_NOTE
- Notes:
- - Name: Android
- Type: NT_ANDROID_TYPE_MEMTAG
- Desc: [[DESC]]
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 45fff0cc4a762..5615d7579a074 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -220,6 +220,7 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
void printVersionInfo() override;
void printArchSpecificInfo() override;
void printStackMap() const override;
+ void printMemtag() override;
const object::ELFObjectFile<ELFT> &getElfObject() const { return ObjF; };
@@ -296,6 +297,10 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
+ virtual void printMemtag(
+ const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
+ const ArrayRef<uint8_t> AndroidNoteDesc) = 0;
+
Expected<ArrayRef<Elf_Versym>>
getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
StringRef *StrTab, const Elf_Shdr **SymTabSec) const;
@@ -577,6 +582,9 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
void printNotes() override;
void printELFLinkerOptions() override;
void printStackSizes() override;
+ void printMemtag(
+ const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
+ const ArrayRef<uint8_t> AndroidNoteDesc) override;
private:
void printHashHistogram(const Elf_Hash &HashTable);
@@ -681,6 +689,9 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
void printNotes() override;
void printELFLinkerOptions() override;
void printStackSizes() override;
+ void printMemtag(
+ const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
+ const ArrayRef<uint8_t> AndroidNoteDesc) override;
private:
void printRelrReloc(const Elf_Relr &R) override;
@@ -2251,7 +2262,29 @@ std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type,
case DT_AARCH64_BTI_PLT:
case DT_AARCH64_PAC_PLT:
case DT_AARCH64_VARIANT_PCS:
+ case DT_AARCH64_MEMTAG_GLOBALSSZ:
return std::to_string(Value);
+ case DT_AARCH64_MEMTAG_MODE:
+ switch (Value) {
+ case 0:
+ return "Synchronous (0)";
+ case 1:
+ return "Asynchronous (1)";
+ default:
+ return (Twine("Unknown (") + Twine(Value) + ")").str();
+ }
+ case DT_AARCH64_MEMTAG_HEAP:
+ case DT_AARCH64_MEMTAG_STACK:
+ switch (Value) {
+ case 0:
+ return "Disabled (0)";
+ case 1:
+ return "Enabled (1)";
+ default:
+ return (Twine("Unknown (") + Twine(Value) + ")").str();
+ }
+ case DT_AARCH64_MEMTAG_GLOBALS:
+ return (Twine("0x") + utohexstr(Value, /*LowerCase=*/true)).str();
default:
break;
}
@@ -5198,6 +5231,23 @@ static bool printAndroidNote(raw_ostream &OS, uint32_t NoteType,
return true;
}
+template <class ELFT>
+void GNUELFDumper<ELFT>::printMemtag(
+ const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
+ const ArrayRef<uint8_t> AndroidNoteDesc) {
+ OS << "Memtag Dynamic Entries:\n";
+ if (DynamicEntries.empty())
+ OS << " < none found >\n";
+ for (const auto &DynamicEntryKV : DynamicEntries)
+ OS << " " << DynamicEntryKV.first << ": " << DynamicEntryKV.second
+ << "\n";
+
+ if (!AndroidNoteDesc.empty()) {
+ OS << "Memtag Android Note:\n";
+ printAndroidNote(OS, ELF::NT_ANDROID_TYPE_MEMTAG, AndroidNoteDesc);
+ }
+}
+
template <typename ELFT>
static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType,
ArrayRef<uint8_t> Desc) {
@@ -5681,7 +5731,7 @@ StringRef getNoteTypeName(const typename ELFT::Note &Note, unsigned ELFType) {
}
template <class ELFT>
-static void printNotesHelper(
+static void processNotesHelper(
const ELFDumper<ELFT> &Dumper,
llvm::function_ref<void(std::optional<StringRef>, typename ELFT::Off,
typename ELFT::Addr)>
@@ -5837,7 +5887,42 @@ template <class ELFT> void GNUELFDumper<ELFT>::printNotes() {
return Error::success();
};
- printNotesHelper(*this, PrintHeader, ProcessNote, []() {});
+ processNotesHelper(*this, /*StartNotesFn=*/PrintHeader,
+ /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/[]() {});
+}
+
+template <typename ELFT> void ELFDumper<ELFT>::printMemtag() {
+ if (Obj.getHeader().e_machine != EM_AARCH64) return;
+ std::vector<std::pair<std::string, std::string>> DynamicEntries;
+ for (const typename ELFT::Dyn &Entry : dynamic_table()) {
+ uintX_t Tag = Entry.getTag();
+ switch (Tag) {
+ case DT_AARCH64_MEMTAG_MODE:
+ case DT_AARCH64_MEMTAG_HEAP:
+ case DT_AARCH64_MEMTAG_STACK:
+ case DT_AARCH64_MEMTAG_GLOBALSSZ:
+ case DT_AARCH64_MEMTAG_GLOBALS:
+ DynamicEntries.emplace_back(Obj.getDynamicTagAsString(Tag),
+ getDynamicEntry(Tag, Entry.getVal()));
+ }
+ }
+
+ ArrayRef<uint8_t> AndroidNoteDesc;
+ auto FindAndroidNote = [&](const Elf_Note &Note, bool IsCore) -> Error {
+ if (Note.getName() == "Android" &&
+ Note.getType() == ELF::NT_ANDROID_TYPE_MEMTAG)
+ AndroidNoteDesc = Note.getDesc();
+ return Error::success();
+ };
+
+ processNotesHelper(
+ *this,
+ /*StartNotesFn=*/
+ [](std::optional<StringRef>, const typename ELFT::Off,
+ const typename ELFT::Addr) {},
+ /*ProcessNoteFn=*/FindAndroidNote, /*FinishNotesFn=*/[]() {});
+
+ printMemtag(DynamicEntries, AndroidNoteDesc);
}
template <class ELFT> void GNUELFDumper<ELFT>::printELFLinkerOptions() {
@@ -7216,6 +7301,22 @@ static bool printAndroidNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
return true;
}
+template <class ELFT>
+void LLVMELFDumper<ELFT>::printMemtag(
+ const ArrayRef<std::pair<std::string, std::string>> DynamicEntries,
+ const ArrayRef<uint8_t> AndroidNoteDesc) {
+ ListScope L(W, "Memtag Dynamic Entries:");
+ if (DynamicEntries.empty())
+ W.printString("< none found >");
+ for (const auto &DynamicEntryKV : DynamicEntries)
+ W.printString(DynamicEntryKV.first, DynamicEntryKV.second);
+
+ if (!AndroidNoteDesc.empty()) {
+ ListScope L(W, "Memtag Android Note:");
+ printAndroidNoteLLVMStyle(ELF::NT_ANDROID_TYPE_MEMTAG, AndroidNoteDesc, W);
+ }
+}
+
template <typename ELFT>
static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType,
ArrayRef<uint8_t> Desc,
@@ -7328,7 +7429,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() {
return Error::success();
};
- printNotesHelper(*this, StartNotes, ProcessNote, EndNotes);
+ processNotesHelper(*this, /*StartNotesFn=*/StartNotes,
+ /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/EndNotes);
}
template <class ELFT> void LLVMELFDumper<ELFT>::printELFLinkerOptions() {
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 258d87240984d..921792f886d0e 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -136,6 +136,7 @@ class ObjDumper {
virtual void printStackSizes() {}
virtual void printSectionDetails() {}
virtual void printArchSpecificInfo() {}
+ virtual void printMemtag() {}
// Only implemented for PE/COFF.
virtual void printCOFFImports() { }
diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td
index 4f7b12f95a60a..fec0adb5e6a6b 100644
--- a/llvm/tools/llvm-readobj/Opts.td
+++ b/llvm/tools/llvm-readobj/Opts.td
@@ -55,6 +55,7 @@ def section_groups : FF<"section-groups", "Display section groups">, Group<grp_e
def gnu_hash_table : FF<"gnu-hash-table", "Display the GNU hash table for dynamic symbols">, Group<grp_elf>;
def hash_symbols : FF<"hash-symbols", "Display the dynamic symbols derived from the hash section">, Group<grp_elf>;
def hash_table : FF<"hash-table", "Display .hash section">, Group<grp_elf>;
+def memtag : FF<"memtag", "Display memory tagging metadata (modes, Android notes, global descriptors)">, Group<grp_elf>;
def needed_libs : FF<"needed-libs", "Display the needed libraries">, Group<grp_elf>;
def notes : FF<"notes", "Display notes">, Group<grp_elf>;
def program_headers : FF<"program-headers", "Display program headers">, Group<grp_elf>;
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index aa49e3087a4dc..d72eec04d06ae 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -136,6 +136,7 @@ static bool GnuHashTable;
static bool HashSymbols;
static bool HashTable;
static bool HashHistogram;
+static bool Memtag;
static bool NeededLibraries;
static bool Notes;
static bool ProgramHeaders;
@@ -266,6 +267,7 @@ static void parseOptions(const opt::InputArgList &Args) {
opts::HashSymbols = Args.hasArg(OPT_hash_symbols);
opts::HashTable = Args.hasArg(OPT_hash_table);
opts::HashHistogram = Args.hasArg(OPT_histogram);
+ opts::Memtag = Args.hasArg(OPT_memtag);
opts::NeededLibraries = Args.hasArg(OPT_needed_libs);
opts::Notes = Args.hasArg(OPT_notes);
opts::PrettyPrint = Args.hasArg(OPT_pretty_print);
@@ -473,6 +475,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
Dumper->printAddrsig();
if (opts::Notes)
Dumper->printNotes();
+ if (opts::Memtag)
+ Dumper->printMemtag();
}
if (Obj.isCOFF()) {
if (opts::COFFImports)
@@ -684,6 +688,7 @@ int llvm_readobj_main(int argc, char **argv, const llvm::ToolContext &) {
opts::Addrsig = true;
opts::PrintStackSizes = true;
}
+ opts::Memtag = true;
}
if (opts::Headers) {
More information about the llvm-commits
mailing list