1 | //===-- memprof_rtl.cpp --------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of MemProfiler, a memory profiler. |
10 | // |
11 | // Main file of the MemProf run-time library. |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "memprof_allocator.h" |
15 | #include "memprof_interceptors.h" |
16 | #include "memprof_interface_internal.h" |
17 | #include "memprof_internal.h" |
18 | #include "memprof_mapping.h" |
19 | #include "memprof_stack.h" |
20 | #include "memprof_stats.h" |
21 | #include "memprof_thread.h" |
22 | #include "sanitizer_common/sanitizer_atomic.h" |
23 | #include "sanitizer_common/sanitizer_flags.h" |
24 | #include "sanitizer_common/sanitizer_interface_internal.h" |
25 | #include "sanitizer_common/sanitizer_libc.h" |
26 | #include "sanitizer_common/sanitizer_symbolizer.h" |
27 | |
28 | #include <time.h> |
29 | |
30 | SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1]; |
31 | |
32 | uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol. |
33 | |
34 | // Allow the user to specify a profile output file via the binary. |
35 | SANITIZER_WEAK_ATTRIBUTE char __memprof_profile_filename[1]; |
36 | |
37 | // Share ClHistogram compiler flag with runtime. |
38 | SANITIZER_WEAK_ATTRIBUTE bool __memprof_histogram; |
39 | |
40 | namespace __memprof { |
41 | |
42 | static void MemprofDie() { |
43 | static atomic_uint32_t num_calls; |
44 | if (atomic_fetch_add(a: &num_calls, v: 1, mo: memory_order_relaxed) != 0) { |
45 | // Don't die twice - run a busy loop. |
46 | while (1) { |
47 | internal_sched_yield(); |
48 | } |
49 | } |
50 | if (common_flags()->print_module_map >= 1) |
51 | DumpProcessMap(); |
52 | if (flags()->unmap_shadow_on_exit) { |
53 | if (kHighShadowEnd) |
54 | UnmapOrDie(addr: (void *)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); |
55 | } |
56 | } |
57 | |
58 | static void MemprofOnDeadlySignal(int signo, void *siginfo, void *context) { |
59 | // We call StartReportDeadlySignal not HandleDeadlySignal so we get the |
60 | // deadly signal message to stderr but no writing to the profile output file |
61 | StartReportDeadlySignal(); |
62 | __memprof_profile_dump(); |
63 | Die(); |
64 | } |
65 | |
66 | static void CheckUnwind() { |
67 | GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check); |
68 | stack.Print(); |
69 | } |
70 | |
71 | // -------------------------- Globals --------------------- {{{1 |
72 | int memprof_inited; |
73 | bool memprof_init_is_running; |
74 | int memprof_timestamp_inited; |
75 | long memprof_init_timestamp_s; |
76 | |
77 | uptr kHighMemEnd; |
78 | |
79 | // -------------------------- Run-time entry ------------------- {{{1 |
80 | // exported functions |
81 | |
82 | #define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() __memprof::RecordAccess(addr); |
83 | #define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \ |
84 | __memprof::RecordAccessHistogram(addr); |
85 | |
86 | #define MEMPROF_MEMORY_ACCESS_CALLBACK(type) \ |
87 | extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_##type(uptr addr) { \ |
88 | MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() \ |
89 | } |
90 | |
91 | #define MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(type) \ |
92 | extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_hist_##type( \ |
93 | uptr addr) { \ |
94 | MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \ |
95 | } |
96 | |
97 | MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(load) |
98 | MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(store) |
99 | |
100 | MEMPROF_MEMORY_ACCESS_CALLBACK(load) |
101 | MEMPROF_MEMORY_ACCESS_CALLBACK(store) |
102 | |
103 | // Force the linker to keep the symbols for various MemProf interface |
104 | // functions. We want to keep those in the executable in order to let the |
105 | // instrumented dynamic libraries access the symbol even if it is not used by |
106 | // the executable itself. This should help if the build system is removing dead |
107 | // code at link time. |
108 | static NOINLINE void force_interface_symbols() { |
109 | volatile int fake_condition = 0; // prevent dead condition elimination. |
110 | // clang-format off |
111 | switch (fake_condition) { |
112 | case 1: __memprof_record_access(addr: nullptr); break; |
113 | case 2: __memprof_record_access_range(addr: nullptr, size: 0); break; |
114 | } |
115 | // clang-format on |
116 | } |
117 | |
118 | static void memprof_atexit() { |
119 | Printf(format: "MemProfiler exit stats:\n" ); |
120 | __memprof_print_accumulated_stats(); |
121 | } |
122 | |
123 | static void InitializeHighMemEnd() { |
124 | kHighMemEnd = GetMaxUserVirtualAddress(); |
125 | // Increase kHighMemEnd to make sure it's properly |
126 | // aligned together with kHighMemBeg: |
127 | kHighMemEnd |= (GetMmapGranularity() << SHADOW_SCALE) - 1; |
128 | } |
129 | |
130 | void PrintAddressSpaceLayout() { |
131 | if (kHighMemBeg) { |
132 | Printf(format: "|| `[%p, %p]` || HighMem ||\n" , (void *)kHighMemBeg, |
133 | (void *)kHighMemEnd); |
134 | Printf(format: "|| `[%p, %p]` || HighShadow ||\n" , (void *)kHighShadowBeg, |
135 | (void *)kHighShadowEnd); |
136 | } |
137 | Printf(format: "|| `[%p, %p]` || ShadowGap ||\n" , (void *)kShadowGapBeg, |
138 | (void *)kShadowGapEnd); |
139 | if (kLowShadowBeg) { |
140 | Printf(format: "|| `[%p, %p]` || LowShadow ||\n" , (void *)kLowShadowBeg, |
141 | (void *)kLowShadowEnd); |
142 | Printf(format: "|| `[%p, %p]` || LowMem ||\n" , (void *)kLowMemBeg, |
143 | (void *)kLowMemEnd); |
144 | } |
145 | Printf(format: "MemToShadow(shadow): %p %p" , (void *)MEM_TO_SHADOW(kLowShadowBeg), |
146 | (void *)MEM_TO_SHADOW(kLowShadowEnd)); |
147 | if (kHighMemBeg) { |
148 | Printf(format: " %p %p" , (void *)MEM_TO_SHADOW(kHighShadowBeg), |
149 | (void *)MEM_TO_SHADOW(kHighShadowEnd)); |
150 | } |
151 | Printf(format: "\n" ); |
152 | Printf(format: "malloc_context_size=%zu\n" , |
153 | (uptr)common_flags()->malloc_context_size); |
154 | |
155 | Printf(format: "SHADOW_SCALE: %d\n" , (int)SHADOW_SCALE); |
156 | Printf(format: "SHADOW_GRANULARITY: %d\n" , (int)SHADOW_GRANULARITY); |
157 | Printf(format: "SHADOW_OFFSET: %p\n" , (void *)SHADOW_OFFSET); |
158 | CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7); |
159 | } |
160 | |
161 | static void MemprofInitInternal() { |
162 | if (LIKELY(memprof_inited)) |
163 | return; |
164 | SanitizerToolName = "MemProfiler" ; |
165 | CHECK(!memprof_init_is_running && "MemProf init calls itself!" ); |
166 | memprof_init_is_running = true; |
167 | |
168 | CacheBinaryName(); |
169 | |
170 | // Initialize flags. This must be done early, because most of the |
171 | // initialization steps look at flags(). |
172 | InitializeFlags(); |
173 | |
174 | AvoidCVE_2016_2143(); |
175 | |
176 | SetMallocContextSize(common_flags()->malloc_context_size); |
177 | |
178 | InitializeHighMemEnd(); |
179 | |
180 | // Make sure we are not statically linked. |
181 | __interception::DoesNotSupportStaticLinking(); |
182 | |
183 | // Install tool-specific callbacks in sanitizer_common. |
184 | AddDieCallback(callback: MemprofDie); |
185 | SetCheckUnwindCallback(CheckUnwind); |
186 | |
187 | // Use profile name specified via the binary itself if it exists, and hasn't |
188 | // been overrriden by a flag at runtime. |
189 | if (__memprof_profile_filename[0] != 0 && !common_flags()->log_path) |
190 | __sanitizer_set_report_path(path: __memprof_profile_filename); |
191 | else |
192 | __sanitizer_set_report_path(path: common_flags()->log_path); |
193 | |
194 | __sanitizer::InitializePlatformEarly(); |
195 | |
196 | // Setup internal allocator callback. |
197 | SetLowLevelAllocateMinAlignment(SHADOW_GRANULARITY); |
198 | |
199 | InitializeMemprofInterceptors(); |
200 | CheckASLR(); |
201 | |
202 | ReplaceSystemMalloc(); |
203 | |
204 | DisableCoreDumperIfNecessary(); |
205 | |
206 | InitializeShadowMemory(); |
207 | |
208 | TSDInit(destructor: PlatformTSDDtor); |
209 | InstallDeadlySignalHandlers(handler: MemprofOnDeadlySignal); |
210 | |
211 | InitializeAllocator(); |
212 | |
213 | if (flags()->atexit) |
214 | Atexit(function: memprof_atexit); |
215 | |
216 | InitializeCoverage(enabled: common_flags()->coverage, coverage_dir: common_flags()->coverage_dir); |
217 | |
218 | // Create main thread. |
219 | MemprofThread *main_thread = CreateMainThread(); |
220 | CHECK_EQ(0, main_thread->tid()); |
221 | force_interface_symbols(); // no-op. |
222 | SanitizerInitializeUnwinder(); |
223 | |
224 | Symbolizer::LateInitialize(); |
225 | |
226 | VReport(1, "MemProfiler Init done\n" ); |
227 | |
228 | memprof_init_is_running = false; |
229 | memprof_inited = 1; |
230 | } |
231 | |
232 | void MemprofInitTime() { |
233 | if (LIKELY(memprof_timestamp_inited)) |
234 | return; |
235 | timespec ts; |
236 | clock_gettime(CLOCK_REALTIME, tp: &ts); |
237 | memprof_init_timestamp_s = ts.tv_sec; |
238 | memprof_timestamp_inited = 1; |
239 | } |
240 | |
241 | // Initialize as requested from some part of MemProf runtime library |
242 | // (interceptors, allocator, etc). |
243 | void MemprofInitFromRtl() { MemprofInitInternal(); } |
244 | |
245 | #if MEMPROF_DYNAMIC |
246 | // Initialize runtime in case it's LD_PRELOAD-ed into uninstrumented executable |
247 | // (and thus normal initializers from .preinit_array or modules haven't run). |
248 | |
249 | class MemprofInitializer { |
250 | public: |
251 | MemprofInitializer() { MemprofInitFromRtl(); } |
252 | }; |
253 | |
254 | static MemprofInitializer memprof_initializer; |
255 | #endif // MEMPROF_DYNAMIC |
256 | |
257 | } // namespace __memprof |
258 | |
259 | // ---------------------- Interface ---------------- {{{1 |
260 | using namespace __memprof; |
261 | |
262 | // Initialize as requested from instrumented application code. |
263 | void __memprof_init() { |
264 | MemprofInitTime(); |
265 | MemprofInitInternal(); |
266 | } |
267 | |
268 | void __memprof_preinit() { MemprofInitInternal(); } |
269 | |
270 | void __memprof_version_mismatch_check_v1() {} |
271 | |
272 | void __memprof_record_access(void const volatile *addr) { |
273 | __memprof::RecordAccess(a: (uptr)addr); |
274 | } |
275 | |
276 | void __memprof_record_access_hist(void const volatile *addr) { |
277 | __memprof::RecordAccessHistogram(a: (uptr)addr); |
278 | } |
279 | |
280 | void __memprof_record_access_range(void const volatile *addr, uptr size) { |
281 | for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize) |
282 | __memprof::RecordAccess(a); |
283 | } |
284 | |
285 | void __memprof_record_access_range_hist(void const volatile *addr, uptr size) { |
286 | for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize) |
287 | __memprof::RecordAccessHistogram(a); |
288 | } |
289 | |
290 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE u16 |
291 | __sanitizer_unaligned_load16(const uu16 *p) { |
292 | __memprof_record_access(addr: p); |
293 | return *p; |
294 | } |
295 | |
296 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE u32 |
297 | __sanitizer_unaligned_load32(const uu32 *p) { |
298 | __memprof_record_access(addr: p); |
299 | return *p; |
300 | } |
301 | |
302 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64 |
303 | __sanitizer_unaligned_load64(const uu64 *p) { |
304 | __memprof_record_access(addr: p); |
305 | return *p; |
306 | } |
307 | |
308 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
309 | __sanitizer_unaligned_store16(uu16 *p, u16 x) { |
310 | __memprof_record_access(addr: p); |
311 | *p = x; |
312 | } |
313 | |
314 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
315 | __sanitizer_unaligned_store32(uu32 *p, u32 x) { |
316 | __memprof_record_access(addr: p); |
317 | *p = x; |
318 | } |
319 | |
320 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
321 | __sanitizer_unaligned_store64(uu64 *p, u64 x) { |
322 | __memprof_record_access(addr: p); |
323 | *p = x; |
324 | } |
325 | |