[llvm] 73df825 - [MTE] Add NT_ANDROID_TYPE_MEMTAG

Mitch Phillips via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 7 11:29:05 PST 2022


Author: Mitch Phillips
Date: 2022-03-07T11:28:56-08:00
New Revision: 73df82572af394667ef38a7492634de84ced2aaf

URL: https://github.com/llvm/llvm-project/commit/73df82572af394667ef38a7492634de84ced2aaf
DIFF: https://github.com/llvm/llvm-project/commit/73df82572af394667ef38a7492634de84ced2aaf.diff

LOG: [MTE] Add NT_ANDROID_TYPE_MEMTAG

This ELF note is aarch64 and Android-specific. It specifies to the
dynamic loader that specific work should be scheduled to enable MTE
protection of stack and heap regions.

Current synthesis of the ".note.android.memtag" ELF note is done in the
Android build system. We'd like to move that to the compiler, and this
is the first step.

Reviewed By: MaskRay, jhenderson

Differential Revision: https://reviews.llvm.org/D119381

Added: 
    llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-memtag.test
    llvm/test/tools/llvm-readobj/ELF/AArch64/note-android-unknown.test

Modified: 
    llvm/include/llvm/BinaryFormat/ELF.h
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/tools/llvm-readobj/ELFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index b0fe46d2cc016..74bb3205807f0 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1559,6 +1559,31 @@ enum {
   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
index 23831cde61276..9792a9bfdff6b 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -177,6 +177,10 @@ void ScalarEnumerationTraits<ELFYAML::ELF_NT>::enumeration(
   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<Hex32>(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
index 0000000000000..c500e7d8179a5
--- /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
index 0000000000000..3e48086ba6a98
--- /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
index b2945795c0ad7..00295993d7dcc 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -5066,6 +5066,57 @@ static bool printGNUNote(raw_ostream &OS, uint32_t NoteType,
   return true;
 }
 
+using AndroidNoteProperties = std::vector<std::pair<StringRef, std::string>>;
+static AndroidNoteProperties getAndroidNoteProperties(uint32_t NoteType,
+                                                      ArrayRef<uint8_t> 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<uint8_t> 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 <typename ELFT>
 static bool printLLVMOMPOFFLOADNote(raw_ostream &OS, uint32_t NoteType,
                                     ArrayRef<uint8_t> Desc) {
@@ -5425,6 +5476,13 @@ const NoteType LLVMOMPOFFLOADNoteTypes[] = {
      "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 @@ StringRef getNoteTypeName(const typename ELFT::Note &Note, unsigned ELFType) {
     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 @@ template <class ELFT> void GNUELFDumper<ELFT>::printNotes() {
           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 @@ static bool printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
   return true;
 }
 
+static bool printAndroidNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> 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 <typename ELFT>
 static bool printLLVMOMPOFFLOADNoteLLVMStyle(uint32_t NoteType,
                                              ArrayRef<uint8_t> Desc,
@@ -7152,6 +7226,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() {
           return N.takeError();
         }
       }
+    } else if (Name == "Android") {
+      if (printAndroidNoteLLVMStyle(Type, Descriptor, W))
+        return Error::success();
     }
     if (!Descriptor.empty()) {
       W.printBinaryBlock("Description data", Descriptor);


        


More information about the llvm-commits mailing list