mtrace-impl.c 5.3 KB

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