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