[GWP-ASan] Add names to anonymous mappings.

Summary:
Adds names to anonymous GWP-ASan mappings. This helps Android with debugging
via. /proc/maps, as GWP-ASan-allocated mappings are now easily identifyable.

Reviewers: eugenis, cferris

Reviewed By: eugenis

Subscribers: merge_guards_bot, #sanitizers, llvm-commits, cryptoad, pcc

Tags: #sanitizers, #llvm

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

GitOrigin-RevId: e1440f594c1409867c4c037b6cda9cdeccdda8fb
diff --git a/guarded_pool_allocator.cpp b/guarded_pool_allocator.cpp
index 214b5a8..c0a0227 100644
--- a/guarded_pool_allocator.cpp
+++ b/guarded_pool_allocator.cpp
@@ -144,16 +144,18 @@
   size_t PoolBytesRequired =
       PageSize * (1 + MaxSimultaneousAllocations) +
       MaxSimultaneousAllocations * maximumAllocationSize();
-  void *GuardedPoolMemory = mapMemory(PoolBytesRequired);
+  void *GuardedPoolMemory = mapMemory(PoolBytesRequired, kGwpAsanGuardPageName);
 
   size_t BytesRequired = MaxSimultaneousAllocations * sizeof(*Metadata);
-  Metadata = reinterpret_cast<AllocationMetadata *>(mapMemory(BytesRequired));
-  markReadWrite(Metadata, BytesRequired);
+  Metadata = reinterpret_cast<AllocationMetadata *>(
+      mapMemory(BytesRequired, kGwpAsanMetadataName));
+  markReadWrite(Metadata, BytesRequired, kGwpAsanMetadataName);
 
   // Allocate memory and set up the free pages queue.
   BytesRequired = MaxSimultaneousAllocations * sizeof(*FreeSlots);
-  FreeSlots = reinterpret_cast<size_t *>(mapMemory(BytesRequired));
-  markReadWrite(FreeSlots, BytesRequired);
+  FreeSlots = reinterpret_cast<size_t *>(
+      mapMemory(BytesRequired, kGwpAsanFreeSlotsName));
+  markReadWrite(FreeSlots, BytesRequired, kGwpAsanFreeSlotsName);
 
   // Multiply the sample rate by 2 to give a good, fast approximation for (1 /
   // SampleRate) chance of sampling.
@@ -183,16 +185,18 @@
 void GuardedPoolAllocator::uninitTestOnly() {
   if (GuardedPagePool) {
     unmapMemory(reinterpret_cast<void *>(GuardedPagePool),
-                GuardedPagePoolEnd - GuardedPagePool);
+                GuardedPagePoolEnd - GuardedPagePool, kGwpAsanGuardPageName);
     GuardedPagePool = 0;
     GuardedPagePoolEnd = 0;
   }
   if (Metadata) {
-    unmapMemory(Metadata, MaxSimultaneousAllocations * sizeof(*Metadata));
+    unmapMemory(Metadata, MaxSimultaneousAllocations * sizeof(*Metadata),
+                kGwpAsanMetadataName);
     Metadata = nullptr;
   }
   if (FreeSlots) {
-    unmapMemory(FreeSlots, MaxSimultaneousAllocations * sizeof(*FreeSlots));
+    unmapMemory(FreeSlots, MaxSimultaneousAllocations * sizeof(*FreeSlots),
+                kGwpAsanFreeSlotsName);
     FreeSlots = nullptr;
   }
   uninstallSignalHandlers();
@@ -228,7 +232,8 @@
   // If a slot is multiple pages in size, and the allocation takes up a single
   // page, we can improve overflow detection by leaving the unused pages as
   // unmapped.
-  markReadWrite(reinterpret_cast<void *>(getPageAddr(Ptr)), Size);
+  markReadWrite(reinterpret_cast<void *>(getPageAddr(Ptr)), Size,
+                kGwpAsanAliveSlotName);
 
   Meta->RecordAllocation(Ptr, Size, Backtrace);
 
@@ -260,8 +265,8 @@
     Meta->RecordDeallocation(Backtrace);
   }
 
-  markInaccessible(reinterpret_cast<void *>(SlotStart),
-                   maximumAllocationSize());
+  markInaccessible(reinterpret_cast<void *>(SlotStart), maximumAllocationSize(),
+                   kGwpAsanGuardPageName);
 
   // And finally, lock again to release the slot back into the pool.
   ScopedLock L(PoolMutex);
