xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/libcollector/heaptrace.c (revision c64d4171c6f912972428361000d29636c687d68b)
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 = (intptr_t) ret;
302   hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
303   collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
304   POP_REENTRANCE (guard);
305   return (void *) ret;
306 }
307 
308 /*------------------------------------------------------------- free */
309 
310 void
311 free (void *ptr)
312 {
313   int *guard;
314   Heap_packet hpacket;
315   /* Linux startup workaround  */
316   if (!heap_mode)
317     {
318       // Tprintf(DBG_LT4,"heaptrace: LINUX free(%p)...\n",ptr);
319       __libc_free (ptr);
320       return;
321     }
322   if (NULL_PTR (malloc))
323     init_heap_intf ();
324   if (CHCK_REENTRANCE (guard))
325     {
326       CALL_REAL (free)(ptr);
327       return;
328     }
329   if (ptr == NULL)
330     return;
331   PUSH_REENTRANCE (guard);
332 
333   /* Get a timestamp before 'free' to enforce consistency */
334   hrtime_t ts = gethrtime ();
335   CALL_REAL (free)(ptr);
336   collector_memset (&hpacket, 0, sizeof ( Heap_packet));
337   hpacket.comm.tsize = sizeof ( Heap_packet);
338   hpacket.comm.tstamp = ts;
339   hpacket.mtype = FREE_TRACE;
340   hpacket.vaddr = (intptr_t) ptr;
341   hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
342   collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
343   POP_REENTRANCE (guard);
344   return;
345 }
346 
347 /*------------------------------------------------------------- realloc */
348 void *
349 realloc (void *ptr, size_t size)
350 {
351   void *ret;
352   int *guard;
353   Heap_packet hpacket;
354 
355   /* Linux startup workaround  */
356   if (!heap_mode)
357     {
358       void * ppp = (void *) __libc_realloc (ptr, size);
359       Tprintf (DBG_LT4, "heaptrace: LINUX realloc(%ld, %p->%p)...\n",
360 	       (long) size, ptr, ppp);
361       return ppp;
362     }
363   if (NULL_PTR (realloc))
364     init_heap_intf ();
365   if (CHCK_REENTRANCE (guard))
366     {
367       ret = (void *) CALL_REAL (realloc)(ptr, size);
368       return ret;
369     }
370   PUSH_REENTRANCE (guard);
371   hrtime_t ts = gethrtime ();
372   ret = (void *) CALL_REAL (realloc)(ptr, size);
373   collector_memset (&hpacket, 0, sizeof ( Heap_packet));
374   hpacket.comm.tsize = sizeof ( Heap_packet);
375   hpacket.comm.tstamp = ts;
376   hpacket.mtype = REALLOC_TRACE;
377   hpacket.size = (Size_type) size;
378   hpacket.vaddr = (intptr_t) ret;
379   hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
380   collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
381   POP_REENTRANCE (guard);
382   return (void *) ret;
383 }
384 
385 /*------------------------------------------------------------- memalign */
386 void *
387 memalign (size_t align, size_t size)
388 {
389   void *ret;
390   int *guard;
391   Heap_packet hpacket;
392   if (NULL_PTR (memalign))
393     init_heap_intf ();
394   if (CHCK_REENTRANCE (guard))
395     {
396       ret = (void *) CALL_REAL (memalign)(align, size);
397       return ret;
398     }
399   PUSH_REENTRANCE (guard);
400   ret = (void *) CALL_REAL (memalign)(align, size);
401   collector_memset (&hpacket, 0, sizeof ( Heap_packet));
402   hpacket.comm.tsize = sizeof ( Heap_packet);
403   hpacket.comm.tstamp = gethrtime ();
404   hpacket.mtype = MALLOC_TRACE;
405   hpacket.size = (Size_type) size;
406   hpacket.vaddr = (intptr_t) ret;
407   hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
408   collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
409   POP_REENTRANCE (guard);
410   return ret;
411 }
412 
413 /*------------------------------------------------------------- valloc */
414 
415 void *
416 valloc (size_t size)
417 {
418   void *ret;
419   int *guard;
420   Heap_packet hpacket;
421   if (NULL_PTR (memalign))
422     init_heap_intf ();
423   if (CHCK_REENTRANCE (guard))
424     {
425       ret = (void *) CALL_REAL (valloc)(size);
426       return ret;
427     }
428   PUSH_REENTRANCE (guard);
429   ret = (void *) CALL_REAL (valloc)(size);
430   collector_memset (&hpacket, 0, sizeof ( Heap_packet));
431   hpacket.comm.tsize = sizeof ( Heap_packet);
432   hpacket.comm.tstamp = gethrtime ();
433   hpacket.mtype = MALLOC_TRACE;
434   hpacket.size = (Size_type) size;
435   hpacket.vaddr = (intptr_t) ret;
436   hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
437   collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
438   POP_REENTRANCE (guard);
439   return ret;
440 }
441 
442 /*------------------------------------------------------------- calloc */
443 void *
444 calloc (size_t size, size_t esize)
445 {
446   void *ret;
447   int *guard;
448   Heap_packet hpacket;
449   if (NULL_PTR (calloc))
450     {
451       if (in_init_heap_intf != 0)
452 	return NULL; // Terminate infinite loop
453       init_heap_intf ();
454     }
455   if (CHCK_REENTRANCE (guard))
456     {
457       ret = (void *) CALL_REAL (calloc)(size, esize);
458       return ret;
459     }
460   PUSH_REENTRANCE (guard);
461   ret = (void *) CALL_REAL (calloc)(size, esize);
462   collector_memset (&hpacket, 0, sizeof ( Heap_packet));
463   hpacket.comm.tsize = sizeof ( Heap_packet);
464   hpacket.comm.tstamp = gethrtime ();
465   hpacket.mtype = MALLOC_TRACE;
466   hpacket.size = (Size_type) (size * esize);
467   hpacket.vaddr = (intptr_t) ret;
468   hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
469   collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
470   POP_REENTRANCE (guard);
471   return ret;
472 }
473 
474 /* __collector_heap_record is used to record java allocations/deallocations.
475  * It uses the same facilities as regular heap tracing for now.
476  */
477 void
478 __collector_heap_record (int mtype, size_t size, void *vaddr)
479 {
480   int *guard;
481   Heap_packet hpacket;
482   if (CHCK_REENTRANCE (guard))
483     return;
484   PUSH_REENTRANCE (guard);
485   collector_memset (&hpacket, 0, sizeof ( Heap_packet));
486   hpacket.comm.tsize = sizeof ( Heap_packet);
487   hpacket.comm.tstamp = gethrtime ();
488   hpacket.mtype = mtype;
489   hpacket.size = (Size_type) size;
490   hpacket.vaddr = (intptr_t) vaddr;
491   hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
492   collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
493   POP_REENTRANCE (guard);
494   return;
495 }
496