#include "memprof_allocator.h"
#include "memprof_interceptors.h"
#include "memprof_interface_internal.h"
#include "memprof_internal.h"
#include "memprof_mapping.h"
#include "memprof_stack.h"
#include "memprof_stats.h"
#include "memprof_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_interface_internal.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
#include <time.h>
uptr __memprof_shadow_memory_dynamic_address;
SANITIZER_WEAK_ATTRIBUTE char __memprof_profile_filename[1];
namespace __memprof {
static void MemprofDie() {
static atomic_uint32_t num_calls;
if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
while (1) {
internal_sched_yield();
}
}
if (common_flags()->print_module_map >= 1)
DumpProcessMap();
if (flags()->unmap_shadow_on_exit) {
if (kHighShadowEnd)
UnmapOrDie((void *)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
static void CheckUnwind() {
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check);
stack.Print();
}
int memprof_inited;
int memprof_init_done;
bool memprof_init_is_running;
int memprof_timestamp_inited;
long memprof_init_timestamp_s;
uptr kHighMemEnd;
#define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() __memprof::RecordAccess(addr);
#define MEMPROF_MEMORY_ACCESS_CALLBACK(type) \
extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_##type(uptr addr) { \
MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() \
}
MEMPROF_MEMORY_ACCESS_CALLBACK(load)
MEMPROF_MEMORY_ACCESS_CALLBACK(store)
static NOINLINE void force_interface_symbols() {
volatile int fake_condition = 0;
switch (fake_condition) {
case 1: __memprof_record_access(nullptr); break;
case 2: __memprof_record_access_range(nullptr, 0); break;
}
}
static void memprof_atexit() {
Printf("MemProfiler exit stats:\n");
__memprof_print_accumulated_stats();
}
static void InitializeHighMemEnd() {
kHighMemEnd = GetMaxUserVirtualAddress();
kHighMemEnd |= (GetMmapGranularity() << SHADOW_SCALE) - 1;
}
void PrintAddressSpaceLayout() {
if (kHighMemBeg) {
Printf("|| `[%p, %p]` || HighMem ||\n", (void *)kHighMemBeg,
(void *)kHighMemEnd);
Printf("|| `[%p, %p]` || HighShadow ||\n", (void *)kHighShadowBeg,
(void *)kHighShadowEnd);
}
Printf("|| `[%p, %p]` || ShadowGap ||\n", (void *)kShadowGapBeg,
(void *)kShadowGapEnd);
if (kLowShadowBeg) {
Printf("|| `[%p, %p]` || LowShadow ||\n", (void *)kLowShadowBeg,
(void *)kLowShadowEnd);
Printf("|| `[%p, %p]` || LowMem ||\n", (void *)kLowMemBeg,
(void *)kLowMemEnd);
}
Printf("MemToShadow(shadow): %p %p", (void *)MEM_TO_SHADOW(kLowShadowBeg),
(void *)MEM_TO_SHADOW(kLowShadowEnd));
if (kHighMemBeg) {
Printf(" %p %p", (void *)MEM_TO_SHADOW(kHighShadowBeg),
(void *)MEM_TO_SHADOW(kHighShadowEnd));
}
Printf("\n");
Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size);
Printf("SHADOW_SCALE: %d\n", (int)SHADOW_SCALE);
Printf("SHADOW_GRANULARITY: %d\n", (int)SHADOW_GRANULARITY);
Printf("SHADOW_OFFSET: 0x%zx\n", (uptr)SHADOW_OFFSET);
CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
}
static void MemprofInitInternal() {
if (LIKELY(memprof_inited))
return;
SanitizerToolName = "MemProfiler";
CHECK(!memprof_init_is_running && "MemProf init calls itself!");
memprof_init_is_running = true;
CacheBinaryName();
InitializeFlags();
AvoidCVE_2016_2143();
SetMallocContextSize(common_flags()->malloc_context_size);
InitializeHighMemEnd();
MemprofDoesNotSupportStaticLinkage();
AddDieCallback(MemprofDie);
SetCheckUnwindCallback(CheckUnwind);
if (__memprof_profile_filename[0] != 0 && !common_flags()->log_path)
__sanitizer_set_report_path(__memprof_profile_filename);
else
__sanitizer_set_report_path(common_flags()->log_path);
__sanitizer::InitializePlatformEarly();
SetLowLevelAllocateMinAlignment(SHADOW_GRANULARITY);
InitializeMemprofInterceptors();
CheckASLR();
ReplaceSystemMalloc();
DisableCoreDumperIfNecessary();
InitializeShadowMemory();
TSDInit(PlatformTSDDtor);
InitializeAllocator();
memprof_inited = 1;
memprof_init_is_running = false;
if (flags()->atexit)
Atexit(memprof_atexit);
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
InitTlsSize();
MemprofThread *main_thread = CreateMainThread();
CHECK_EQ(0, main_thread->tid());
force_interface_symbols();
SanitizerInitializeUnwinder();
Symbolizer::LateInitialize();
VReport(1, "MemProfiler Init done\n");
memprof_init_done = 1;
}
void MemprofInitTime() {
if (LIKELY(memprof_timestamp_inited))
return;
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
memprof_init_timestamp_s = ts.tv_sec;
memprof_timestamp_inited = 1;
}
void MemprofInitFromRtl() { MemprofInitInternal(); }
#if MEMPROF_DYNAMIC
class MemprofInitializer {
public:
MemprofInitializer() { MemprofInitFromRtl(); }
};
static MemprofInitializer memprof_initializer;
#endif
}
using namespace __memprof;
void __memprof_init() {
MemprofInitTime();
MemprofInitInternal();
}
void __memprof_preinit() { MemprofInitInternal(); }
void __memprof_version_mismatch_check_v1() {}
void __memprof_record_access(void const volatile *addr) {
__memprof::RecordAccess((uptr)addr);
}
void __memprof_record_access_range(void const volatile *addr, uptr size) {
for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize)
__memprof::RecordAccess(a);
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u16
__sanitizer_unaligned_load16(const uu16 *p) {
__memprof_record_access(p);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u32
__sanitizer_unaligned_load32(const uu32 *p) {
__memprof_record_access(p);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64
__sanitizer_unaligned_load64(const uu64 *p) {
__memprof_record_access(p);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__sanitizer_unaligned_store16(uu16 *p, u16 x) {
__memprof_record_access(p);
*p = x;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__sanitizer_unaligned_store32(uu32 *p, u32 x) {
__memprof_record_access(p);
*p = x;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__sanitizer_unaligned_store64(uu64 *p, u64 x) {
__memprof_record_access(p);
*p = x;
}