OSDN Git Service

2004-06-29 Frank Ch. Eigler <fche@redhat.com>
[pf3gnuchains/gcc-fork.git] / libmudflap / mf-impl.h
1 /* Implementation header for mudflap runtime library.
2    Mudflap: narrow-pointer bounds-checking by tree rewriting.  
3    Copyright (C) 2002, 2003 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 2, or (at your option) any later
12 version.
13  
14 In addition to the permissions in the GNU General Public License, the
15 Free Software Foundation gives you unlimited permission to link the
16 compiled version of this file into combinations with other programs,
17 and to distribute those combinations without any restriction coming
18 from the use of this file.  (The General Public License restrictions
19 do apply in other respects; for example, they cover modification of
20 the file, and distribution when not linked into a combine
21 executable.)
22  
23 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
24 WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
26 for more details.
27                                                                                 
28 You should have received a copy of the GNU General Public License
29 along with GCC; see the file COPYING.  If not, write to the Free
30 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
31 02111-1307, USA.  */
32
33 #ifndef __MF_IMPL_H
34 #define __MF_IMPL_H
35
36 #ifdef _MUDFLAP
37 #error "Do not compile this file with -fmudflap!"
38 #endif
39
40 #if HAVE_PTHREAD_H
41 #include <pthread.h>
42 #elif LIBMUDFLAPTH
43 #error "Cannot build libmudflapth without pthread.h."
44 #endif
45
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 enum __mf_state_enum { active, reentrant }; 
95
96 /* The __mf_options structure records optional or tunable aspects of the
97  mudflap library's behavior. There is a single global instance of this
98  structure which is populated from user input (in an environment variable)
99  when the library initializes. */
100
101 struct __mf_options
102 {
103   /* Emit a trace message for each call. */
104   unsigned trace_mf_calls;
105
106   /* Collect and emit statistics. */
107   unsigned collect_stats;
108
109   /* Set up a SIGUSR1 -> __mf_report handler. */
110   unsigned sigusr1_report;
111
112   /* Execute internal checking code. */
113   unsigned internal_checking;
114
115   /* Age object liveness periodically. */
116   unsigned tree_aging;
117
118   /* Adapt the lookup cache to working set. */
119   unsigned adapt_cache;
120
121   /* Print list of leaked heap objects on shutdown. */
122   unsigned print_leaks;       
123
124   /* Detect reads of uninitialized objects. */
125   unsigned check_initialization;       
126
127   /* Print verbose description of violations. */
128   unsigned verbose_violations;
129
130   /* Abbreviate duplicate object descriptions.  */
131   unsigned abbreviate;
132
133   /* Emit internal tracing message. */
134   unsigned verbose_trace;
135
136   /* Support multiple threads.  XXX: not yet implemented. */
137   /* unsigned multi_threaded; */
138
139   /* Wipe stack/heap objects upon unwind.  */
140   unsigned wipe_stack;
141   unsigned wipe_heap;
142
143   /* Maintain a queue of this many deferred free()s, 
144      to trap use of freed memory. */
145   unsigned free_queue_length;
146
147   /* Maintain a history of this many past unregistered objects. */
148   unsigned persistent_count;
149
150   /* Pad allocated extents by this many bytes on either side. */
151   unsigned crumple_zone;
152
153   /* Maintain this many stack frames for contexts. */
154   unsigned backtrace;
155
156 #ifdef LIBMUDFLAPTH
157   /* Thread stack size.  */
158   unsigned thread_stack;
159 #endif
160
161   /* Major operation mode */
162   enum
163   {
164     mode_nop,        /* mudflaps do nothing */
165     mode_populate,   /* mudflaps populate tree but do not check for violations */
166     mode_check,      /* mudflaps populate and check for violations (normal) */
167     mode_violate     /* mudflaps trigger a violation on every call (diagnostic) */
168   }
169   mudflap_mode;
170
171
172   /* How to handle a violation. */
173
174   enum
175   {
176     viol_nop,        /* Return control to application. */ 
177     viol_segv,       /* Signal self with segv. */
178     viol_abort,      /* Call abort (). */
179     viol_gdb         /* Fork a debugger on self */
180   }
181   violation_mode;
182
183   /* Violation heuristics selection. */
184   unsigned heur_stack_bound; /* allow current stack region */
185   unsigned heur_proc_map;  /* allow & cache /proc/self/map regions.  */
186   unsigned heur_start_end; /* allow _start .. _end */
187   unsigned heur_std_data; /* allow & cache stdlib data */
188 };
189
190
191 #ifdef PIC
192
193 /* This is a table of dynamically resolved function pointers. */
194
195 struct __mf_dynamic_entry
196 {
197   void *pointer;
198   char *name;
199   char *version;
200 };
201
202 /* The definition of the array (mf-runtime.c) must match the enums!  */
203 extern struct __mf_dynamic_entry __mf_dynamic[];
204 enum __mf_dynamic_index
205
206   dyn_calloc, dyn_free, dyn_malloc, dyn_mmap,
207   dyn_munmap, dyn_realloc, 
208   dyn_INITRESOLVE,  /* Marker for last init-time resolution. */
209 #ifdef LIBMUDFLAPTH 
210   dyn_pthread_create,
211   dyn_pthread_join,
212   dyn_pthread_exit
213 #endif
214 };
215
216 #endif /* PIC */
217
218 /* ------------------------------------------------------------------------ */
219 /* Private global variables. */
220 /* ------------------------------------------------------------------------ */
221
222 #ifdef LIBMUDFLAPTH
223 extern pthread_mutex_t __mf_biglock;
224 #define LOCKTH() do { extern unsigned long __mf_lock_contention; \
225                       int rc = pthread_mutex_trylock (& __mf_biglock); \
226                       if (rc) { __mf_lock_contention ++; \
227                                 rc = pthread_mutex_lock (& __mf_biglock); } \
228                       assert (rc==0); } while (0)
229 #define UNLOCKTH() do { int rc = pthread_mutex_unlock (& __mf_biglock); \
230                         assert (rc==0); } while (0)
231 #else
232 #define LOCKTH() do {} while (0)
233 #define UNLOCKTH() do {} while (0)
234 #endif
235
236 #ifdef LIBMUDFLAPTH
237 extern enum __mf_state_enum *__mf_state_perthread ();
238 #define __mf_state (* __mf_state_perthread ())
239 #else 
240 extern enum __mf_state_enum __mf_state;
241 #endif
242 extern int __mf_starting_p;
243
244 extern struct __mf_options __mf_opts;
245
246 /* ------------------------------------------------------------------------ */
247 /* Utility macros. */
248 /* ------------------------------------------------------------------------ */
249
250 #define UNLIKELY(e) (__builtin_expect (!!(e), 0))
251 #define LIKELY(e) (__builtin_expect (!!(e), 1))
252 #define STRINGIFY2(e) #e
253 #define STRINGIFY(e) STRINGIFY2(e)
254
255 #ifdef LIBMUDFLAPTH
256 #define VERBOSE_TRACE(...) \
257   do { if (UNLIKELY (__mf_opts.verbose_trace)) {  \
258       fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
259       fprintf (stderr, __VA_ARGS__); \
260     } } while (0)
261 #define TRACE(...) \
262   do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
263       fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
264       fprintf (stderr, __VA_ARGS__); \
265     } } while (0)
266 #else
267 #define VERBOSE_TRACE(...) \
268   do { if (UNLIKELY (__mf_opts.verbose_trace)) {  \
269       fprintf (stderr, "mf: "); \
270       fprintf (stderr, __VA_ARGS__); \
271     } } while (0)
272 #define TRACE(...) \
273   do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
274       fprintf (stderr, "mf: "); \
275       fprintf (stderr, __VA_ARGS__); \
276     } } while (0)
277 #endif
278
279
280 #define __MF_PERSIST_MAX 256
281 #define __MF_FREEQ_MAX 256
282
283 /* 
284    Wrapping and redirection:
285
286    Mudflap redirects a number of libc functions into itself, for "cheap"
287    verification (eg. strcpy, bzero, memcpy) and also to register /
288    unregister regions of memory as they are manipulated by the program
289    (eg. malloc/free, mmap/munmap).
290
291    There are two methods of wrapping. 
292
293    (1) The static method involves a list of -wrap=foo flags being passed to
294    the linker, which then links references to "foo" to the symbol
295    "__wrap_foo", and links references to "__real_foo" to the symbol "foo".
296    When compiled without -DPIC, libmudflap.a contains such __wrap_foo
297    functions which delegate to __real_foo functions in libc to get their
298    work done.
299
300    (2) The dynamic method involves providing a definition of symbol foo in
301    libmudflap.so and linking it earlier in the compiler command line,
302    before libc.so. The function "foo" in libmudflap must then call
303    dlsym(RTLD_NEXT, "foo") to acquire a pointer to the "real" libc foo, or
304    at least the "next" foo in the dynamic link resolution order.
305
306    We switch between these two techniques by the presence of the -DPIC
307    #define passed in by libtool when building libmudflap.
308 */
309
310
311 #ifdef PIC
312
313 extern void __mf_resolve_single_dynamic (struct __mf_dynamic_entry *);
314
315 #define _GNU_SOURCE
316 #include <dlfcn.h>
317
318 #define WRAPPER(ret, fname, ...)                      \
319 ret __wrap_ ## fname (__VA_ARGS__)                    \
320     __attribute__ (( alias  (#fname)  ));             \
321 ret __real_ ## fname (__VA_ARGS__)                    \
322     __attribute__ (( alias  (#fname)  ));             \
323 ret fname (__VA_ARGS__)
324 #define DECLARE(ty, fname, ...)                       \
325  typedef ty (*__mf_fn_ ## fname) (__VA_ARGS__);       \
326  extern ty __mf_0fn_ ## fname (__VA_ARGS__);
327 #define CALL_REAL(fname, ...)                         \
328   ({__mf_starting_p \
329      ? __mf_0fn_ ## fname (__VA_ARGS__) \
330     : (__mf_resolve_single_dynamic (& __mf_dynamic[dyn_ ## fname]), \
331        (((__mf_fn_ ## fname)(__mf_dynamic[dyn_ ## fname].pointer)) (__VA_ARGS__)));})
332 #define CALL_BACKUP(fname, ...)                       \
333   __mf_0fn_ ## fname(__VA_ARGS__)
334
335 #else /* not PIC --> static library */
336
337 #define WRAPPER(ret, fname, ...)            \
338 ret __wrap_ ## fname (__VA_ARGS__)
339 #define DECLARE(ty, fname, ...)             \
340  extern ty __real_ ## fname (__VA_ARGS__)
341 #define CALL_REAL(fname, ...)               \
342  __real_ ## fname (__VA_ARGS__)
343 #define CALL_BACKUP(fname, ...)             \
344   __real_ ## fname(__VA_ARGS__)
345
346 #endif /* PIC */
347
348 /* WRAPPER2 is for functions intercepted via macros at compile time. */
349 #define WRAPPER2(ret, fname, ...)                     \
350 ret __mfwrap_ ## fname (__VA_ARGS__)
351
352
353 /* Utility macros for mf-hooks*.c */
354
355 #define MF_VALIDATE_EXTENT(value,size,acc,context) \
356  do { \
357   if (UNLIKELY (size > 0 && __MF_CACHE_MISS_P (value, size))) \
358     __mf_check ((void *) (value), (size), acc, "(" context ")"); \
359  } while (0)
360 #define BEGIN_PROTECT(fname, ...)       \
361   if (UNLIKELY (__mf_starting_p)) \
362   {                                         \
363     return CALL_BACKUP(fname, __VA_ARGS__); \
364   }                                         \
365   else if (UNLIKELY (__mf_state == reentrant))   \
366   {                                         \
367     extern unsigned long __mf_reentrancy;   \
368     __mf_reentrancy ++; \
369     return CALL_REAL(fname, __VA_ARGS__);   \
370   }                                         \
371   else                                      \
372   {                                         \
373     TRACE ("%s\n", __PRETTY_FUNCTION__); \
374   }
375
376
377 /* Unlocked variants of main entry points from mf-runtime.h.  */
378 extern void __mfu_check (void *ptr, size_t sz, int type, const char *location);
379 extern void __mfu_register (void *ptr, size_t sz, int type, const char *name);
380 extern void __mfu_unregister (void *ptr, size_t sz, int type);
381 extern void __mfu_report ();
382 extern int __mfu_set_options (const char *opts);
383
384
385 #endif /* __MF_IMPL_H */