[compiler-rt] Support MemProf on darwin (PR #69640)
Manman Ren via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 19 14:13:15 PDT 2023
https://github.com/manman-ren created https://github.com/llvm/llvm-project/pull/69640
None
>From 86dc0db55bf6aa629639b1beac5c2cf5f39177ec Mon Sep 17 00:00:00 2001
From: Manman Ren <mren at fb.com>
Date: Tue, 10 Oct 2023 20:54:07 -0700
Subject: [PATCH 1/2] memprof support on Darwin
---
clang/lib/Driver/ToolChains/Darwin.cpp | 3 +
clang/test/Driver/darwin-memprof.c | 13 +++++
.../cmake/Modules/AllSupportedArchDefs.cmake | 2 +-
compiler-rt/cmake/config-ix.cmake | 4 +-
compiler-rt/lib/memprof/CMakeLists.txt | 30 +++++++++-
compiler-rt/lib/memprof/memprof_allocator.cpp | 4 ++
compiler-rt/lib/memprof/memprof_allocator.h | 25 +++++---
.../lib/memprof/memprof_interceptors.cpp | 5 +-
.../lib/memprof/memprof_interceptors.h | 6 ++
compiler-rt/lib/memprof/memprof_linux.cpp | 5 +-
compiler-rt/lib/memprof/memprof_mac.cpp | 58 +++++++++++++++++++
.../lib/memprof/memprof_malloc_linux.cpp | 5 +-
.../lib/memprof/memprof_malloc_mac.cpp | 37 ++++++++++++
.../lib/memprof/memprof_new_delete.cpp | 4 ++
compiler-rt/lib/memprof/tests/CMakeLists.txt | 2 +-
compiler-rt/test/memprof/CMakeLists.txt | 2 +-
16 files changed, 184 insertions(+), 21 deletions(-)
create mode 100644 clang/test/Driver/darwin-memprof.c
create mode 100644 compiler-rt/lib/memprof/memprof_mac.cpp
create mode 100644 compiler-rt/lib/memprof/memprof_malloc_mac.cpp
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 15b9889157b903c..e3a7a29e196e435 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1505,6 +1505,9 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
"Static sanitizer runtimes not supported");
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
}
+ if (Sanitize.needsMemProfRt()) {
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "memprof");
+ }
if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
diff --git a/clang/test/Driver/darwin-memprof.c b/clang/test/Driver/darwin-memprof.c
new file mode 100644
index 000000000000000..67746d88823b4a8
--- /dev/null
+++ b/clang/test/Driver/darwin-memprof.c
@@ -0,0 +1,13 @@
+// Test sanitizer link flags on Darwin.
+
+// RUN: %clang -### --target=x86_64-darwin \
+// RUN: -stdlib=platform -fmemory-profile %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MEMPROF %s
+
+// CHECK-MEMPROF: "{{.*}}ld{{(.exe)?}}"
+// CHECK-MEMPROF-NOT: "-lstdc++"
+// CHECK-MEMPROF-NOT: "-lc++"
+// CHECK-MEMPROF: libclang_rt.memprof_osx_dynamic.dylib"
+// CHECK-MEMPROF: "-rpath" "@executable_path"
+// CHECK-MEMPROF: "-rpath" "{{.*}}lib{{.*}}darwin"
+
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index 416777171d2ca75..e34f4d8804ddcb8 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -61,7 +61,7 @@ endif()
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}
${LOONGARCH64})
set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64} ${RISCV64})
-set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64})
+set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64} ${ARM64})
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64}
${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
${RISCV32} ${RISCV64} ${LOONGARCH64})
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index a8e078f1ebc9888..ebf62b2fdb5e8ee 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -446,6 +446,7 @@ if(APPLE)
endif()
set(SANITIZER_COMMON_SUPPORTED_OS osx)
+ set(MEMPROF_SUPPORTED_OS osx)
set(PROFILE_SUPPORTED_OS osx)
set(TSAN_SUPPORTED_OS osx)
set(XRAY_SUPPORTED_OS osx)
@@ -566,6 +567,7 @@ if(APPLE)
message(STATUS "${platform} supported arches: ${DARWIN_${platform}_ARCHS}")
if(DARWIN_${platform}_ARCHS)
list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform})
+ list(APPEND MEMPROF_SUPPORTED_OS ${platform})
list(APPEND PROFILE_SUPPORTED_OS ${platform})
list_intersect(DARWIN_${platform}_TSAN_ARCHS DARWIN_${platform}_ARCHS ALL_TSAN_SUPPORTED_ARCH)
@@ -782,7 +784,7 @@ else()
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND MEMPROF_SUPPORTED_ARCH AND
- OS_NAME MATCHES "Linux")
+ OS_NAME MATCHES "Darwin|Linux")
set(COMPILER_RT_HAS_MEMPROF TRUE)
else()
set(COMPILER_RT_HAS_MEMPROF FALSE)
diff --git a/compiler-rt/lib/memprof/CMakeLists.txt b/compiler-rt/lib/memprof/CMakeLists.txt
index 3f55c2f5e075eed..b8bbcc55da11866 100644
--- a/compiler-rt/lib/memprof/CMakeLists.txt
+++ b/compiler-rt/lib/memprof/CMakeLists.txt
@@ -7,7 +7,9 @@ set(MEMPROF_SOURCES
memprof_interceptors.cpp
memprof_interceptors_memintrinsics.cpp
memprof_linux.cpp
+ memprof_mac.cpp
memprof_malloc_linux.cpp
+ memprof_malloc_mac.cpp
memprof_mibmap.cpp
memprof_posix.cpp
memprof_rawprofile.cpp
@@ -79,7 +81,7 @@ append_list_if(COMPILER_RT_HAS_LIBLOG log MEMPROF_DYNAMIC_LIBS)
# Compile MemProf sources into an object library.
add_compiler_rt_object_libraries(RTMemprof_dynamic
- OS ${SANITIZER_COMMON_SUPPORTED_OS}
+ OS ${MEMPROF_SUPPORTED_OS}
ARCHS ${MEMPROF_SUPPORTED_ARCH}
SOURCES ${MEMPROF_SOURCES} ${MEMPROF_CXX_SOURCES}
ADDITIONAL_HEADERS ${MEMPROF_HEADERS}
@@ -87,6 +89,7 @@ add_compiler_rt_object_libraries(RTMemprof_dynamic
DEFS ${MEMPROF_DYNAMIC_DEFINITIONS}
DEPS ${MEMPROF_DEPS})
+if(NOT APPLE)
add_compiler_rt_object_libraries(RTMemprof
ARCHS ${MEMPROF_SUPPORTED_ARCH}
SOURCES ${MEMPROF_SOURCES}
@@ -116,10 +119,31 @@ add_compiler_rt_object_libraries(RTMemprof_dynamic_version_script_dummy
CFLAGS ${MEMPROF_DYNAMIC_CFLAGS}
DEFS ${MEMPROF_DYNAMIC_DEFINITIONS}
DEPS ${MEMPROF_DEPS})
+endif()
# Build MemProf runtimes shipped with Clang.
add_compiler_rt_component(memprof)
-
+if(APPLE)
+ add_weak_symbols("asan" WEAK_SYMBOL_LINK_FLAGS)
+ add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS)
+ add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS)
+ add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
+ add_weak_symbols("xray" WEAK_SYMBOL_LINK_FLAGS)
+ add_compiler_rt_runtime(clang_rt.memprof
+ SHARED
+ OS ${MEMPROF_SUPPORTED_OS}
+ ARCHS ${MEMPROF_SUPPORTED_ARCH}
+ OBJECT_LIBS RTMemprof_dynamic
+ RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTSanitizerCommonCoverage
+ RTSanitizerCommonSymbolizer
+ CFLAGS ${MEMPROF_DYNAMIC_CFLAGS}
+ LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} # copied from asan, non-APPLE uses MEMPROF_DYNAMIC_LINK_FLAGS
+ DEFS ${MEMPROF_DYNAMIC_DEFINITIONS}
+ PARENT_TARGET memprof)
+else()
# Build separate libraries for each target.
set(MEMPROF_COMMON_RUNTIME_OBJECT_LIBS
@@ -204,7 +228,7 @@ foreach(arch ${MEMPROF_SUPPORTED_ARCH})
add_dependencies(memprof clang_rt.memprof-${arch}-symbols)
endif()
endforeach()
-
+endif()
if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp
index efdfa5ad04a6917..aeaa458ef0d9b4f 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.cpp
+++ b/compiler-rt/lib/memprof/memprof_allocator.cpp
@@ -78,7 +78,11 @@ static int GetCpuId(void) {
// will seg fault as the address of __vdso_getcpu will be null.
if (!memprof_inited)
return -1;
+#if SANITIZER_APPLE
+ return 0;
+#else
return sched_getcpu();
+#endif
}
// Compute the timestamp in ms.
diff --git a/compiler-rt/lib/memprof/memprof_allocator.h b/compiler-rt/lib/memprof/memprof_allocator.h
index 14c61c7325e3f03..3f379825059936b 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.h
+++ b/compiler-rt/lib/memprof/memprof_allocator.h
@@ -20,13 +20,6 @@
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_list.h"
-#if !defined(__x86_64__)
-#error Unsupported platform
-#endif
-#if !SANITIZER_CAN_USE_ALLOCATOR64
-#error Only 64-bit allocator supported
-#endif
-
namespace __memprof {
enum AllocType {
@@ -46,6 +39,7 @@ struct MemprofMapUnmapCallback {
void OnUnmap(uptr p, uptr size) const;
};
+#if SANITIZER_CAN_USE_ALLOCATOR64
constexpr uptr kAllocatorSpace = 0x600000000000ULL;
constexpr uptr kAllocatorSize = 0x40000000000ULL; // 4T.
typedef DefaultSizeClassMap SizeClassMap;
@@ -63,6 +57,23 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name.
template <typename AddressSpaceView>
using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
+#endif
+#if !SANITIZER_CAN_USE_ALLOCATOR64
+typedef CompactSizeClassMap SizeClassMap;
+template <typename AddressSpaceViewTy> struct AP32 {
+ static const uptr kSpaceBeg = 0;
+ static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
+ static const uptr kMetadataSize = 0;
+ typedef __memprof::SizeClassMap SizeClassMap;
+ static const uptr kRegionSizeLog = 20;
+ using AddressSpaceView = AddressSpaceViewTy;
+ typedef MemprofMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+template <typename AddressSpaceView>
+using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
+using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
+#endif
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
diff --git a/compiler-rt/lib/memprof/memprof_interceptors.cpp b/compiler-rt/lib/memprof/memprof_interceptors.cpp
index 8925ec5bbaa3728..35d7621e61dc3f8 100644
--- a/compiler-rt/lib/memprof/memprof_interceptors.cpp
+++ b/compiler-rt/lib/memprof/memprof_interceptors.cpp
@@ -131,6 +131,7 @@ static thread_return_t THREAD_CALLING_CONV memprof_thread_start(void *arg) {
return t->ThreadStart(GetTid(), ¶m->is_registered);
}
+#if !defined(SANITIZER_APPLE)
INTERCEPTOR(int, pthread_create, void *thread, void *attr,
void *(*start_routine)(void *), void *arg) {
EnsureMainThreadIDIsCorrect();
@@ -305,6 +306,7 @@ INTERCEPTOR(long long, atoll, const char *nptr) {
MEMPROF_READ_STRING(nptr, (real_endptr - nptr) + 1);
return result;
}
+#endif
// ---------------------- InitializeMemprofInterceptors ---------------- {{{1
namespace __memprof {
@@ -314,6 +316,7 @@ void InitializeMemprofInterceptors() {
was_called_once = true;
InitializeCommonInterceptors();
+#if !defined(SANITIZER_APPLE)
// Intercept str* functions.
MEMPROF_INTERCEPT_FUNC(strcat);
MEMPROF_INTERCEPT_FUNC(strcpy);
@@ -322,7 +325,6 @@ void InitializeMemprofInterceptors() {
MEMPROF_INTERCEPT_FUNC(strdup);
MEMPROF_INTERCEPT_FUNC(__strdup);
MEMPROF_INTERCEPT_FUNC(index);
-
MEMPROF_INTERCEPT_FUNC(atoi);
MEMPROF_INTERCEPT_FUNC(atol);
MEMPROF_INTERCEPT_FUNC(strtol);
@@ -332,6 +334,7 @@ void InitializeMemprofInterceptors() {
// Intercept threading-related functions
MEMPROF_INTERCEPT_FUNC(pthread_create);
MEMPROF_INTERCEPT_FUNC(pthread_join);
+#endif
InitializePlatformInterceptors();
diff --git a/compiler-rt/lib/memprof/memprof_interceptors.h b/compiler-rt/lib/memprof/memprof_interceptors.h
index 20edef42a5150b5..1021c15aff1183c 100644
--- a/compiler-rt/lib/memprof/memprof_interceptors.h
+++ b/compiler-rt/lib/memprof/memprof_interceptors.h
@@ -40,6 +40,7 @@ DECLARE_REAL(char *, strncpy, char *to, const char *from, uptr size)
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
DECLARE_REAL(char *, strstr, const char *s1, const char *s2)
+#if !SANITIZER_APPLE
#define MEMPROF_INTERCEPT_FUNC(name) \
do { \
if (!INTERCEPT_FUNCTION(name)) \
@@ -56,6 +57,11 @@ DECLARE_REAL(char *, strstr, const char *s1, const char *s2)
VReport(1, "MemProfiler: failed to intercept '%s@@%s' or '%s'\n", #name, \
ver, #name); \
} while (0)
+#endif
+#if SANITIZER_APPLE
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define MEMPROF_INTERCEPT_FUNC(name)
+#endif // SANITIZER_APPLE
#define MEMPROF_INTERCEPTOR_ENTER(ctx, func) \
ctx = 0; \
diff --git a/compiler-rt/lib/memprof/memprof_linux.cpp b/compiler-rt/lib/memprof/memprof_linux.cpp
index fcd927023f5c3de..09122864a1a16b1 100644
--- a/compiler-rt/lib/memprof/memprof_linux.cpp
+++ b/compiler-rt/lib/memprof/memprof_linux.cpp
@@ -12,9 +12,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if !SANITIZER_LINUX
-#error Unsupported OS
-#endif
+#if SANITIZER_LINUX
#include "memprof_interceptors.h"
#include "memprof_internal.h"
@@ -72,3 +70,4 @@ uptr FindDynamicShadowStart() {
void *MemprofDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }
} // namespace __memprof
+#endif
diff --git a/compiler-rt/lib/memprof/memprof_mac.cpp b/compiler-rt/lib/memprof/memprof_mac.cpp
new file mode 100644
index 000000000000000..71439501bb11f50
--- /dev/null
+++ b/compiler-rt/lib/memprof/memprof_mac.cpp
@@ -0,0 +1,58 @@
+//===-- memprof_mac.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemProfiler, a memory profiler.
+//
+// Mac-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_APPLE
+
+#include "memprof_interceptors.h"
+#include "memprof_internal.h"
+#include "memprof_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_freebsd.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <unistd.h>
+#include <unwind.h>
+
+namespace __memprof {
+
+void InitializePlatformInterceptors() {}
+void InitializePlatformExceptionHandlers() {}
+
+// No-op. Mac does not support static linkage anyway.
+void *MemprofDoesNotSupportStaticLinkage() {
+ return 0;
+}
+
+uptr FindDynamicShadowStart() {
+ uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd);
+ return MapDynamicShadow(shadow_size_bytes, SHADOW_SCALE,
+ /*min_shadow_base_alignment*/ 0, kHighMemEnd);
+}
+
+void *MemprofDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }
+
+} // namespace __memprof
+#endif
diff --git a/compiler-rt/lib/memprof/memprof_malloc_linux.cpp b/compiler-rt/lib/memprof/memprof_malloc_linux.cpp
index ef753fcaa4addd8..fc6ee797ddd34fb 100644
--- a/compiler-rt/lib/memprof/memprof_malloc_linux.cpp
+++ b/compiler-rt/lib/memprof/memprof_malloc_linux.cpp
@@ -14,9 +14,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if !SANITIZER_LINUX
-#error Unsupported OS
-#endif
+#if SANITIZER_LINUX
#include "memprof_allocator.h"
#include "memprof_interceptors.h"
@@ -149,3 +147,4 @@ INTERCEPTOR(void, malloc_stats, void) { __memprof_print_accumulated_stats(); }
namespace __memprof {
void ReplaceSystemMalloc() {}
} // namespace __memprof
+#endif
diff --git a/compiler-rt/lib/memprof/memprof_malloc_mac.cpp b/compiler-rt/lib/memprof/memprof_malloc_mac.cpp
new file mode 100644
index 000000000000000..eb3427ba8dbc295
--- /dev/null
+++ b/compiler-rt/lib/memprof/memprof_malloc_mac.cpp
@@ -0,0 +1,37 @@
+//===-- memprof_malloc_mac.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemProfiler, a memory profiler.
+//
+// Mac-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_APPLE
+
+#include "memprof_allocator.h"
+#include "memprof_interceptors.h"
+#include "memprof_internal.h"
+#include "memprof_stack.h"
+#include "sanitizer_common/sanitizer_allocator_checks.h"
+#include "sanitizer_common/sanitizer_allocator_dlsym.h"
+#include "sanitizer_common/sanitizer_errno.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+// ---------------------- Replacement functions ---------------- {{{1
+using namespace __memprof;
+
+struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
+ static bool UseImpl() { return memprof_init_is_running; }
+};
+
+namespace __memprof {
+void ReplaceSystemMalloc() {}
+} // namespace __memprof
+
+#endif
diff --git a/compiler-rt/lib/memprof/memprof_new_delete.cpp b/compiler-rt/lib/memprof/memprof_new_delete.cpp
index cae5de301367abe..312b8e01e8849c3 100644
--- a/compiler-rt/lib/memprof/memprof_new_delete.cpp
+++ b/compiler-rt/lib/memprof/memprof_new_delete.cpp
@@ -43,6 +43,7 @@ enum class align_val_t : size_t {};
ReportOutOfMemory(size, &stack); \
return res;
+#if !SANITIZER_APPLE
CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size) {
OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
@@ -77,6 +78,7 @@ void *operator new[](size_t size, std::align_val_t align,
std::nothrow_t const &) {
OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/);
}
+#endif
#define OPERATOR_DELETE_BODY(type) \
GET_STACK_TRACE_FREE; \
@@ -94,6 +96,7 @@ void *operator new[](size_t size, std::align_val_t align,
GET_STACK_TRACE_FREE; \
memprof_delete(ptr, size, static_cast<uptr>(align), &stack, type);
+#if !SANITIZER_APPLE
CXX_OPERATOR_ATTRIBUTE
void operator delete(void *ptr)NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW); }
CXX_OPERATOR_ATTRIBUTE
@@ -143,3 +146,4 @@ void operator delete[](void *ptr, size_t size,
std::align_val_t align) NOEXCEPT {
OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR);
}
+#endif
diff --git a/compiler-rt/lib/memprof/tests/CMakeLists.txt b/compiler-rt/lib/memprof/tests/CMakeLists.txt
index f812bd1f86ff8fa..5763c0b7107292e 100644
--- a/compiler-rt/lib/memprof/tests/CMakeLists.txt
+++ b/compiler-rt/lib/memprof/tests/CMakeLists.txt
@@ -46,7 +46,7 @@ set(MEMPROF_UNITTEST_LINK_LIBRARIES
${SANITIZER_TEST_CXX_LIBRARIES})
list(APPEND MEMPROF_UNITTEST_LINK_LIBRARIES "dl")
-if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST MEMPROF_SUPPORTED_ARCH)
+if(NOT APPLE AND COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST MEMPROF_SUPPORTED_ARCH)
# MemProf unit tests are only run on the host machine.
set(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH})
diff --git a/compiler-rt/test/memprof/CMakeLists.txt b/compiler-rt/test/memprof/CMakeLists.txt
index 8a29919b177024d..5f68b383de2990b 100644
--- a/compiler-rt/test/memprof/CMakeLists.txt
+++ b/compiler-rt/test/memprof/CMakeLists.txt
@@ -4,7 +4,7 @@ set(MEMPROF_TESTSUITES)
set(MEMPROF_DYNAMIC_TESTSUITES)
macro(get_bits_for_arch arch bits)
- if (${arch} MATCHES "x86_64")
+ if (${arch} MATCHES "x86_64|arm64")
set(${bits} 64)
else()
message(FATAL_ERROR "Unexpected target architecture: ${arch}")
>From 8ce32592e780e693a9378f30237a25629a822897 Mon Sep 17 00:00:00 2001
From: Manman Ren <mren at fb.com>
Date: Wed, 18 Oct 2023 10:36:24 -0700
Subject: [PATCH 2/2] update memprof on darwin
---
compiler-rt/cmake/config-ix.cmake | 2 +
compiler-rt/lib/memprof/memprof_allocator.cpp | 58 ++++++++++++-
compiler-rt/lib/memprof/memprof_allocator.h | 4 +
compiler-rt/lib/memprof/memprof_flags.inc | 2 +
.../lib/memprof/memprof_interceptors.cpp | 2 +
.../lib/memprof/memprof_malloc_mac.cpp | 41 ++++++++-
.../Darwin/asan-symbolize-templated-cxx.cpp | 2 +-
compiler-rt/test/memprof/CMakeLists.txt | 34 ++++----
.../memprof/TestCases/Darwin/memprof_dump.cpp | 83 +++++++++++++++++++
compiler-rt/test/memprof/lit.cfg.py | 2 +-
10 files changed, 209 insertions(+), 21 deletions(-)
create mode 100644 compiler-rt/test/memprof/TestCases/Darwin/memprof_dump.cpp
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index ebf62b2fdb5e8ee..58ca5469f34021e 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -749,8 +749,10 @@ endif()
if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD|SunOS")
set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE)
+ set(COMPILER_RT_MEMPROF_HAS_STATIC_RUNTIME TRUE)
else()
set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME FALSE)
+ set(COMPILER_RT_MEMPROF_HAS_STATIC_RUNTIME TRUE)
endif()
# TODO: Add builtins support.
diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp
index aeaa458ef0d9b4f..1e4891ca2e519fc 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.cpp
+++ b/compiler-rt/lib/memprof/memprof_allocator.cpp
@@ -265,9 +265,12 @@ struct Allocator {
atomic_uint8_t destructing;
atomic_uint8_t constructed;
bool print_text;
+ bool print_binary_refs;
// ------------------- Initialization ------------------------
- explicit Allocator(LinkerInitialized) : print_text(flags()->print_text) {
+ explicit Allocator(LinkerInitialized)
+ : print_text(flags()->print_text),
+ print_binary_refs(flags()->print_binary_refs) {
atomic_store_relaxed(&destructing, 0);
atomic_store_relaxed(&constructed, 1);
}
@@ -283,6 +286,7 @@ struct Allocator {
Print(Value->mib, Key, bool(Arg));
}
+ using SegmentEntry = ::llvm::memprof::SegmentEntry;
void FinishAndWrite() {
if (print_text && common_flags()->print_module_map)
DumpProcessMap();
@@ -290,6 +294,46 @@ struct Allocator {
allocator.ForceLock();
InsertLiveBlocks();
+#if SANITIZER_APPLE
+ if (print_binary_refs) {
+ __sanitizer::ListOfModules List;
+ List.init();
+ ArrayRef<LoadedModule> Modules(List.begin(), List.end());
+ for (const auto &Module : Modules) {
+ for (const auto &Segment : Module.ranges()) {
+ if (true) { // Segment.executable) {
+ SegmentEntry Entry(Segment.beg, Segment.end, Module.base_address());
+ // CHECK(Module.uuid_size() <= MEMPROF_BUILDID_MAX_SIZE);
+ // Entry.BuildIdSize = Module.uuid_size();
+ memcpy(Entry.BuildId, Module.uuid(), Module.uuid_size());
+ // Print out the segment information.
+ Printf(" -\n");
+ Printf("[MemProf] BuildId: ");
+ for (size_t I = 0; I < Module.uuid_size() /*Entry.BuildIdSize*/;
+ I++) {
+ Printf("%02x", Entry.BuildId[I]);
+ }
+ Printf("\n");
+ Printf("[MemProf] BuildIdName: %s\n", Module.full_name());
+ // If it is the main binary, check shadow.
+ Printf("[MemProf] Start: 0x%zx\n", Entry.Start);
+ if (AddrIsInLowMem(Entry.Start)) {
+ for (auto t = Entry.Start & SHADOW_MASK; t < Entry.End;
+ t += MEM_GRANULARITY) {
+ // should not be 64, as it will include the next shadow memory
+ u64 c = GetShadowCount(t, 60);
+ if (c > 0)
+ Printf("[MemProf] Shadow: %p %d\n", (void *)t, c);
+ }
+ }
+ Printf("[MemProf] End: 0x%zx\n", Entry.End);
+ Printf("[MemProf] Offset: 0x%zx\n", Entry.Offset);
+ } else {
+ }
+ }
+ }
+ }
+#endif
if (print_text) {
if (!flags()->print_terse)
Printf("Recorded MIBs (incl. live on exit):\n");
@@ -710,6 +754,18 @@ uptr memprof_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
return usable_size;
}
+uptr memprof_mz_size(const void *ptr) {
+ return instance.AllocationSize(reinterpret_cast<uptr>(ptr));
+}
+
+void memprof_mz_force_lock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
+ instance.ForceLock();
+}
+
+void memprof_mz_force_unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
+ instance.ForceUnlock();
+}
+
} // namespace __memprof
// ---------------------- Interface ---------------- {{{1
diff --git a/compiler-rt/lib/memprof/memprof_allocator.h b/compiler-rt/lib/memprof/memprof_allocator.h
index 3f379825059936b..e55b0e041ffb310 100644
--- a/compiler-rt/lib/memprof/memprof_allocator.h
+++ b/compiler-rt/lib/memprof/memprof_allocator.h
@@ -112,6 +112,10 @@ int memprof_posix_memalign(void **memptr, uptr alignment, uptr size,
BufferedStackTrace *stack);
uptr memprof_malloc_usable_size(const void *ptr, uptr pc, uptr bp);
+uptr memprof_mz_size(const void *ptr);
+void memprof_mz_force_lock();
+void memprof_mz_force_unlock();
+
void PrintInternalAllocatorStats();
} // namespace __memprof
diff --git a/compiler-rt/lib/memprof/memprof_flags.inc b/compiler-rt/lib/memprof/memprof_flags.inc
index ee0760ddc302a61..d0268a705a55d36 100644
--- a/compiler-rt/lib/memprof/memprof_flags.inc
+++ b/compiler-rt/lib/memprof/memprof_flags.inc
@@ -39,3 +39,5 @@ MEMPROF_FLAG(bool, print_text, false,
"If set, prints the heap profile in text format. Else use the raw binary serialization format.")
MEMPROF_FLAG(bool, print_terse, false,
"If set, prints memory profile in a terse format. Only applicable if print_text = true.")
+MEMPROF_FLAG(bool, print_binary_refs, false,
+ "If set, prints the references to binaries.")
diff --git a/compiler-rt/lib/memprof/memprof_interceptors.cpp b/compiler-rt/lib/memprof/memprof_interceptors.cpp
index 35d7621e61dc3f8..231bf2ba2956907 100644
--- a/compiler-rt/lib/memprof/memprof_interceptors.cpp
+++ b/compiler-rt/lib/memprof/memprof_interceptors.cpp
@@ -18,7 +18,9 @@
#include "memprof_stack.h"
#include "memprof_stats.h"
#include "sanitizer_common/sanitizer_libc.h"
+#if SANITIZER_POSIX
#include "sanitizer_common/sanitizer_posix.h"
+#endif
namespace __memprof {
diff --git a/compiler-rt/lib/memprof/memprof_malloc_mac.cpp b/compiler-rt/lib/memprof/memprof_malloc_mac.cpp
index eb3427ba8dbc295..8f3b3d8f601ea3e 100644
--- a/compiler-rt/lib/memprof/memprof_malloc_mac.cpp
+++ b/compiler-rt/lib/memprof/memprof_malloc_mac.cpp
@@ -30,8 +30,43 @@ struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
static bool UseImpl() { return memprof_init_is_running; }
};
-namespace __memprof {
-void ReplaceSystemMalloc() {}
-} // namespace __memprof
+#define COMMON_MALLOC_ZONE_NAME "memprof"
+#define COMMON_MALLOC_ENTER() ENSURE_MEMPROF_INITED()
+#define COMMON_MALLOC_SANITIZER_INITIALIZED memprof_inited
+#define COMMON_MALLOC_FORCE_LOCK() memprof_mz_force_lock()
+#define COMMON_MALLOC_FORCE_UNLOCK() memprof_mz_force_unlock()
+#define COMMON_MALLOC_MEMALIGN(alignment, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = memprof_memalign(alignment, size, &stack, FROM_MALLOC)
+#define COMMON_MALLOC_MALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = memprof_malloc(size, &stack)
+#define COMMON_MALLOC_REALLOC(ptr, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = memprof_realloc(ptr, size, &stack);
+#define COMMON_MALLOC_CALLOC(count, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = memprof_calloc(count, size, &stack);
+#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \
+ GET_STACK_TRACE_MALLOC; \
+ int res = memprof_posix_memalign(memptr, alignment, size, &stack);
+#define COMMON_MALLOC_VALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = memprof_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
+#define COMMON_MALLOC_FREE(ptr) \
+ GET_STACK_TRACE_FREE; \
+ memprof_free(ptr, &stack, FROM_MALLOC);
+#define COMMON_MALLOC_SIZE(ptr) uptr size = memprof_mz_size(ptr);
+#define COMMON_MALLOC_FILL_STATS(zone, stats)
+#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name)
+#define COMMON_MALLOC_NAMESPACE __memprof
+#define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0
+#define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 1
+#include "sanitizer_common/sanitizer_malloc_mac.inc"
+
+namespace {
+
+void mi_extra_init(sanitizer_malloc_introspection_t *mi) {}
+} // namespace
#endif
diff --git a/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-templated-cxx.cpp b/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-templated-cxx.cpp
index 3d726a32b7eaa50..858afebb09d3827 100644
--- a/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-templated-cxx.cpp
+++ b/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-templated-cxx.cpp
@@ -28,7 +28,7 @@ IntW *a;
template <class T>
void writeToA(T new_value) {
- // CHECK: heap-use-after-free
+ // CHECK: heap-use-after-free bar
// NOTE: atos seems to emit the `void` return type here for some reason.
// CHECK: #{{[0-9]+}} 0x{{.+}} in {{(void +)?}}writeToA<IntWrapper<void{{ *}}(int)>{{ *}}>(IntWrapper<void{{ *}}(int)>) asan-symbolize-templated-cxx.cpp:[[@LINE+1]]
*a = new_value;
diff --git a/compiler-rt/test/memprof/CMakeLists.txt b/compiler-rt/test/memprof/CMakeLists.txt
index 5f68b383de2990b..32b7bce97723674 100644
--- a/compiler-rt/test/memprof/CMakeLists.txt
+++ b/compiler-rt/test/memprof/CMakeLists.txt
@@ -36,14 +36,16 @@ foreach(arch ${MEMPROF_TEST_ARCH})
)
list(APPEND MEMPROF_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
- string(TOLOWER "-${arch}-${OS_NAME}-dynamic" MEMPROF_TEST_CONFIG_SUFFIX)
- set(MEMPROF_TEST_DYNAMIC True)
- set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}DynamicConfig)
- configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
- ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py)
- list(APPEND MEMPROF_DYNAMIC_TESTSUITES
- ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+ if(COMPILER_RT_MEMPROF_HAS_STATIC_RUNTIME)
+ string(TOLOWER "-${arch}-${OS_NAME}-dynamic" MEMPROF_TEST_CONFIG_SUFFIX)
+ set(MEMPROF_TEST_DYNAMIC True)
+ set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}DynamicConfig)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py)
+ list(APPEND MEMPROF_DYNAMIC_TESTSUITES
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+ endif()
endforeach()
add_lit_testsuite(check-memprof "Running the MemProfiler tests"
@@ -51,10 +53,12 @@ add_lit_testsuite(check-memprof "Running the MemProfiler tests"
DEPENDS ${MEMPROF_TEST_DEPS})
set_target_properties(check-memprof PROPERTIES FOLDER "Compiler-RT Misc")
-add_lit_testsuite(check-memprof-dynamic
- "Running the MemProfiler tests with dynamic runtime"
- ${MEMPROF_DYNAMIC_TESTSUITES}
- ${exclude_from_check_all.g}
- DEPENDS ${MEMPROF_DYNAMIC_TEST_DEPS})
-set_target_properties(check-memprof-dynamic
- PROPERTIES FOLDER "Compiler-RT Misc")
+if(COMPILER_RT_MEMPROF_HAS_STATIC_RUNTIME)
+ add_lit_testsuite(check-memprof-dynamic
+ "Running the MemProfiler tests with dynamic runtime"
+ ${MEMPROF_DYNAMIC_TESTSUITES}
+ ${exclude_from_check_all.g}
+ DEPENDS ${MEMPROF_DYNAMIC_TEST_DEPS})
+ set_target_properties(check-memprof-dynamic
+ PROPERTIES FOLDER "Compiler-RT Misc")
+endif()
diff --git a/compiler-rt/test/memprof/TestCases/Darwin/memprof_dump.cpp b/compiler-rt/test/memprof/TestCases/Darwin/memprof_dump.cpp
new file mode 100644
index 000000000000000..aa132321c25c610
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/Darwin/memprof_dump.cpp
@@ -0,0 +1,83 @@
+// UNSUPPORTED: ios
+
+// RUN: %clangxx_memprof -O0 %s -o %t
+// RUN: %env_memprof_opts=print_binary_refs=true:print_text=true:log_path=stdout:verbosity=2 %run %t &> %t.log
+// RUN: llvm-nm %t &> %t2.log
+// RUN: cat %t2.log %t.log | FileCheck %s
+
+#include <sanitizer/memprof_interface.h>
+struct __attribute__((visibility("default"))) A {
+ virtual void foo() {}
+};
+
+void test_1(A *p) {
+ // A has default visibility, so no need for type.checked.load.
+ p->foo();
+}
+
+struct __attribute__((visibility("hidden")))
+[[clang::lto_visibility_public]] B {
+ virtual void foo() {}
+};
+
+void test_2(B *p) {
+ // B has public LTO visibility, so no need for type.checked.load.
+ p->foo();
+}
+
+struct __attribute__((visibility("hidden"))) C {
+ virtual void foo() {}
+ virtual void bar() {}
+};
+
+void test_3(C *p) {
+ // C has hidden visibility, so we generate type.checked.load to allow VFE.
+ p->foo();
+}
+
+void test_4(C *p) {
+ // When using type.checked.load, we pass the vtable offset to the intrinsic,
+ // rather than adding it to the pointer with a GEP.
+ p->bar();
+}
+
+void test_5(C *p, void (C::*q)(void)) {
+ // We also use type.checked.load for the virtual side of member function
+ // pointer calls. We use a GEP to calculate the address to load from and pass
+ // 0 as the offset to the intrinsic, because we know that the load must be
+ // from exactly the point marked by one of the function-type metadatas (in
+ // this case "_ZTSM1CFvvE.virtual"). If we passed the offset from the member
+ // function pointer to the intrinsic, this information would be lost. No
+ // codegen changes on the non-virtual side.
+ (p->*q)();
+}
+int main() {
+ C *p = new C;
+ test_3(p);
+ test_4(p);
+ //__memprof_profile_dump(); // dump accesses to p, no dumping to access of the vtable
+ A *a = new A;
+ test_1(a);
+ B *b = new B;
+ test_2(b);
+ __sanitizer_set_report_path("stdout");
+ //__memprof_profile_dump();
+ //__sanitizer_set_report_path(nullptr);
+ return 0; // at exit, dump accesses to a, b
+}
+// CHECK: __ZTV1A
+// CHECK: __ZTV1B
+// 5 sections corresponding to xxx xxx __got __mod_init_func __const
+// vtables are in __const
+// CHECK: BuildIdName:{{.*}}memprof-vtable
+// CHECK: Offset:
+// CHECK: BuildIdName:{{.*}}memprof-vtable
+// CHECK: Offset:
+// CHECK: BuildIdName:{{.*}}memprof-vtable
+// CHECK: Offset:
+// CHECK: BuildIdName:{{.*}}memprof-vtable
+// CHECK: Offset:
+// CHECK: BuildIdName:{{.*}}memprof-vtable
+// CHECK-NEXT: Start:
+// symbol address for __ZTV1B + 0x10 Offset is the address in "Shadow:" (+0x10 to get the vfunc pointer)
+// CHECK-NEXT: Shadow: {{.*}}
diff --git a/compiler-rt/test/memprof/lit.cfg.py b/compiler-rt/test/memprof/lit.cfg.py
index 4e5d7ba405a2019..28446280cab6bc3 100644
--- a/compiler-rt/test/memprof/lit.cfg.py
+++ b/compiler-rt/test/memprof/lit.cfg.py
@@ -106,7 +106,7 @@ def build_invocation(compile_flags):
config.substitutions.append(("%pie", "-pie"))
# Only run the tests on supported OSs.
-if config.host_os not in ["Linux"]:
+if config.host_os not in ["Linux", "Darwin"]:
config.unsupported = True
if not config.parallelism_group:
More information about the llvm-commits
mailing list