diff --git a/llvm/docs/CommandGuide/llvm-readelf.rst b/llvm/docs/CommandGuide/llvm-readelf.rst --- a/llvm/docs/CommandGuide/llvm-readelf.rst +++ b/llvm/docs/CommandGuide/llvm-readelf.rst @@ -116,6 +116,12 @@ 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 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 --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -208,6 +208,12 @@ 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 --- a/llvm/include/llvm/BinaryFormat/DynamicTags.def +++ b/llvm/include/llvm/BinaryFormat/DynamicTags.def @@ -126,6 +126,11 @@ 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-missing.test b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag-missing.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag-missing.test @@ -0,0 +1,25 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s +# RUN: llvm-readobj --memtag %t | FileCheck %s + +## Ensure the header is printed, even if there's no relevant dynamic entries. +# CHECK: Memtag Dynamic Entries +# CHECK-NEXT: < none found > + +## Ensure that for --memtag, we don't print irrelevant dynamic entries. +# CHECK-NOT: DT_INIT_ARRAY + +# CHECK-NOT: Memtag Android Note + +--- !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/memtag.test b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test @@ -0,0 +1,176 @@ +# 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 + +--- !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 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 --- 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 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -220,6 +220,7 @@ void printVersionInfo() override; void printArchSpecificInfo() override; void printStackMap() const override; + void printMemtag() override; const object::ELFObjectFile &getElfObject() const { return ObjF; }; @@ -296,6 +297,10 @@ virtual void printMipsGOT(const MipsGOTParser &Parser) = 0; virtual void printMipsPLT(const MipsGOTParser &Parser) = 0; + virtual void printMemtag( + const ArrayRef> &DynamicEntries, + ArrayRef AndroidNoteDesc) = 0; + Expected> getVersionTable(const Elf_Shdr &Sec, ArrayRef *SymTab, StringRef *StrTab, const Elf_Shdr **SymTabSec) const; @@ -577,6 +582,9 @@ void printNotes() override; void printELFLinkerOptions() override; void printStackSizes() override; + void printMemtag( + const ArrayRef> &DynamicEntries, + ArrayRef AndroidNoteDesc) override; private: void printHashHistogram(const Elf_Hash &HashTable); @@ -681,6 +689,9 @@ void printNotes() override; void printELFLinkerOptions() override; void printStackSizes() override; + void printMemtag( + const ArrayRef> &DynamicEntries, + ArrayRef AndroidNoteDesc) override; private: void printRelrReloc(const Elf_Relr &R) override; @@ -2251,7 +2262,29 @@ 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 (") + std::to_string(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 (") + std::to_string(Value) + ")").str(); + } + case DT_AARCH64_MEMTAG_GLOBALS: + return (Twine("0x") + utohexstr(Value, /*LowerCase=*/true)).str(); default: break; } @@ -5198,6 +5231,23 @@ return true; } +template +void GNUELFDumper::printMemtag( + const ArrayRef> &DynamicEntries, + ArrayRef 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 static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType, ArrayRef Desc) { @@ -5681,7 +5731,7 @@ } template -static void printNotesHelper( +static void processNotesHelper( const ELFDumper &Dumper, llvm::function_ref, typename ELFT::Off, typename ELFT::Addr)> @@ -5837,7 +5887,41 @@ return Error::success(); }; - printNotesHelper(*this, PrintHeader, ProcessNote, []() {}); + processNotesHelper(*this, /*StartNotesFn=*/PrintHeader, + /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/[]() {}); +} + +template void ELFDumper::printMemtag() { + std::vector> 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).c_str(), + getDynamicEntry(Tag, Entry.getVal())); + } + } + + ArrayRef 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, const typename ELFT::Off, + const typename ELFT::Addr) {}, + /*ProcessNoteFn=*/FindAndroidNote, /*FinishNotesFn=*/[]() {}); + + printMemtag(DynamicEntries, AndroidNoteDesc); } template void GNUELFDumper::printELFLinkerOptions() { @@ -7216,6 +7300,22 @@ return true; } +template +void LLVMELFDumper::printMemtag( + const ArrayRef> &DynamicEntries, + ArrayRef 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 static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType, ArrayRef Desc, @@ -7328,7 +7428,8 @@ return Error::success(); }; - printNotesHelper(*this, StartNotes, ProcessNote, EndNotes); + processNotesHelper(*this, /*StartNotesFn=*/StartNotes, + /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/EndNotes); } template void LLVMELFDumper::printELFLinkerOptions() { diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -136,6 +136,7 @@ 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 --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -55,6 +55,7 @@ def gnu_hash_table : FF<"gnu-hash-table", "Display the GNU hash table for dynamic symbols">, Group; def hash_symbols : FF<"hash-symbols", "Display the dynamic symbols derived from the hash section">, Group; def hash_table : FF<"hash-table", "Display .hash section">, Group; +def memtag : FF<"memtag", "Display memory tagging metadata (modes, Android notes, global descriptors)">, Group; def needed_libs : FF<"needed-libs", "Display the needed libraries">, Group; def notes : FF<"notes", "Display notes">, Group; def program_headers : FF<"program-headers", "Display program headers">, Group; diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -135,6 +135,7 @@ static bool HashSymbols; static bool HashTable; static bool HashHistogram; +static bool Memtag; static bool NeededLibraries; static bool Notes; static bool ProgramHeaders; @@ -265,6 +266,7 @@ 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); @@ -472,6 +474,8 @@ Dumper->printAddrsig(); if (opts::Notes) Dumper->printNotes(); + if (opts::Memtag) + Dumper->printMemtag(); } if (Obj.isCOFF()) { if (opts::COFFImports) @@ -683,6 +687,7 @@ opts::Addrsig = true; opts::PrintStackSizes = true; } + opts::Memtag = true; } if (opts::Headers) {