13d4bba30STeresa Johnson //===-- memprof_rtl.cpp --------------------------------------------------===// 23d4bba30STeresa Johnson // 33d4bba30STeresa Johnson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 43d4bba30STeresa Johnson // See https://llvm.org/LICENSE.txt for license information. 53d4bba30STeresa Johnson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63d4bba30STeresa Johnson // 73d4bba30STeresa Johnson //===----------------------------------------------------------------------===// 83d4bba30STeresa Johnson // 93d4bba30STeresa Johnson // This file is a part of MemProfiler, a memory profiler. 103d4bba30STeresa Johnson // 113d4bba30STeresa Johnson // Main file of the MemProf run-time library. 123d4bba30STeresa Johnson //===----------------------------------------------------------------------===// 133d4bba30STeresa Johnson 143d4bba30STeresa Johnson #include "memprof_allocator.h" 153d4bba30STeresa Johnson #include "memprof_interceptors.h" 163d4bba30STeresa Johnson #include "memprof_interface_internal.h" 173d4bba30STeresa Johnson #include "memprof_internal.h" 183d4bba30STeresa Johnson #include "memprof_mapping.h" 193d4bba30STeresa Johnson #include "memprof_stack.h" 203d4bba30STeresa Johnson #include "memprof_stats.h" 213d4bba30STeresa Johnson #include "memprof_thread.h" 223d4bba30STeresa Johnson #include "sanitizer_common/sanitizer_atomic.h" 233d4bba30STeresa Johnson #include "sanitizer_common/sanitizer_flags.h" 2411b0506cSFlorian Mayer #include "sanitizer_common/sanitizer_interface_internal.h" 253d4bba30STeresa Johnson #include "sanitizer_common/sanitizer_libc.h" 263d4bba30STeresa Johnson #include "sanitizer_common/sanitizer_symbolizer.h" 27ed4fbe6dSPetr Hosek 28ed4fbe6dSPetr Hosek #include <time.h> 293d4bba30STeresa Johnson 30*2e33ed9eSEllis Hoag SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1]; 31*2e33ed9eSEllis Hoag 323d4bba30STeresa Johnson uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol. 333d4bba30STeresa Johnson 34311801a0STeresa Johnson // Allow the user to specify a profile output file via the binary. 35311801a0STeresa Johnson SANITIZER_WEAK_ATTRIBUTE char __memprof_profile_filename[1]; 36311801a0STeresa Johnson 3730b93db5SMatthew Weingarten // Share ClHistogram compiler flag with runtime. 3830b93db5SMatthew Weingarten SANITIZER_WEAK_ATTRIBUTE bool __memprof_histogram; 3930b93db5SMatthew Weingarten 403d4bba30STeresa Johnson namespace __memprof { 413d4bba30STeresa Johnson 423d4bba30STeresa Johnson static void MemprofDie() { 433d4bba30STeresa Johnson static atomic_uint32_t num_calls; 443d4bba30STeresa Johnson if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) { 453d4bba30STeresa Johnson // Don't die twice - run a busy loop. 463d4bba30STeresa Johnson while (1) { 47d49aaaf4SFlorian Mayer internal_sched_yield(); 483d4bba30STeresa Johnson } 493d4bba30STeresa Johnson } 503d4bba30STeresa Johnson if (common_flags()->print_module_map >= 1) 513d4bba30STeresa Johnson DumpProcessMap(); 523d4bba30STeresa Johnson if (flags()->unmap_shadow_on_exit) { 533d4bba30STeresa Johnson if (kHighShadowEnd) 543d4bba30STeresa Johnson UnmapOrDie((void *)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); 553d4bba30STeresa Johnson } 563d4bba30STeresa Johnson } 573d4bba30STeresa Johnson 589e80add2SEnna1 static void MemprofOnDeadlySignal(int signo, void *siginfo, void *context) { 599e80add2SEnna1 // We call StartReportDeadlySignal not HandleDeadlySignal so we get the 609e80add2SEnna1 // deadly signal message to stderr but no writing to the profile output file 619e80add2SEnna1 StartReportDeadlySignal(); 629e80add2SEnna1 __memprof_profile_dump(); 639e80add2SEnna1 Die(); 649e80add2SEnna1 } 659e80add2SEnna1 662721e27cSDmitry Vyukov static void CheckUnwind() { 672721e27cSDmitry Vyukov GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check); 682721e27cSDmitry Vyukov stack.Print(); 693d4bba30STeresa Johnson } 703d4bba30STeresa Johnson 713d4bba30STeresa Johnson // -------------------------- Globals --------------------- {{{1 723d4bba30STeresa Johnson int memprof_inited; 733d4bba30STeresa Johnson bool memprof_init_is_running; 743d4bba30STeresa Johnson int memprof_timestamp_inited; 753d4bba30STeresa Johnson long memprof_init_timestamp_s; 763d4bba30STeresa Johnson 773d4bba30STeresa Johnson uptr kHighMemEnd; 783d4bba30STeresa Johnson 793d4bba30STeresa Johnson // -------------------------- Run-time entry ------------------- {{{1 803d4bba30STeresa Johnson // exported functions 813d4bba30STeresa Johnson 823d4bba30STeresa Johnson #define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() __memprof::RecordAccess(addr); 8330b93db5SMatthew Weingarten #define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \ 8430b93db5SMatthew Weingarten __memprof::RecordAccessHistogram(addr); 853d4bba30STeresa Johnson 863d4bba30STeresa Johnson #define MEMPROF_MEMORY_ACCESS_CALLBACK(type) \ 873d4bba30STeresa Johnson extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_##type(uptr addr) { \ 883d4bba30STeresa Johnson MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() \ 893d4bba30STeresa Johnson } 903d4bba30STeresa Johnson 9130b93db5SMatthew Weingarten #define MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(type) \ 9230b93db5SMatthew Weingarten extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_hist_##type( \ 9330b93db5SMatthew Weingarten uptr addr) { \ 9430b93db5SMatthew Weingarten MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \ 9530b93db5SMatthew Weingarten } 9630b93db5SMatthew Weingarten 9730b93db5SMatthew Weingarten MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(load) 9830b93db5SMatthew Weingarten MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(store) 9930b93db5SMatthew Weingarten 1003d4bba30STeresa Johnson MEMPROF_MEMORY_ACCESS_CALLBACK(load) 1013d4bba30STeresa Johnson MEMPROF_MEMORY_ACCESS_CALLBACK(store) 1023d4bba30STeresa Johnson 1033d4bba30STeresa Johnson // Force the linker to keep the symbols for various MemProf interface 1043d4bba30STeresa Johnson // functions. We want to keep those in the executable in order to let the 1053d4bba30STeresa Johnson // instrumented dynamic libraries access the symbol even if it is not used by 1063d4bba30STeresa Johnson // the executable itself. This should help if the build system is removing dead 1073d4bba30STeresa Johnson // code at link time. 1083d4bba30STeresa Johnson static NOINLINE void force_interface_symbols() { 1093d4bba30STeresa Johnson volatile int fake_condition = 0; // prevent dead condition elimination. 1103d4bba30STeresa Johnson // clang-format off 1113d4bba30STeresa Johnson switch (fake_condition) { 1123d4bba30STeresa Johnson case 1: __memprof_record_access(nullptr); break; 1133d4bba30STeresa Johnson case 2: __memprof_record_access_range(nullptr, 0); break; 1143d4bba30STeresa Johnson } 1153d4bba30STeresa Johnson // clang-format on 1163d4bba30STeresa Johnson } 1173d4bba30STeresa Johnson 1183d4bba30STeresa Johnson static void memprof_atexit() { 1193d4bba30STeresa Johnson Printf("MemProfiler exit stats:\n"); 1203d4bba30STeresa Johnson __memprof_print_accumulated_stats(); 1213d4bba30STeresa Johnson } 1223d4bba30STeresa Johnson 1233d4bba30STeresa Johnson static void InitializeHighMemEnd() { 1243d4bba30STeresa Johnson kHighMemEnd = GetMaxUserVirtualAddress(); 1253d4bba30STeresa Johnson // Increase kHighMemEnd to make sure it's properly 1263d4bba30STeresa Johnson // aligned together with kHighMemBeg: 1273d4bba30STeresa Johnson kHighMemEnd |= (GetMmapGranularity() << SHADOW_SCALE) - 1; 1283d4bba30STeresa Johnson } 1293d4bba30STeresa Johnson 1303d4bba30STeresa Johnson void PrintAddressSpaceLayout() { 1313d4bba30STeresa Johnson if (kHighMemBeg) { 1323d4bba30STeresa Johnson Printf("|| `[%p, %p]` || HighMem ||\n", (void *)kHighMemBeg, 1333d4bba30STeresa Johnson (void *)kHighMemEnd); 1343d4bba30STeresa Johnson Printf("|| `[%p, %p]` || HighShadow ||\n", (void *)kHighShadowBeg, 1353d4bba30STeresa Johnson (void *)kHighShadowEnd); 1363d4bba30STeresa Johnson } 1373d4bba30STeresa Johnson Printf("|| `[%p, %p]` || ShadowGap ||\n", (void *)kShadowGapBeg, 1383d4bba30STeresa Johnson (void *)kShadowGapEnd); 1393d4bba30STeresa Johnson if (kLowShadowBeg) { 1403d4bba30STeresa Johnson Printf("|| `[%p, %p]` || LowShadow ||\n", (void *)kLowShadowBeg, 1413d4bba30STeresa Johnson (void *)kLowShadowEnd); 1423d4bba30STeresa Johnson Printf("|| `[%p, %p]` || LowMem ||\n", (void *)kLowMemBeg, 1433d4bba30STeresa Johnson (void *)kLowMemEnd); 1443d4bba30STeresa Johnson } 1453d4bba30STeresa Johnson Printf("MemToShadow(shadow): %p %p", (void *)MEM_TO_SHADOW(kLowShadowBeg), 1463d4bba30STeresa Johnson (void *)MEM_TO_SHADOW(kLowShadowEnd)); 1473d4bba30STeresa Johnson if (kHighMemBeg) { 1483d4bba30STeresa Johnson Printf(" %p %p", (void *)MEM_TO_SHADOW(kHighShadowBeg), 1493d4bba30STeresa Johnson (void *)MEM_TO_SHADOW(kHighShadowEnd)); 1503d4bba30STeresa Johnson } 1513d4bba30STeresa Johnson Printf("\n"); 1523d4bba30STeresa Johnson Printf("malloc_context_size=%zu\n", 1533d4bba30STeresa Johnson (uptr)common_flags()->malloc_context_size); 1543d4bba30STeresa Johnson 1553d4bba30STeresa Johnson Printf("SHADOW_SCALE: %d\n", (int)SHADOW_SCALE); 1563d4bba30STeresa Johnson Printf("SHADOW_GRANULARITY: %d\n", (int)SHADOW_GRANULARITY); 1578698160dSVitaly Buka Printf("SHADOW_OFFSET: %p\n", (void *)SHADOW_OFFSET); 1583d4bba30STeresa Johnson CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7); 1593d4bba30STeresa Johnson } 1603d4bba30STeresa Johnson 1613d4bba30STeresa Johnson static void MemprofInitInternal() { 1623d4bba30STeresa Johnson if (LIKELY(memprof_inited)) 1633d4bba30STeresa Johnson return; 1643d4bba30STeresa Johnson SanitizerToolName = "MemProfiler"; 1653d4bba30STeresa Johnson CHECK(!memprof_init_is_running && "MemProf init calls itself!"); 1663d4bba30STeresa Johnson memprof_init_is_running = true; 1673d4bba30STeresa Johnson 1683d4bba30STeresa Johnson CacheBinaryName(); 1693d4bba30STeresa Johnson 1703d4bba30STeresa Johnson // Initialize flags. This must be done early, because most of the 1713d4bba30STeresa Johnson // initialization steps look at flags(). 1723d4bba30STeresa Johnson InitializeFlags(); 1733d4bba30STeresa Johnson 1743d4bba30STeresa Johnson AvoidCVE_2016_2143(); 1753d4bba30STeresa Johnson 1763d4bba30STeresa Johnson SetMallocContextSize(common_flags()->malloc_context_size); 1773d4bba30STeresa Johnson 1783d4bba30STeresa Johnson InitializeHighMemEnd(); 1793d4bba30STeresa Johnson 1803d4bba30STeresa Johnson // Make sure we are not statically linked. 1818443ce56SFangrui Song __interception::DoesNotSupportStaticLinking(); 1823d4bba30STeresa Johnson 1833d4bba30STeresa Johnson // Install tool-specific callbacks in sanitizer_common. 1843d4bba30STeresa Johnson AddDieCallback(MemprofDie); 1852721e27cSDmitry Vyukov SetCheckUnwindCallback(CheckUnwind); 1863d4bba30STeresa Johnson 187311801a0STeresa Johnson // Use profile name specified via the binary itself if it exists, and hasn't 188311801a0STeresa Johnson // been overrriden by a flag at runtime. 189311801a0STeresa Johnson if (__memprof_profile_filename[0] != 0 && !common_flags()->log_path) 190311801a0STeresa Johnson __sanitizer_set_report_path(__memprof_profile_filename); 191311801a0STeresa Johnson else 192311801a0STeresa Johnson __sanitizer_set_report_path(common_flags()->log_path); 193311801a0STeresa Johnson 1943d4bba30STeresa Johnson __sanitizer::InitializePlatformEarly(); 1953d4bba30STeresa Johnson 1963d4bba30STeresa Johnson // Setup internal allocator callback. 1973d4bba30STeresa Johnson SetLowLevelAllocateMinAlignment(SHADOW_GRANULARITY); 1983d4bba30STeresa Johnson 1993d4bba30STeresa Johnson InitializeMemprofInterceptors(); 2003d4bba30STeresa Johnson CheckASLR(); 2013d4bba30STeresa Johnson 2023d4bba30STeresa Johnson ReplaceSystemMalloc(); 2033d4bba30STeresa Johnson 2043d4bba30STeresa Johnson DisableCoreDumperIfNecessary(); 2053d4bba30STeresa Johnson 2063d4bba30STeresa Johnson InitializeShadowMemory(); 2073d4bba30STeresa Johnson 2083d4bba30STeresa Johnson TSDInit(PlatformTSDDtor); 2099e80add2SEnna1 InstallDeadlySignalHandlers(MemprofOnDeadlySignal); 2103d4bba30STeresa Johnson 2113d4bba30STeresa Johnson InitializeAllocator(); 2123d4bba30STeresa Johnson 2133d4bba30STeresa Johnson if (flags()->atexit) 2143d4bba30STeresa Johnson Atexit(memprof_atexit); 2153d4bba30STeresa Johnson 2163d4bba30STeresa Johnson InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); 2173d4bba30STeresa Johnson 2183d4bba30STeresa Johnson // Create main thread. 2193d4bba30STeresa Johnson MemprofThread *main_thread = CreateMainThread(); 2203d4bba30STeresa Johnson CHECK_EQ(0, main_thread->tid()); 2213d4bba30STeresa Johnson force_interface_symbols(); // no-op. 2223d4bba30STeresa Johnson SanitizerInitializeUnwinder(); 2233d4bba30STeresa Johnson 2243d4bba30STeresa Johnson Symbolizer::LateInitialize(); 2253d4bba30STeresa Johnson 2263d4bba30STeresa Johnson VReport(1, "MemProfiler Init done\n"); 2273d4bba30STeresa Johnson 22879ebb638SSnehasish Kumar memprof_init_is_running = false; 22979ebb638SSnehasish Kumar memprof_inited = 1; 2303d4bba30STeresa Johnson } 2313d4bba30STeresa Johnson 2323d4bba30STeresa Johnson void MemprofInitTime() { 2333d4bba30STeresa Johnson if (LIKELY(memprof_timestamp_inited)) 2343d4bba30STeresa Johnson return; 2353d4bba30STeresa Johnson timespec ts; 236d7e71b5dSJeroen Dobbelaere clock_gettime(CLOCK_REALTIME, &ts); 2373d4bba30STeresa Johnson memprof_init_timestamp_s = ts.tv_sec; 2383d4bba30STeresa Johnson memprof_timestamp_inited = 1; 2393d4bba30STeresa Johnson } 2403d4bba30STeresa Johnson 2413d4bba30STeresa Johnson // Initialize as requested from some part of MemProf runtime library 2423d4bba30STeresa Johnson // (interceptors, allocator, etc). 2433d4bba30STeresa Johnson void MemprofInitFromRtl() { MemprofInitInternal(); } 2443d4bba30STeresa Johnson 2453d4bba30STeresa Johnson #if MEMPROF_DYNAMIC 2463d4bba30STeresa Johnson // Initialize runtime in case it's LD_PRELOAD-ed into uninstrumented executable 2473d4bba30STeresa Johnson // (and thus normal initializers from .preinit_array or modules haven't run). 2483d4bba30STeresa Johnson 2493d4bba30STeresa Johnson class MemprofInitializer { 2503d4bba30STeresa Johnson public: 2513d4bba30STeresa Johnson MemprofInitializer() { MemprofInitFromRtl(); } 2523d4bba30STeresa Johnson }; 2533d4bba30STeresa Johnson 2543d4bba30STeresa Johnson static MemprofInitializer memprof_initializer; 2553d4bba30STeresa Johnson #endif // MEMPROF_DYNAMIC 2563d4bba30STeresa Johnson 2573d4bba30STeresa Johnson } // namespace __memprof 2583d4bba30STeresa Johnson 2593d4bba30STeresa Johnson // ---------------------- Interface ---------------- {{{1 2603d4bba30STeresa Johnson using namespace __memprof; 2613d4bba30STeresa Johnson 2623d4bba30STeresa Johnson // Initialize as requested from instrumented application code. 2633d4bba30STeresa Johnson void __memprof_init() { 2643d4bba30STeresa Johnson MemprofInitTime(); 2653d4bba30STeresa Johnson MemprofInitInternal(); 2663d4bba30STeresa Johnson } 2673d4bba30STeresa Johnson 2683d4bba30STeresa Johnson void __memprof_preinit() { MemprofInitInternal(); } 2693d4bba30STeresa Johnson 2703d4bba30STeresa Johnson void __memprof_version_mismatch_check_v1() {} 2713d4bba30STeresa Johnson 2723d4bba30STeresa Johnson void __memprof_record_access(void const volatile *addr) { 2733d4bba30STeresa Johnson __memprof::RecordAccess((uptr)addr); 2743d4bba30STeresa Johnson } 2753d4bba30STeresa Johnson 27630b93db5SMatthew Weingarten void __memprof_record_access_hist(void const volatile *addr) { 27730b93db5SMatthew Weingarten __memprof::RecordAccessHistogram((uptr)addr); 27830b93db5SMatthew Weingarten } 27930b93db5SMatthew Weingarten 2800d8bdc17STeresa Johnson void __memprof_record_access_range(void const volatile *addr, uptr size) { 2810d8bdc17STeresa Johnson for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize) 2820d8bdc17STeresa Johnson __memprof::RecordAccess(a); 2833d4bba30STeresa Johnson } 2843d4bba30STeresa Johnson 28530b93db5SMatthew Weingarten void __memprof_record_access_range_hist(void const volatile *addr, uptr size) { 28630b93db5SMatthew Weingarten for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize) 28730b93db5SMatthew Weingarten __memprof::RecordAccessHistogram(a); 28830b93db5SMatthew Weingarten } 28930b93db5SMatthew Weingarten 2903d4bba30STeresa Johnson extern "C" SANITIZER_INTERFACE_ATTRIBUTE u16 2913d4bba30STeresa Johnson __sanitizer_unaligned_load16(const uu16 *p) { 2923d4bba30STeresa Johnson __memprof_record_access(p); 2933d4bba30STeresa Johnson return *p; 2943d4bba30STeresa Johnson } 2953d4bba30STeresa Johnson 2963d4bba30STeresa Johnson extern "C" SANITIZER_INTERFACE_ATTRIBUTE u32 2973d4bba30STeresa Johnson __sanitizer_unaligned_load32(const uu32 *p) { 2983d4bba30STeresa Johnson __memprof_record_access(p); 2993d4bba30STeresa Johnson return *p; 3003d4bba30STeresa Johnson } 3013d4bba30STeresa Johnson 3023d4bba30STeresa Johnson extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64 3033d4bba30STeresa Johnson __sanitizer_unaligned_load64(const uu64 *p) { 3043d4bba30STeresa Johnson __memprof_record_access(p); 3053d4bba30STeresa Johnson return *p; 3063d4bba30STeresa Johnson } 3073d4bba30STeresa Johnson 3083d4bba30STeresa Johnson extern "C" SANITIZER_INTERFACE_ATTRIBUTE void 3093d4bba30STeresa Johnson __sanitizer_unaligned_store16(uu16 *p, u16 x) { 3103d4bba30STeresa Johnson __memprof_record_access(p); 3113d4bba30STeresa Johnson *p = x; 3123d4bba30STeresa Johnson } 3133d4bba30STeresa Johnson 3143d4bba30STeresa Johnson extern "C" SANITIZER_INTERFACE_ATTRIBUTE void 3153d4bba30STeresa Johnson __sanitizer_unaligned_store32(uu32 *p, u32 x) { 3163d4bba30STeresa Johnson __memprof_record_access(p); 3173d4bba30STeresa Johnson *p = x; 3183d4bba30STeresa Johnson } 3193d4bba30STeresa Johnson 3203d4bba30STeresa Johnson extern "C" SANITIZER_INTERFACE_ATTRIBUTE void 3213d4bba30STeresa Johnson __sanitizer_unaligned_store64(uu64 *p, u64 x) { 3223d4bba30STeresa Johnson __memprof_record_access(p); 3233d4bba30STeresa Johnson *p = x; 3243d4bba30STeresa Johnson } 325