1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
15 #include "tools/android/heap_profiler/heap_profiler.h"
17 #define HEAP_PROFILER_EXPORT __attribute__((visibility("default")))
20 static inline __attribute__((always_inline
))
21 uint32_t get_backtrace(uintptr_t* frames
, uint32_t max_depth
);
23 // Function pointers typedefs for the hooked symbols.
24 typedef void* (*mmap_t
)(void*, size_t, int, int, int, off_t
);
25 typedef void* (*mmap2_t
)(void*, size_t, int, int, int, off_t
);
26 typedef void* (*mmap64_t
)(void*, size_t, int, int, int, off64_t
);
27 typedef void* (*mremap_t
)(void*, size_t, size_t, unsigned long);
28 typedef int (*munmap_t
)(void*, size_t);
29 typedef void* (*malloc_t
)(size_t);
30 typedef void* (*calloc_t
)(size_t, size_t);
31 typedef void* (*realloc_t
)(void*, size_t);
32 typedef void (*free_t
)(void*);
34 // And their actual definitions.
35 static mmap_t real_mmap
;
36 static mmap2_t real_mmap2
;
37 static mmap64_t real_mmap64
;
38 static mremap_t real_mremap
;
39 static munmap_t real_munmap
;
40 static malloc_t real_malloc
;
41 static calloc_t real_calloc
;
42 static realloc_t real_realloc
;
43 static free_t real_free
;
44 static int* has_forked_off_zygote
;
46 HEAP_PROFILER_EXPORT
const HeapStats
* heap_profiler_stats_for_tests
;
48 // +---------------------------------------------------------------------------+
49 // + Initialization of heap_profiler and lookup of hooks' addresses +
50 // +---------------------------------------------------------------------------+
51 __attribute__((constructor
))
52 static void initialize() {
53 real_mmap
= (mmap_t
) dlsym(RTLD_NEXT
, "mmap");
54 real_mmap2
= (mmap_t
) dlsym(RTLD_NEXT
, "mmap2");
55 real_mmap64
= (mmap64_t
) dlsym(RTLD_NEXT
, "mmap64");
56 real_mremap
= (mremap_t
) dlsym(RTLD_NEXT
, "mremap");
57 real_munmap
= (munmap_t
) dlsym(RTLD_NEXT
, "munmap");
58 real_malloc
= (malloc_t
) dlsym(RTLD_NEXT
, "malloc");
59 real_calloc
= (calloc_t
) dlsym(RTLD_NEXT
, "calloc");
60 real_realloc
= (realloc_t
) dlsym(RTLD_NEXT
, "realloc");
61 real_free
= (free_t
) dlsym(RTLD_NEXT
, "free");
63 // gMallocLeakZygoteChild is an extra useful piece of information to have.
64 // When available, it tells whether we're in the zygote (=0) or forked (=1)
65 // a child off it. In the worst case it will be NULL and we'll just ignore it.
66 has_forked_off_zygote
= (int*) dlsym(RTLD_NEXT
, "gMallocLeakZygoteChild");
68 // Allocate room for the HeapStats area and initialize the heap profiler.
69 // Make an explicit map of /dev/zero (instead of MAP_ANONYMOUS), so that the
70 // heap_dump tool can easily spot the mapping in the target process.
71 int fd
= open("/dev/zero", O_RDONLY
);
73 abort(); // This world has gone wrong. Good night Vienna.
76 HeapStats
* stats
= (HeapStats
*) real_mmap(
77 0, sizeof(HeapStats
), PROT_READ
| PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
78 heap_profiler_stats_for_tests
= stats
;
79 heap_profiler_init(stats
);
82 static inline __attribute__((always_inline
)) void unwind_and_record_alloc(
83 void* start
, size_t size
, uint32_t flags
) {
84 const int errno_save
= errno
;
85 uintptr_t frames
[HEAP_PROFILER_MAX_DEPTH
];
86 const uint32_t depth
= get_backtrace(frames
, HEAP_PROFILER_MAX_DEPTH
);
87 if (has_forked_off_zygote
!= NULL
&& *has_forked_off_zygote
== 0)
88 flags
|= HEAP_PROFILER_FLAGS_IN_ZYGOTE
;
89 heap_profiler_alloc(start
, size
, frames
, depth
, flags
);
93 static inline __attribute__((always_inline
)) void discard_alloc(
94 void* start
, size_t size
, uint32_t* old_flags
) {
95 const int errno_save
= errno
;
96 heap_profiler_free(start
, size
, old_flags
);
100 // Flags are non-functional extra decorators that are made available to the
101 // final heap_dump tool, to get more details about the source of the allocation.
102 static uint32_t get_flags_for_mmap(int fd
) {
103 return HEAP_PROFILER_FLAGS_MMAP
| (fd
? HEAP_PROFILER_FLAGS_MMAP_FILE
: 0);
106 // +---------------------------------------------------------------------------+
107 // + Actual mmap/malloc hooks +
108 // +---------------------------------------------------------------------------+
109 HEAP_PROFILER_EXPORT
void* mmap(
110 void* addr
, size_t size
, int prot
, int flags
, int fd
, off_t offset
) {
111 void* ret
= real_mmap(addr
, size
, prot
, flags
, fd
, offset
);
112 if (ret
!= MAP_FAILED
)
113 unwind_and_record_alloc(ret
, size
, get_flags_for_mmap(fd
));
117 HEAP_PROFILER_EXPORT
void* mmap2(
118 void* addr
, size_t size
, int prot
, int flags
, int fd
, off_t pgoffset
) {
119 void* ret
= real_mmap2(addr
, size
, prot
, flags
, fd
, pgoffset
);
120 if (ret
!= MAP_FAILED
)
121 unwind_and_record_alloc(ret
, size
, get_flags_for_mmap(fd
));
125 HEAP_PROFILER_EXPORT
void* mmap64(
126 void* addr
, size_t size
, int prot
, int flags
, int fd
, off64_t offset
) {
127 void* ret
= real_mmap64(addr
, size
, prot
, flags
, fd
, offset
);
128 if (ret
!= MAP_FAILED
)
129 unwind_and_record_alloc(ret
, size
, get_flags_for_mmap(fd
));
133 HEAP_PROFILER_EXPORT
void* mremap(
134 void* addr
, size_t oldlen
, size_t newlen
, unsigned long flags
) {
135 void* ret
= real_mremap(addr
, oldlen
, newlen
, flags
);
136 if (ret
!= MAP_FAILED
) {
139 discard_alloc(addr
, oldlen
, &flags
);
141 unwind_and_record_alloc(ret
, newlen
, flags
);
146 HEAP_PROFILER_EXPORT
int munmap(void* ptr
, size_t size
) {
147 int ret
= real_munmap(ptr
, size
);
148 discard_alloc(ptr
, size
, /*old_flags=*/NULL
);
152 HEAP_PROFILER_EXPORT
void* malloc(size_t byte_count
) {
153 void* ret
= real_malloc(byte_count
);
155 unwind_and_record_alloc(ret
, byte_count
, HEAP_PROFILER_FLAGS_MALLOC
);
159 HEAP_PROFILER_EXPORT
void* calloc(size_t nmemb
, size_t size
) {
160 void* ret
= real_calloc(nmemb
, size
);
162 unwind_and_record_alloc(ret
, nmemb
* size
, HEAP_PROFILER_FLAGS_MALLOC
);
166 HEAP_PROFILER_EXPORT
void* realloc(void* ptr
, size_t size
) {
167 void* ret
= real_realloc(ptr
, size
);
170 discard_alloc(ptr
, 0, &flags
);
172 unwind_and_record_alloc(ret
, size
, flags
| HEAP_PROFILER_FLAGS_MALLOC
);
176 HEAP_PROFILER_EXPORT
void free(void* ptr
) {
178 discard_alloc(ptr
, 0, /*old_flags=*/NULL
);
181 // +---------------------------------------------------------------------------+
182 // + Stack unwinder +
183 // +---------------------------------------------------------------------------+
186 uint32_t frame_count
;
188 bool have_skipped_self
;
189 } stack_crawl_state_t
;
191 static _Unwind_Reason_Code
unwind_fn(struct _Unwind_Context
* ctx
, void* arg
) {
192 stack_crawl_state_t
* state
= (stack_crawl_state_t
*) arg
;
193 uintptr_t ip
= _Unwind_GetIP(ctx
);
195 if (ip
!= 0 && !state
->have_skipped_self
) {
196 state
->have_skipped_self
= true;
197 return _URC_NO_REASON
;
200 state
->frames
[state
->frame_count
++] = ip
;
201 return (state
->frame_count
>= state
->max_depth
) ?
202 _URC_END_OF_STACK
: _URC_NO_REASON
;
205 static uint32_t get_backtrace(uintptr_t* frames
, uint32_t max_depth
) {
206 stack_crawl_state_t state
= {.frames
= frames
, .max_depth
= max_depth
};
207 _Unwind_Backtrace(unwind_fn
, &state
);
208 return state
.frame_count
;