-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[sanitizer_common] Implement address sanitizer on AIX: process memory mapping #138537
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
@llvm/pr-subscribers-compiler-rt-sanitizer Author: Jake Egan (jakeegan) ChangesImplement process memory mapping on AIX using Full diff: https://github.com/llvm/llvm-project/pull/138537.diff 4 Files Affected:
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 6e6dfd2f33ebf..c22df5948aca8 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -26,6 +26,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
sanitizer_platform_limits_solaris.cpp
sanitizer_posix.cpp
sanitizer_printf.cpp
+ sanitizer_procmaps_aix.cpp
sanitizer_procmaps_common.cpp
sanitizer_procmaps_bsd.cpp
sanitizer_procmaps_fuchsia.cpp
@@ -109,6 +110,7 @@ set(SANITIZER_IMPL_HEADERS
sancov_flags.h
sancov_flags.inc
sanitizer_addrhashmap.h
+ sanitizer_aix.h
sanitizer_allocator.h
sanitizer_allocator_checks.h
sanitizer_allocator_combined.h
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_aix.h b/compiler-rt/lib/sanitizer_common/sanitizer_aix.h
new file mode 100644
index 0000000000000..80c4dd53db7c0
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_aix.h
@@ -0,0 +1,43 @@
+//===-- sanitizer_aix.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries and
+// provides definitions for AIX-specific functions.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_AIX_H
+#define SANITIZER_AIX_H
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_AIX
+# include "sanitizer_common.h"
+# include "sanitizer_posix.h"
+
+struct prmap;
+typedef struct prmap prmap_t;
+
+namespace __sanitizer {
+
+struct ProcSelfMapsBuff {
+ char *data;
+ uptr mmaped_size;
+ uptr len;
+ prmap_t *mapEnd;
+};
+
+struct MemoryMappingLayoutData {
+ ProcSelfMapsBuff proc_self_maps;
+ const char *current;
+};
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_AIX
+#endif // SANITIZER_AIX_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
index d713ddf847dfb..0dcb8b1eb3046 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
@@ -17,14 +17,15 @@
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_APPLE || SANITIZER_SOLARIS || SANITIZER_HAIKU || \
- SANITIZER_FUCHSIA
-
-#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_fuchsia.h"
-#include "sanitizer_linux.h"
-#include "sanitizer_mac.h"
-#include "sanitizer_mutex.h"
+ SANITIZER_FUCHSIA || SANITIZER_AIX
+
+# include "sanitizer_aix.h"
+# include "sanitizer_common.h"
+# include "sanitizer_fuchsia.h"
+# include "sanitizer_internal_defs.h"
+# include "sanitizer_linux.h"
+# include "sanitizer_mac.h"
+# include "sanitizer_mutex.h"
namespace __sanitizer {
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
new file mode 100644
index 0000000000000..c291f6a608e07
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
@@ -0,0 +1,132 @@
+//===-- sanitizer_procmaps_aix.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (AIX-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_AIX
+# include <assert.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <sys/procfs.h>
+
+# include "sanitizer_common.h"
+# include "sanitizer_file.h"
+# include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+static int qsort_comp(const void *va, const void *vb) {
+ const prmap_t *a = (const prmap_t *)va;
+ const prmap_t *b = (const prmap_t *)vb;
+
+ if (a->pr_vaddr < b->pr_vaddr)
+ return -1;
+
+ if (a->pr_vaddr > b->pr_vaddr)
+ return 1;
+
+ return 0;
+}
+
+static prmap_t *SortProcMapEntries(char *buffer) {
+ prmap_t *begin = (prmap_t *)buffer;
+ prmap_t *mapIter = begin;
+ // The AIX procmap utility detects the end of the array of `prmap`s by finding
+ // an entry where pr_size and pr_vaddr are both zero.
+ while (mapIter->pr_size != 0 || mapIter->pr_vaddr != 0) ++mapIter;
+ prmap_t *end = mapIter;
+
+ size_t count = end - begin;
+ size_t elemSize = sizeof(prmap_t);
+ qsort(begin, count, elemSize, qsort_comp);
+
+ return end;
+}
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
+ uptr pid = internal_getpid();
+ constexpr unsigned BUFFER_SIZE = 128;
+ char filenameBuf[BUFFER_SIZE] = {};
+ internal_snprintf(filenameBuf, BUFFER_SIZE, "/proc/%d/map", pid);
+ if (!ReadFileToBuffer(filenameBuf, &proc_maps->data, &proc_maps->mmaped_size,
+ &proc_maps->len)) {
+ proc_maps->data = nullptr;
+ proc_maps->mmaped_size = 0;
+ proc_maps->len = 0;
+ proc_maps->mapEnd = nullptr;
+ return;
+ }
+
+ proc_maps->mapEnd = SortProcMapEntries(proc_maps->data);
+}
+
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
+ if (Error())
+ return false; // simulate empty maps
+
+ const prmap_t *mapIter = (const prmap_t *)data_.current;
+
+ if (mapIter >= data_.proc_self_maps.mapEnd)
+ return false;
+
+ // Skip the kernel segment.
+ if ((mapIter->pr_mflags & MA_TYPE_MASK) == MA_KERNTEXT)
+ ++mapIter;
+
+ if (mapIter >= data_.proc_self_maps.mapEnd)
+ return false;
+
+ segment->start = (uptr)mapIter->pr_vaddr;
+ segment->end = segment->start + mapIter->pr_size;
+
+ segment->protection = 0;
+ uint32_t flags = mapIter->pr_mflags;
+ if (flags & MA_READ)
+ segment->protection |= kProtectionRead;
+ if (flags & MA_WRITE)
+ segment->protection |= kProtectionWrite;
+ if (flags & MA_EXEC)
+ segment->protection |= kProtectionExecute;
+
+ uint32_t type = mapIter->pr_mflags & MA_TYPE_MASK;
+ if (type == MA_SLIBTEXT || type == MA_PLIBDATA)
+ segment->protection |= kProtectionShared;
+
+ if (segment->filename && mapIter->pr_pathoff) {
+ uptr len;
+ constexpr unsigned BUFFER_SIZE = 128;
+ char objPath[BUFFER_SIZE] = {};
+ // Use path /proc/<pid>/object/<object_id>
+ // TODO: Pass a separate path from mapIter->pr_pathoff to display to the
+ // user.
+ // TODO: Append the archive member name if it exists.
+ internal_snprintf(objPath, BUFFER_SIZE, "/proc/%d/object/%s",
+ internal_getpid(), mapIter->pr_mapname);
+ len = Min((uptr)internal_strlen(objPath), segment->filename_size - 1);
+ internal_strncpy(segment->filename, objPath, len);
+ segment->filename[len] = 0;
+
+ } else if (segment->filename) {
+ segment->filename[0] = 0;
+ }
+
+ assert(mapIter->pr_off == 0 && "expect a zero offset into module.");
+ segment->offset = 0;
+
+ ++mapIter;
+ data_.current = (const char *)mapIter;
+
+ return true;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_AIX
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I didn't look into AIX specifics
Please (7/n) -> issue #
Done for this one. |
I guess I don't mind if you continue counting, if you find it usefull, Just drop #138916 into description. |
Implement process memory mapping on AIX using
sys/procfs.h
. We don't have direct access to the full path in the case of user libraries or executables, so we use the path/proc/<pid>/object/<object_id>
for now.#138916