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 <m...@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 <m...@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: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits