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.
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.
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.
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)
--- /dev/null
+# 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
+++ /dev/null
-# 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]]
void printVersionInfo() override;
void printArchSpecificInfo() override;
void printStackMap() const override;
+ void printMemtag() override;
const object::ELFObjectFile<ELFT> &getElfObject() const { return ObjF; };
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;
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);
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;
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;
}
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) {
}
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)>
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() {
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,
return Error::success();
};
- printNotesHelper(*this, StartNotes, ProcessNote, EndNotes);
+ processNotesHelper(*this, /*StartNotesFn=*/StartNotes,
+ /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/EndNotes);
}
template <class ELFT> void LLVMELFDumper<ELFT>::printELFLinkerOptions() {
virtual void printStackSizes() {}
virtual void printSectionDetails() {}
virtual void printArchSpecificInfo() {}
+ virtual void printMemtag() {}
// Only implemented for PE/COFF.
virtual void printCOFFImports() { }
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>;
static bool HashSymbols;
static bool HashTable;
static bool HashHistogram;
+static bool Memtag;
static bool NeededLibraries;
static bool Notes;
static bool ProgramHeaders;
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);
Dumper->printAddrsig();
if (opts::Notes)
Dumper->printNotes();
+ if (opts::Memtag)
+ Dumper->printMemtag();
}
if (Obj.isCOFF()) {
if (opts::COFFImports)
opts::Addrsig = true;
opts::PrintStackSizes = true;
}
+ opts::Memtag = true;
}
if (opts::Headers) {