Update install.texi, and regenerate INSTALL.
[glibc.git] / malloc / mtrace-impl.c
blob0e10ab7f604cda4851ae686249df9d2b1f5ecfc4
1 /* mtrace implementation for `malloc'.
2 Copyright (C) 1991-2021 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.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, see
19 <https://www.gnu.org/licenses/>. */
22 #include <malloc.h>
23 #include <mcheck.h>
25 #include <dlfcn.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <inttypes.h>
32 #include <libc-internal.h>
33 #include <dso_handle.h>
35 #include <kernel-features.h>
37 #define TRACE_BUFFER_SIZE 512
39 static FILE *mallstream;
40 static const char mallenv[] = "MALLOC_TRACE";
41 static char *malloc_trace_buffer;
43 static void
44 tr_where (const void *caller, Dl_info *info)
46 if (caller != NULL)
48 if (info != NULL)
50 char *buf = (char *) "";
51 if (info->dli_sname != NULL)
53 size_t len = strlen (info->dli_sname);
54 buf = alloca (len + 6 + 2 * sizeof (void *));
55 char sign;
56 ptrdiff_t offset =
57 (ptrdiff_t) info->dli_saddr - (ptrdiff_t) caller;
59 if (caller >= (const void *) info->dli_saddr)
61 sign = '+';
62 offset = -offset;
64 else
65 sign = '-';
67 sprintf (buf, "(%s%c%" PRIxPTR ")", info->dli_sname, sign,
68 offset);
71 fprintf (mallstream, "@ %s%s%s[%p] ", info->dli_fname ? : "",
72 info->dli_fname ? ":" : "",
73 buf, caller);
75 else
76 fprintf (mallstream, "@ [%p] ", caller);
80 static Dl_info *
81 lock_and_info (const void *caller, Dl_info *mem)
83 if (caller == NULL)
84 return NULL;
86 Dl_info *res = dladdr (caller, mem) ? mem : NULL;
88 flockfile (mallstream);
90 return res;
93 static void
94 free_mtrace (void *ptr, const void *caller)
96 if (ptr == NULL)
97 return;
99 Dl_info mem;
100 Dl_info *info = lock_and_info (caller, &mem);
101 tr_where (caller, info);
102 /* Be sure to print it first. */
103 fprintf (mallstream, "- %p\n", ptr);
104 funlockfile (mallstream);
107 static void
108 malloc_mtrace_after (void *block, size_t size, const void *caller)
110 Dl_info mem;
111 Dl_info *info = lock_and_info (caller, &mem);
113 tr_where (caller, info);
114 /* We could be printing a NULL here; that's OK. */
115 fprintf (mallstream, "+ %p %#lx\n", block, (unsigned long int) size);
117 funlockfile (mallstream);
120 static void
121 realloc_mtrace_after (void *block, const void *oldptr, size_t size,
122 const void *caller)
124 Dl_info mem;
125 Dl_info *info = lock_and_info (caller, &mem);
127 tr_where (caller, info);
128 if (block == NULL)
130 if (size != 0)
131 /* Failed realloc. */
132 fprintf (mallstream, "! %p %#lx\n", oldptr, (unsigned long int) size);
133 else
134 fprintf (mallstream, "- %p\n", oldptr);
136 else if (oldptr == NULL)
137 fprintf (mallstream, "+ %p %#lx\n", block, (unsigned long int) size);
138 else
140 fprintf (mallstream, "< %p\n", oldptr);
141 tr_where (caller, info);
142 fprintf (mallstream, "> %p %#lx\n", block, (unsigned long int) size);
145 funlockfile (mallstream);
148 static void
149 memalign_mtrace_after (void *block, size_t size, const void *caller)
151 Dl_info mem;
152 Dl_info *info = lock_and_info (caller, &mem);
154 tr_where (caller, info);
155 /* We could be printing a NULL here; that's OK. */
156 fprintf (mallstream, "+ %p %#lx\n", block, (unsigned long int) size);
158 funlockfile (mallstream);
161 /* This function gets called to make sure all memory the library
162 allocates get freed and so does not irritate the user when studying
163 the mtrace output. */
164 static void
165 release_libc_mem (void)
167 /* Only call the free function if we still are running in mtrace mode. */
168 if (mallstream != NULL)
169 __libc_freeres ();
172 /* We enable tracing if the environment variable MALLOC_TRACE is set. */
174 static void
175 do_mtrace (void)
177 static int added_atexit_handler;
178 char *mallfile;
180 /* Don't panic if we're called more than once. */
181 if (mallstream != NULL)
182 return;
184 mallfile = secure_getenv (mallenv);
185 if (mallfile != NULL)
187 char *mtb = malloc (TRACE_BUFFER_SIZE);
188 if (mtb == NULL)
189 return;
191 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
192 if (mallstream != NULL)
194 /* Be sure it doesn't malloc its buffer! */
195 malloc_trace_buffer = mtb;
196 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
197 fprintf (mallstream, "= Start\n");
198 if (!added_atexit_handler)
200 added_atexit_handler = 1;
201 __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
202 __dso_handle);
204 __malloc_debug_enable (MALLOC_MTRACE_HOOK);
206 else
207 free (mtb);
211 static void
212 do_muntrace (void)
214 __malloc_debug_disable (MALLOC_MTRACE_HOOK);
215 if (mallstream == NULL)
216 return;
218 /* Do the reverse of what done in mtrace: first reset the hooks and
219 MALLSTREAM, and only after that write the trailer and close the
220 file. */
221 FILE *f = mallstream;
222 mallstream = NULL;
224 fprintf (f, "= End\n");
225 fclose (f);