OSDN Git Service

2004-07-27 Frank Ch. Eigler <fche@redhat.com>
[pf3gnuchains/gcc-fork.git] / libmudflap / mf-runtime.c
1 /* Mudflap: narrow-pointer bounds-checking by tree rewriting.
2    Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3    Contributed by Frank Ch. Eigler <fche@redhat.com>
4    and Graydon Hoare <graydon@redhat.com>
5    Splay Tree code originally by Mark Mitchell <mark@markmitchell.com>,
6    adapted from libiberty.
7
8 This file is part of GCC.
9
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14
15 In addition to the permissions in the GNU General Public License, the
16 Free Software Foundation gives you unlimited permission to link the
17 compiled version of this file into combinations with other programs,
18 and to distribute those combinations without any restriction coming
19 from the use of this file.  (The General Public License restrictions
20 do apply in other respects; for example, they cover modification of
21 the file, and distribution when not linked into a combine
22 executable.)
23
24 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
25 WARRANTY; without even the implied warranty of MERCHANTABILITY or
26 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27 for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with GCC; see the file COPYING.  If not, write to the Free
31 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
32 02111-1307, USA.  */
33
34 #include "config.h"
35
36 /* These attempt to coax various unix flavours to declare all our
37    needed tidbits in the system headers.  */
38 #if !defined(__FreeBSD__)
39 #define _POSIX_SOURCE
40 #endif /* Some BSDs break <sys/socket.h> if this is defined. */
41 #define _GNU_SOURCE 
42 #define _XOPEN_SOURCE
43 #define _BSD_TYPES
44 #define __EXTENSIONS__
45 #define _ALL_SOURCE
46 #define _LARGE_FILE_API
47 #define _XOPEN_SOURCE_EXTENDED 1
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <sys/types.h>
52 #include <sys/time.h>
53 #include <time.h>
54 #include <unistd.h>
55 #ifdef HAVE_EXECINFO_H
56 #include <execinfo.h>
57 #endif
58 #ifdef HAVE_SIGNAL_H
59 #include <signal.h>
60 #endif
61 #include <assert.h>
62
63 #include <string.h>
64 #include <limits.h>
65 #include <sys/types.h>
66 #include <signal.h>
67 #include <errno.h>
68 #include <ctype.h>
69
70 #include "mf-runtime.h"
71 #include "mf-impl.h"
72
73
74 /* ------------------------------------------------------------------------ */
75 /* Splay-tree implementation.  */
76
77 typedef uintptr_t mfsplay_tree_key;
78 typedef void *mfsplay_tree_value;
79
80 /* Forward declaration for a node in the tree.  */
81 typedef struct mfsplay_tree_node_s *mfsplay_tree_node;
82
83 /* The type of a function used to iterate over the tree.  */
84 typedef int (*mfsplay_tree_foreach_fn) (mfsplay_tree_node, void *);
85
86 /* The nodes in the splay tree.  */
87 struct mfsplay_tree_node_s
88 {
89   /* Data.  */
90   mfsplay_tree_key key;
91   mfsplay_tree_value value;
92   /* Children.  */
93   mfsplay_tree_node left;
94   mfsplay_tree_node right;
95   /* XXX: The addition of a parent pointer may eliminate some recursion.  */
96 };
97
98 /* The splay tree itself.  */
99 struct mfsplay_tree_s
100 {
101   /* The root of the tree.  */
102   mfsplay_tree_node root;
103
104   /* The last key value for which the tree has been splayed, but not
105      since modified.  */
106   mfsplay_tree_key last_splayed_key;
107   int last_splayed_key_p;
108
109   /* Statistics.  */
110   unsigned num_keys;
111
112   /* Traversal recursion control flags.  */
113   unsigned max_depth;
114   unsigned depth;
115   unsigned rebalance_p;
116 };
117 typedef struct mfsplay_tree_s *mfsplay_tree;
118
119 static mfsplay_tree mfsplay_tree_new (void);
120 static mfsplay_tree_node mfsplay_tree_insert (mfsplay_tree, mfsplay_tree_key, mfsplay_tree_value);
121 static void mfsplay_tree_remove (mfsplay_tree, mfsplay_tree_key);
122 static mfsplay_tree_node mfsplay_tree_lookup (mfsplay_tree, mfsplay_tree_key);
123 static mfsplay_tree_node mfsplay_tree_predecessor (mfsplay_tree, mfsplay_tree_key);
124 static mfsplay_tree_node mfsplay_tree_successor (mfsplay_tree, mfsplay_tree_key);
125 static int mfsplay_tree_foreach (mfsplay_tree, mfsplay_tree_foreach_fn, void *);
126 static void mfsplay_tree_rebalance (mfsplay_tree sp);
127
128 /* ------------------------------------------------------------------------ */
129 /* Utility macros */
130
131 #define CTOR  __attribute__ ((constructor))
132 #define DTOR  __attribute__ ((destructor))
133
134
135 /* Codes to describe the context in which a violation occurs. */
136 #define __MF_VIOL_UNKNOWN 0
137 #define __MF_VIOL_READ 1
138 #define __MF_VIOL_WRITE 2
139 #define __MF_VIOL_REGISTER 3
140 #define __MF_VIOL_UNREGISTER 4
141 #define __MF_VIOL_WATCH 5
142
143 /* Protect against recursive calls. */
144 #define BEGIN_RECURSION_PROTECT() do { \
145   if (UNLIKELY (__mf_state == reentrant)) { \
146     write (2, "mf: erroneous reentrancy detected in `", 38); \
147     write (2, __PRETTY_FUNCTION__, strlen(__PRETTY_FUNCTION__)); \
148     write (2, "'\n", 2); \
149     abort (); } \
150   __mf_state = reentrant;  \
151   } while (0)
152
153 #define END_RECURSION_PROTECT() do { \
154   __mf_state = active; \
155   } while (0)
156
157
158
159 /* ------------------------------------------------------------------------ */
160 /* Required globals.  */
161
162 #define LOOKUP_CACHE_MASK_DFL 1023
163 #define LOOKUP_CACHE_SIZE_MAX 4096 /* Allows max CACHE_MASK 0x0FFF */
164 #define LOOKUP_CACHE_SHIFT_DFL 2
165
166 struct __mf_cache __mf_lookup_cache [LOOKUP_CACHE_SIZE_MAX];
167 uintptr_t __mf_lc_mask = LOOKUP_CACHE_MASK_DFL;
168 unsigned char __mf_lc_shift = LOOKUP_CACHE_SHIFT_DFL;
169 #define LOOKUP_CACHE_SIZE (__mf_lc_mask + 1)
170
171 struct __mf_options __mf_opts;
172
173 int __mf_starting_p = 1;
174 #ifndef LIBMUDFLAPTH
175 enum __mf_state_enum __mf_state = active;
176 #else
177 /* See __mf_state_perthread() in mf-hooks.c. */
178 #endif
179
180
181 #ifdef LIBMUDFLAPTH
182 pthread_mutex_t __mf_biglock =
183 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
184        PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
185 #else
186        PTHREAD_MUTEX_INITIALIZER;
187 #endif
188 #endif
189
190 /* Use HAVE_PTHREAD_H here instead of LIBMUDFLAPTH, so that even
191    the libmudflap.la (no threading support) can diagnose whether
192    the application is linked with -lpthread.  See __mf_usage() below.  */
193 #if HAVE_PTHREAD_H
194 #ifdef _POSIX_THREADS
195 #pragma weak pthread_join
196 #else
197 #define pthread_join NULL
198 #endif
199 const void *threads_active_p = (void *) pthread_join;
200 #endif
201
202
203 /* ------------------------------------------------------------------------ */
204 /* stats-related globals.  */
205
206 static unsigned long __mf_count_check;
207 static unsigned long __mf_lookup_cache_reusecount [LOOKUP_CACHE_SIZE_MAX];
208 static unsigned long __mf_count_register;
209 static unsigned long __mf_total_register_size [__MF_TYPE_MAX+1];
210 static unsigned long __mf_count_unregister;
211 static unsigned long __mf_total_unregister_size;
212 static unsigned long __mf_count_violation [__MF_VIOL_WATCH+1];
213 static unsigned long __mf_sigusr1_received;
214 static unsigned long __mf_sigusr1_handled;
215 /* not static */ unsigned long __mf_reentrancy;
216 #ifdef LIBMUDFLAPTH
217 /* not static */ unsigned long __mf_lock_contention;
218 #endif
219
220
221 /* ------------------------------------------------------------------------ */
222 /* mode-check-related globals.  */
223
224 typedef struct __mf_object
225 {
226   uintptr_t low, high; /* __mf_register parameters */
227   const char *name;
228   char type; /* __MF_TYPE_something */
229   char watching_p; /* Trigger a VIOL_WATCH on access? */
230   unsigned read_count; /* Number of times __mf_check/read was called on this object.  */
231   unsigned write_count; /* Likewise for __mf_check/write.  */
232   unsigned liveness; /* A measure of recent checking activity.  */
233   unsigned description_epoch; /* Last epoch __mf_describe_object printed this.  */
234
235   uintptr_t alloc_pc;
236   struct timeval alloc_time;
237   char **alloc_backtrace;
238   size_t alloc_backtrace_size;
239 #ifdef LIBMUDFLAPTH
240   pthread_t alloc_thread;
241 #endif
242
243   int deallocated_p;
244   uintptr_t dealloc_pc;
245   struct timeval dealloc_time;
246   char **dealloc_backtrace;
247   size_t dealloc_backtrace_size;
248 #ifdef LIBMUDFLAPTH
249   pthread_t dealloc_thread;
250 #endif
251 } __mf_object_t;
252
253 /* Live objects: splay trees, separated by type, ordered on .low (base address).  */
254 /* Actually stored as static vars within lookup function below.  */
255
256 /* Dead objects: circular arrays; _MIN_CEM .. _MAX_CEM only */
257 static unsigned __mf_object_dead_head[__MF_TYPE_MAX_CEM+1]; /* next empty spot */
258 static __mf_object_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIST_MAX];
259
260
261 /* ------------------------------------------------------------------------ */
262 /* Forward function declarations */
263
264 void __mf_init () CTOR;
265 static void __mf_sigusr1_respond ();
266 static unsigned __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high, 
267                                    __mf_object_t **objs, unsigned max_objs);
268 static unsigned __mf_find_objects2 (uintptr_t ptr_low, uintptr_t ptr_high, 
269                                     __mf_object_t **objs, unsigned max_objs, int type);
270 static unsigned __mf_find_dead_objects (uintptr_t ptr_low, uintptr_t ptr_high, 
271                                         __mf_object_t **objs, unsigned max_objs);
272 static void __mf_adapt_cache ();
273 static void __mf_describe_object (__mf_object_t *obj);
274 static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag);
275 static mfsplay_tree __mf_object_tree (int type);
276 static void __mf_link_object (__mf_object_t *node);
277 static void __mf_unlink_object (__mf_object_t *node);
278
279
280 /* ------------------------------------------------------------------------ */
281 /* Configuration engine */
282
283 static void
284 __mf_set_default_options ()
285 {
286   memset (& __mf_opts, 0, sizeof (__mf_opts));
287
288   __mf_opts.adapt_cache = 1000003;
289   __mf_opts.abbreviate = 1;
290   __mf_opts.verbose_violations = 1;
291   __mf_opts.free_queue_length = 4;
292   __mf_opts.persistent_count = 100;
293   __mf_opts.crumple_zone = 32;
294   __mf_opts.backtrace = 4;
295   __mf_opts.timestamps = 1;
296   __mf_opts.mudflap_mode = mode_check;
297   __mf_opts.violation_mode = viol_nop;
298   __mf_opts.heur_std_data = 1;
299 #ifdef LIBMUDFLAPTH
300   __mf_opts.thread_stack = 0;
301 #endif
302 }
303
304 static struct option
305 {
306   char *name;
307   char *description;
308   enum
309     {
310       set_option,
311       read_integer_option,
312     } type;
313   int value;
314   int *target;
315
316 options [] =
317   {
318     {"mode-nop", 
319      "mudflaps do nothing", 
320      set_option, (int)mode_nop, (int *)&__mf_opts.mudflap_mode},    
321     {"mode-populate", 
322      "mudflaps populate object tree", 
323      set_option, (int)mode_populate, (int *)&__mf_opts.mudflap_mode},    
324     {"mode-check", 
325      "mudflaps check for memory violations",
326      set_option, (int)mode_check, (int *)&__mf_opts.mudflap_mode},
327     {"mode-violate", 
328      "mudflaps always cause violations (diagnostic)",
329      set_option, (int)mode_violate, (int *)&__mf_opts.mudflap_mode},
330    
331     {"viol-nop", 
332      "violations do not change program execution",
333      set_option, (int)viol_nop, (int *)&__mf_opts.violation_mode},
334     {"viol-abort", 
335      "violations cause a call to abort()",
336      set_option, (int)viol_abort, (int *)&__mf_opts.violation_mode},
337     {"viol-segv", 
338      "violations are promoted to SIGSEGV signals",
339      set_option, (int)viol_segv, (int *)&__mf_opts.violation_mode},
340     {"viol-gdb", 
341      "violations fork a gdb process attached to current program",
342      set_option, (int)viol_gdb, (int *)&__mf_opts.violation_mode},
343     {"trace-calls", 
344      "trace calls to mudflap runtime library",
345      set_option, 1, &__mf_opts.trace_mf_calls},
346     {"verbose-trace", 
347      "trace internal events within mudflap runtime library",
348      set_option, 1, &__mf_opts.verbose_trace},
349     {"collect-stats", 
350      "collect statistics on mudflap's operation",
351      set_option, 1, &__mf_opts.collect_stats},
352 #ifdef SIGUSR1
353     {"sigusr1-report",
354      "print report upon SIGUSR1",
355      set_option, 1, &__mf_opts.sigusr1_report},
356 #endif
357     {"internal-checking", 
358      "perform more expensive internal checking",
359      set_option, 1, &__mf_opts.internal_checking},
360     {"print-leaks", 
361      "print any memory leaks at program shutdown",
362      set_option, 1, &__mf_opts.print_leaks},
363     {"check-initialization", 
364      "detect uninitialized object reads",
365      set_option, 1, &__mf_opts.check_initialization},
366     {"verbose-violations", 
367      "print verbose messages when memory violations occur",
368      set_option, 1, &__mf_opts.verbose_violations},
369     {"abbreviate", 
370      "abbreviate repetitive listings",
371      set_option, 1, &__mf_opts.abbreviate},
372     {"timestamps", 
373      "track object lifetime timestamps",
374      set_option, 1, &__mf_opts.timestamps},
375     {"ignore-reads", 
376      "ignore read accesses - assume okay",
377      set_option, 1, &__mf_opts.ignore_reads},
378     {"wipe-stack",
379      "wipe stack objects at unwind",
380      set_option, 1, &__mf_opts.wipe_stack},
381     {"wipe-heap",
382      "wipe heap objects at free",
383      set_option, 1, &__mf_opts.wipe_heap},
384     {"heur-proc-map", 
385      "support /proc/self/map heuristics",
386      set_option, 1, &__mf_opts.heur_proc_map},
387     {"heur-stack-bound",
388      "enable a simple upper stack bound heuristic",
389      set_option, 1, &__mf_opts.heur_stack_bound},
390     {"heur-start-end", 
391      "support _start.._end heuristics",
392      set_option, 1, &__mf_opts.heur_start_end},
393     {"heur-stdlib", 
394      "register standard library data (argv, errno, stdin, ...)",
395      set_option, 1, &__mf_opts.heur_std_data},
396     {"free-queue-length", 
397      "queue N deferred free() calls before performing them",
398      read_integer_option, 0, &__mf_opts.free_queue_length},
399     {"persistent-count", 
400      "keep a history of N unregistered regions",
401      read_integer_option, 0, &__mf_opts.persistent_count},
402     {"crumple-zone", 
403      "surround allocations with crumple zones of N bytes",
404      read_integer_option, 0, &__mf_opts.crumple_zone},
405     /* XXX: not type-safe.
406     {"lc-mask", 
407      "set lookup cache size mask to N (2**M - 1)",
408      read_integer_option, 0, (int *)(&__mf_lc_mask)},
409     {"lc-shift", 
410      "set lookup cache pointer shift",
411      read_integer_option, 0, (int *)(&__mf_lc_shift)},
412     */
413     {"lc-adapt", 
414      "adapt mask/shift parameters after N cache misses",
415      read_integer_option, 1, &__mf_opts.adapt_cache},
416     {"backtrace", 
417      "keep an N-level stack trace of each call context",
418      read_integer_option, 0, &__mf_opts.backtrace},
419 #ifdef LIBMUDFLAPTH
420     {"thread-stack", 
421      "override thread stacks allocation: N kB",
422      read_integer_option, 0, &__mf_opts.thread_stack},
423 #endif
424     {0, 0, set_option, 0, NULL}
425   };
426
427 static void
428 __mf_usage ()
429 {
430   struct option *opt;
431
432   fprintf (stderr, 
433            "This is a %s%sGCC \"mudflap\" memory-checked binary.\n"
434            "Mudflap is Copyright (C) 2002-2004 Free Software Foundation, Inc.\n"
435            "\n"
436            "The mudflap code can be controlled by an environment variable:\n"
437            "\n"
438            "$ export MUDFLAP_OPTIONS='<options>'\n"
439            "$ <mudflapped_program>\n"
440            "\n"
441            "where <options> is a space-separated list of \n"
442            "any of the following options.  Use `-no-OPTION' to disable options.\n"
443            "\n",
444 #if HAVE_PTHREAD_H
445            (threads_active_p ? "multi-threaded " : "single-threaded "),
446 #else
447            "",
448 #endif
449 #if LIBMUDFLAPTH
450            "thread-aware "
451 #else
452            "thread-unaware "
453 #endif
454             );
455   /* XXX: The multi-threaded thread-unaware combination is bad.  */
456
457   for (opt = options; opt->name; opt++)
458     {
459       int default_p = (opt->value == * opt->target);
460
461       switch (opt->type)
462         {
463           char buf[128];
464         case set_option:
465           fprintf (stderr, "-%-23.23s %s", opt->name, opt->description);
466           if (default_p)
467             fprintf (stderr, " [active]\n");
468           else
469             fprintf (stderr, "\n");
470           break;
471         case read_integer_option:
472           strncpy (buf, opt->name, 128);
473           strncpy (buf + strlen (opt->name), "=N", 2);
474           fprintf (stderr, "-%-23.23s %s", buf, opt->description);
475           fprintf (stderr, " [%d]\n", * opt->target);
476           break;          
477         default: abort();
478         }
479     }
480
481   fprintf (stderr, "\n");
482 }
483
484
485 int 
486 __mf_set_options (const char *optstr)
487 {
488   int rc;
489   LOCKTH ();
490   BEGIN_RECURSION_PROTECT ();
491   rc = __mfu_set_options (optstr);
492   /* XXX: It's not really that easy.  A change to a bunch of parameters
493      can require updating auxiliary state or risk crashing: 
494      free_queue_length, crumple_zone ... */
495   END_RECURSION_PROTECT ();
496   UNLOCKTH ();
497   return rc;
498 }
499
500
501 int 
502 __mfu_set_options (const char *optstr)
503 {
504   struct option *opts = 0;
505   char *nxt = 0;
506   long tmp = 0;
507   int rc = 0;
508   const char *saved_optstr = optstr;
509
510   /* XXX: bounds-check for optstr! */
511
512   while (*optstr)
513     {
514       switch (*optstr) {
515       case ' ':
516       case '\t':
517       case '\n':
518         optstr++;
519         break;
520
521       case '-':
522         if (*optstr+1)
523           {         
524             int negate = 0;
525             optstr++;
526
527             if (*optstr == '?' || 
528                 strncmp (optstr, "help", 4) == 0)
529               {
530                 /* Caller will print help and exit.  */
531                 return -1;
532               }
533             
534             if (strncmp (optstr, "no-", 3) == 0)
535               {
536                 negate = 1;
537                 optstr = & optstr[3];
538               }
539             
540             for (opts = options; opts->name; opts++)
541               {
542                 if (strncmp (optstr, opts->name, strlen (opts->name)) == 0)
543                   {
544                     optstr += strlen (opts->name);
545                     assert (opts->target);
546                     switch (opts->type) 
547                       {
548                       case set_option:
549                         if (negate)
550                           *(opts->target) = 0;
551                         else
552                           *(opts->target) = opts->value;
553                         break;
554                       case read_integer_option:
555                         if (! negate && (*optstr == '=' && *(optstr+1)))
556                           {
557                             optstr++;
558                             tmp = strtol (optstr, &nxt, 10);
559                             if ((optstr != nxt) && (tmp != LONG_MAX))
560                               {
561                                 optstr = nxt;                           
562                                 *(opts->target) = (int)tmp;
563                               }
564                           }
565                         else if (negate)
566                           * opts->target = 0;
567                         break;
568                       }
569                   }
570               }
571           }
572         break;
573         
574       default:
575         fprintf (stderr, 
576                  "warning: unrecognized string '%s' in mudflap options\n",
577                  optstr);
578         optstr += strlen (optstr);
579         rc = -1;
580         break;
581       }
582     }
583
584   /* Special post-processing: bound __mf_lc_mask and free_queue_length for security. */
585   __mf_lc_mask &= (LOOKUP_CACHE_SIZE_MAX - 1);
586   __mf_opts.free_queue_length &= (__MF_FREEQ_MAX - 1);
587
588   /* Clear the lookup cache, in case the parameters got changed.  */
589   /* XXX: race */
590   memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
591   /* void slot 0 */
592   __mf_lookup_cache[0].low = MAXPTR;
593
594   TRACE ("set options from `%s'\n", saved_optstr);
595
596   /* Call this unconditionally, in case -sigusr1-report was toggled. */
597   __mf_sigusr1_respond ();
598
599   return rc;
600 }
601
602
603 #ifdef PIC
604
605 void 
606 __mf_resolve_single_dynamic (struct __mf_dynamic_entry *e)
607 {
608   char *err;
609
610   assert (e);
611   if (e->pointer) return;
612
613 #if HAVE_DLVSYM
614   if (e->version != NULL && e->version[0] != '\0') /* non-null/empty */
615     e->pointer = dlvsym (RTLD_NEXT, e->name, e->version);
616   else
617 #endif
618     e->pointer = dlsym (RTLD_NEXT, e->name);
619   
620   err = dlerror ();
621
622   if (err)
623     {
624       fprintf (stderr, "mf: error in dlsym(\"%s\"): %s\n",
625                e->name, err);
626       abort ();
627     }  
628   if (! e->pointer)
629     {
630       fprintf (stderr, "mf: dlsym(\"%s\") = NULL\n", e->name);
631       abort ();
632     }
633 }
634
635
636 static void 
637 __mf_resolve_dynamics () 
638 {
639   int i;
640   for (i = 0; i < dyn_INITRESOLVE; i++)
641     __mf_resolve_single_dynamic (& __mf_dynamic[i]);
642 }
643
644
645 /* NB: order must match enums in mf-impl.h */
646 struct __mf_dynamic_entry __mf_dynamic [] =
647 {
648   {NULL, "calloc", NULL},
649   {NULL, "free", NULL},
650   {NULL, "malloc", NULL},
651   {NULL, "mmap", NULL},
652   {NULL, "munmap", NULL},
653   {NULL, "realloc", NULL},
654   {NULL, "DUMMY", NULL}, /* dyn_INITRESOLVE */
655 #ifdef LIBMUDFLAPTH
656   {NULL, "pthread_create", PTHREAD_CREATE_VERSION},
657   {NULL, "pthread_join", NULL},
658   {NULL, "pthread_exit", NULL}
659 #endif
660 };
661
662 #endif /* PIC */
663
664
665
666 /* ------------------------------------------------------------------------ */
667
668 /* Lookup & manage automatic initialization of the five or so splay trees.  */
669 static mfsplay_tree
670 __mf_object_tree (int type)
671 {
672   static mfsplay_tree trees [__MF_TYPE_MAX+1];
673   assert (type >= 0 && type <= __MF_TYPE_MAX);
674   if (UNLIKELY (trees[type] == NULL))
675     trees[type] = mfsplay_tree_new ();
676   return trees[type];
677 }
678
679
680 /* not static */void
681 __mf_init ()
682 {
683   char *ov = 0;
684
685   /* Return if initialization has already been done. */
686   if (LIKELY (__mf_starting_p == 0))
687     return;
688
689   /* This initial bootstrap phase requires that __mf_starting_p = 1. */
690 #ifdef PIC
691   __mf_resolve_dynamics ();
692 #endif
693   __mf_starting_p = 0;
694
695   __mf_set_default_options ();
696
697   ov = getenv ("MUDFLAP_OPTIONS");
698   if (ov)
699     {
700       int rc = __mfu_set_options (ov);
701       if (rc < 0)
702         {
703           __mf_usage ();
704           exit (1);
705         }
706     }
707
708   /* Initialize to a non-zero description epoch. */
709   __mf_describe_object (NULL);
710
711 #define REG_RESERVED(obj) \
712   __mf_register (& obj, sizeof(obj), __MF_TYPE_NOACCESS, # obj)
713
714   REG_RESERVED (__mf_lookup_cache);
715   REG_RESERVED (__mf_lc_mask);
716   REG_RESERVED (__mf_lc_shift);
717   /* XXX: others of our statics?  */
718
719   /* Prevent access to *NULL. */
720   __mf_register (MINPTR, 1, __MF_TYPE_NOACCESS, "NULL");
721   __mf_lookup_cache[0].low = (uintptr_t) -1;
722 }
723
724
725
726 int
727 __wrap_main (int argc, char* argv[])
728 {
729   extern char **environ;
730   extern int main ();
731   static int been_here = 0;
732
733   if (__mf_opts.heur_std_data && ! been_here)
734     {
735       unsigned i;
736
737       been_here = 1;
738       __mf_register (argv, sizeof(char *)*(argc+1), __MF_TYPE_STATIC, "argv[]");
739       for (i=0; i<argc; i++)
740         {
741           unsigned j = strlen (argv[i]);
742           __mf_register (argv[i], j+1, __MF_TYPE_STATIC, "argv element");
743         }
744
745       for (i=0; ; i++)
746         {
747           char *e = environ[i];
748           unsigned j;
749           if (e == NULL) break;
750           j = strlen (environ[i]);
751           __mf_register (environ[i], j+1, __MF_TYPE_STATIC, "environ element");
752         }
753       __mf_register (environ, sizeof(char *)*(i+1), __MF_TYPE_STATIC, "environ[]");
754
755       __mf_register (& errno, sizeof (errno), __MF_TYPE_STATIC, "errno area");
756
757       __mf_register (stdin,  sizeof (*stdin),  __MF_TYPE_STATIC, "stdin");
758       __mf_register (stdout, sizeof (*stdout), __MF_TYPE_STATIC, "stdout");
759       __mf_register (stderr, sizeof (*stderr), __MF_TYPE_STATIC, "stderr");
760
761       /* Make some effort to register ctype.h static arrays.  */
762       /* XXX: e.g., on Solaris, may need to register __ctype, _ctype, __ctype_mask, __toupper, etc. */
763       /* On modern Linux GLIBC, these are thread-specific and changeable, and are dealt
764          with in mf-hooks2.c.  */
765     }
766
767 #ifdef PIC
768   return main (argc, argv, environ);
769 #else
770   return __real_main (argc, argv, environ);
771 #endif
772 }
773
774
775
776 extern void __mf_fini () DTOR;
777 void __mf_fini ()
778 {
779   TRACE ("__mf_fini\n");
780   __mfu_report ();
781 }
782
783
784
785 /* ------------------------------------------------------------------------ */
786 /* __mf_check */
787
788 void __mf_check (void *ptr, size_t sz, int type, const char *location)
789 {
790   LOCKTH ();
791   BEGIN_RECURSION_PROTECT ();
792   __mfu_check (ptr, sz, type, location);
793   END_RECURSION_PROTECT ();
794   UNLOCKTH ();
795 }
796
797
798 void __mfu_check (void *ptr, size_t sz, int type, const char *location)
799 {
800   unsigned entry_idx = __MF_CACHE_INDEX (ptr);
801   struct __mf_cache *entry = & __mf_lookup_cache [entry_idx];
802   int judgement = 0; /* 0=undecided; <0=violation; >0=okay */
803   uintptr_t ptr_low = (uintptr_t) ptr;
804   uintptr_t ptr_high = CLAMPSZ (ptr, sz);
805   struct __mf_cache old_entry = *entry;
806
807   if (UNLIKELY (__mf_opts.sigusr1_report))
808     __mf_sigusr1_respond ();
809
810   TRACE ("check ptr=%p b=%u size=%lu %s location=`%s'\n",
811          ptr, entry_idx, (unsigned long)sz,
812          (type == 0 ? "read" : "write"), location);
813   
814   switch (__mf_opts.mudflap_mode)
815     {
816     case mode_nop:
817       /* It is tempting to poison the cache here similarly to
818          mode_populate.  However that eliminates a valuable
819          distinction between these two modes.  mode_nop is useful to
820          let a user count & trace every single check / registration
821          call.  mode_populate is useful to let a program run fast
822          while unchecked.
823       */
824       judgement = 1;
825       break;
826
827     case mode_populate:
828       entry->low = ptr_low;
829       entry->high = ptr_high;
830       judgement = 1;
831       break;
832
833     case mode_check:
834       {
835         unsigned heuristics = 0;
836         
837         /* Advance aging/adaptation counters.  */
838         static unsigned adapt_count;
839         adapt_count ++;
840         if (UNLIKELY (__mf_opts.adapt_cache > 0 &&
841                       adapt_count > __mf_opts.adapt_cache))
842           {
843             adapt_count = 0;
844             __mf_adapt_cache ();
845           }
846         
847         /* Looping only occurs if heuristics were triggered.  */
848         while (judgement == 0)
849           {
850             DECLARE (void, free, void *p);
851             __mf_object_t* ovr_obj[1];
852             unsigned obj_count;
853             __mf_object_t** all_ovr_obj = NULL;
854             __mf_object_t** dealloc_me = NULL;
855             unsigned i;
856
857             /* Find all overlapping objects.  Be optimistic that there is just one.  */
858             obj_count = __mf_find_objects (ptr_low, ptr_high, ovr_obj, 1);
859             if (UNLIKELY (obj_count > 1))
860               {
861                 /* Allocate a real buffer and do the search again.  */
862                 DECLARE (void *, malloc, size_t c);
863                 unsigned n;
864                 all_ovr_obj = CALL_REAL (malloc, (sizeof (__mf_object_t *) *
865                                                    obj_count));
866                 if (all_ovr_obj == NULL) abort ();
867                 n = __mf_find_objects (ptr_low, ptr_high, all_ovr_obj, obj_count);
868                 assert (n == obj_count);
869                 dealloc_me = all_ovr_obj;
870               }
871             else 
872               {
873                 all_ovr_obj = ovr_obj;
874                 dealloc_me = NULL;
875               }
876
877             /* Update object statistics.  */
878             for (i = 0; i < obj_count; i++)
879               {
880                 __mf_object_t *obj = all_ovr_obj[i];
881                 assert (obj != NULL);
882                 if (type == __MF_CHECK_READ)
883                   obj->read_count ++;
884                 else
885                   obj->write_count ++;
886                 obj->liveness ++;
887               }
888             
889             /* Iterate over the various objects.  There are a number of special cases.  */
890             for (i = 0; i < obj_count; i++)
891               {
892                   __mf_object_t *obj = all_ovr_obj[i];
893
894                 /* Any __MF_TYPE_NOACCESS hit is bad.  */
895                 if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS))
896                   judgement = -1;
897
898                 /* Any object with a watch flag is bad.  */
899                 if (UNLIKELY (obj->watching_p))
900                   judgement = -2; /* trigger VIOL_WATCH */
901             
902                 /* A read from an uninitialized object is bad. */
903                 if (UNLIKELY (__mf_opts.check_initialization
904                               /* reading */
905                               && type == __MF_CHECK_READ
906                               /* not written */
907                               && obj->write_count == 0
908                               /* uninitialized (heap) */
909                               && obj->type == __MF_TYPE_HEAP))
910                   judgement = -1;
911               }
912
913             /* We now know that the access spans one or more valid objects.  */
914             if (LIKELY (judgement >= 0))
915               for (i = 0; i < obj_count; i++)
916                 {
917                   __mf_object_t *obj = all_ovr_obj[i];
918                   
919                   /* Is this access entirely contained within this object?  */
920                   if (LIKELY (ptr_low >= obj->low && ptr_high <= obj->high))
921                     {
922                       /* Valid access.  */
923                       entry->low = obj->low;
924                       entry->high = obj->high;
925                       judgement = 1;
926                     }
927
928                   /* XXX: Access runs off left or right side of this
929                           object.  That could be okay, if there are
930                           other objects that fill in all the holes. */
931                 }
932
933             if (dealloc_me != NULL)
934               CALL_REAL (free, dealloc_me);
935
936             /* If the judgment is still unknown at this stage, loop
937                around at most one more time.  */
938             if (judgement == 0)
939               {
940                 if (heuristics++ < 2) /* XXX parametrize this number? */
941                   judgement = __mf_heuristic_check (ptr_low, ptr_high);
942                 else
943                   judgement = -1;
944               }
945           }
946
947       }
948       break;
949
950     case mode_violate:
951       judgement = -1;
952       break;
953     }
954
955   if (__mf_opts.collect_stats)
956     {
957       __mf_count_check ++;
958       
959       if (LIKELY (old_entry.low != entry->low || old_entry.high != entry->high))
960         /* && (old_entry.low != 0) && (old_entry.high != 0)) */
961         __mf_lookup_cache_reusecount [entry_idx] ++;    
962     }
963   
964   if (UNLIKELY (judgement < 0))
965     __mf_violation (ptr, sz,
966                     (uintptr_t) __builtin_return_address (0), location,
967                     ((judgement == -1) ? 
968                      (type == __MF_CHECK_READ ? __MF_VIOL_READ : __MF_VIOL_WRITE) :
969                      __MF_VIOL_WATCH));
970 }
971
972
973 static __mf_object_t *
974 __mf_insert_new_object (uintptr_t low, uintptr_t high, int type, 
975                         const char *name, uintptr_t pc)
976 {
977   DECLARE (void *, calloc, size_t c, size_t n);
978
979   __mf_object_t *new_obj;
980   new_obj = CALL_REAL (calloc, 1, sizeof(__mf_object_t));
981   new_obj->low = low;
982   new_obj->high = high;
983   new_obj->type = type;
984   new_obj->name = name;
985   new_obj->alloc_pc = pc;
986 #if HAVE_GETTIMEOFDAY
987   if (__mf_opts.timestamps)
988     gettimeofday (& new_obj->alloc_time, NULL);
989 #endif
990 #if LIBMUDFLAPTH
991   new_obj->alloc_thread = pthread_self ();
992 #endif
993
994   if (__mf_opts.backtrace > 0 && (type == __MF_TYPE_HEAP || type == __MF_TYPE_HEAP_I))
995     new_obj->alloc_backtrace_size = 
996       __mf_backtrace (& new_obj->alloc_backtrace,
997                       (void *) pc, 2);
998   
999   __mf_link_object (new_obj);
1000   return new_obj;
1001 }
1002
1003
1004 static void 
1005 __mf_uncache_object (__mf_object_t *old_obj)
1006 {
1007   /* Remove any low/high pointers for this object from the lookup cache.  */
1008   
1009   /* Can it possibly exist in the cache?  */
1010   if (LIKELY (old_obj->read_count + old_obj->write_count))
1011     {
1012       uintptr_t low = old_obj->low;
1013       uintptr_t high = old_obj->high;
1014       unsigned idx_low = __MF_CACHE_INDEX (low);
1015       unsigned idx_high = __MF_CACHE_INDEX (high);
1016       unsigned i;
1017       for (i = idx_low; i <= idx_high; i++)
1018         {
1019           struct __mf_cache *entry = & __mf_lookup_cache [i];
1020           /* NB: the "||" in the following test permits this code to
1021              tolerate the situation introduced by __mf_check over
1022              contiguous objects, where a cache entry spans several 
1023              objects.  */
1024           if (entry->low == low || entry->high == high)
1025             {
1026               entry->low = MAXPTR;
1027               entry->high = MINPTR;
1028             }
1029         }
1030     }
1031 }
1032
1033
1034 void
1035 __mf_register (void *ptr, size_t sz, int type, const char *name)
1036 {
1037   LOCKTH ();
1038   BEGIN_RECURSION_PROTECT ();
1039   __mfu_register (ptr, sz, type, name);
1040   END_RECURSION_PROTECT ();
1041   UNLOCKTH ();
1042 }
1043
1044
1045 void
1046 __mfu_register (void *ptr, size_t sz, int type, const char *name)
1047 {
1048   TRACE ("register ptr=%p size=%lu type=%x name='%s'\n", 
1049          ptr, (unsigned long) sz, type, name ? name : "");
1050
1051   if (__mf_opts.collect_stats)
1052     {
1053       __mf_count_register ++;
1054       __mf_total_register_size [(type < 0) ? 0 :
1055                                 (type > __MF_TYPE_MAX) ? 0 : 
1056                                 type] += sz;
1057     }
1058
1059   if (UNLIKELY (__mf_opts.sigusr1_report))
1060     __mf_sigusr1_respond ();
1061
1062   switch (__mf_opts.mudflap_mode)
1063     {
1064     case mode_nop:
1065       break;
1066       
1067     case mode_violate:
1068       __mf_violation (ptr, sz, (uintptr_t) __builtin_return_address (0), NULL,
1069                       __MF_VIOL_REGISTER);
1070       break;
1071
1072     case mode_populate:
1073       /* Clear the cache.  */
1074       /* XXX: why the entire cache? */
1075       /* XXX: race */
1076       memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
1077       /* void slot 0 */
1078       __mf_lookup_cache[0].low = MAXPTR;
1079       break;
1080
1081     case mode_check:
1082       {
1083         __mf_object_t *ovr_objs [1];
1084         unsigned num_overlapping_objs;
1085         uintptr_t low = (uintptr_t) ptr;
1086         uintptr_t high = CLAMPSZ (ptr, sz);
1087         uintptr_t pc = (uintptr_t) __builtin_return_address (0);
1088         
1089         /* Treat unknown size indication as 1.  */
1090         if (UNLIKELY (sz == 0)) sz = 1;
1091
1092         /* Look for objects only of the same type.  This will e.g. permit a registration
1093            of a STATIC overlapping with a GUESS, and a HEAP with a NOACCESS.  At
1094            __mf_check time however harmful overlaps will be detected. */
1095         num_overlapping_objs = __mf_find_objects2 (low, high, ovr_objs, 1, type);
1096
1097         /* Handle overlaps.  */
1098         if (UNLIKELY (num_overlapping_objs > 0))
1099           {
1100             __mf_object_t *ovr_obj = ovr_objs[0];
1101             
1102             /* Accept certain specific duplication pairs.  */
1103             if (((type == __MF_TYPE_STATIC) || (type == __MF_TYPE_GUESS))
1104                 && ovr_obj->low == low
1105                 && ovr_obj->high == high
1106                 && ovr_obj->type == type)
1107               {
1108                 /* Duplicate registration for static objects may come
1109                    from distinct compilation units.  */
1110                 VERBOSE_TRACE ("harmless duplicate reg %p-%p `%s'\n", 
1111                                (void *) low, (void *) high, 
1112                                (ovr_obj->name ? ovr_obj->name : ""));
1113                 break;
1114               }
1115
1116             /* Alas, a genuine violation.  */
1117             else
1118               {
1119                 /* Two or more *real* mappings here. */
1120                 __mf_violation ((void *) ptr, sz,
1121                                 (uintptr_t) __builtin_return_address (0), NULL,
1122                                 __MF_VIOL_REGISTER);
1123               }
1124           }
1125         else /* No overlapping objects: AOK.  */
1126           __mf_insert_new_object (low, high, type, name, pc);
1127         
1128         /* We could conceivably call __mf_check() here to prime the cache,
1129            but then the read_count/write_count field is not reliable.  */
1130         break;
1131       }
1132     } /* end switch (__mf_opts.mudflap_mode) */
1133 }
1134
1135
1136 void
1137 __mf_unregister (void *ptr, size_t sz, int type)
1138 {
1139   LOCKTH ();
1140   BEGIN_RECURSION_PROTECT ();
1141   __mfu_unregister (ptr, sz, type);
1142   END_RECURSION_PROTECT ();
1143   UNLOCKTH ();
1144 }
1145
1146
1147 void
1148 __mfu_unregister (void *ptr, size_t sz, int type)
1149 {
1150   DECLARE (void, free, void *ptr);
1151
1152   if (UNLIKELY (__mf_opts.sigusr1_report))
1153     __mf_sigusr1_respond ();
1154
1155   TRACE ("unregister ptr=%p size=%lu type=%x\n", ptr, (unsigned long) sz, type);
1156
1157   switch (__mf_opts.mudflap_mode)
1158     { 
1159     case mode_nop:
1160       break;
1161
1162     case mode_violate:
1163       __mf_violation (ptr, sz,
1164                       (uintptr_t) __builtin_return_address (0), NULL,
1165                       __MF_VIOL_UNREGISTER);
1166       break;
1167
1168     case mode_populate:
1169       /* Clear the cache.  */
1170       /* XXX: race */
1171       memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
1172       /* void slot 0 */
1173       __mf_lookup_cache[0].low = MAXPTR;
1174       break;
1175
1176     case mode_check:
1177       {
1178         __mf_object_t *old_obj = NULL;
1179         __mf_object_t *del_obj = NULL;  /* Object to actually delete. */
1180         __mf_object_t *objs[1] = {NULL};
1181         unsigned num_overlapping_objs;
1182
1183         num_overlapping_objs = __mf_find_objects2 ((uintptr_t) ptr,
1184                                                    CLAMPSZ (ptr, sz), objs, 1, type);
1185
1186         /* Special case for HEAP_I - see free & realloc hook.  They don't
1187            know whether the input region was HEAP or HEAP_I before
1188            unmapping it.  Here we give HEAP a try in case HEAP_I
1189            failed.  */
1190         if ((type == __MF_TYPE_HEAP_I) && (num_overlapping_objs == 0))
1191           {
1192             num_overlapping_objs = __mf_find_objects2 ((uintptr_t) ptr,
1193                                                        CLAMPSZ (ptr, sz), objs, 1, __MF_TYPE_HEAP);
1194           }
1195
1196         old_obj = objs[0];
1197         if (UNLIKELY ((num_overlapping_objs != 1) /* more than one overlap */
1198                       || ((sz == 0) ? 0 : (sz != (old_obj->high - old_obj->low + 1))) /* size mismatch */
1199                       || ((uintptr_t) ptr != old_obj->low))) /* base mismatch */
1200           {
1201             __mf_violation (ptr, sz,
1202                             (uintptr_t) __builtin_return_address (0), NULL,
1203                             __MF_VIOL_UNREGISTER);
1204             break;
1205           }
1206
1207         __mf_unlink_object (old_obj);
1208         __mf_uncache_object (old_obj);
1209
1210         /* Wipe buffer contents if desired.  */
1211         if ((__mf_opts.wipe_stack && old_obj->type == __MF_TYPE_STACK)
1212             || (__mf_opts.wipe_heap && (old_obj->type == __MF_TYPE_HEAP 
1213                                         || old_obj->type == __MF_TYPE_HEAP_I)))
1214           {
1215             memset ((void *) old_obj->low,
1216                     0,
1217                     (size_t) (old_obj->high - old_obj->low + 1));
1218           }
1219         
1220         /* Manage the object cemetary.  */
1221         if (__mf_opts.persistent_count > 0 && 
1222             old_obj->type >= 0 && 
1223             old_obj->type <= __MF_TYPE_MAX_CEM)
1224           {
1225             old_obj->deallocated_p = 1;
1226             old_obj->dealloc_pc = (uintptr_t) __builtin_return_address (0);
1227 #if HAVE_GETTIMEOFDAY
1228             if (__mf_opts.timestamps)
1229               gettimeofday (& old_obj->dealloc_time, NULL);
1230 #endif
1231 #ifdef LIBMUDFLAPTH
1232             old_obj->dealloc_thread = pthread_self ();
1233 #endif
1234
1235             if (__mf_opts.backtrace > 0 && old_obj->type == __MF_TYPE_HEAP)
1236               old_obj->dealloc_backtrace_size = 
1237                 __mf_backtrace (& old_obj->dealloc_backtrace,
1238                                 NULL, 2);
1239
1240             /* Encourage this object to be displayed again in current epoch.  */
1241             old_obj->description_epoch --;
1242
1243             /* Put this object into the cemetary.  This may require this plot to
1244                be recycled, and the previous resident to be designated del_obj.  */
1245             {
1246               unsigned row = old_obj->type;
1247               unsigned plot = __mf_object_dead_head [row];
1248               
1249               del_obj = __mf_object_cemetary [row][plot];
1250               __mf_object_cemetary [row][plot] = old_obj;
1251               plot ++;
1252               if (plot == __mf_opts.persistent_count) plot = 0;
1253               __mf_object_dead_head [row] = plot;
1254             }
1255           }
1256         else
1257           del_obj = old_obj;
1258         
1259         if (__mf_opts.print_leaks)
1260           {
1261             if ((old_obj->read_count + old_obj->write_count) == 0 &&
1262                 (old_obj->type == __MF_TYPE_HEAP 
1263                  || old_obj->type == __MF_TYPE_HEAP_I))
1264               {
1265                 fprintf (stderr, 
1266                          "*******\n"
1267                          "mudflap warning: unaccessed registered object:\n");
1268                 __mf_describe_object (old_obj);
1269               }
1270           }
1271         
1272         if (del_obj != NULL) /* May or may not equal old_obj.  */
1273           {
1274             if (__mf_opts.backtrace > 0)
1275               {
1276                 CALL_REAL(free, del_obj->alloc_backtrace);
1277                 if (__mf_opts.persistent_count > 0)
1278                   {
1279                     CALL_REAL(free, del_obj->dealloc_backtrace);
1280                   }
1281               }
1282             CALL_REAL(free, del_obj);
1283           }
1284         
1285         break;
1286       }
1287     } /* end switch (__mf_opts.mudflap_mode) */
1288
1289
1290   if (__mf_opts.collect_stats)
1291     {
1292       __mf_count_unregister ++;
1293       __mf_total_unregister_size += sz;
1294     }
1295 }
1296
1297
1298
1299 struct tree_stats
1300 {
1301   unsigned obj_count;
1302   unsigned long total_size;
1303   unsigned live_obj_count;
1304   double total_weight;
1305   double weighted_size;
1306   unsigned long weighted_address_bits [sizeof (uintptr_t) * 8][2];
1307 };
1308
1309
1310
1311 static int
1312 __mf_adapt_cache_fn (mfsplay_tree_node n, void *param)
1313 {
1314   __mf_object_t *obj = (__mf_object_t *) n->value;
1315   struct tree_stats *s = (struct tree_stats *) param;
1316
1317   assert (obj != NULL && s != NULL);
1318   
1319   /* Exclude never-accessed objects.  */
1320   if (obj->read_count + obj->write_count)
1321     {
1322       s->obj_count ++;
1323       s->total_size += (obj->high - obj->low + 1);
1324
1325       if (obj->liveness)
1326         {
1327           unsigned i;
1328           uintptr_t addr;
1329
1330           /* VERBOSE_TRACE ("analyze low=%p live=%u name=`%s'\n",
1331              (void *) obj->low, obj->liveness, obj->name); */
1332
1333           s->live_obj_count ++;
1334           s->total_weight += (double) obj->liveness;
1335           s->weighted_size +=
1336             (double) (obj->high - obj->low + 1) *
1337             (double) obj->liveness;
1338
1339           addr = obj->low;
1340           for (i=0; i<sizeof(uintptr_t) * 8; i++)
1341             {
1342               unsigned bit = addr & 1;
1343               s->weighted_address_bits[i][bit] += obj->liveness;
1344               addr = addr >> 1;
1345             }
1346
1347           /* Age the liveness value.  */
1348           obj->liveness >>= 1;
1349         }
1350     }
1351
1352   return 0;
1353 }
1354
1355
1356 static void
1357 __mf_adapt_cache ()
1358 {
1359   struct tree_stats s;
1360   uintptr_t new_mask = 0;
1361   unsigned char new_shift;
1362   float cache_utilization;
1363   float max_value;
1364   static float smoothed_new_shift = -1.0;
1365   unsigned i;
1366
1367   memset (&s, 0, sizeof (s));
1368
1369   mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP), __mf_adapt_cache_fn, (void *) & s);
1370   mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP_I), __mf_adapt_cache_fn, (void *) & s);
1371   mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_STACK), __mf_adapt_cache_fn, (void *) & s);
1372   mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_STATIC), __mf_adapt_cache_fn, (void *) & s);
1373   mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_GUESS), __mf_adapt_cache_fn, (void *) & s);
1374
1375   /* Maybe we're dealing with funny aging/adaptation parameters, or an
1376      empty tree.  Just leave the cache alone in such cases, rather
1377      than risk dying by division-by-zero.  */
1378   if (! (s.obj_count > 0) && (s.live_obj_count > 0) && (s.total_weight > 0.0))
1379     return;
1380
1381   /* Guess a good value for the shift parameter by finding an address bit that is a
1382      good discriminant of lively objects.  */
1383   max_value = 0.0;
1384   for (i=0; i<sizeof (uintptr_t)*8; i++)
1385     {
1386       float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1];
1387       if (max_value < value) max_value = value;
1388     }
1389   for (i=0; i<sizeof (uintptr_t)*8; i++)
1390     {
1391       float shoulder_factor = 0.7;  /* Include slightly less popular bits too.  */
1392       float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1];
1393       if (value >= max_value * shoulder_factor)
1394         break;
1395     }
1396   if (smoothed_new_shift < 0) smoothed_new_shift = __mf_lc_shift;
1397   /* Converge toward this slowly to reduce flapping. */  
1398   smoothed_new_shift = 0.9*smoothed_new_shift + 0.1*i;
1399   new_shift = (unsigned) (smoothed_new_shift + 0.5);
1400   assert (new_shift < sizeof (uintptr_t)*8);
1401
1402   /* Count number of used buckets.  */
1403   cache_utilization = 0.0;
1404   for (i = 0; i < (1 + __mf_lc_mask); i++)
1405     if (__mf_lookup_cache[i].low != 0 || __mf_lookup_cache[i].high != 0)
1406       cache_utilization += 1.0;
1407   cache_utilization /= (1 + __mf_lc_mask);
1408
1409   new_mask |= 0x3ff; /* XXX: force a large cache.  */
1410   new_mask &= (LOOKUP_CACHE_SIZE_MAX - 1);
1411
1412   VERBOSE_TRACE ("adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => "
1413                  "util=%u%% m=%p s=%u\n",
1414                  s.obj_count, s.live_obj_count, s.total_size, s.total_weight, s.weighted_size,
1415                  (unsigned)(cache_utilization*100.0), (void *) new_mask, new_shift);
1416
1417   /* We should reinitialize cache if its parameters have changed.  */
1418   if (new_mask != __mf_lc_mask ||
1419       new_shift != __mf_lc_shift)
1420     {
1421       __mf_lc_mask = new_mask;
1422       __mf_lc_shift = new_shift;
1423       /* XXX: race */
1424       memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
1425       /* void slot 0 */
1426       __mf_lookup_cache[0].low = MAXPTR;
1427     }
1428 }
1429
1430
1431
1432 /* __mf_find_object[s] */
1433
1434 /* Find overlapping live objecs between [low,high].  Return up to
1435    max_objs of their pointers in objs[].  Return total count of
1436    overlaps (may exceed max_objs). */
1437
1438 unsigned 
1439 __mf_find_objects2 (uintptr_t ptr_low, uintptr_t ptr_high, 
1440                     __mf_object_t **objs, unsigned max_objs, int type)
1441 {
1442   unsigned count = 0;
1443   mfsplay_tree t = __mf_object_tree (type);
1444   mfsplay_tree_key k = (mfsplay_tree_key) ptr_low;
1445   int direction;
1446
1447   mfsplay_tree_node n = mfsplay_tree_lookup (t, k);
1448   /* An exact match for base address implies a hit.  */
1449   if (n != NULL)
1450     {
1451       if (count < max_objs)
1452         objs[count] = (__mf_object_t *) n->value;
1453       count ++;
1454     }
1455
1456   /* Iterate left then right near this key value to find all overlapping objects. */
1457   for (direction = 0; direction < 2; direction ++)
1458     {
1459       /* Reset search origin.  */
1460       k = (mfsplay_tree_key) ptr_low;
1461
1462       while (1)
1463         {
1464           __mf_object_t *obj;
1465               
1466           n = (direction == 0 ? mfsplay_tree_successor (t, k) : mfsplay_tree_predecessor (t, k));
1467           if (n == NULL) break;
1468           obj = (__mf_object_t *) n->value;
1469               
1470           if (! (obj->low <= ptr_high && obj->high >= ptr_low)) /* No overlap? */
1471             break;
1472               
1473           if (count < max_objs)
1474             objs[count] = (__mf_object_t *) n->value;
1475           count ++;
1476
1477           k = (mfsplay_tree_key) obj->low;
1478         }
1479     }
1480
1481   return count;
1482 }
1483
1484
1485 unsigned
1486 __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high,
1487                    __mf_object_t **objs, unsigned max_objs)
1488 {
1489   int type;
1490   unsigned count = 0;
1491
1492   /* Search each splay tree for overlaps.  */
1493   for (type = __MF_TYPE_NOACCESS; type <= __MF_TYPE_GUESS; type++)
1494     {
1495       unsigned c = __mf_find_objects2 (ptr_low, ptr_high, objs, max_objs, type);
1496       if (c > max_objs)
1497         {
1498           max_objs = 0;
1499           objs = NULL;
1500         }
1501       else /* NB: C may equal 0 */
1502         {
1503           max_objs -= c;
1504           objs += c;
1505         }
1506       count += c;
1507     }
1508
1509   return count;
1510 }
1511
1512
1513
1514 /* __mf_link_object */
1515
1516 static void
1517 __mf_link_object (__mf_object_t *node)
1518 {
1519   mfsplay_tree t = __mf_object_tree (node->type);
1520   mfsplay_tree_insert (t, (mfsplay_tree_key) node->low, (mfsplay_tree_value) node);
1521 }
1522
1523 /* __mf_unlink_object */
1524
1525 static void
1526 __mf_unlink_object (__mf_object_t *node)
1527 {
1528   mfsplay_tree t = __mf_object_tree (node->type);
1529   mfsplay_tree_remove (t, (mfsplay_tree_key) node->low);
1530 }
1531
1532 /* __mf_find_dead_objects */
1533
1534 /* Find overlapping dead objecs between [low,high].  Return up to
1535    max_objs of their pointers in objs[].  Return total count of
1536    overlaps (may exceed max_objs).  */
1537
1538 static unsigned
1539 __mf_find_dead_objects (uintptr_t low, uintptr_t high,
1540                         __mf_object_t **objs, unsigned max_objs)
1541 {
1542   if (__mf_opts.persistent_count > 0)
1543     {
1544       unsigned count = 0;
1545       unsigned recollection = 0;
1546       unsigned row = 0;
1547       
1548       assert (low <= high);
1549       assert (max_objs == 0 || objs != NULL);
1550       
1551       /* Widen the search from the most recent plots in each row, looking
1552          backward in time.  */
1553       recollection = 0;
1554       while (recollection < __mf_opts.persistent_count)
1555         {
1556           count = 0;
1557           
1558           for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++)
1559             {
1560               unsigned plot;
1561               unsigned i;
1562               
1563               plot = __mf_object_dead_head [row];
1564               for (i = 0; i <= recollection; i ++)
1565                 {
1566                   __mf_object_t *obj;
1567                   
1568                   /* Look backward through row: it's a circular buffer.  */
1569                   if (plot > 0) plot --;
1570                   else plot = __mf_opts.persistent_count - 1;
1571                   
1572                   obj = __mf_object_cemetary [row][plot];
1573                   if (obj && obj->low <= high && obj->high >= low)
1574                     {
1575                       /* Found an overlapping dead object!  */
1576                       if (count < max_objs)
1577                         objs [count] = obj;
1578                       count ++;
1579                     }
1580                 }
1581             }
1582           
1583           if (count)
1584             break;
1585           
1586           /* Look farther back in time.  */
1587           recollection = (recollection * 2) + 1;
1588         }
1589       
1590       return count;
1591     } else {
1592       return 0;
1593     }
1594 }
1595
1596 /* __mf_describe_object */
1597
1598 static void
1599 __mf_describe_object (__mf_object_t *obj)
1600 {
1601   static unsigned epoch = 0;
1602   if (obj == NULL)
1603     {
1604       epoch ++;
1605       return;
1606     }
1607
1608   if (__mf_opts.abbreviate && obj->description_epoch == epoch)
1609     {
1610       fprintf (stderr,
1611                "mudflap object %p: name=`%s'\n",
1612                (void *) obj, (obj->name ? obj->name : ""));
1613       return;
1614     }
1615   else
1616     obj->description_epoch = epoch;
1617
1618   fprintf (stderr,
1619            "mudflap object %p: name=`%s'\n"
1620            "bounds=[%p,%p] size=%lu area=%s check=%ur/%uw liveness=%u%s\n"
1621            "alloc time=%lu.%06lu pc=%p"
1622 #ifdef LIBMUDFLAPTH
1623            " thread=%u"
1624 #endif
1625            "\n",
1626            (void *) obj, (obj->name ? obj->name : ""), 
1627            (void *) obj->low, (void *) obj->high,
1628            (unsigned long) (obj->high - obj->low + 1),
1629            (obj->type == __MF_TYPE_NOACCESS ? "no-access" :
1630             obj->type == __MF_TYPE_HEAP ? "heap" :
1631             obj->type == __MF_TYPE_HEAP_I ? "heap-init" :
1632             obj->type == __MF_TYPE_STACK ? "stack" :
1633             obj->type == __MF_TYPE_STATIC ? "static" :
1634             obj->type == __MF_TYPE_GUESS ? "guess" :
1635             "unknown"),
1636            obj->read_count, obj->write_count, obj->liveness, 
1637            obj->watching_p ? " watching" : "",
1638            obj->alloc_time.tv_sec, obj->alloc_time.tv_usec, 
1639            (void *) obj->alloc_pc
1640 #ifdef LIBMUDFLAPTH
1641            , (unsigned) obj->alloc_thread
1642 #endif
1643            );
1644
1645   if (__mf_opts.backtrace > 0)
1646   {
1647     unsigned i;
1648     for (i=0; i<obj->alloc_backtrace_size; i++)
1649       fprintf (stderr, "      %s\n", obj->alloc_backtrace[i]);
1650   }
1651
1652   if (__mf_opts.persistent_count > 0)
1653     {
1654       if (obj->deallocated_p)
1655         {
1656           fprintf (stderr, "dealloc time=%lu.%06lu pc=%p"
1657 #ifdef LIBMUDFLAPTH
1658                    " thread=%u"
1659 #endif
1660                    "\n",
1661                    obj->dealloc_time.tv_sec, obj->dealloc_time.tv_usec, 
1662                    (void *) obj->dealloc_pc
1663 #ifdef LIBMUDFLAPTH
1664                    , (unsigned) obj->dealloc_thread
1665 #endif
1666                    );
1667
1668
1669           if (__mf_opts.backtrace > 0)
1670           {
1671             unsigned i;
1672             for (i=0; i<obj->dealloc_backtrace_size; i++)
1673               fprintf (stderr, "      %s\n", obj->dealloc_backtrace[i]);
1674           }
1675         }
1676     }
1677 }
1678
1679
1680 static int
1681 __mf_report_leaks_fn (mfsplay_tree_node n, void *param)
1682 {
1683   __mf_object_t *node = (__mf_object_t *) n->value;
1684   unsigned *count = (unsigned *) param;
1685
1686   if (count != NULL)
1687     (*count) ++;
1688
1689   fprintf (stderr, "Leaked object %u:\n", (*count));
1690   __mf_describe_object (node);
1691
1692   return 0;
1693 }
1694
1695
1696 static unsigned
1697 __mf_report_leaks ()
1698 {
1699   unsigned count = 0;
1700
1701   (void) mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP),
1702                              __mf_report_leaks_fn, & count);
1703   (void) mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP_I),
1704                              __mf_report_leaks_fn, & count);
1705
1706   return count;
1707 }
1708
1709 /* ------------------------------------------------------------------------ */
1710 /* __mf_report */
1711
1712 void
1713 __mf_report ()
1714 {
1715   LOCKTH ();
1716   BEGIN_RECURSION_PROTECT ();
1717   __mfu_report ();
1718   END_RECURSION_PROTECT ();
1719   UNLOCKTH ();
1720 }
1721
1722 void
1723 __mfu_report ()
1724 {
1725   if (__mf_opts.collect_stats)
1726     {
1727       fprintf (stderr,
1728                "*******\n"
1729                "mudflap stats:\n"
1730                "calls to __mf_check: %lu\n"
1731                "         __mf_register: %lu [%luB, %luB, %luB, %luB, %luB]\n"
1732                "         __mf_unregister: %lu [%luB]\n"
1733                "         __mf_violation: [%lu, %lu, %lu, %lu, %lu]\n",
1734                __mf_count_check,
1735                __mf_count_register,
1736                __mf_total_register_size[0], __mf_total_register_size[1],
1737                __mf_total_register_size[2], __mf_total_register_size[3],
1738                __mf_total_register_size[4], /* XXX */
1739                __mf_count_unregister, __mf_total_unregister_size,
1740                __mf_count_violation[0], __mf_count_violation[1],
1741                __mf_count_violation[2], __mf_count_violation[3],
1742                __mf_count_violation[4]);
1743
1744       fprintf (stderr,
1745                "calls with reentrancy: %lu\n", __mf_reentrancy);
1746 #ifdef LIBMUDFLAPTH
1747       fprintf (stderr,
1748                "           lock contention: %lu\n", __mf_lock_contention);
1749 #endif
1750
1751       /* Lookup cache stats.  */
1752       {
1753         unsigned i;
1754         unsigned max_reuse = 0;
1755         unsigned num_used = 0;
1756         unsigned num_unused = 0;
1757
1758         for (i = 0; i < LOOKUP_CACHE_SIZE; i++)
1759           {
1760             if (__mf_lookup_cache_reusecount[i])
1761               num_used ++;
1762             else
1763               num_unused ++;
1764             if (max_reuse < __mf_lookup_cache_reusecount[i])
1765               max_reuse = __mf_lookup_cache_reusecount[i];
1766           }
1767         fprintf (stderr, "lookup cache slots used: %u  unused: %u  peak-reuse: %u\n",
1768                  num_used, num_unused, max_reuse);
1769       }
1770
1771       {
1772         unsigned live_count;
1773         live_count = __mf_find_objects (MINPTR, MAXPTR, NULL, 0);
1774         fprintf (stderr, "number of live objects: %u\n", live_count);
1775       }
1776
1777       if (__mf_opts.persistent_count > 0)
1778         {
1779           unsigned dead_count = 0;
1780           unsigned row, plot;
1781           for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++)
1782             for (plot = 0 ; plot < __mf_opts.persistent_count; plot ++)
1783               if (__mf_object_cemetary [row][plot] != 0)
1784                 dead_count ++;
1785           fprintf (stderr, "          zombie objects: %u\n", dead_count);
1786         }
1787     }
1788   if (__mf_opts.print_leaks && (__mf_opts.mudflap_mode == mode_check))
1789     {
1790       unsigned l;
1791       extern void * __mf_wrap_alloca_indirect (size_t c);
1792
1793       /* Free up any remaining alloca()'d blocks.  */
1794       __mf_wrap_alloca_indirect (0);
1795       __mf_describe_object (NULL); /* Reset description epoch.  */
1796       l = __mf_report_leaks ();
1797       fprintf (stderr, "number of leaked objects: %u\n", l);
1798     }
1799 }
1800
1801 /* __mf_backtrace */
1802
1803 size_t
1804 __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels)
1805 {
1806   void ** pc_array;
1807   unsigned pc_array_size = __mf_opts.backtrace + guess_omit_levels;
1808   unsigned remaining_size;
1809   unsigned omitted_size = 0;
1810   unsigned i;
1811   DECLARE (void, free, void *ptr);
1812   DECLARE (void *, calloc, size_t c, size_t n);
1813   DECLARE (void *, malloc, size_t n);
1814
1815   pc_array = CALL_REAL (calloc, pc_array_size, sizeof (void *) );
1816 #ifdef HAVE_BACKTRACE
1817   pc_array_size = backtrace (pc_array, pc_array_size);
1818 #else
1819 #define FETCH(n) do { if (pc_array_size >= n) { \
1820                  pc_array[n] = __builtin_return_address(n); \
1821                  if (pc_array[n] == 0) pc_array_size = n; } } while (0)
1822
1823   /* Unroll some calls __builtin_return_address because this function
1824      only takes a literal integer parameter.  */
1825   FETCH (0);
1826 #if 0
1827   /* XXX: __builtin_return_address sometimes crashes (!) on >0 arguments,
1828      rather than simply returning 0.  :-(  */
1829   FETCH (1);
1830   FETCH (2);
1831   FETCH (3);
1832   FETCH (4);
1833   FETCH (5);
1834   FETCH (6);
1835   FETCH (7);
1836   FETCH (8);
1837   if (pc_array_size > 8) pc_array_size = 9;
1838 #else
1839   if (pc_array_size > 0) pc_array_size = 1;
1840 #endif
1841
1842 #undef FETCH
1843 #endif
1844
1845   /* We want to trim the first few levels of the stack traceback,
1846      since they contain libmudflap wrappers and junk.  If pc_array[]
1847      ends up containing a non-NULL guess_pc, then trim everything
1848      before that.  Otherwise, omit the first guess_omit_levels
1849      entries. */
1850   
1851   if (guess_pc != NULL)
1852     for (i=0; i<pc_array_size; i++)
1853       if (pc_array [i] == guess_pc)
1854         omitted_size = i;
1855
1856   if (omitted_size == 0) /* No match? */
1857     if (pc_array_size > guess_omit_levels)
1858       omitted_size = guess_omit_levels;
1859
1860   remaining_size = pc_array_size - omitted_size;
1861
1862 #ifdef HAVE_BACKTRACE_SYMBOLS
1863   *symbols = backtrace_symbols (pc_array + omitted_size, remaining_size);
1864 #else
1865   {
1866     /* Let's construct a buffer by hand.  It will have <remaining_size>
1867        char*'s at the front, pointing at individual strings immediately
1868        afterwards.  */
1869     void *buffer;
1870     char *chars;
1871     char **pointers;
1872     enum { perline = 30 };
1873     buffer = CALL_REAL (malloc, remaining_size * (perline + sizeof(char *)));
1874     pointers = (char **) buffer;
1875     chars = (char *)buffer + (remaining_size * sizeof (char *));
1876     for (i = 0; i < remaining_size; i++)
1877       {
1878         pointers[i] = chars;
1879         sprintf (chars, "[0x%p]", pc_array [omitted_size + i]);
1880         chars = chars + perline;
1881       }
1882     *symbols = pointers;
1883   }
1884 #endif
1885   CALL_REAL (free, pc_array);
1886
1887   return remaining_size;
1888 }
1889
1890 /* ------------------------------------------------------------------------ */
1891 /* __mf_violation */
1892
1893 void
1894 __mf_violation (void *ptr, size_t sz, uintptr_t pc, 
1895                 const char *location, int type)
1896 {
1897   char buf [128];
1898   static unsigned violation_number;
1899   DECLARE(void, free, void *ptr);
1900
1901   TRACE ("violation pc=%p location=%s type=%d ptr=%p size=%lu\n", 
1902          (void *) pc, 
1903          (location != NULL ? location : ""), type, ptr, (unsigned long) sz);
1904
1905   if (__mf_opts.collect_stats)
1906     __mf_count_violation [(type < 0) ? 0 :
1907                           (type > __MF_VIOL_WATCH) ? 0 :
1908                           type] ++;
1909
1910   /* Print out a basic warning message.  */
1911   if (__mf_opts.verbose_violations)
1912   {
1913     unsigned dead_p;
1914     unsigned num_helpful = 0;
1915     struct timeval now = { 0, 0 };
1916 #if HAVE_GETTIMEOFDAY
1917     gettimeofday (& now, NULL);
1918 #endif
1919
1920     violation_number ++;
1921     fprintf (stderr,
1922              "*******\n"
1923              "mudflap violation %u (%s): time=%lu.%06lu "
1924              "ptr=%p size=%lu\npc=%p%s%s%s\n", 
1925              violation_number,
1926              ((type == __MF_VIOL_READ) ? "check/read" :
1927               (type == __MF_VIOL_WRITE) ? "check/write" :
1928               (type == __MF_VIOL_REGISTER) ? "register" :
1929               (type == __MF_VIOL_UNREGISTER) ? "unregister" :
1930               (type == __MF_VIOL_WATCH) ? "watch" : "unknown"),
1931              now.tv_sec, now.tv_usec, 
1932              (void *) ptr, (unsigned long)sz, (void *) pc,
1933              (location != NULL ? " location=`" : ""),
1934              (location != NULL ? location : ""),
1935              (location != NULL ? "'" : ""));
1936
1937     if (__mf_opts.backtrace > 0)
1938       {
1939         char ** symbols;
1940         unsigned i, num;
1941         
1942         num = __mf_backtrace (& symbols, (void *) pc, 2);
1943         /* Note: backtrace_symbols calls malloc().  But since we're in
1944            __mf_violation and presumably __mf_check, it'll detect
1945            recursion, and not put the new string into the database.  */
1946         
1947         for (i=0; i<num; i++)
1948           fprintf (stderr, "      %s\n", symbols[i]);
1949         
1950         /* Calling free() here would trigger a violation.  */
1951         CALL_REAL(free, symbols);
1952       }
1953     
1954     
1955     /* Look for nearby objects.  For this, we start with s_low/s_high
1956        pointing to the given area, looking for overlapping objects.
1957        If none show up, widen the search area and keep looking. */
1958     
1959     if (sz == 0) sz = 1;
1960     
1961     for (dead_p = 0; dead_p <= 1; dead_p ++) /* for dead_p in 0 1 */
1962       {
1963         enum {max_objs = 3}; /* magic */
1964         __mf_object_t *objs[max_objs];
1965         unsigned num_objs = 0;
1966         uintptr_t s_low, s_high;
1967         unsigned tries = 0;
1968         unsigned i;
1969         
1970         s_low = (uintptr_t) ptr;
1971         s_high = CLAMPSZ (ptr, sz);
1972
1973         while (tries < 16) /* magic */
1974           {
1975             if (dead_p)
1976               num_objs = __mf_find_dead_objects (s_low, s_high, objs, max_objs);
1977             else
1978               num_objs = __mf_find_objects (s_low, s_high, objs, max_objs);
1979
1980             if (num_objs) /* good enough */
1981               break;
1982
1983             tries ++;
1984
1985             /* XXX: tune this search strategy.  It's too dependent on
1986              sz, which can vary from 1 to very big (when array index
1987              checking) numbers. */
1988             s_low = CLAMPSUB (s_low, (sz * tries * tries));
1989             s_high = CLAMPADD (s_high, (sz * tries * tries));
1990           }
1991
1992         for (i = 0; i < min (num_objs, max_objs); i++)
1993           {
1994             __mf_object_t *obj = objs[i];
1995             uintptr_t low = (uintptr_t) ptr;
1996             uintptr_t high = CLAMPSZ (ptr, sz);
1997             unsigned before1 = (low < obj->low) ? obj->low - low : 0;
1998             unsigned after1 = (low > obj->high) ? low - obj->high : 0;
1999             unsigned into1 = (high >= obj->low && low <= obj->high) ? low - obj->low : 0;
2000             unsigned before2 = (high < obj->low) ? obj->low - high : 0;
2001             unsigned after2 = (high > obj->high) ? high - obj->high : 0;
2002             unsigned into2 = (high >= obj->low && low <= obj->high) ? high - obj->low : 0;
2003
2004             fprintf (stderr, "Nearby object %u: checked region begins %uB %s and ends %uB %s\n",
2005                      num_helpful + i + 1,
2006                      (before1 ? before1 : after1 ? after1 : into1),
2007                      (before1 ? "before" : after1 ? "after" : "into"),
2008                      (before2 ? before2 : after2 ? after2 : into2),
2009                      (before2 ? "before" : after2 ? "after" : "into"));
2010             __mf_describe_object (obj);
2011           }
2012         num_helpful += num_objs;
2013       }
2014
2015     fprintf (stderr, "number of nearby objects: %u\n", num_helpful);
2016   }
2017
2018   /* How to finally handle this violation?  */
2019   switch (__mf_opts.violation_mode)
2020     {
2021     case viol_nop:
2022       break;
2023     case viol_segv:
2024       kill (getpid(), SIGSEGV);
2025       break;
2026     case viol_abort:
2027       abort ();
2028       break;
2029     case viol_gdb:
2030
2031       snprintf (buf, 128, "gdb --pid=%u", (unsigned) getpid ());
2032       system (buf);
2033       /* XXX: should probably fork() && sleep(GDB_WAIT_PARAMETER)
2034       instead, and let the forked child execlp() gdb.  That way, this
2035       subject process can be resumed under the supervision of gdb.
2036       This can't happen now, since system() only returns when gdb
2037       dies.  In that case, we need to beware of starting a second
2038       concurrent gdb child upon the next violation.  (But if the first
2039       gdb dies, then starting a new one is appropriate.)  */
2040       break;
2041     }
2042 }
2043
2044 /* ------------------------------------------------------------------------ */
2045
2046
2047 unsigned __mf_watch (void *ptr, size_t sz)
2048 {
2049   unsigned rc;
2050   LOCKTH ();
2051   BEGIN_RECURSION_PROTECT ();
2052   rc = __mf_watch_or_not (ptr, sz, 1);
2053   END_RECURSION_PROTECT ();
2054   UNLOCKTH ();
2055   return rc;
2056 }
2057
2058 unsigned __mf_unwatch (void *ptr, size_t sz)
2059 {
2060   unsigned rc;
2061   LOCKTH ();
2062   rc = __mf_watch_or_not (ptr, sz, 0);
2063   UNLOCKTH ();
2064   return rc;
2065 }
2066
2067
2068 static unsigned
2069 __mf_watch_or_not (void *ptr, size_t sz, char flag)
2070 {
2071   uintptr_t ptr_high = CLAMPSZ (ptr, sz);
2072   uintptr_t ptr_low = (uintptr_t) ptr;
2073   unsigned count = 0;
2074
2075   TRACE ("%s ptr=%p size=%lu\n",
2076          (flag ? "watch" : "unwatch"), ptr, (unsigned long) sz);
2077   
2078   switch (__mf_opts.mudflap_mode)
2079     {
2080     case mode_nop:
2081     case mode_populate:
2082     case mode_violate:
2083       count = 0;
2084       break;
2085
2086     case mode_check:
2087       {
2088         __mf_object_t **all_ovr_objs;
2089         unsigned obj_count;
2090         unsigned n;
2091         DECLARE (void *, malloc, size_t c);
2092         DECLARE (void, free, void *p);
2093
2094         obj_count = __mf_find_objects (ptr_low, ptr_high, NULL, 0);
2095         VERBOSE_TRACE (" %u:", obj_count);
2096
2097         all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_t *) * obj_count));
2098         if (all_ovr_objs == NULL) abort ();
2099         n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count);
2100         assert (n == obj_count);
2101
2102         for (n = 0; n < obj_count; n ++)
2103           {
2104             __mf_object_t *obj = all_ovr_objs[n];
2105
2106             VERBOSE_TRACE (" [%p]", (void *) obj);
2107             if (obj->watching_p != flag)
2108               {
2109                 obj->watching_p = flag;
2110                 count ++;
2111
2112                 /* Remove object from cache, to ensure next access
2113                    goes through __mf_check().  */
2114                 if (flag)
2115                   __mf_uncache_object (obj);
2116               }
2117           }
2118         CALL_REAL (free, all_ovr_objs);
2119       }
2120       break;
2121     }
2122
2123   return count;
2124 }
2125
2126
2127 void
2128 __mf_sigusr1_handler (int num)
2129 {
2130   __mf_sigusr1_received ++;
2131 }
2132
2133 /* Install or remove SIGUSR1 handler as necessary.
2134    Also, respond to a received pending SIGUSR1.  */
2135 void
2136 __mf_sigusr1_respond ()
2137 {
2138   static int handler_installed;
2139
2140 #ifdef SIGUSR1
2141   /* Manage handler */
2142   if (__mf_opts.sigusr1_report && ! handler_installed)
2143     {
2144       signal (SIGUSR1, __mf_sigusr1_handler);
2145       handler_installed = 1;
2146     }
2147   else if(! __mf_opts.sigusr1_report && handler_installed)
2148     {
2149       signal (SIGUSR1, SIG_DFL);
2150       handler_installed = 0;
2151     }
2152 #endif
2153
2154   /* Manage enqueued signals */
2155   if (__mf_sigusr1_received > __mf_sigusr1_handled)
2156     {
2157       __mf_sigusr1_handled ++;
2158       assert (__mf_state == reentrant);
2159       __mfu_report ();
2160       handler_installed = 0; /* We may need to re-enable signal; this might be a SysV library. */
2161     }
2162 }
2163
2164
2165 /* XXX: provide an alternative __assert_fail function that cannot
2166    fail due to libmudflap infinite recursion.  */
2167 #ifndef NDEBUG
2168
2169 static void
2170 write_itoa (int fd, unsigned n)
2171 {
2172   enum x { bufsize = sizeof(n)*4 };
2173   char buf [bufsize];
2174   unsigned i;
2175
2176   for (i=0; i<bufsize-1; i++)
2177     {
2178       unsigned digit = n % 10;
2179       buf[bufsize-2-i] = digit + '0';
2180       n /= 10;
2181       if (n == 0) 
2182         {
2183           char *m = & buf [bufsize-2-i];
2184           buf[bufsize-1] = '\0';
2185           write (fd, m, strlen(m));
2186           break;
2187         }
2188     }
2189 }
2190
2191
2192 void
2193 __assert_fail (const char *msg, const char *file, unsigned line, const char *func)
2194 {
2195 #define write2(string) write (2, (string), strlen ((string)));
2196   write2("mf");
2197 #ifdef LIBMUDFLAPTH
2198   write2("(");
2199   write_itoa (2, (unsigned) pthread_self ());  
2200   write2(")");
2201 #endif
2202   write2(": assertion failure: `");
2203   write (2, msg, strlen (msg));
2204   write2("' in ");
2205   write (2, func, strlen (func));
2206   write2(" at ");
2207   write (2, file, strlen (file));
2208   write2(":");
2209   write_itoa (2, line);
2210   write2("\n");
2211 #undef write2
2212   abort ();
2213 }
2214
2215
2216 #endif
2217
2218
2219
2220 /* Adapted splay tree code, originally from libiberty.  It has been
2221    specialized for libmudflap as requested by RMS.  */
2222
2223 static void
2224 mfsplay_tree_free (void *p)
2225 {
2226   DECLARE (void, free, void *p);
2227   CALL_REAL (free, p);
2228 }
2229
2230 static void *
2231 mfsplay_tree_xmalloc (size_t s)
2232 {
2233   DECLARE (void *, malloc, size_t s);
2234   return CALL_REAL (malloc, s);
2235 }
2236
2237
2238 static void mfsplay_tree_splay (mfsplay_tree, mfsplay_tree_key);
2239 static mfsplay_tree_node mfsplay_tree_splay_helper (mfsplay_tree,
2240                                                 mfsplay_tree_key,
2241                                                 mfsplay_tree_node *,
2242                                                 mfsplay_tree_node *,
2243                                                 mfsplay_tree_node *);
2244 static void *mfsplay_tree_xmalloc (size_t size);
2245 static void mfsplay_tree_free (void *object);
2246
2247
2248
2249 /* Inline comparison function specialized for libmudflap's key type.  */
2250 static inline int
2251 compare_uintptr_t (mfsplay_tree_key k1, mfsplay_tree_key k2)
2252 {
2253   if ((uintptr_t) k1 < (uintptr_t) k2)
2254     return -1;
2255   else if ((uintptr_t) k1 > (uintptr_t) k2)
2256     return 1;
2257   else
2258     return 0;
2259 }
2260
2261
2262 /* Help splay SP around KEY.  PARENT and GRANDPARENT are the parent
2263    and grandparent, respectively, of NODE.  */
2264
2265 static mfsplay_tree_node
2266 mfsplay_tree_splay_helper (mfsplay_tree sp,
2267                          mfsplay_tree_key key,
2268                          mfsplay_tree_node * node,
2269                          mfsplay_tree_node * parent,
2270                          mfsplay_tree_node * grandparent)
2271 {
2272   mfsplay_tree_node *next;
2273   mfsplay_tree_node n;
2274   int comparison;
2275
2276   n = *node;
2277
2278   if (!n)
2279     return *parent;
2280
2281   comparison = compare_uintptr_t (key, n->key);
2282
2283   if (comparison == 0)
2284     /* We've found the target.  */
2285     next = 0;
2286   else if (comparison < 0)
2287     /* The target is to the left.  */
2288     next = &n->left;
2289   else
2290     /* The target is to the right.  */
2291     next = &n->right;
2292
2293   if (next)
2294     {
2295       /* Check whether our recursion depth is too high.  Abort this search,
2296          and signal that a rebalance is required to continue.  */
2297       if (sp->depth > sp->max_depth)
2298         {
2299           sp->rebalance_p = 1;
2300           return n;
2301          }
2302
2303       /* Continue down the tree.  */
2304       sp->depth ++;
2305       n = mfsplay_tree_splay_helper (sp, key, next, node, parent);
2306       sp->depth --;
2307
2308       /* The recursive call will change the place to which NODE
2309          points.  */
2310       if (*node != n || sp->rebalance_p)
2311         return n;
2312     }
2313
2314   if (!parent)
2315     /* NODE is the root.  We are done.  */
2316     return n;
2317
2318   /* First, handle the case where there is no grandparent (i.e.,
2319    *PARENT is the root of the tree.)  */
2320   if (!grandparent)
2321     {
2322       if (n == (*parent)->left)
2323         {
2324           *node = n->right;
2325           n->right = *parent;
2326         }
2327       else
2328         {
2329           *node = n->left;
2330           n->left = *parent;
2331         }
2332       *parent = n;
2333       return n;
2334     }
2335
2336   /* Next handle the cases where both N and *PARENT are left children,
2337      or where both are right children.  */
2338   if (n == (*parent)->left && *parent == (*grandparent)->left)
2339     {
2340       mfsplay_tree_node p = *parent;
2341
2342       (*grandparent)->left = p->right;
2343       p->right = *grandparent;
2344       p->left = n->right;
2345       n->right = p;
2346       *grandparent = n;
2347       return n;
2348     }
2349   else if (n == (*parent)->right && *parent == (*grandparent)->right)
2350     {
2351       mfsplay_tree_node p = *parent;
2352
2353       (*grandparent)->right = p->left;
2354       p->left = *grandparent;
2355       p->right = n->left;
2356       n->left = p;
2357       *grandparent = n;
2358       return n;
2359     }
2360
2361   /* Finally, deal with the case where N is a left child, but *PARENT
2362      is a right child, or vice versa.  */
2363   if (n == (*parent)->left)
2364     {
2365       (*parent)->left = n->right;
2366       n->right = *parent;
2367       (*grandparent)->right = n->left;
2368       n->left = *grandparent;
2369       *grandparent = n;
2370       return n;
2371     }
2372   else
2373     {
2374       (*parent)->right = n->left;
2375       n->left = *parent;
2376       (*grandparent)->left = n->right;
2377       n->right = *grandparent;
2378       *grandparent = n;
2379       return n;
2380     }
2381 }
2382
2383
2384
2385 static int
2386 mfsplay_tree_rebalance_helper1 (mfsplay_tree_node n, void *array_ptr)
2387 {
2388   mfsplay_tree_node **p = array_ptr;
2389   *(*p) = n;
2390   (*p)++;
2391   return 0;
2392 }
2393
2394
2395 static mfsplay_tree_node
2396 mfsplay_tree_rebalance_helper2 (mfsplay_tree_node * array, unsigned low,
2397                               unsigned high)
2398 {
2399   unsigned middle = low + (high - low) / 2;
2400   mfsplay_tree_node n = array[middle];
2401
2402   /* Note that since we're producing a balanced binary tree, it is not a problem
2403      that this function is recursive.  */
2404   if (low + 1 <= middle)
2405     n->left = mfsplay_tree_rebalance_helper2 (array, low, middle - 1);
2406   else
2407     n->left = NULL;
2408
2409   if (middle + 1 <= high)
2410     n->right = mfsplay_tree_rebalance_helper2 (array, middle + 1, high);
2411   else
2412     n->right = NULL;
2413
2414   return n;
2415 }
2416
2417
2418 /* Rebalance the entire tree.  Do this by copying all the node
2419    pointers into an array, then cleverly re-linking them.  */
2420 static void
2421 mfsplay_tree_rebalance (mfsplay_tree sp)
2422 {
2423   mfsplay_tree_node *all_nodes, *all_nodes_1;
2424
2425   if (sp->num_keys <= 2)
2426     return;
2427
2428   all_nodes = mfsplay_tree_xmalloc (sizeof (mfsplay_tree_node) * sp->num_keys);
2429
2430   /* Traverse all nodes to copy their addresses into this array.  */
2431   all_nodes_1 = all_nodes;
2432   mfsplay_tree_foreach (sp, mfsplay_tree_rebalance_helper1,
2433                       (void *) &all_nodes_1);
2434
2435   /* Relink all the nodes.  */
2436   sp->root = mfsplay_tree_rebalance_helper2 (all_nodes, 0, sp->num_keys - 1);
2437
2438   mfsplay_tree_free (all_nodes);
2439 }
2440
2441
2442 /* Splay SP around KEY.  */
2443 static void
2444 mfsplay_tree_splay (mfsplay_tree sp, mfsplay_tree_key key)
2445 {
2446   if (sp->root == 0)
2447     return;
2448
2449   /* If we just splayed the tree with the same key, do nothing.  */
2450   if (sp->last_splayed_key_p &&
2451       compare_uintptr_t (sp->last_splayed_key, key) == 0)
2452     return;
2453
2454   /* Compute a maximum recursion depth for a splay tree with NUM nodes.
2455      The idea is to limit excessive stack usage if we're facing
2456      degenerate access patterns.  Unfortunately such patterns can occur
2457      e.g. during static initialization, where many static objects might
2458      be registered in increasing address sequence, or during a case where
2459      large tree-like heap data structures are allocated quickly. 
2460
2461      On x86, this corresponds to roughly 200K of stack usage. 
2462      XXX: For libmudflapth, this could be a function of __mf_opts.thread_stack.  */
2463   sp->max_depth = 2500;
2464   sp->rebalance_p = sp->depth = 0;
2465
2466   mfsplay_tree_splay_helper (sp, key, &sp->root, NULL, NULL);
2467   if (sp->rebalance_p)
2468     {
2469       mfsplay_tree_rebalance (sp);
2470
2471       sp->rebalance_p = sp->depth = 0;
2472       mfsplay_tree_splay_helper (sp, key, &sp->root, NULL, NULL);
2473
2474       if (sp->rebalance_p)
2475         abort ();
2476     }
2477
2478
2479   /* Cache this splay key. */
2480   sp->last_splayed_key = key;
2481   sp->last_splayed_key_p = 1;
2482 }
2483
2484
2485
2486 /* Allocate a new splay tree.  */
2487 static mfsplay_tree
2488 mfsplay_tree_new ()
2489 {
2490   mfsplay_tree sp = mfsplay_tree_xmalloc (sizeof (struct mfsplay_tree_s));
2491   sp->root = NULL;
2492   sp->last_splayed_key_p = 0;
2493   sp->num_keys = 0;
2494
2495   return sp;
2496 }
2497
2498
2499
2500 /* Insert a new node (associating KEY with DATA) into SP.  If a
2501    previous node with the indicated KEY exists, its data is replaced
2502    with the new value.  Returns the new node.  */
2503 static mfsplay_tree_node
2504 mfsplay_tree_insert (mfsplay_tree sp, mfsplay_tree_key key, mfsplay_tree_value value)
2505 {
2506   int comparison = 0;
2507
2508   mfsplay_tree_splay (sp, key);
2509
2510   if (sp->root)
2511     comparison = compare_uintptr_t (sp->root->key, key);
2512
2513   if (sp->root && comparison == 0)
2514     {
2515       /* If the root of the tree already has the indicated KEY, just
2516          replace the value with VALUE.  */
2517       sp->root->value = value;
2518     }
2519   else
2520     {
2521       /* Create a new node, and insert it at the root.  */
2522       mfsplay_tree_node node;
2523
2524       node = mfsplay_tree_xmalloc (sizeof (struct mfsplay_tree_node_s));
2525       node->key = key;
2526       node->value = value;
2527       sp->num_keys++;
2528       if (!sp->root)
2529         node->left = node->right = 0;
2530       else if (comparison < 0)
2531         {
2532           node->left = sp->root;
2533           node->right = node->left->right;
2534           node->left->right = 0;
2535         }
2536       else
2537         {
2538           node->right = sp->root;
2539           node->left = node->right->left;
2540           node->right->left = 0;
2541         }
2542
2543       sp->root = node;
2544       sp->last_splayed_key_p = 0;
2545     }
2546
2547   return sp->root;
2548 }
2549
2550 /* Remove KEY from SP.  It is not an error if it did not exist.  */
2551
2552 static void
2553 mfsplay_tree_remove (mfsplay_tree sp, mfsplay_tree_key key)
2554 {
2555   mfsplay_tree_splay (sp, key);
2556   sp->last_splayed_key_p = 0;
2557   if (sp->root && compare_uintptr_t (sp->root->key, key) == 0)
2558     {
2559       mfsplay_tree_node left, right;
2560       left = sp->root->left;
2561       right = sp->root->right;
2562       /* Delete the root node itself.  */
2563       mfsplay_tree_free (sp->root);
2564       sp->num_keys--;
2565       /* One of the children is now the root.  Doesn't matter much
2566          which, so long as we preserve the properties of the tree.  */
2567       if (left)
2568         {
2569           sp->root = left;
2570           /* If there was a right child as well, hang it off the 
2571              right-most leaf of the left child.  */
2572           if (right)
2573             {
2574               while (left->right)
2575                 left = left->right;
2576               left->right = right;
2577             }
2578         }
2579       else
2580         sp->root = right;
2581     }
2582 }
2583
2584 /* Lookup KEY in SP, returning VALUE if present, and NULL 
2585    otherwise.  */
2586
2587 static mfsplay_tree_node
2588 mfsplay_tree_lookup (mfsplay_tree sp, mfsplay_tree_key key)
2589 {
2590   mfsplay_tree_splay (sp, key);
2591   if (sp->root && compare_uintptr_t (sp->root->key, key) == 0)
2592     return sp->root;
2593   else
2594     return 0;
2595 }
2596
2597
2598 /* Return the immediate predecessor KEY, or NULL if there is no
2599    predecessor.  KEY need not be present in the tree.  */
2600
2601 static mfsplay_tree_node
2602 mfsplay_tree_predecessor (mfsplay_tree sp, mfsplay_tree_key key)
2603 {
2604   int comparison;
2605   mfsplay_tree_node node;
2606   /* If the tree is empty, there is certainly no predecessor.  */
2607   if (!sp->root)
2608     return NULL;
2609   /* Splay the tree around KEY.  That will leave either the KEY
2610      itself, its predecessor, or its successor at the root.  */
2611   mfsplay_tree_splay (sp, key);
2612   comparison = compare_uintptr_t (sp->root->key, key);
2613   /* If the predecessor is at the root, just return it.  */
2614   if (comparison < 0)
2615     return sp->root;
2616   /* Otherwise, find the rightmost element of the left subtree.  */
2617   node = sp->root->left;
2618   if (node)
2619     while (node->right)
2620       node = node->right;
2621   return node;
2622 }
2623
2624 /* Return the immediate successor KEY, or NULL if there is no
2625    successor.  KEY need not be present in the tree.  */
2626
2627 static mfsplay_tree_node
2628 mfsplay_tree_successor (mfsplay_tree sp, mfsplay_tree_key key)
2629 {
2630   int comparison;
2631   mfsplay_tree_node node;
2632   /* If the tree is empty, there is certainly no successor.  */
2633   if (!sp->root)
2634     return NULL;
2635   /* Splay the tree around KEY.  That will leave either the KEY
2636      itself, its predecessor, or its successor at the root.  */
2637   mfsplay_tree_splay (sp, key);
2638   comparison = compare_uintptr_t (sp->root->key, key);
2639   /* If the successor is at the root, just return it.  */
2640   if (comparison > 0)
2641     return sp->root;
2642   /* Otherwise, find the leftmost element of the right subtree.  */
2643   node = sp->root->right;
2644   if (node)
2645     while (node->left)
2646       node = node->left;
2647   return node;
2648 }
2649
2650 /* Call FN, passing it the DATA, for every node in SP, following an
2651    in-order traversal.  If FN every returns a non-zero value, the
2652    iteration ceases immediately, and the value is returned.
2653    Otherwise, this function returns 0.
2654    
2655    This function simulates recursion using dynamically allocated
2656    arrays, since it may be called from mfsplay_tree_rebalance(), which
2657    in turn means that the tree is already uncomfortably deep for stack
2658    space limits.  */
2659 static int
2660 mfsplay_tree_foreach (mfsplay_tree st, mfsplay_tree_foreach_fn fn, void *data)
2661 {
2662   mfsplay_tree_node *stack1;
2663   char *stack2;
2664   unsigned sp;
2665   int val = 0;
2666   enum s { s_left, s_here, s_right, s_up };
2667
2668   if (st->root == NULL) /* => num_keys == 0 */
2669     return 0;
2670
2671   stack1 = mfsplay_tree_xmalloc (sizeof (mfsplay_tree_node) * st->num_keys);
2672   stack2 = mfsplay_tree_xmalloc (sizeof (char) * st->num_keys);
2673
2674   sp = 0;
2675   stack1 [sp] = st->root;
2676   stack2 [sp] = s_left;
2677
2678   while (1)
2679     {
2680       mfsplay_tree_node n;
2681       enum s s;
2682
2683       n = stack1 [sp];
2684       s = stack2 [sp];
2685
2686       /* Handle each of the four possible states separately.  */
2687
2688       /* 1: We're here to traverse the left subtree (if any).  */
2689       if (s == s_left)
2690         {
2691           stack2 [sp] = s_here;
2692           if (n->left != NULL)
2693             {
2694               sp ++;
2695               stack1 [sp] = n->left;
2696               stack2 [sp] = s_left;
2697             }
2698         }
2699
2700       /* 2: We're here to traverse this node.  */
2701       else if (s == s_here)
2702         {
2703           stack2 [sp] = s_right;
2704           val = (*fn) (n, data);
2705           if (val) break;
2706         }
2707
2708       /* 3: We're here to traverse the right subtree (if any).  */
2709       else if (s == s_right)
2710         {
2711           stack2 [sp] = s_up;
2712           if (n->right != NULL)
2713             {
2714               sp ++;
2715               stack1 [sp] = n->right;
2716               stack2 [sp] = s_left;
2717             }
2718         }
2719
2720       /* 4: We're here after both subtrees (if any) have been traversed.  */
2721       else if (s == s_up)
2722         {
2723           /* Pop the stack.  */
2724           if (sp == 0) break; /* Popping off the root note: we're finished!  */
2725           sp --;
2726         }
2727
2728       else
2729         abort ();
2730     }
2731
2732   mfsplay_tree_free (stack1);
2733   mfsplay_tree_free (stack2);
2734   return val;
2735 }