diff --git a/guarded_pool_allocator.h b/guarded_pool_allocator.h
index c9a5e5e..3dfd66a 100644
--- a/guarded_pool_allocator.h
+++ b/guarded_pool_allocator.h
@@ -28,6 +28,9 @@
 // otherwise).
 class GuardedPoolAllocator {
 public:
+  // Name of the GWP-ASan mapping that for `Metadata`.
+  static constexpr const char *kGwpAsanMetadataName = "GWP-ASan Metadata";
+
   static constexpr uint64_t kInvalidThreadID = UINT64_MAX;
 
   enum class Error {
@@ -154,6 +157,14 @@
   static uint64_t getThreadID();
 
 private:
+  // Name of actively-occupied slot mappings.
+  static constexpr const char *kGwpAsanAliveSlotName = "GWP-ASan Alive Slot";
+  // Name of the guard pages. This includes all slots that are not actively in
+  // use (i.e. were never used, or have been free()'d).)
+  static constexpr const char *kGwpAsanGuardPageName = "GWP-ASan Guard Page";
+  // Name of the mapping for `FreeSlots`.
+  static constexpr const char *kGwpAsanFreeSlotsName = "GWP-ASan Metadata";
+
   static constexpr size_t kInvalidSlotID = SIZE_MAX;
 
   // These functions anonymously map memory or change the permissions of mapped
@@ -162,11 +173,13 @@
   // return on error, instead electing to kill the calling process on failure.
   // Note that memory is initially mapped inaccessible. In order for RW
   // mappings, call mapMemory() followed by markReadWrite() on the returned
-  // pointer.
-  void *mapMemory(size_t Size) const;
-  void unmapMemory(void *Addr, size_t Size) const;
-  void markReadWrite(void *Ptr, size_t Size) const;
-  void markInaccessible(void *Ptr, size_t Size) const;
+  // pointer. Each mapping is named on platforms that support it, primarily
+  // Android. This name must be a statically allocated string, as the Android
+  // kernel uses the string pointer directly.
+  void *mapMemory(size_t Size, const char *Name) const;
+  void unmapMemory(void *Ptr, size_t Size, const char *Name) const;
+  void markReadWrite(void *Ptr, size_t Size, const char *Name) const;
+  void markInaccessible(void *Ptr, size_t Size, const char *Name) const;
 
   // Get the page size from the platform-specific implementation. Only needs to
   // be called once, and the result should be cached in PageSize in this class.
diff --git a/platform_specific/guarded_pool_allocator_posix.cpp b/platform_specific/guarded_pool_allocator_posix.cpp
index 0083308..6cdb40c 100644
--- a/platform_specific/guarded_pool_allocator_posix.cpp
+++ b/platform_specific/guarded_pool_allocator_posix.cpp
@@ -17,9 +17,22 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-namespace gwp_asan {
+#ifdef ANDROID
+#include <sys/prctl.h>
+#define PR_SET_VMA 0x53564d41
+#define PR_SET_VMA_ANON_NAME 0
+#endif // ANDROID
 
-void *GuardedPoolAllocator::mapMemory(size_t Size) const {
+void MaybeSetMappingName(void *Mapping, size_t Size, const char *Name) {
+#ifdef ANDROID
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Mapping, Size, Name);
+#endif // ANDROID
+  // Anonymous mapping names are only supported on Android.
+  return;
+}
+
+namespace gwp_asan {
+void *GuardedPoolAllocator::mapMemory(size_t Size, const char *Name) const {
   void *Ptr =
       mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 
@@ -28,29 +41,35 @@
     Printf("  mmap(nullptr, %zu, ...) failed.\n", Size);
     exit(EXIT_FAILURE);
   }
+  MaybeSetMappingName(Ptr, Size, Name);
   return Ptr;
 }
 
-void GuardedPoolAllocator::unmapMemory(void *Addr, size_t Size) const {
-  int Res = munmap(Addr, Size);
+void GuardedPoolAllocator::unmapMemory(void *Ptr, size_t Size,
+                                       const char *Name) const {
+  int Res = munmap(Ptr, Size);
 
   if (Res != 0) {
     Printf("Failed to unmap guarded pool allocator memory, errno: %d\n", errno);
-    Printf("  unmmap(%p, %zu, ...) failed.\n", Addr, Size);
+    Printf("  unmmap(%p, %zu, ...) failed.\n", Ptr, Size);
     exit(EXIT_FAILURE);
   }
+  MaybeSetMappingName(Ptr, Size, Name);
 }
 
-void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size) const {
+void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size,
+                                         const char *Name) const {
   if (mprotect(Ptr, Size, PROT_READ | PROT_WRITE) != 0) {
     Printf("Failed to set guarded pool allocator memory at as RW, errno: %d\n",
            errno);
     Printf("  mprotect(%p, %zu, RW) failed.\n", Ptr, Size);
     exit(EXIT_FAILURE);
   }
+  MaybeSetMappingName(Ptr, Size, Name);
 }
 
-void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size) const {
+void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size,
+                                            const char *Name) const {
   // mmap() a PROT_NONE page over the address to release it to the system, if
   // we used mprotect() here the system would count pages in the quarantine
   // against the RSS.
@@ -62,6 +81,7 @@
     Printf("  mmap(%p, %zu, NONE, ...) failed.\n", Ptr, Size);
     exit(EXIT_FAILURE);
   }
+  MaybeSetMappingName(Ptr, Size, Name);
 }
 
 size_t GuardedPoolAllocator::getPlatformPageSize() {