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