1*404b540aSrobert /* Implementation header for mudflap runtime library.
2*404b540aSrobert Mudflap: narrow-pointer bounds-checking by tree rewriting.
3*404b540aSrobert Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
4*404b540aSrobert Contributed by Frank Ch. Eigler <fche@redhat.com>
5*404b540aSrobert and Graydon Hoare <graydon@redhat.com>
6*404b540aSrobert
7*404b540aSrobert This file is part of GCC.
8*404b540aSrobert
9*404b540aSrobert GCC is free software; you can redistribute it and/or modify it under
10*404b540aSrobert the terms of the GNU General Public License as published by the Free
11*404b540aSrobert Software Foundation; either version 2, or (at your option) any later
12*404b540aSrobert version.
13*404b540aSrobert
14*404b540aSrobert In addition to the permissions in the GNU General Public License, the
15*404b540aSrobert Free Software Foundation gives you unlimited permission to link the
16*404b540aSrobert compiled version of this file into combinations with other programs,
17*404b540aSrobert and to distribute those combinations without any restriction coming
18*404b540aSrobert from the use of this file. (The General Public License restrictions
19*404b540aSrobert do apply in other respects; for example, they cover modification of
20*404b540aSrobert the file, and distribution when not linked into a combine
21*404b540aSrobert executable.)
22*404b540aSrobert
23*404b540aSrobert GCC is distributed in the hope that it will be useful, but WITHOUT ANY
24*404b540aSrobert WARRANTY; without even the implied warranty of MERCHANTABILITY or
25*404b540aSrobert FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26*404b540aSrobert for more details.
27*404b540aSrobert
28*404b540aSrobert You should have received a copy of the GNU General Public License
29*404b540aSrobert along with GCC; see the file COPYING. If not, write to the Free
30*404b540aSrobert Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
31*404b540aSrobert 02110-1301, USA. */
32*404b540aSrobert
33*404b540aSrobert #ifndef __MF_IMPL_H
34*404b540aSrobert #define __MF_IMPL_H
35*404b540aSrobert
36*404b540aSrobert #ifdef _MUDFLAP
37*404b540aSrobert #error "Do not compile this file with -fmudflap!"
38*404b540aSrobert #endif
39*404b540aSrobert
40*404b540aSrobert #if HAVE_PTHREAD_H
41*404b540aSrobert #include <pthread.h>
42*404b540aSrobert #elif LIBMUDFLAPTH
43*404b540aSrobert #error "Cannot build libmudflapth without pthread.h."
44*404b540aSrobert #endif
45*404b540aSrobert
46*404b540aSrobert #if HAVE_STDINT_H
47*404b540aSrobert #include <stdint.h>
48*404b540aSrobert #else
49*404b540aSrobert typedef __mf_uintptr_t uintptr_t;
50*404b540aSrobert #endif
51*404b540aSrobert
52*404b540aSrobert /* Private definitions related to mf-runtime.h */
53*404b540aSrobert
54*404b540aSrobert #define __MF_TYPE_MAX_CEM __MF_TYPE_STACK /* largest type# for the cemetary */
55*404b540aSrobert #define __MF_TYPE_MAX __MF_TYPE_GUESS
56*404b540aSrobert
57*404b540aSrobert
58*404b540aSrobert #ifndef max
59*404b540aSrobert #define max(a,b) ((a) > (b) ? (a) : (b))
60*404b540aSrobert #endif
61*404b540aSrobert
62*404b540aSrobert #ifndef min
63*404b540aSrobert #define min(a,b) ((a) < (b) ? (a) : (b))
64*404b540aSrobert #endif
65*404b540aSrobert
66*404b540aSrobert /* Address calculation macros. */
67*404b540aSrobert
68*404b540aSrobert #define MINPTR ((uintptr_t) 0)
69*404b540aSrobert #define MAXPTR (~ (uintptr_t) 0)
70*404b540aSrobert
71*404b540aSrobert /* Clamp the addition/subtraction of uintptr_t's to [MINPTR,MAXPTR] */
72*404b540aSrobert #define CLAMPSUB(ptr,offset) (((uintptr_t) ptr) >= (offset) ? ((uintptr_t) ptr)-((uintptr_t) offset) : MINPTR)
73*404b540aSrobert #define CLAMPADD(ptr,offset) (((uintptr_t) ptr) <= MAXPTR-(offset) ? ((uintptr_t) ptr)+((uintptr_t) offset) : MAXPTR)
74*404b540aSrobert #define CLAMPSZ(ptr,size) ((size) ? (((uintptr_t) ptr) <= MAXPTR-(size)+1 ? ((uintptr_t) ptr)+((uintptr_t) size) - 1 : MAXPTR) : ((uintptr_t) ptr))
75*404b540aSrobert
76*404b540aSrobert #define __MF_CACHE_INDEX(ptr) ((((uintptr_t) (ptr)) >> __mf_lc_shift) & __mf_lc_mask)
77*404b540aSrobert #define __MF_CACHE_MISS_P(ptr,sz) ({ \
78*404b540aSrobert struct __mf_cache *elem = & __mf_lookup_cache[__MF_CACHE_INDEX((ptr))]; \
79*404b540aSrobert ((elem->low > (uintptr_t) (ptr)) || \
80*404b540aSrobert (elem->high < (CLAMPADD((uintptr_t) (ptr), (uintptr_t) CLAMPSUB(sz,1) )))); })
81*404b540aSrobert /* XXX: the above should use CLAMPSZ () */
82*404b540aSrobert
83*404b540aSrobert
84*404b540aSrobert
85*404b540aSrobert /* Private functions. */
86*404b540aSrobert
87*404b540aSrobert extern void __mf_violation (void *ptr, size_t sz,
88*404b540aSrobert uintptr_t pc, const char *location,
89*404b540aSrobert int type);
90*404b540aSrobert extern size_t __mf_backtrace (char ***, void *, unsigned);
91*404b540aSrobert extern int __mf_heuristic_check (uintptr_t, uintptr_t);
92*404b540aSrobert
93*404b540aSrobert /* ------------------------------------------------------------------------ */
94*404b540aSrobert /* Type definitions. */
95*404b540aSrobert /* ------------------------------------------------------------------------ */
96*404b540aSrobert
97*404b540aSrobert /* The mf_state type codes describe recursion and initialization order.
98*404b540aSrobert
99*404b540aSrobert reentrant means we are inside a mf-runtime support routine, such as
100*404b540aSrobert __mf_register, and thus there should be no calls to any wrapped functions,
101*404b540aSrobert such as the wrapped malloc. This indicates a bug if it occurs.
102*404b540aSrobert in_malloc means we are inside a real malloc call inside a wrapped malloc
103*404b540aSrobert call, and thus there should be no calls to any wrapped functions like the
104*404b540aSrobert wrapped mmap. This happens on some systems due to how the system libraries
105*404b540aSrobert are constructed. */
106*404b540aSrobert
107*404b540aSrobert enum __mf_state_enum { active, reentrant, in_malloc };
108*404b540aSrobert
109*404b540aSrobert /* The __mf_options structure records optional or tunable aspects of the
110*404b540aSrobert mudflap library's behavior. There is a single global instance of this
111*404b540aSrobert structure which is populated from user input (in an environment variable)
112*404b540aSrobert when the library initializes. */
113*404b540aSrobert
114*404b540aSrobert struct __mf_options
115*404b540aSrobert {
116*404b540aSrobert /* Emit a trace message for each call. */
117*404b540aSrobert unsigned trace_mf_calls;
118*404b540aSrobert
119*404b540aSrobert /* Collect and emit statistics. */
120*404b540aSrobert unsigned collect_stats;
121*404b540aSrobert
122*404b540aSrobert /* Set up a SIGUSR1 -> __mf_report handler. */
123*404b540aSrobert unsigned sigusr1_report;
124*404b540aSrobert
125*404b540aSrobert /* Execute internal checking code. */
126*404b540aSrobert unsigned internal_checking;
127*404b540aSrobert
128*404b540aSrobert /* Age object liveness periodically. */
129*404b540aSrobert unsigned tree_aging;
130*404b540aSrobert
131*404b540aSrobert /* Adapt the lookup cache to working set. */
132*404b540aSrobert unsigned adapt_cache;
133*404b540aSrobert
134*404b540aSrobert /* Print list of leaked heap objects on shutdown. */
135*404b540aSrobert unsigned print_leaks;
136*404b540aSrobert
137*404b540aSrobert /* Detect reads of uninitialized objects. */
138*404b540aSrobert unsigned check_initialization;
139*404b540aSrobert
140*404b540aSrobert /* Print verbose description of violations. */
141*404b540aSrobert unsigned verbose_violations;
142*404b540aSrobert
143*404b540aSrobert /* Abbreviate duplicate object descriptions. */
144*404b540aSrobert unsigned abbreviate;
145*404b540aSrobert
146*404b540aSrobert /* Emit internal tracing message. */
147*404b540aSrobert unsigned verbose_trace;
148*404b540aSrobert
149*404b540aSrobert /* Wipe stack/heap objects upon unwind. */
150*404b540aSrobert unsigned wipe_stack;
151*404b540aSrobert unsigned wipe_heap;
152*404b540aSrobert
153*404b540aSrobert /* Maintain a queue of this many deferred free()s,
154*404b540aSrobert to trap use of freed memory. */
155*404b540aSrobert unsigned free_queue_length;
156*404b540aSrobert
157*404b540aSrobert /* Maintain a history of this many past unregistered objects. */
158*404b540aSrobert unsigned persistent_count;
159*404b540aSrobert
160*404b540aSrobert /* Pad allocated extents by this many bytes on either side. */
161*404b540aSrobert unsigned crumple_zone;
162*404b540aSrobert
163*404b540aSrobert /* Maintain this many stack frames for contexts. */
164*404b540aSrobert unsigned backtrace;
165*404b540aSrobert
166*404b540aSrobert /* Ignore read operations even if mode_check is in effect. */
167*404b540aSrobert unsigned ignore_reads;
168*404b540aSrobert
169*404b540aSrobert /* Collect register/unregister timestamps. */
170*404b540aSrobert unsigned timestamps;
171*404b540aSrobert
172*404b540aSrobert #ifdef LIBMUDFLAPTH
173*404b540aSrobert /* Thread stack size. */
174*404b540aSrobert unsigned thread_stack;
175*404b540aSrobert #endif
176*404b540aSrobert
177*404b540aSrobert /* Major operation mode */
178*404b540aSrobert #define mode_nop 0 /* Do nothing. */
179*404b540aSrobert #define mode_populate 1 /* Populate tree but do not check for violations. */
180*404b540aSrobert #define mode_check 2 /* Populate and check for violations (normal). */
181*404b540aSrobert #define mode_violate 3 /* Trigger a violation on every call (diagnostic). */
182*404b540aSrobert unsigned mudflap_mode;
183*404b540aSrobert
184*404b540aSrobert /* How to handle a violation. */
185*404b540aSrobert #define viol_nop 0 /* Return control to application. */
186*404b540aSrobert #define viol_segv 1 /* Signal self with segv. */
187*404b540aSrobert #define viol_abort 2 /* Call abort (). */
188*404b540aSrobert #define viol_gdb 3 /* Fork a debugger on self */
189*404b540aSrobert unsigned violation_mode;
190*404b540aSrobert
191*404b540aSrobert /* Violation heuristics selection. */
192*404b540aSrobert unsigned heur_stack_bound; /* allow current stack region */
193*404b540aSrobert unsigned heur_proc_map; /* allow & cache /proc/self/map regions. */
194*404b540aSrobert unsigned heur_start_end; /* allow _start .. _end */
195*404b540aSrobert unsigned heur_std_data; /* allow & cache stdlib data */
196*404b540aSrobert };
197*404b540aSrobert
198*404b540aSrobert
199*404b540aSrobert #ifdef PIC
200*404b540aSrobert
201*404b540aSrobert /* This is a table of dynamically resolved function pointers. */
202*404b540aSrobert
203*404b540aSrobert struct __mf_dynamic_entry
204*404b540aSrobert {
205*404b540aSrobert void *pointer;
206*404b540aSrobert char *name;
207*404b540aSrobert char *version;
208*404b540aSrobert };
209*404b540aSrobert
210*404b540aSrobert /* The definition of the array (mf-runtime.c) must match the enums! */
211*404b540aSrobert extern struct __mf_dynamic_entry __mf_dynamic[];
212*404b540aSrobert enum __mf_dynamic_index
213*404b540aSrobert {
214*404b540aSrobert dyn_calloc, dyn_free, dyn_malloc, dyn_mmap,
215*404b540aSrobert dyn_munmap, dyn_realloc,
216*404b540aSrobert dyn_INITRESOLVE, /* Marker for last init-time resolution. */
217*404b540aSrobert #ifdef LIBMUDFLAPTH
218*404b540aSrobert dyn_pthread_create
219*404b540aSrobert #endif
220*404b540aSrobert };
221*404b540aSrobert
222*404b540aSrobert #endif /* PIC */
223*404b540aSrobert
224*404b540aSrobert /* ------------------------------------------------------------------------ */
225*404b540aSrobert /* Private global variables. */
226*404b540aSrobert /* ------------------------------------------------------------------------ */
227*404b540aSrobert
228*404b540aSrobert #ifdef LIBMUDFLAPTH
229*404b540aSrobert extern pthread_mutex_t __mf_biglock;
230*404b540aSrobert #define LOCKTH() do { extern unsigned long __mf_lock_contention; \
231*404b540aSrobert int rc = pthread_mutex_trylock (& __mf_biglock); \
232*404b540aSrobert if (rc) { __mf_lock_contention ++; \
233*404b540aSrobert rc = pthread_mutex_lock (& __mf_biglock); } \
234*404b540aSrobert assert (rc==0); } while (0)
235*404b540aSrobert #define UNLOCKTH() do { int rc = pthread_mutex_unlock (& __mf_biglock); \
236*404b540aSrobert assert (rc==0); } while (0)
237*404b540aSrobert #else
238*404b540aSrobert #define LOCKTH() do {} while (0)
239*404b540aSrobert #define UNLOCKTH() do {} while (0)
240*404b540aSrobert #endif
241*404b540aSrobert
242*404b540aSrobert #if defined(LIBMUDFLAPTH) && !defined(HAVE_TLS)
243*404b540aSrobert extern enum __mf_state_enum __mf_get_state (void);
244*404b540aSrobert extern void __mf_set_state (enum __mf_state_enum);
245*404b540aSrobert #else
246*404b540aSrobert # ifdef LIBMUDFLAPTH
247*404b540aSrobert extern __thread enum __mf_state_enum __mf_state_1;
248*404b540aSrobert # else
249*404b540aSrobert extern enum __mf_state_enum __mf_state_1;
250*404b540aSrobert # endif
__mf_get_state(void)251*404b540aSrobert static inline enum __mf_state_enum __mf_get_state (void)
252*404b540aSrobert {
253*404b540aSrobert return __mf_state_1;
254*404b540aSrobert }
__mf_set_state(enum __mf_state_enum s)255*404b540aSrobert static inline void __mf_set_state (enum __mf_state_enum s)
256*404b540aSrobert {
257*404b540aSrobert __mf_state_1 = s;
258*404b540aSrobert }
259*404b540aSrobert #endif
260*404b540aSrobert
261*404b540aSrobert extern int __mf_starting_p;
262*404b540aSrobert extern struct __mf_options __mf_opts;
263*404b540aSrobert
264*404b540aSrobert /* ------------------------------------------------------------------------ */
265*404b540aSrobert /* Utility macros. */
266*404b540aSrobert /* ------------------------------------------------------------------------ */
267*404b540aSrobert
268*404b540aSrobert #define UNLIKELY(e) (__builtin_expect (!!(e), 0))
269*404b540aSrobert #define LIKELY(e) (__builtin_expect (!!(e), 1))
270*404b540aSrobert #define STRINGIFY2(e) #e
271*404b540aSrobert #define STRINGIFY(e) STRINGIFY2(e)
272*404b540aSrobert
273*404b540aSrobert #ifdef LIBMUDFLAPTH
274*404b540aSrobert #define VERBOSE_TRACE(...) \
275*404b540aSrobert do { if (UNLIKELY (__mf_opts.verbose_trace)) { \
276*404b540aSrobert fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
277*404b540aSrobert fprintf (stderr, __VA_ARGS__); \
278*404b540aSrobert } } while (0)
279*404b540aSrobert #define TRACE(...) \
280*404b540aSrobert do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
281*404b540aSrobert fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
282*404b540aSrobert fprintf (stderr, __VA_ARGS__); \
283*404b540aSrobert } } while (0)
284*404b540aSrobert #else
285*404b540aSrobert #define VERBOSE_TRACE(...) \
286*404b540aSrobert do { if (UNLIKELY (__mf_opts.verbose_trace)) { \
287*404b540aSrobert fprintf (stderr, "mf: "); \
288*404b540aSrobert fprintf (stderr, __VA_ARGS__); \
289*404b540aSrobert } } while (0)
290*404b540aSrobert #define TRACE(...) \
291*404b540aSrobert do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
292*404b540aSrobert fprintf (stderr, "mf: "); \
293*404b540aSrobert fprintf (stderr, __VA_ARGS__); \
294*404b540aSrobert } } while (0)
295*404b540aSrobert #endif
296*404b540aSrobert
297*404b540aSrobert
298*404b540aSrobert #define __MF_PERSIST_MAX 256
299*404b540aSrobert #define __MF_FREEQ_MAX 256
300*404b540aSrobert
301*404b540aSrobert /*
302*404b540aSrobert Wrapping and redirection:
303*404b540aSrobert
304*404b540aSrobert Mudflap redirects a number of libc functions into itself, for "cheap"
305*404b540aSrobert verification (eg. strcpy, bzero, memcpy) and also to register /
306*404b540aSrobert unregister regions of memory as they are manipulated by the program
307*404b540aSrobert (eg. malloc/free, mmap/munmap).
308*404b540aSrobert
309*404b540aSrobert There are two methods of wrapping.
310*404b540aSrobert
311*404b540aSrobert (1) The static method involves a list of -wrap=foo flags being passed to
312*404b540aSrobert the linker, which then links references to "foo" to the symbol
313*404b540aSrobert "__wrap_foo", and links references to "__real_foo" to the symbol "foo".
314*404b540aSrobert When compiled without -DPIC, libmudflap.a contains such __wrap_foo
315*404b540aSrobert functions which delegate to __real_foo functions in libc to get their
316*404b540aSrobert work done.
317*404b540aSrobert
318*404b540aSrobert (2) The dynamic method involves providing a definition of symbol foo in
319*404b540aSrobert libmudflap.so and linking it earlier in the compiler command line,
320*404b540aSrobert before libc.so. The function "foo" in libmudflap must then call
321*404b540aSrobert dlsym(RTLD_NEXT, "foo") to acquire a pointer to the "real" libc foo, or
322*404b540aSrobert at least the "next" foo in the dynamic link resolution order.
323*404b540aSrobert
324*404b540aSrobert We switch between these two techniques by the presence of the -DPIC
325*404b540aSrobert #define passed in by libtool when building libmudflap.
326*404b540aSrobert */
327*404b540aSrobert
328*404b540aSrobert
329*404b540aSrobert #ifdef PIC
330*404b540aSrobert
331*404b540aSrobert extern void __mf_resolve_single_dynamic (struct __mf_dynamic_entry *);
332*404b540aSrobert
333*404b540aSrobert #define _GNU_SOURCE
334*404b540aSrobert #include <dlfcn.h>
335*404b540aSrobert
336*404b540aSrobert #define WRAPPER(ret, fname, ...) \
337*404b540aSrobert ret __wrap_ ## fname (__VA_ARGS__) \
338*404b540aSrobert __attribute__ (( alias (#fname) )); \
339*404b540aSrobert ret __real_ ## fname (__VA_ARGS__) \
340*404b540aSrobert __attribute__ (( alias (#fname) )); \
341*404b540aSrobert ret fname (__VA_ARGS__)
342*404b540aSrobert #define DECLARE(ty, fname, ...) \
343*404b540aSrobert typedef ty (*__mf_fn_ ## fname) (__VA_ARGS__); \
344*404b540aSrobert extern ty __mf_0fn_ ## fname (__VA_ARGS__);
345*404b540aSrobert #define CALL_REAL(fname, ...) \
346*404b540aSrobert ({__mf_starting_p \
347*404b540aSrobert ? __mf_0fn_ ## fname (__VA_ARGS__) \
348*404b540aSrobert : (__mf_resolve_single_dynamic (& __mf_dynamic[dyn_ ## fname]), \
349*404b540aSrobert (((__mf_fn_ ## fname)(__mf_dynamic[dyn_ ## fname].pointer)) (__VA_ARGS__)));})
350*404b540aSrobert #define CALL_BACKUP(fname, ...) \
351*404b540aSrobert __mf_0fn_ ## fname(__VA_ARGS__)
352*404b540aSrobert
353*404b540aSrobert #else /* not PIC --> static library */
354*404b540aSrobert
355*404b540aSrobert #define WRAPPER(ret, fname, ...) \
356*404b540aSrobert ret __wrap_ ## fname (__VA_ARGS__)
357*404b540aSrobert #define DECLARE(ty, fname, ...) \
358*404b540aSrobert extern ty __real_ ## fname (__VA_ARGS__)
359*404b540aSrobert #define CALL_REAL(fname, ...) \
360*404b540aSrobert __real_ ## fname (__VA_ARGS__)
361*404b540aSrobert #define CALL_BACKUP(fname, ...) \
362*404b540aSrobert __real_ ## fname(__VA_ARGS__)
363*404b540aSrobert
364*404b540aSrobert #endif /* PIC */
365*404b540aSrobert
366*404b540aSrobert /* WRAPPER2 is for functions intercepted via macros at compile time. */
367*404b540aSrobert #define WRAPPER2(ret, fname, ...) \
368*404b540aSrobert ret __mfwrap_ ## fname (__VA_ARGS__)
369*404b540aSrobert
370*404b540aSrobert
371*404b540aSrobert /* Utility macros for mf-hooks*.c */
372*404b540aSrobert
373*404b540aSrobert #define MF_VALIDATE_EXTENT(value,size,acc,context) \
374*404b540aSrobert do { \
375*404b540aSrobert if (UNLIKELY (size > 0 && __MF_CACHE_MISS_P (value, size))) \
376*404b540aSrobert if (acc == __MF_CHECK_WRITE || ! __mf_opts.ignore_reads) \
377*404b540aSrobert __mf_check ((void *) (value), (size), acc, "(" context ")"); \
378*404b540aSrobert } while (0)
379*404b540aSrobert #define BEGIN_PROTECT(fname, ...) \
380*404b540aSrobert if (UNLIKELY (__mf_starting_p)) \
381*404b540aSrobert { \
382*404b540aSrobert return CALL_BACKUP(fname, __VA_ARGS__); \
383*404b540aSrobert } \
384*404b540aSrobert else if (UNLIKELY (__mf_get_state () == reentrant)) \
385*404b540aSrobert { \
386*404b540aSrobert extern unsigned long __mf_reentrancy; \
387*404b540aSrobert __mf_reentrancy ++; \
388*404b540aSrobert return CALL_REAL(fname, __VA_ARGS__); \
389*404b540aSrobert } \
390*404b540aSrobert else if (UNLIKELY (__mf_get_state () == in_malloc)) \
391*404b540aSrobert { \
392*404b540aSrobert return CALL_REAL(fname, __VA_ARGS__); \
393*404b540aSrobert } \
394*404b540aSrobert else \
395*404b540aSrobert { \
396*404b540aSrobert TRACE ("%s\n", __PRETTY_FUNCTION__); \
397*404b540aSrobert }
398*404b540aSrobert
399*404b540aSrobert /* There is an assumption here that these will only be called in routines
400*404b540aSrobert that call BEGIN_PROTECT at the start, and hence the state must always
401*404b540aSrobert be active when BEGIN_MALLOC_PROTECT is called. */
402*404b540aSrobert #define BEGIN_MALLOC_PROTECT() \
403*404b540aSrobert __mf_set_state (in_malloc)
404*404b540aSrobert
405*404b540aSrobert #define END_MALLOC_PROTECT() \
406*404b540aSrobert __mf_set_state (active)
407*404b540aSrobert
408*404b540aSrobert /* Unlocked variants of main entry points from mf-runtime.h. */
409*404b540aSrobert extern void __mfu_check (void *ptr, size_t sz, int type, const char *location);
410*404b540aSrobert extern void __mfu_register (void *ptr, size_t sz, int type, const char *name);
411*404b540aSrobert extern void __mfu_unregister (void *ptr, size_t sz, int type);
412*404b540aSrobert extern void __mfu_report ();
413*404b540aSrobert extern int __mfu_set_options (const char *opts);
414*404b540aSrobert
415*404b540aSrobert
416*404b540aSrobert #endif /* __MF_IMPL_H */
417