OSDN Git Service

2005-06-14 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, 2004 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 #if HAVE_STDINT_H
47 #include <stdint.h>
48 #else
49 typedef __mf_uintptr_t uintptr_t;
50 #endif
51
52 /* Private definitions related to mf-runtime.h  */
53
54 #define __MF_TYPE_MAX_CEM  __MF_TYPE_STACK  /* largest type# for the cemetary */
55 #define __MF_TYPE_MAX __MF_TYPE_GUESS
56
57
58 #ifndef max
59 #define max(a,b) ((a) > (b) ? (a) : (b))
60 #endif
61
62 #ifndef min
63 #define min(a,b) ((a) < (b) ? (a) : (b))
64 #endif
65
66 /* Address calculation macros.  */
67
68 #define MINPTR ((uintptr_t) 0)
69 #define MAXPTR (~ (uintptr_t) 0)
70
71 /* Clamp the addition/subtraction of uintptr_t's to [MINPTR,MAXPTR] */
72 #define CLAMPSUB(ptr,offset) (((uintptr_t) ptr) >= (offset) ? ((uintptr_t) ptr)-((uintptr_t) offset) : MINPTR)
73 #define CLAMPADD(ptr,offset) (((uintptr_t) ptr) <= MAXPTR-(offset) ? ((uintptr_t) ptr)+((uintptr_t) offset) : MAXPTR)
74 #define CLAMPSZ(ptr,size) ((size) ? (((uintptr_t) ptr) <= MAXPTR-(size)+1 ? ((uintptr_t) ptr)+((uintptr_t) size) - 1 : MAXPTR) : ((uintptr_t) ptr))
75
76 #define __MF_CACHE_INDEX(ptr) ((((uintptr_t) (ptr)) >> __mf_lc_shift) & __mf_lc_mask)
77 #define __MF_CACHE_MISS_P(ptr,sz) ({ \
78              struct __mf_cache *elem = & __mf_lookup_cache[__MF_CACHE_INDEX((ptr))]; \
79              ((elem->low > (uintptr_t) (ptr)) ||                  \
80               (elem->high < (CLAMPADD((uintptr_t) (ptr), (uintptr_t) CLAMPSUB(sz,1) )))); })
81 /* XXX: the above should use CLAMPSZ () */
82
83
84
85 /* Private functions. */
86
87 extern void __mf_violation (void *ptr, size_t sz,
88                             uintptr_t pc, const char *location,
89                             int type);
90 extern size_t __mf_backtrace (char ***, void *, unsigned);
91 extern int __mf_heuristic_check (uintptr_t, uintptr_t);
92
93 /* ------------------------------------------------------------------------ */
94 /* Type definitions. */
95 /* ------------------------------------------------------------------------ */
96
97 /* The mf_state type codes describe recursion and initialization order. */
98
99 enum __mf_state_enum { active, reentrant };
100
101 /* The __mf_options structure records optional or tunable aspects of the
102  mudflap library's behavior. There is a single global instance of this
103  structure which is populated from user input (in an environment variable)
104  when the library initializes. */
105
106 struct __mf_options
107 {
108   /* Emit a trace message for each call. */
109   unsigned trace_mf_calls;
110
111   /* Collect and emit statistics. */
112   unsigned collect_stats;
113
114   /* Set up a SIGUSR1 -> __mf_report handler. */
115   unsigned sigusr1_report;
116
117   /* Execute internal checking code. */
118   unsigned internal_checking;
119
120   /* Age object liveness periodically. */
121   unsigned tree_aging;
122
123   /* Adapt the lookup cache to working set. */
124   unsigned adapt_cache;
125
126   /* Print list of leaked heap objects on shutdown. */
127   unsigned print_leaks;
128
129   /* Detect reads of uninitialized objects. */
130   unsigned check_initialization;
131
132   /* Print verbose description of violations. */
133   unsigned verbose_violations;
134
135   /* Abbreviate duplicate object descriptions.  */
136   unsigned abbreviate;
137
138   /* Emit internal tracing message. */
139   unsigned verbose_trace;
140
141   /* Wipe stack/heap objects upon unwind.  */
142   unsigned wipe_stack;
143   unsigned wipe_heap;
144
145   /* Maintain a queue of this many deferred free()s,
146      to trap use of freed memory. */
147   unsigned free_queue_length;
148
149   /* Maintain a history of this many past unregistered objects. */
150   unsigned persistent_count;
151
152   /* Pad allocated extents by this many bytes on either side. */
153   unsigned crumple_zone;
154
155   /* Maintain this many stack frames for contexts. */
156   unsigned backtrace;
157
158   /* Ignore read operations even if mode_check is in effect.  */
159   unsigned ignore_reads;
160
161   /* Collect register/unregister timestamps.  */
162   unsigned timestamps;
163
164 #ifdef LIBMUDFLAPTH
165   /* Thread stack size.  */
166   unsigned thread_stack;
167 #endif
168
169   /* Major operation mode */
170 #define mode_nop 0      /* Do nothing.  */
171 #define mode_populate 1 /* Populate tree but do not check for violations.  */
172 #define mode_check 2    /* Populate and check for violations (normal).  */
173 #define mode_violate 3  /* Trigger a violation on every call (diagnostic).  */
174   unsigned mudflap_mode;
175
176   /* How to handle a violation. */
177 #define viol_nop 0   /* Return control to application. */
178 #define viol_segv 1  /* Signal self with segv. */
179 #define viol_abort 2 /* Call abort (). */
180 #define viol_gdb 3   /* Fork a debugger on self */
181   unsigned 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 extern struct __mf_options __mf_opts;
244
245 /* ------------------------------------------------------------------------ */
246 /* Utility macros. */
247 /* ------------------------------------------------------------------------ */
248
249 #define UNLIKELY(e) (__builtin_expect (!!(e), 0))
250 #define LIKELY(e) (__builtin_expect (!!(e), 1))
251 #define STRINGIFY2(e) #e
252 #define STRINGIFY(e) STRINGIFY2(e)
253
254 #ifdef LIBMUDFLAPTH
255 #define VERBOSE_TRACE(...) \
256   do { if (UNLIKELY (__mf_opts.verbose_trace)) {  \
257       fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
258       fprintf (stderr, __VA_ARGS__); \
259     } } while (0)
260 #define TRACE(...) \
261   do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
262       fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
263       fprintf (stderr, __VA_ARGS__); \
264     } } while (0)
265 #else
266 #define VERBOSE_TRACE(...) \
267   do { if (UNLIKELY (__mf_opts.verbose_trace)) {  \
268       fprintf (stderr, "mf: "); \
269       fprintf (stderr, __VA_ARGS__); \
270     } } while (0)
271 #define TRACE(...) \
272   do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
273       fprintf (stderr, "mf: "); \
274       fprintf (stderr, __VA_ARGS__); \
275     } } while (0)
276 #endif
277
278
279 #define __MF_PERSIST_MAX 256
280 #define __MF_FREEQ_MAX 256
281
282 /*
283    Wrapping and redirection:
284
285    Mudflap redirects a number of libc functions into itself, for "cheap"
286    verification (eg. strcpy, bzero, memcpy) and also to register /
287    unregister regions of memory as they are manipulated by the program
288    (eg. malloc/free, mmap/munmap).
289
290    There are two methods of wrapping.
291
292    (1) The static method involves a list of -wrap=foo flags being passed to
293    the linker, which then links references to "foo" to the symbol
294    "__wrap_foo", and links references to "__real_foo" to the symbol "foo".
295    When compiled without -DPIC, libmudflap.a contains such __wrap_foo
296    functions which delegate to __real_foo functions in libc to get their
297    work done.
298
299    (2) The dynamic method involves providing a definition of symbol foo in
300    libmudflap.so and linking it earlier in the compiler command line,
301    before libc.so. The function "foo" in libmudflap must then call
302    dlsym(RTLD_NEXT, "foo") to acquire a pointer to the "real" libc foo, or
303    at least the "next" foo in the dynamic link resolution order.
304
305    We switch between these two techniques by the presence of the -DPIC
306    #define passed in by libtool when building libmudflap.
307 */
308
309
310 #ifdef PIC
311
312 extern void __mf_resolve_single_dynamic (struct __mf_dynamic_entry *);
313
314 #define _GNU_SOURCE
315 #include <dlfcn.h>
316
317 #define WRAPPER(ret, fname, ...)                      \
318 ret __wrap_ ## fname (__VA_ARGS__)                    \
319     __attribute__ (( alias  (#fname)  ));             \
320 ret __real_ ## fname (__VA_ARGS__)                    \
321     __attribute__ (( alias  (#fname)  ));             \
322 ret fname (__VA_ARGS__)
323 #define DECLARE(ty, fname, ...)                       \
324  typedef ty (*__mf_fn_ ## fname) (__VA_ARGS__);       \
325  extern ty __mf_0fn_ ## fname (__VA_ARGS__);
326 #define CALL_REAL(fname, ...)                         \
327   ({__mf_starting_p \
328      ? __mf_0fn_ ## fname (__VA_ARGS__) \
329     : (__mf_resolve_single_dynamic (& __mf_dynamic[dyn_ ## fname]), \
330        (((__mf_fn_ ## fname)(__mf_dynamic[dyn_ ## fname].pointer)) (__VA_ARGS__)));})
331 #define CALL_BACKUP(fname, ...)                       \
332   __mf_0fn_ ## fname(__VA_ARGS__)
333
334 #else /* not PIC --> static library */
335
336 #define WRAPPER(ret, fname, ...)            \
337 ret __wrap_ ## fname (__VA_ARGS__)
338 #define DECLARE(ty, fname, ...)             \
339  extern ty __real_ ## fname (__VA_ARGS__)
340 #define CALL_REAL(fname, ...)               \
341  __real_ ## fname (__VA_ARGS__)
342 #define CALL_BACKUP(fname, ...)             \
343   __real_ ## fname(__VA_ARGS__)
344
345 #endif /* PIC */
346
347 /* WRAPPER2 is for functions intercepted via macros at compile time. */
348 #define WRAPPER2(ret, fname, ...)                     \
349 ret __mfwrap_ ## fname (__VA_ARGS__)
350
351
352 /* Utility macros for mf-hooks*.c */
353
354 #define MF_VALIDATE_EXTENT(value,size,acc,context) \
355  do { \
356   if (UNLIKELY (size > 0 && __MF_CACHE_MISS_P (value, size))) \
357     if (acc == __MF_CHECK_WRITE || ! __mf_opts.ignore_reads) \
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 */