(root)/
glibc-2.38/
malloc/
mtrace-impl.c
       1  /* mtrace implementation for `malloc'.
       2     Copyright (C) 1991-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  
      20  #include <malloc.h>
      21  #include <mcheck.h>
      22  
      23  #include <dlfcn.h>
      24  #include <fcntl.h>
      25  #include <stdio.h>
      26  #include <string.h>
      27  #include <stdlib.h>
      28  #include <inttypes.h>
      29  
      30  #include <libc-internal.h>
      31  #include <dso_handle.h>
      32  
      33  #include <kernel-features.h>
      34  
      35  static FILE *mallstream;
      36  static const char mallenv[] = "MALLOC_TRACE";
      37  
      38  static void
      39  tr_where (const void *caller, Dl_info *info)
      40  {
      41    if (caller != NULL)
      42      {
      43        if (info != NULL)
      44          {
      45            char *buf = (char *) "";
      46            if (info->dli_sname != NULL)
      47              {
      48                size_t len = strlen (info->dli_sname);
      49                buf = alloca (len + 6 + 2 * sizeof (void *));
      50  	      char sign;
      51  	      ptrdiff_t offset =
      52  		(ptrdiff_t) info->dli_saddr - (ptrdiff_t) caller;
      53  
      54  	      if (caller >= (const void *) info->dli_saddr)
      55  		{
      56  		  sign = '+';
      57  		  offset = -offset;
      58  		}
      59  	      else
      60  		  sign = '-';
      61  
      62  	      sprintf (buf, "(%s%c%" PRIxPTR ")", info->dli_sname, sign,
      63  		       offset);
      64              }
      65  
      66  	  fprintf (mallstream, "@ %s%s%s[0x%" PRIxPTR "] ",
      67  		   info->dli_fname ? : "", info->dli_fname ? ":" : "", buf,
      68  		   caller - info->dli_fbase);
      69          }
      70        else
      71          fprintf (mallstream, "@ [%p] ", caller);
      72      }
      73  }
      74  
      75  static Dl_info *
      76  lock_and_info (const void *caller, Dl_info *mem)
      77  {
      78    if (caller == NULL)
      79      return NULL;
      80  
      81    Dl_info *res = dladdr (caller, mem) ? mem : NULL;
      82  
      83    flockfile (mallstream);
      84  
      85    return res;
      86  }
      87  
      88  static void
      89  free_mtrace (void *ptr, const void *caller)
      90  {
      91    if (ptr == NULL)
      92      return;
      93  
      94    Dl_info mem;
      95    Dl_info *info = lock_and_info (caller, &mem);
      96    tr_where (caller, info);
      97    /* Be sure to print it first.  */
      98    fprintf (mallstream, "- %p\n", ptr);
      99    funlockfile (mallstream);
     100  }
     101  
     102  static void
     103  malloc_mtrace_after (void *block, size_t size, const void *caller)
     104  {
     105    Dl_info mem;
     106    Dl_info *info = lock_and_info (caller, &mem);
     107  
     108    tr_where (caller, info);
     109    /* We could be printing a NULL here; that's OK.  */
     110    fprintf (mallstream, "+ %p %#lx\n", block, (unsigned long int) size);
     111  
     112    funlockfile (mallstream);
     113  }
     114  
     115  static void
     116  realloc_mtrace_after (void *block, const void *oldptr, size_t size,
     117  		      const void *caller)
     118  {
     119    Dl_info mem;
     120    Dl_info *info = lock_and_info (caller, &mem);
     121  
     122    tr_where (caller, info);
     123    if (block == NULL)
     124      {
     125        if (size != 0)
     126          /* Failed realloc.  */
     127  	fprintf (mallstream, "! %p %#lx\n", oldptr, (unsigned long int) size);
     128        else
     129          fprintf (mallstream, "- %p\n", oldptr);
     130      }
     131    else if (oldptr == NULL)
     132      fprintf (mallstream, "+ %p %#lx\n", block, (unsigned long int) size);
     133    else
     134      {
     135        fprintf (mallstream, "< %p\n", oldptr);
     136        tr_where (caller, info);
     137        fprintf (mallstream, "> %p %#lx\n", block, (unsigned long int) size);
     138      }
     139  
     140    funlockfile (mallstream);
     141  }
     142  
     143  static void
     144  memalign_mtrace_after (void *block, size_t size, const void *caller)
     145  {
     146    Dl_info mem;
     147    Dl_info *info = lock_and_info (caller, &mem);
     148  
     149    tr_where (caller, info);
     150    /* We could be printing a NULL here; that's OK.  */
     151    fprintf (mallstream, "+ %p %#lx\n", block, (unsigned long int) size);
     152  
     153    funlockfile (mallstream);
     154  }
     155  
     156  /* This function gets called to make sure all memory the library
     157     allocates get freed and so does not irritate the user when studying
     158     the mtrace output.  */
     159  static void
     160  release_libc_mem (void)
     161  {
     162    /* Only call the free function if we still are running in mtrace mode.  */
     163    if (mallstream != NULL)
     164      __libc_freeres ();
     165  }
     166  
     167  /* We enable tracing if the environment variable MALLOC_TRACE is set.  */
     168  
     169  static void
     170  do_mtrace (void)
     171  {
     172    static int added_atexit_handler;
     173    char *mallfile;
     174  
     175    /* Don't panic if we're called more than once.  */
     176    if (mallstream != NULL)
     177      return;
     178  
     179    mallfile = secure_getenv (mallenv);
     180    if (mallfile != NULL)
     181      {
     182        mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
     183        if (mallstream != NULL)
     184          {
     185            /* Be sure it doesn't malloc its buffer!  */
     186  	  static char tracebuf [512];
     187  
     188  	  setvbuf (mallstream, tracebuf, _IOFBF, sizeof (tracebuf));
     189            fprintf (mallstream, "= Start\n");
     190            if (!added_atexit_handler)
     191              {
     192                added_atexit_handler = 1;
     193                __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
     194  			    __dso_handle);
     195              }
     196  	  __malloc_debug_enable (MALLOC_MTRACE_HOOK);
     197          }
     198      }
     199  }
     200  
     201  static void
     202  do_muntrace (void)
     203  {
     204    __malloc_debug_disable (MALLOC_MTRACE_HOOK);
     205    if (mallstream == NULL)
     206      return;
     207  
     208    /* Do the reverse of what done in mtrace: first reset the hooks and
     209       MALLSTREAM, and only after that write the trailer and close the
     210       file.  */
     211    FILE *f = mallstream;
     212    mallstream = NULL;
     213  
     214    fprintf (f, "= End\n");
     215    fclose (f);
     216  }