Path: blob/main/contrib/llvm-project/compiler-rt/lib/memprof/memprof_rtl.cpp
35236 views
//===-- memprof_rtl.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of MemProfiler, a memory profiler.9//10// Main file of the MemProf run-time library.11//===----------------------------------------------------------------------===//1213#include "memprof_allocator.h"14#include "memprof_interceptors.h"15#include "memprof_interface_internal.h"16#include "memprof_internal.h"17#include "memprof_mapping.h"18#include "memprof_stack.h"19#include "memprof_stats.h"20#include "memprof_thread.h"21#include "sanitizer_common/sanitizer_atomic.h"22#include "sanitizer_common/sanitizer_flags.h"23#include "sanitizer_common/sanitizer_interface_internal.h"24#include "sanitizer_common/sanitizer_libc.h"25#include "sanitizer_common/sanitizer_symbolizer.h"2627#include <time.h>2829uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol.3031// Allow the user to specify a profile output file via the binary.32SANITIZER_WEAK_ATTRIBUTE char __memprof_profile_filename[1];3334// Share ClHistogram compiler flag with runtime.35SANITIZER_WEAK_ATTRIBUTE bool __memprof_histogram;3637namespace __memprof {3839static void MemprofDie() {40static atomic_uint32_t num_calls;41if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {42// Don't die twice - run a busy loop.43while (1) {44internal_sched_yield();45}46}47if (common_flags()->print_module_map >= 1)48DumpProcessMap();49if (flags()->unmap_shadow_on_exit) {50if (kHighShadowEnd)51UnmapOrDie((void *)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);52}53}5455static void MemprofOnDeadlySignal(int signo, void *siginfo, void *context) {56// We call StartReportDeadlySignal not HandleDeadlySignal so we get the57// deadly signal message to stderr but no writing to the profile output file58StartReportDeadlySignal();59__memprof_profile_dump();60Die();61}6263static void CheckUnwind() {64GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check);65stack.Print();66}6768// -------------------------- Globals --------------------- {{{169int memprof_inited;70bool memprof_init_is_running;71int memprof_timestamp_inited;72long memprof_init_timestamp_s;7374uptr kHighMemEnd;7576// -------------------------- Run-time entry ------------------- {{{177// exported functions7879#define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() __memprof::RecordAccess(addr);80#define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \81__memprof::RecordAccessHistogram(addr);8283#define MEMPROF_MEMORY_ACCESS_CALLBACK(type) \84extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_##type(uptr addr) { \85MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() \86}8788#define MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(type) \89extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_hist_##type( \90uptr addr) { \91MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \92}9394MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(load)95MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(store)9697MEMPROF_MEMORY_ACCESS_CALLBACK(load)98MEMPROF_MEMORY_ACCESS_CALLBACK(store)99100// Force the linker to keep the symbols for various MemProf interface101// functions. We want to keep those in the executable in order to let the102// instrumented dynamic libraries access the symbol even if it is not used by103// the executable itself. This should help if the build system is removing dead104// code at link time.105static NOINLINE void force_interface_symbols() {106volatile int fake_condition = 0; // prevent dead condition elimination.107// clang-format off108switch (fake_condition) {109case 1: __memprof_record_access(nullptr); break;110case 2: __memprof_record_access_range(nullptr, 0); break;111}112// clang-format on113}114115static void memprof_atexit() {116Printf("MemProfiler exit stats:\n");117__memprof_print_accumulated_stats();118}119120static void InitializeHighMemEnd() {121kHighMemEnd = GetMaxUserVirtualAddress();122// Increase kHighMemEnd to make sure it's properly123// aligned together with kHighMemBeg:124kHighMemEnd |= (GetMmapGranularity() << SHADOW_SCALE) - 1;125}126127void PrintAddressSpaceLayout() {128if (kHighMemBeg) {129Printf("|| `[%p, %p]` || HighMem ||\n", (void *)kHighMemBeg,130(void *)kHighMemEnd);131Printf("|| `[%p, %p]` || HighShadow ||\n", (void *)kHighShadowBeg,132(void *)kHighShadowEnd);133}134Printf("|| `[%p, %p]` || ShadowGap ||\n", (void *)kShadowGapBeg,135(void *)kShadowGapEnd);136if (kLowShadowBeg) {137Printf("|| `[%p, %p]` || LowShadow ||\n", (void *)kLowShadowBeg,138(void *)kLowShadowEnd);139Printf("|| `[%p, %p]` || LowMem ||\n", (void *)kLowMemBeg,140(void *)kLowMemEnd);141}142Printf("MemToShadow(shadow): %p %p", (void *)MEM_TO_SHADOW(kLowShadowBeg),143(void *)MEM_TO_SHADOW(kLowShadowEnd));144if (kHighMemBeg) {145Printf(" %p %p", (void *)MEM_TO_SHADOW(kHighShadowBeg),146(void *)MEM_TO_SHADOW(kHighShadowEnd));147}148Printf("\n");149Printf("malloc_context_size=%zu\n",150(uptr)common_flags()->malloc_context_size);151152Printf("SHADOW_SCALE: %d\n", (int)SHADOW_SCALE);153Printf("SHADOW_GRANULARITY: %d\n", (int)SHADOW_GRANULARITY);154Printf("SHADOW_OFFSET: %p\n", (void *)SHADOW_OFFSET);155CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);156}157158static void MemprofInitInternal() {159if (LIKELY(memprof_inited))160return;161SanitizerToolName = "MemProfiler";162CHECK(!memprof_init_is_running && "MemProf init calls itself!");163memprof_init_is_running = true;164165CacheBinaryName();166167// Initialize flags. This must be done early, because most of the168// initialization steps look at flags().169InitializeFlags();170171AvoidCVE_2016_2143();172173SetMallocContextSize(common_flags()->malloc_context_size);174175InitializeHighMemEnd();176177// Make sure we are not statically linked.178__interception::DoesNotSupportStaticLinking();179180// Install tool-specific callbacks in sanitizer_common.181AddDieCallback(MemprofDie);182SetCheckUnwindCallback(CheckUnwind);183184// Use profile name specified via the binary itself if it exists, and hasn't185// been overrriden by a flag at runtime.186if (__memprof_profile_filename[0] != 0 && !common_flags()->log_path)187__sanitizer_set_report_path(__memprof_profile_filename);188else189__sanitizer_set_report_path(common_flags()->log_path);190191__sanitizer::InitializePlatformEarly();192193// Setup internal allocator callback.194SetLowLevelAllocateMinAlignment(SHADOW_GRANULARITY);195196InitializeMemprofInterceptors();197CheckASLR();198199ReplaceSystemMalloc();200201DisableCoreDumperIfNecessary();202203InitializeShadowMemory();204205TSDInit(PlatformTSDDtor);206InstallDeadlySignalHandlers(MemprofOnDeadlySignal);207208InitializeAllocator();209210if (flags()->atexit)211Atexit(memprof_atexit);212213InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);214215// interceptors216InitTlsSize();217218// Create main thread.219MemprofThread *main_thread = CreateMainThread();220CHECK_EQ(0, main_thread->tid());221force_interface_symbols(); // no-op.222SanitizerInitializeUnwinder();223224Symbolizer::LateInitialize();225226VReport(1, "MemProfiler Init done\n");227228memprof_init_is_running = false;229memprof_inited = 1;230}231232void MemprofInitTime() {233if (LIKELY(memprof_timestamp_inited))234return;235timespec ts;236clock_gettime(CLOCK_REALTIME, &ts);237memprof_init_timestamp_s = ts.tv_sec;238memprof_timestamp_inited = 1;239}240241// Initialize as requested from some part of MemProf runtime library242// (interceptors, allocator, etc).243void MemprofInitFromRtl() { MemprofInitInternal(); }244245#if MEMPROF_DYNAMIC246// Initialize runtime in case it's LD_PRELOAD-ed into uninstrumented executable247// (and thus normal initializers from .preinit_array or modules haven't run).248249class MemprofInitializer {250public:251MemprofInitializer() { MemprofInitFromRtl(); }252};253254static MemprofInitializer memprof_initializer;255#endif // MEMPROF_DYNAMIC256257} // namespace __memprof258259// ---------------------- Interface ---------------- {{{1260using namespace __memprof;261262// Initialize as requested from instrumented application code.263void __memprof_init() {264MemprofInitTime();265MemprofInitInternal();266}267268void __memprof_preinit() { MemprofInitInternal(); }269270void __memprof_version_mismatch_check_v1() {}271272void __memprof_record_access(void const volatile *addr) {273__memprof::RecordAccess((uptr)addr);274}275276void __memprof_record_access_hist(void const volatile *addr) {277__memprof::RecordAccessHistogram((uptr)addr);278}279280void __memprof_record_access_range(void const volatile *addr, uptr size) {281for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize)282__memprof::RecordAccess(a);283}284285void __memprof_record_access_range_hist(void const volatile *addr, uptr size) {286for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize)287__memprof::RecordAccessHistogram(a);288}289290extern "C" SANITIZER_INTERFACE_ATTRIBUTE u16291__sanitizer_unaligned_load16(const uu16 *p) {292__memprof_record_access(p);293return *p;294}295296extern "C" SANITIZER_INTERFACE_ATTRIBUTE u32297__sanitizer_unaligned_load32(const uu32 *p) {298__memprof_record_access(p);299return *p;300}301302extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64303__sanitizer_unaligned_load64(const uu64 *p) {304__memprof_record_access(p);305return *p;306}307308extern "C" SANITIZER_INTERFACE_ATTRIBUTE void309__sanitizer_unaligned_store16(uu16 *p, u16 x) {310__memprof_record_access(p);311*p = x;312}313314extern "C" SANITIZER_INTERFACE_ATTRIBUTE void315__sanitizer_unaligned_store32(uu32 *p, u32 x) {316__memprof_record_access(p);317*p = x;318}319320extern "C" SANITIZER_INTERFACE_ATTRIBUTE void321__sanitizer_unaligned_store64(uu64 *p, u64 x) {322__memprof_record_access(p);323*p = x;324}325326327