1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file. 4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <dlfcn.h> 6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <errno.h> 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <fcntl.h> 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <stdbool.h> 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <stdlib.h> 10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <string.h> 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <sys/mman.h> 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <unistd.h> 13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <unwind.h> 14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "tools/android/heap_profiler/heap_profiler.h" 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define HEAP_PROFILER_EXPORT __attribute__((visibility("default"))) 18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic inline __attribute__((always_inline)) 21116680a4aac90f2aa7413d9095a592090648e557Ben Murdochuint32_t get_backtrace(uintptr_t* frames, uint32_t max_depth); 22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Function pointers typedefs for the hooked symbols. 24116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void* (*mmap_t)(void*, size_t, int, int, int, off_t); 25116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void* (*mmap2_t)(void*, size_t, int, int, int, off_t); 26116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void* (*mmap64_t)(void*, size_t, int, int, int, off64_t); 27116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void* (*mremap_t)(void*, size_t, size_t, unsigned long); 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef int (*munmap_t)(void*, size_t); 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void* (*malloc_t)(size_t); 30116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void* (*calloc_t)(size_t, size_t); 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void* (*realloc_t)(void*, size_t); 32116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef void (*free_t)(void*); 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// And their actual definitions. 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic mmap_t real_mmap; 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic mmap2_t real_mmap2; 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic mmap64_t real_mmap64; 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic mremap_t real_mremap; 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic munmap_t real_munmap; 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic malloc_t real_malloc; 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic calloc_t real_calloc; 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic realloc_t real_realloc; 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic free_t real_free; 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic int* has_forked_off_zygote; 45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 46116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT const HeapStats* heap_profiler_stats_for_tests; 47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// +---------------------------------------------------------------------------+ 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// + Initialization of heap_profiler and lookup of hooks' addresses + 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// +---------------------------------------------------------------------------+ 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch__attribute__((constructor)) 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic void initialize() { 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_mmap = (mmap_t) dlsym(RTLD_NEXT, "mmap"); 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_mmap2 = (mmap_t) dlsym(RTLD_NEXT, "mmap2"); 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_mmap64 = (mmap64_t) dlsym(RTLD_NEXT, "mmap64"); 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_mremap = (mremap_t) dlsym(RTLD_NEXT, "mremap"); 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_munmap = (munmap_t) dlsym(RTLD_NEXT, "munmap"); 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_malloc = (malloc_t) dlsym(RTLD_NEXT, "malloc"); 59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_calloc = (calloc_t) dlsym(RTLD_NEXT, "calloc"); 60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_realloc = (realloc_t) dlsym(RTLD_NEXT, "realloc"); 61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_free = (free_t) dlsym(RTLD_NEXT, "free"); 62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // gMallocLeakZygoteChild is an extra useful piece of information to have. 64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // When available, it tells whether we're in the zygote (=0) or forked (=1) 65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // a child off it. In the worst case it will be NULL and we'll just ignore it. 66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch has_forked_off_zygote = (int*) dlsym(RTLD_NEXT, "gMallocLeakZygoteChild"); 67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Allocate room for the HeapStats area and initialize the heap profiler. 69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Make an explicit map of /dev/zero (instead of MAP_ANONYMOUS), so that the 70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // heap_dump tool can easily spot the mapping in the target process. 71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int fd = open("/dev/zero", O_RDONLY); 72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (fd < 0) { 73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch abort(); // This world has gone wrong. Good night Vienna. 74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch HeapStats* stats = (HeapStats*) real_mmap( 77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 0, sizeof(HeapStats), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch heap_profiler_stats_for_tests = stats; 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch heap_profiler_init(stats); 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 82116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic inline __attribute__((always_inline)) void unwind_and_record_alloc( 83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* start, size_t size, uint32_t flags) { 84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const int errno_save = errno; 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uintptr_t frames[HEAP_PROFILER_MAX_DEPTH]; 86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const uint32_t depth = get_backtrace(frames, HEAP_PROFILER_MAX_DEPTH); 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (has_forked_off_zygote != NULL && *has_forked_off_zygote == 0) 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch flags |= HEAP_PROFILER_FLAGS_IN_ZYGOTE; 89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch heap_profiler_alloc(start, size, frames, depth, flags); 90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch errno = errno_save; 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 93116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic inline __attribute__((always_inline)) void discard_alloc( 94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* start, size_t size, uint32_t* old_flags) { 95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const int errno_save = errno; 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch heap_profiler_free(start, size, old_flags); 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch errno = errno_save; 98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Flags are non-functional extra decorators that are made available to the 101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// final heap_dump tool, to get more details about the source of the allocation. 102116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic uint32_t get_flags_for_mmap(int fd) { 103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return HEAP_PROFILER_FLAGS_MMAP | (fd ? HEAP_PROFILER_FLAGS_MMAP_FILE : 0); 104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// +---------------------------------------------------------------------------+ 107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// + Actual mmap/malloc hooks + 108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// +---------------------------------------------------------------------------+ 109116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void* mmap( 110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* addr, size_t size, int prot, int flags, int fd, off_t offset) { 111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* ret = real_mmap(addr, size, prot, flags, fd, offset); 112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ret != MAP_FAILED) 113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unwind_and_record_alloc(ret, size, get_flags_for_mmap(fd)); 114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 117116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void* mmap2( 118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* addr, size_t size, int prot, int flags, int fd, off_t pgoffset) { 119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* ret = real_mmap2(addr, size, prot, flags, fd, pgoffset); 120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ret != MAP_FAILED) 121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unwind_and_record_alloc(ret, size, get_flags_for_mmap(fd)); 122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 125116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void* mmap64( 126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* addr, size_t size, int prot, int flags, int fd, off64_t offset) { 127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* ret = real_mmap64(addr, size, prot, flags, fd, offset); 128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ret != MAP_FAILED) 129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unwind_and_record_alloc(ret, size, get_flags_for_mmap(fd)); 130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 133116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void* mremap( 134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* addr, size_t oldlen, size_t newlen, unsigned long flags) { 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* ret = real_mremap(addr, oldlen, newlen, flags); 136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ret != MAP_FAILED) { 137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uint32_t flags = 0; 138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (addr) 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch discard_alloc(addr, oldlen, &flags); 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (newlen > 0) 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unwind_and_record_alloc(ret, newlen, flags); 142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 146116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT int munmap(void* ptr, size_t size) { 147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int ret = real_munmap(ptr, size); 148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch discard_alloc(ptr, size, /*old_flags=*/NULL); 149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 152116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void* malloc(size_t byte_count) { 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* ret = real_malloc(byte_count); 154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ret != NULL) 155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unwind_and_record_alloc(ret, byte_count, HEAP_PROFILER_FLAGS_MALLOC); 156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 159116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void* calloc(size_t nmemb, size_t size) { 160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* ret = real_calloc(nmemb, size); 161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ret != NULL) 162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unwind_and_record_alloc(ret, nmemb * size, HEAP_PROFILER_FLAGS_MALLOC); 163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 166116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void* realloc(void* ptr, size_t size) { 167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch void* ret = real_realloc(ptr, size); 168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uint32_t flags = 0; 169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ptr) 170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch discard_alloc(ptr, 0, &flags); 171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ret != NULL) 172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unwind_and_record_alloc(ret, size, flags | HEAP_PROFILER_FLAGS_MALLOC); 173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return ret; 174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 176116680a4aac90f2aa7413d9095a592090648e557Ben MurdochHEAP_PROFILER_EXPORT void free(void* ptr) { 177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch real_free(ptr); 178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch discard_alloc(ptr, 0, /*old_flags=*/NULL); 179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// +---------------------------------------------------------------------------+ 182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// + Stack unwinder + 183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// +---------------------------------------------------------------------------+ 184116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef struct { 185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uintptr_t* frames; 186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uint32_t frame_count; 187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uint32_t max_depth; 188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool have_skipped_self; 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} stack_crawl_state_t; 190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 191116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic _Unwind_Reason_Code unwind_fn(struct _Unwind_Context* ctx, void* arg) { 192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch stack_crawl_state_t* state = (stack_crawl_state_t*) arg; 193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch uintptr_t ip = _Unwind_GetIP(ctx); 194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (ip != 0 && !state->have_skipped_self) { 196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch state->have_skipped_self = true; 197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return _URC_NO_REASON; 198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch state->frames[state->frame_count++] = ip; 201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return (state->frame_count >= state->max_depth) ? 202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch _URC_END_OF_STACK : _URC_NO_REASON; 203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 205116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic uint32_t get_backtrace(uintptr_t* frames, uint32_t max_depth) { 206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch stack_crawl_state_t state = {.frames = frames, .max_depth = max_depth}; 207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch _Unwind_Backtrace(unwind_fn, &state); 208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return state.frame_count; 209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 210