mtrace.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /* More debugging hooks for `malloc'.
  2. Copyright (C) 1991-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. Written April 2, 1991 by John Gilmore of Cygnus Support.
  5. Based on mcheck.c by Mike Haertel.
  6. The GNU C Library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  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. You should have received a copy of the GNU Lesser General Public
  15. License along with the GNU C Library; if not, see
  16. <http://www.gnu.org/licenses/>. */
  17. #ifndef _MALLOC_INTERNAL
  18. # define _MALLOC_INTERNAL
  19. # include <malloc.h>
  20. # include <mcheck.h>
  21. # include <libc-lock.h>
  22. #endif
  23. #include <dlfcn.h>
  24. #include <fcntl.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <_itoa.h>
  29. #include <libc-internal.h>
  30. #include <dso_handle.h>
  31. #include <libio/iolibio.h>
  32. #define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
  33. #define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
  34. #include <kernel-features.h>
  35. #define TRACE_BUFFER_SIZE 512
  36. static FILE *mallstream;
  37. static const char mallenv[] = "MALLOC_TRACE";
  38. static char *malloc_trace_buffer;
  39. __libc_lock_define_initialized (static, lock);
  40. /* Address to breakpoint on accesses to... */
  41. void *mallwatch;
  42. /* Old hook values. */
  43. static void (*tr_old_free_hook) (void *ptr, const void *);
  44. static void *(*tr_old_malloc_hook) (size_t size, const void *);
  45. static void *(*tr_old_realloc_hook) (void *ptr, size_t size,
  46. const void *);
  47. static void *(*tr_old_memalign_hook) (size_t __alignment, size_t __size,
  48. const void *);
  49. /* This function is called when the block being alloc'd, realloc'd, or
  50. freed has an address matching the variable "mallwatch". In a debugger,
  51. set "mallwatch" to the address of interest, then put a breakpoint on
  52. tr_break. */
  53. extern void tr_break (void) __THROW;
  54. libc_hidden_proto (tr_break)
  55. void
  56. tr_break (void)
  57. {
  58. }
  59. libc_hidden_def (tr_break)
  60. static void
  61. tr_where (const void *caller, Dl_info *info)
  62. {
  63. if (caller != NULL)
  64. {
  65. if (info != NULL)
  66. {
  67. char *buf = (char *) "";
  68. if (info->dli_sname != NULL)
  69. {
  70. size_t len = strlen (info->dli_sname);
  71. buf = alloca (len + 6 + 2 * sizeof (void *));
  72. buf[0] = '(';
  73. __stpcpy (_fitoa (caller >= (const void *) info->dli_saddr
  74. ? caller - (const void *) info->dli_saddr
  75. : (const void *) info->dli_saddr - caller,
  76. __stpcpy (__mempcpy (buf + 1, info->dli_sname,
  77. len),
  78. caller >= (void *) info->dli_saddr
  79. ? "+0x" : "-0x"),
  80. 16, 0),
  81. ")");
  82. }
  83. fprintf (mallstream, "@ %s%s%s[%p] ",
  84. info->dli_fname ? : "", info->dli_fname ? ":" : "",
  85. buf, caller);
  86. }
  87. else
  88. fprintf (mallstream, "@ [%p] ", caller);
  89. }
  90. }
  91. static Dl_info *
  92. lock_and_info (const void *caller, Dl_info *mem)
  93. {
  94. if (caller == NULL)
  95. return NULL;
  96. Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
  97. __libc_lock_lock (lock);
  98. return res;
  99. }
  100. static void
  101. tr_freehook (void *ptr, const void *caller)
  102. {
  103. if (ptr == NULL)
  104. return;
  105. Dl_info mem;
  106. Dl_info *info = lock_and_info (caller, &mem);
  107. tr_where (caller, info);
  108. /* Be sure to print it first. */
  109. fprintf (mallstream, "- %p\n", ptr);
  110. if (ptr == mallwatch)
  111. {
  112. __libc_lock_unlock (lock);
  113. tr_break ();
  114. __libc_lock_lock (lock);
  115. }
  116. __free_hook = tr_old_free_hook;
  117. if (tr_old_free_hook != NULL)
  118. (*tr_old_free_hook)(ptr, caller);
  119. else
  120. free (ptr);
  121. __free_hook = tr_freehook;
  122. __libc_lock_unlock (lock);
  123. }
  124. static void *
  125. tr_mallochook (size_t size, const void *caller)
  126. {
  127. void *hdr;
  128. Dl_info mem;
  129. Dl_info *info = lock_and_info (caller, &mem);
  130. __malloc_hook = tr_old_malloc_hook;
  131. if (tr_old_malloc_hook != NULL)
  132. hdr = (void *) (*tr_old_malloc_hook)(size, caller);
  133. else
  134. hdr = (void *) malloc (size);
  135. __malloc_hook = tr_mallochook;
  136. tr_where (caller, info);
  137. /* We could be printing a NULL here; that's OK. */
  138. fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
  139. __libc_lock_unlock (lock);
  140. if (hdr == mallwatch)
  141. tr_break ();
  142. return hdr;
  143. }
  144. static void *
  145. tr_reallochook (void *ptr, size_t size, const void *caller)
  146. {
  147. void *hdr;
  148. if (ptr == mallwatch)
  149. tr_break ();
  150. Dl_info mem;
  151. Dl_info *info = lock_and_info (caller, &mem);
  152. __free_hook = tr_old_free_hook;
  153. __malloc_hook = tr_old_malloc_hook;
  154. __realloc_hook = tr_old_realloc_hook;
  155. if (tr_old_realloc_hook != NULL)
  156. hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
  157. else
  158. hdr = (void *) realloc (ptr, size);
  159. __free_hook = tr_freehook;
  160. __malloc_hook = tr_mallochook;
  161. __realloc_hook = tr_reallochook;
  162. tr_where (caller, info);
  163. if (hdr == NULL)
  164. {
  165. if (size != 0)
  166. /* Failed realloc. */
  167. fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
  168. else
  169. fprintf (mallstream, "- %p\n", ptr);
  170. }
  171. else if (ptr == NULL)
  172. fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
  173. else
  174. {
  175. fprintf (mallstream, "< %p\n", ptr);
  176. tr_where (caller, info);
  177. fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
  178. }
  179. __libc_lock_unlock (lock);
  180. if (hdr == mallwatch)
  181. tr_break ();
  182. return hdr;
  183. }
  184. static void *
  185. tr_memalignhook (size_t alignment, size_t size, const void *caller)
  186. {
  187. void *hdr;
  188. Dl_info mem;
  189. Dl_info *info = lock_and_info (caller, &mem);
  190. __memalign_hook = tr_old_memalign_hook;
  191. __malloc_hook = tr_old_malloc_hook;
  192. if (tr_old_memalign_hook != NULL)
  193. hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
  194. else
  195. hdr = (void *) memalign (alignment, size);
  196. __memalign_hook = tr_memalignhook;
  197. __malloc_hook = tr_mallochook;
  198. tr_where (caller, info);
  199. /* We could be printing a NULL here; that's OK. */
  200. fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
  201. __libc_lock_unlock (lock);
  202. if (hdr == mallwatch)
  203. tr_break ();
  204. return hdr;
  205. }
  206. #ifdef _LIBC
  207. /* This function gets called to make sure all memory the library
  208. allocates get freed and so does not irritate the user when studying
  209. the mtrace output. */
  210. static void __libc_freeres_fn_section
  211. release_libc_mem (void)
  212. {
  213. /* Only call the free function if we still are running in mtrace mode. */
  214. if (mallstream != NULL)
  215. __libc_freeres ();
  216. }
  217. #endif
  218. /* We enable tracing if either the environment variable MALLOC_TRACE
  219. is set, or if the variable mallwatch has been patched to an address
  220. that the debugging user wants us to stop on. When patching mallwatch,
  221. don't forget to set a breakpoint on tr_break! */
  222. void
  223. mtrace (void)
  224. {
  225. #ifdef _LIBC
  226. static int added_atexit_handler;
  227. #endif
  228. char *mallfile;
  229. /* Don't panic if we're called more than once. */
  230. if (mallstream != NULL)
  231. return;
  232. #ifdef _LIBC
  233. /* When compiling the GNU libc we use the secure getenv function
  234. which prevents the misuse in case of SUID or SGID enabled
  235. programs. */
  236. mallfile = __libc_secure_getenv (mallenv);
  237. #else
  238. mallfile = getenv (mallenv);
  239. #endif
  240. if (mallfile != NULL || mallwatch != NULL)
  241. {
  242. char *mtb = malloc (TRACE_BUFFER_SIZE);
  243. if (mtb == NULL)
  244. return;
  245. mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
  246. if (mallstream != NULL)
  247. {
  248. /* Be sure it doesn't malloc its buffer! */
  249. malloc_trace_buffer = mtb;
  250. setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
  251. fprintf (mallstream, "= Start\n");
  252. tr_old_free_hook = __free_hook;
  253. __free_hook = tr_freehook;
  254. tr_old_malloc_hook = __malloc_hook;
  255. __malloc_hook = tr_mallochook;
  256. tr_old_realloc_hook = __realloc_hook;
  257. __realloc_hook = tr_reallochook;
  258. tr_old_memalign_hook = __memalign_hook;
  259. __memalign_hook = tr_memalignhook;
  260. #ifdef _LIBC
  261. if (!added_atexit_handler)
  262. {
  263. added_atexit_handler = 1;
  264. __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
  265. __dso_handle);
  266. }
  267. #endif
  268. }
  269. else
  270. free (mtb);
  271. }
  272. }
  273. void
  274. muntrace (void)
  275. {
  276. if (mallstream == NULL)
  277. return;
  278. /* Do the reverse of what done in mtrace: first reset the hooks and
  279. MALLSTREAM, and only after that write the trailer and close the
  280. file. */
  281. FILE *f = mallstream;
  282. mallstream = NULL;
  283. __free_hook = tr_old_free_hook;
  284. __malloc_hook = tr_old_malloc_hook;
  285. __realloc_hook = tr_old_realloc_hook;
  286. __memalign_hook = tr_old_memalign_hook;
  287. fprintf (f, "= End\n");
  288. fclose (f);
  289. }