gprofng: Don't hardcode -Wno-nonnull-compare
[binutils-gdb.git] / gprofng / libcollector / heaptrace.c
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2 Contributed by Oracle.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 /*
22 * Heap tracing events
23 */
24
25 #include "config.h"
26 #include <dlfcn.h>
27
28 #include "gp-defs.h"
29 #include "collector_module.h"
30 #include "gp-experiment.h"
31 #include "data_pckts.h"
32 #include "tsd.h"
33
34 /* TprintfT(<level>,...) definitions. Adjust per module as needed */
35 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
36 #define DBG_LT1 1 // for configuration details, warnings
37 #define DBG_LT2 2
38 #define DBG_LT3 3
39 #define DBG_LT4 4
40
41 /* define the packets to be written out */
42 typedef struct Heap_packet
43 { /* Malloc/free tracing packet */
44 Common_packet comm;
45 Heap_type mtype; /* subtype of packet */
46 Size_type size; /* size of malloc/realloc request */
47 Vaddr_type vaddr; /* vaddr given to free or returned from malloc/realloc */
48 Vaddr_type ovaddr; /* Previous vaddr given to realloc */
49 } Heap_packet;
50
51 static int init_heap_intf ();
52 static int open_experiment (const char *);
53 static int start_data_collection (void);
54 static int stop_data_collection (void);
55 static int close_experiment (void);
56 static int detach_experiment (void);
57
58 static ModuleInterface module_interface = {
59 SP_HEAPTRACE_FILE, /* description */
60 NULL, /* initInterface */
61 open_experiment, /* openExperiment */
62 start_data_collection, /* startDataCollection */
63 stop_data_collection, /* stopDataCollection */
64 close_experiment, /* closeExperiment */
65 detach_experiment /* detachExperiment (fork child) */
66 };
67
68 static CollectorInterface *collector_interface = NULL;
69 static int heap_mode = 0;
70 static CollectorModule heap_hndl = COLLECTOR_MODULE_ERR;
71 static unsigned heap_key = COLLECTOR_TSD_INVALID_KEY;
72
73 #define CHCK_REENTRANCE(x) ( !heap_mode || ((x) = collector_interface->getKey( heap_key )) == NULL || (*(x) != 0) )
74 #define PUSH_REENTRANCE(x) ((*(x))++)
75 #define POP_REENTRANCE(x) ((*(x))--)
76 #define CALL_REAL(x) (__real_##x)
77 #define NULL_PTR(x) (__real_##x == NULL)
78 #define gethrtime collector_interface->getHiResTime
79
80 #ifdef DEBUG
81 #define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
82 #define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
83 #else
84 #define Tprintf(...)
85 #define TprintfT(...)
86 #endif
87
88 static void *(*__real_malloc)(size_t) = NULL;
89 static void (*__real_free)(void *);
90 static void *(*__real_realloc)(void *, size_t);
91 static void *(*__real_memalign)(size_t, size_t);
92 static void *(*__real_calloc)(size_t, size_t);
93 static void *(*__real_valloc)(size_t);
94 static char *(*__real_strchr)(const char *, int);
95
96 void *__libc_malloc (size_t);
97 void __libc_free (void *);
98 void *__libc_realloc (void *, size_t);
99
100 static void
101 collector_memset (void *s, int c, size_t n)
102 {
103 unsigned char *s1 = s;
104 while (n--)
105 *s1++ = (unsigned char) c;
106 }
107
108 void
109 __collector_module_init (CollectorInterface *_collector_interface)
110 {
111 if (_collector_interface == NULL)
112 return;
113 collector_interface = _collector_interface;
114 Tprintf (0, "heaptrace: __collector_module_init\n");
115 heap_hndl = collector_interface->registerModule (&module_interface);
116
117 /* Initialize next module */
118 ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
119 if (next_init != NULL)
120 next_init (_collector_interface);
121 return;
122 }
123
124 static int
125 open_experiment (const char *exp)
126 {
127 if (collector_interface == NULL)
128 {
129 Tprintf (0, "heaptrace: collector_interface is null.\n");
130 return COL_ERROR_HEAPINIT;
131 }
132 if (heap_hndl == COLLECTOR_MODULE_ERR)
133 {
134 Tprintf (0, "heaptrace: handle create failed.\n");
135 collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
136 SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
137 return COL_ERROR_HEAPINIT;
138 }
139 TprintfT (0, "heaptrace: open_experiment %s\n", exp);
140 if (NULL_PTR (malloc))
141 init_heap_intf ();
142
143 const char *params = collector_interface->getParams ();
144 while (params)
145 {
146 if ((params[0] == 'H') && (params[1] == ':'))
147 {
148 params += 2;
149 break;
150 }
151 params = CALL_REAL (strchr)(params, ';');
152 if (params)
153 params++;
154 }
155 if (params == NULL) /* Heap data collection not specified */
156 return COL_ERROR_HEAPINIT;
157
158 heap_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
159 if (heap_key == (unsigned) - 1)
160 {
161 Tprintf (0, "heaptrace: TSD key create failed.\n");
162 collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
163 SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
164 return COL_ERROR_HEAPINIT;
165 }
166 collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_HEAPTRACE);
167 collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
168 module_interface.description);
169
170 /* Record Heap_packet description */
171 Heap_packet *pp = NULL;
172 collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"Heap tracing data\">\n", HEAP_PCKT);
173 collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n",
174 &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
175 collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
176 &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
177 collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
178 &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
179 collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
180 &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
181 collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
182 &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
183 collector_interface->writeLog (" <field name=\"HTYPE\" uname=\"Heap trace function type\" offset=\"%d\" type=\"%s\"/>\n",
184 &pp->mtype, sizeof (pp->mtype) == 4 ? "INT32" : "INT64");
185 collector_interface->writeLog (" <field name=\"HSIZE\" uname=\"Memory size\" offset=\"%d\" type=\"%s\"/>\n",
186 &pp->size, sizeof (pp->size) == 4 ? "UINT32" : "UINT64");
187 collector_interface->writeLog (" <field name=\"HVADDR\" uname=\"Memory address\" offset=\"%d\" type=\"%s\"/>\n",
188 &pp->vaddr, sizeof (pp->vaddr) == 4 ? "UINT32" : "UINT64");
189 collector_interface->writeLog (" <field name=\"HOVADDR\" uname=\"Previous memory address\" offset=\"%d\" type=\"%s\"/>\n",
190 &pp->ovaddr, sizeof (pp->ovaddr) == 4 ? "UINT32" : "UINT64");
191 collector_interface->writeLog (" </profpckt>\n");
192 collector_interface->writeLog ("</profile>\n");
193 return COL_ERROR_NONE;
194 }
195
196 static int
197 start_data_collection (void)
198 {
199 heap_mode = 1;
200 Tprintf (0, "heaptrace: start_data_collection\n");
201 return 0;
202 }
203
204 static int
205 stop_data_collection (void)
206 {
207 heap_mode = 0;
208 Tprintf (0, "heaptrace: stop_data_collection\n");
209 return 0;
210 }
211
212 static int
213 close_experiment (void)
214 {
215 heap_mode = 0;
216 heap_key = COLLECTOR_TSD_INVALID_KEY;
217 Tprintf (0, "heaptrace: close_experiment\n");
218 return 0;
219 }
220
221 static int
222 detach_experiment (void)
223 /* fork child. Clean up state but don't write to experiment */
224 {
225 heap_mode = 0;
226 heap_key = COLLECTOR_TSD_INVALID_KEY;
227 Tprintf (0, "heaptrace: detach_experiment\n");
228 return 0;
229 }
230
231 static int in_init_heap_intf = 0; // Flag that we are in init_heap_intf()
232
233 static int
234 init_heap_intf ()
235 {
236 void *dlflag;
237 in_init_heap_intf = 1;
238 __real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc");
239 if (__real_malloc == NULL)
240 {
241 /* We are probably dlopened after libthread/libc,
242 * try to search in the previously loaded objects
243 */
244 __real_malloc = (void*(*)(size_t))dlsym (RTLD_DEFAULT, "malloc");
245 if (__real_malloc == NULL)
246 {
247 Tprintf (0, "heaptrace: ERROR: real malloc not found\n");
248 in_init_heap_intf = 0;
249 return 1;
250 }
251 Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_DEFAULT\n");
252 dlflag = RTLD_DEFAULT;
253 }
254 else
255 {
256 Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_NEXT\n");
257 dlflag = RTLD_NEXT;
258 }
259 __real_free = (void(*)(void *))dlsym (dlflag, "free");
260 __real_realloc = (void*(*)(void *, size_t))dlsym (dlflag, "realloc");
261 __real_memalign = (void*(*)(size_t, size_t))dlsym (dlflag, "memalign");
262 __real_calloc = (void*(*)(size_t, size_t))dlsym (dlflag, "calloc");
263 __real_valloc = (void*(*)(size_t))dlsym (dlflag, "valloc");
264 __real_strchr = (char*(*)(const char *, int))dlsym (dlflag, "strchr");
265 Tprintf (0, "heaptrace: init_heap_intf done\n");
266 in_init_heap_intf = 0;
267 return 0;
268 }
269
270 /*------------------------------------------------------------- malloc */
271
272 void *
273 malloc (size_t size)
274 {
275 void *ret;
276 int *guard;
277 Heap_packet hpacket;
278 /* Linux startup workaround */
279 if (!heap_mode)
280 {
281 void *ppp = (void *) __libc_malloc (size);
282 Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)...\n", (long) size, ppp);
283 return ppp;
284 }
285 if (NULL_PTR (malloc))
286 init_heap_intf ();
287 if (CHCK_REENTRANCE (guard))
288 {
289 ret = (void *) CALL_REAL (malloc)(size);
290 Tprintf (DBG_LT4, "heaptrace: real malloc(%ld) = %p\n", (long) size, ret);
291 return ret;
292 }
293 PUSH_REENTRANCE (guard);
294
295 ret = (void *) CALL_REAL (malloc)(size);
296 collector_memset (&hpacket, 0, sizeof ( Heap_packet));
297 hpacket.comm.tsize = sizeof ( Heap_packet);
298 hpacket.comm.tstamp = gethrtime ();
299 hpacket.mtype = MALLOC_TRACE;
300 hpacket.size = (Size_type) size;
301 hpacket.vaddr = (Vaddr_type) ret;
302 hpacket.ovaddr = (Vaddr_type) 0;
303 hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
304 collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
305 POP_REENTRANCE (guard);
306 return (void *) ret;
307 }
308
309 /*------------------------------------------------------------- free */
310
311 void
312 free (void *ptr)
313 {
314 int *guard;
315 Heap_packet hpacket;
316 /* Linux startup workaround */
317 if (!heap_mode)
318 {
319 // Tprintf(DBG_LT4,"heaptrace: LINUX free(%p)...\n",ptr);
320 __libc_free (ptr);
321 return;
322 }
323 if (NULL_PTR (malloc))
324 init_heap_intf ();
325 if (CHCK_REENTRANCE (guard))
326 {
327 CALL_REAL (free)(ptr);
328 return;
329 }
330 if (ptr == NULL)
331 return;
332 PUSH_REENTRANCE (guard);
333
334 /* Get a timestamp before 'free' to enforce consistency */
335 hrtime_t ts = gethrtime ();
336 CALL_REAL (free)(ptr);
337 collector_memset (&hpacket, 0, sizeof ( Heap_packet));
338 hpacket.comm.tsize = sizeof ( Heap_packet);
339 hpacket.comm.tstamp = ts;
340 hpacket.mtype = FREE_TRACE;
341 hpacket.size = (Size_type) 0;
342 hpacket.vaddr = (Vaddr_type) ptr;
343 hpacket.ovaddr = (Vaddr_type) 0;
344 hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
345 collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
346 POP_REENTRANCE (guard);
347 return;
348 }
349
350 /*------------------------------------------------------------- realloc */
351 void *
352 realloc (void *ptr, size_t size)
353 {
354 void *ret;
355 int *guard;
356 Heap_packet hpacket;
357
358 /* Linux startup workaround */
359 if (!heap_mode)
360 {
361 void * ppp = (void *) __libc_realloc (ptr, size);
362 Tprintf (DBG_LT4, "heaptrace: LINUX realloc(%ld, %p->%p)...\n",
363 (long) size, ptr, ppp);
364 return ppp;
365 }
366 if (NULL_PTR (realloc))
367 init_heap_intf ();
368 if (CHCK_REENTRANCE (guard))
369 {
370 ret = (void *) CALL_REAL (realloc)(ptr, size);
371 return ret;
372 }
373 PUSH_REENTRANCE (guard);
374 hrtime_t ts = gethrtime ();
375 ret = (void *) CALL_REAL (realloc)(ptr, size);
376 collector_memset (&hpacket, 0, sizeof ( Heap_packet));
377 hpacket.comm.tsize = sizeof ( Heap_packet);
378 hpacket.comm.tstamp = ts;
379 hpacket.mtype = REALLOC_TRACE;
380 hpacket.size = (Size_type) size;
381 hpacket.vaddr = (Vaddr_type) ret;
382 hpacket.ovaddr = (Vaddr_type) ptr;
383 hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
384 collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
385 POP_REENTRANCE (guard);
386 return (void *) ret;
387 }
388
389 /*------------------------------------------------------------- memalign */
390 void *
391 memalign (size_t align, size_t size)
392 {
393 void *ret;
394 int *guard;
395 Heap_packet hpacket;
396 if (NULL_PTR (memalign))
397 init_heap_intf ();
398 if (CHCK_REENTRANCE (guard))
399 {
400 ret = (void *) CALL_REAL (memalign)(align, size);
401 return ret;
402 }
403 PUSH_REENTRANCE (guard);
404 ret = (void *) CALL_REAL (memalign)(align, size);
405 collector_memset (&hpacket, 0, sizeof ( Heap_packet));
406 hpacket.comm.tsize = sizeof ( Heap_packet);
407 hpacket.comm.tstamp = gethrtime ();
408 hpacket.mtype = MALLOC_TRACE;
409 hpacket.size = (Size_type) size;
410 hpacket.vaddr = (Vaddr_type) ret;
411 hpacket.ovaddr = (Vaddr_type) 0;
412 hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
413 collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
414 POP_REENTRANCE (guard);
415 return ret;
416 }
417
418 /*------------------------------------------------------------- valloc */
419
420 void *
421 valloc (size_t size)
422 {
423 void *ret;
424 int *guard;
425 Heap_packet hpacket;
426 if (NULL_PTR (memalign))
427 init_heap_intf ();
428 if (CHCK_REENTRANCE (guard))
429 {
430 ret = (void *) CALL_REAL (valloc)(size);
431 return ret;
432 }
433 PUSH_REENTRANCE (guard);
434 ret = (void *) CALL_REAL (valloc)(size);
435 collector_memset (&hpacket, 0, sizeof ( Heap_packet));
436 hpacket.comm.tsize = sizeof ( Heap_packet);
437 hpacket.comm.tstamp = gethrtime ();
438 hpacket.mtype = MALLOC_TRACE;
439 hpacket.size = (Size_type) size;
440 hpacket.vaddr = (Vaddr_type) ret;
441 hpacket.ovaddr = (Vaddr_type) 0;
442 hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
443 collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
444 POP_REENTRANCE (guard);
445 return ret;
446 }
447
448 /*------------------------------------------------------------- calloc */
449 void *
450 calloc (size_t size, size_t esize)
451 {
452 void *ret;
453 int *guard;
454 Heap_packet hpacket;
455 if (NULL_PTR (calloc))
456 {
457 if (in_init_heap_intf != 0)
458 return NULL; // Terminate infinite loop
459 init_heap_intf ();
460 }
461 if (CHCK_REENTRANCE (guard))
462 {
463 ret = (void *) CALL_REAL (calloc)(size, esize);
464 return ret;
465 }
466 PUSH_REENTRANCE (guard);
467 ret = (void *) CALL_REAL (calloc)(size, esize);
468 collector_memset (&hpacket, 0, sizeof ( Heap_packet));
469 hpacket.comm.tsize = sizeof ( Heap_packet);
470 hpacket.comm.tstamp = gethrtime ();
471 hpacket.mtype = MALLOC_TRACE;
472 hpacket.size = (Size_type) (size * esize);
473 hpacket.vaddr = (Vaddr_type) ret;
474 hpacket.ovaddr = (Vaddr_type) 0;
475 hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
476 collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
477 POP_REENTRANCE (guard);
478 return ret;
479 }
480
481 /* __collector_heap_record is used to record java allocations/deallocations.
482 * It uses the same facilities as regular heap tracing for now.
483 */
484 void
485 __collector_heap_record (int mtype, size_t size, void *vaddr)
486 {
487 int *guard;
488 Heap_packet hpacket;
489 if (CHCK_REENTRANCE (guard))
490 return;
491 PUSH_REENTRANCE (guard);
492 collector_memset (&hpacket, 0, sizeof ( Heap_packet));
493 hpacket.comm.tsize = sizeof ( Heap_packet);
494 hpacket.comm.tstamp = gethrtime ();
495 hpacket.mtype = mtype;
496 hpacket.size = (Size_type) size;
497 hpacket.vaddr = (Vaddr_type) vaddr;
498 hpacket.ovaddr = (Vaddr_type) 0;
499 hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
500 collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
501 POP_REENTRANCE (guard);
502 return;
503 }