diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1559,6 +1559,31 @@ NT_GNU_PROPERTY_TYPE_0 = 5, }; +// Android note types. +enum { + NT_ANDROID_TYPE_IDENT = 1, + NT_ANDROID_TYPE_KUSER = 3, + NT_ANDROID_TYPE_MEMTAG = 4, +}; + +// Memory tagging values used in NT_ANDROID_TYPE_MEMTAG notes. +enum { + // Enumeration to determine the tagging mode. In Android-land, 'SYNC' means + // running all threads in MTE Synchronous mode, and 'ASYNC' means to use the + // kernels auto-upgrade feature to allow for either MTE Asynchronous, + // Asymmetric, or Synchronous mode. This allows silicon vendors to specify, on + // a per-cpu basis what 'ASYNC' should mean. Generally, the expectation is + // "pick the most precise mode that's very fast". + NT_MEMTAG_LEVEL_NONE = 0, + NT_MEMTAG_LEVEL_ASYNC = 1, + NT_MEMTAG_LEVEL_SYNC = 2, + NT_MEMTAG_LEVEL_MASK = 3, + // Bits indicating whether the loader should prepare for MTE to be enabled on + // the heap and/or stack. + NT_MEMTAG_HEAP = 4, + NT_MEMTAG_STACK = 8, +}; + // Property types used in GNU_PROPERTY_TYPE_0 notes. enum : unsigned { GNU_PROPERTY_STACK_SIZE = 1, diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -177,6 +177,10 @@ ECase(NT_AMD_PAL_METADATA); // AMDGPU specific notes. (Code Object V3) ECase(NT_AMDGPU_METADATA); + // Android specific notes. + ECase(NT_ANDROID_TYPE_IDENT); + ECase(NT_ANDROID_TYPE_KUSER); + ECase(NT_ANDROID_TYPE_MEMTAG); #undef ECase IO.enumFallback(Value); } 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 new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test @@ -0,0 +1,80 @@ +# 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/test/tools/llvm-readobj/ELF/AArch64/note-android-unknown.test b/llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-unknown.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-unknown.test @@ -0,0 +1,37 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readelf --notes %t | FileCheck %s --check-prefixes=GNU +# RUN: llvm-readobj --notes %t | FileCheck %s --check-prefixes=LLVM + +# GNU: Displaying notes found in: .note.android.unknown +# GNU-NEXT: Owner Data size Description +# GNU-NEXT: Android 0x00000005 Unknown note type: (0x00001337) +# GNU-NEXT: description data: 01 23 45 67 89 + +# LLVM: Notes [ +# LLVM-NEXT: NoteSection { +# LLVM-NEXT: Name: .note.android.unknown +# LLVM-NEXT: Offset: 0x40 +# LLVM-NEXT: Size: 0x1C +# LLVM-NEXT: Note { +# LLVM-NEXT: Owner: Android +# LLVM-NEXT: Data size: 0x5 +# LLVM-NEXT: Type: Unknown (0x00001337) +# LLVM-NEXT: Description data ( +# LLVM-NEXT: 0000: 01234567 89 +# LLVM-NEXT: ) +# LLVM-NEXT: } +# LLVM-NEXT: } +# LLVM-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN +Sections: + - Name: .note.android.unknown + Type: SHT_NOTE + Notes: + - Name: Android + Type: 0x1337 + Desc: 0123456789 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 @@ -5066,6 +5066,57 @@ return true; } +using AndroidNoteProperties = std::vector>; +static AndroidNoteProperties getAndroidNoteProperties(uint32_t NoteType, + ArrayRef Desc) { + AndroidNoteProperties Props; + switch (NoteType) { + case ELF::NT_ANDROID_TYPE_MEMTAG: + if (Desc.empty()) { + Props.emplace_back("Invalid .note.android.memtag", ""); + return Props; + } + + switch (Desc[0] & NT_MEMTAG_LEVEL_MASK) { + case NT_MEMTAG_LEVEL_NONE: + Props.emplace_back("Tagging Mode", "NONE"); + break; + case NT_MEMTAG_LEVEL_ASYNC: + Props.emplace_back("Tagging Mode", "ASYNC"); + break; + case NT_MEMTAG_LEVEL_SYNC: + Props.emplace_back("Tagging Mode", "SYNC"); + break; + default: + Props.emplace_back( + "Tagging Mode", + ("Unknown (" + Twine::utohexstr(Desc[0] & NT_MEMTAG_LEVEL_MASK) + ")") + .str()); + break; + } + Props.emplace_back("Heap", + (Desc[0] & NT_MEMTAG_HEAP) ? "Enabled" : "Disabled"); + Props.emplace_back("Stack", + (Desc[0] & NT_MEMTAG_STACK) ? "Enabled" : "Disabled"); + break; + default: + return Props; + } + return Props; +} + +static bool printAndroidNote(raw_ostream &OS, uint32_t NoteType, + ArrayRef Desc) { + // Return true if we were able to pretty-print the note, false otherwise. + AndroidNoteProperties Props = getAndroidNoteProperties(NoteType, Desc); + if (Props.empty()) + return false; + for (const auto &KV : Props) + OS << " " << KV.first << ": " << KV.second << '\n'; + OS << '\n'; + return true; +} + template static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType, ArrayRef Desc) { @@ -5425,6 +5476,13 @@ "NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION (producing toolchain version)"}, }; +const NoteType AndroidNoteTypes[] = { + {ELF::NT_ANDROID_TYPE_IDENT, "NT_ANDROID_TYPE_IDENT"}, + {ELF::NT_ANDROID_TYPE_KUSER, "NT_ANDROID_TYPE_KUSER"}, + {ELF::NT_ANDROID_TYPE_MEMTAG, + "NT_ANDROID_TYPE_MEMTAG (Android memory tagging information)"}, +}; + const NoteType CoreNoteTypes[] = { {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"}, {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"}, @@ -5533,6 +5591,8 @@ return FindNote(AMDGPUNoteTypes); if (Name == "LLVMOMPOFFLOAD") return FindNote(LLVMOMPOFFLOADNoteTypes); + if (Name == "Android") + return FindNote(AndroidNoteTypes); if (ELFType == ELF::ET_CORE) return FindNote(CoreNoteTypes); @@ -5683,6 +5743,9 @@ return NoteOrErr.takeError(); } } + } else if (Name == "Android") { + if (printAndroidNote(OS, Type, Descriptor)) + return Error::success(); } if (!Descriptor.empty()) { OS << " description data:"; @@ -7050,6 +7113,17 @@ return true; } +static bool printAndroidNoteLLVMStyle(uint32_t NoteType, ArrayRef Desc, + ScopedPrinter &W) { + // Return true if we were able to pretty-print the note, false otherwise. + AndroidNoteProperties Props = getAndroidNoteProperties(NoteType, Desc); + if (Props.empty()) + return false; + for (const auto &KV : Props) + W.printString(KV.first, KV.second); + return true; +} + template static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType, ArrayRef Desc, @@ -7152,6 +7226,9 @@ return N.takeError(); } } + } else if (Name == "Android") { + if (printAndroidNoteLLVMStyle(Type, Descriptor, W)) + return Error::success(); } if (!Descriptor.empty()) { W.printBinaryBlock("Description data", Descriptor);