OSDN Git Service

* Makefile.in (local-distclean): Also remove fastjar.
[pf3gnuchains/gcc-fork.git] / boehm-gc / dbg_mlc.c
index 079e43b..f329cc8 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999 by Hewlett-Packard Company.  All rights reserved.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, October 9, 1995 1:16 pm PDT */
-# include "gc_priv.h"
 
-/* Do we want to and know how to save the call stack at the time of    */
-/* an allocation?  How much space do we want to use in each object?    */
+#include "dbg_mlc.h"
 
-# define START_FLAG ((word)0xfedcedcb)
-# define END_FLAG ((word)0xbcdecdef)
-       /* Stored both one past the end of user object, and one before  */
-       /* the end of the object as seen by the allocator.              */
+void GC_default_print_heap_obj_proc();
+GC_API void GC_register_finalizer_no_order
+       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+                 GC_finalization_proc *ofn, GC_PTR *ocd));
 
 
-/* Object header */
-typedef struct {
-    char * oh_string;          /* object descriptor string     */
-    word oh_int;               /* object descriptor integers   */
-#   ifdef NEED_CALLINFO
-      struct callinfo oh_ci[NFRAMES];
-#   endif
-    word oh_sz;                        /* Original malloc arg.         */
-    word oh_sf;                        /* start flag */
-} oh;
-/* The size of the above structure is assumed not to dealign things,   */
-/* and to be a multiple of the word length.                            */
-
-#define DEBUG_BYTES (sizeof (oh) + sizeof (word))
-#undef ROUNDED_UP_WORDS
-#define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
-
-
-#ifdef SAVE_CALL_CHAIN
-#   define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
-#   define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
-#else
-# ifdef GC_ADD_CALLER
-#   define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
-#   define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
-# else
-#   define ADD_CALL_CHAIN(base, ra)
-#   define PRINT_CALL_CHAIN(base)
-# endif
-#endif
-
 /* Check whether object with base pointer p has debugging info */ 
 /* p is assumed to point to a legitimate object in our part    */
 /* of the heap.                                                        */
@@ -80,15 +47,145 @@ ptr_t p;
     return(FALSE);
 }
 
-/* Return start of object that might have debugging info.  */
-ptr_t GC_debug_object_start(p)
-ptr_t p;
-{
-    register word * result = (word *)((oh *)p + 1);
-    if (! GC_has_debug_info(p))
-        return(p);
-    return((ptr_t)result);
-}
+#ifdef KEEP_BACK_PTRS
+  /* Store back pointer to source in dest, if that appears to be possible. */
+  /* This is not completely safe, since we may mistakenly conclude that           */
+  /* dest has a debugging wrapper.  But the error probability is very     */
+  /* small, and this shouldn't be used in production code.                */
+  /* We assume that dest is the real base pointer.  Source will usually    */
+  /* be a pointer to the interior of an object.                                   */
+  void GC_store_back_pointer(ptr_t source, ptr_t dest)
+  {
+    if (GC_has_debug_info(dest)) {
+      ((oh *)dest) -> oh_back_ptr = (ptr_t)HIDE_POINTER(source);
+    }
+  }
+
+  void GC_marked_for_finalization(ptr_t dest) {
+    GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
+  }
+
+  /* Store information about the object referencing dest in *base_p    */
+  /* and *offset_p.                                                    */
+  /*   source is root ==> *base_p = address, *offset_p = 0             */
+  /*   source is heap object ==> *base_p != 0, *offset_p = offset      */
+  /*   Returns 1 on success, 0 if source couldn't be determined.       */
+  /* Dest can be any address within a heap object.                     */
+  GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p)
+  {
+    oh * hdr = (oh *)GC_base(dest);
+    ptr_t bp;
+    ptr_t bp_base;
+    if (!GC_has_debug_info((ptr_t) hdr)) return GC_NO_SPACE;
+    bp = hdr -> oh_back_ptr;
+    if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD;
+    if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG;
+    if (0 == bp) return GC_UNREFERENCED;
+    bp = REVEAL_POINTER(bp);
+    bp_base = GC_base(bp);
+    if (0 == bp_base) {
+      *base_p = bp;
+      *offset_p = 0;
+      return GC_REFD_FROM_ROOT;
+    } else {
+      if (GC_has_debug_info(bp_base)) bp_base += sizeof(oh);
+      *base_p = bp_base;
+      *offset_p = bp - bp_base;
+      return GC_REFD_FROM_HEAP;
+    }
+  }
+
+  /* Generate a random heap address.           */
+  /* The resulting address is in the heap, but */
+  /* not necessarily inside a valid object.    */
+  void *GC_generate_random_heap_address(void)
+  {
+    int i;
+    int heap_offset = random() % GC_heapsize;
+    for (i = 0; i < GC_n_heap_sects; ++ i) {
+       int size = GC_heap_sects[i].hs_bytes;
+       if (heap_offset < size) {
+           return GC_heap_sects[i].hs_start + heap_offset;
+       } else {
+           heap_offset -= size;
+       }
+    }
+    ABORT("GC_generate_random_heap_address: size inconsistency");
+    /*NOTREACHED*/
+    return 0;
+  }
+
+  /* Generate a random address inside a valid marked heap object. */
+  void *GC_generate_random_valid_address(void)
+  {
+    ptr_t result;
+    ptr_t base;
+    for (;;) {
+       result = GC_generate_random_heap_address();
+       base = GC_base(result);
+       if (0 == base) continue;
+       if (!GC_is_marked(base)) continue;
+       return result;
+    }
+  }
+
+  /* Print back trace for p */
+  void GC_print_backtrace(void *p)
+  {
+    void *current = p;
+    int i;
+    GC_ref_kind source;
+    size_t offset;
+    void *base;
+
+    GC_print_heap_obj(GC_base(current));
+    GC_err_printf0("\n");
+    for (i = 0; ; ++i) {
+      source = GC_get_back_ptr_info(current, &base, &offset);
+      if (GC_UNREFERENCED == source) {
+       GC_err_printf0("Reference could not be found\n");
+       goto out;
+      }
+      if (GC_NO_SPACE == source) {
+       GC_err_printf0("No debug info in object: Can't find reference\n");
+       goto out;
+      }
+      GC_err_printf1("Reachable via %d levels of pointers from ",
+                (unsigned long)i);
+      switch(source) {
+       case GC_REFD_FROM_ROOT:
+         GC_err_printf1("root at 0x%lx\n", (unsigned long)base);
+         goto out;
+       case GC_REFD_FROM_REG:
+         GC_err_printf0("root in register\n");
+         goto out;
+       case GC_FINALIZER_REFD:
+         GC_err_printf0("list of finalizable objects\n");
+         goto out;
+       case GC_REFD_FROM_HEAP:
+         GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
+         /* Take GC_base(base) to get real base, i.e. header. */
+         GC_print_heap_obj(GC_base(base));
+         GC_err_printf0("\n");
+         break;
+      }
+      current = base;
+    }
+    out:;
+  }
+
+  /* Force a garbage collection and generate a backtrace from a        */
+  /* random heap address.                                      */
+  void GC_generate_random_backtrace(void)
+  {
+    void * current;
+    GC_gcollect();
+    current = GC_generate_random_valid_address();
+    GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current);
+    GC_print_backtrace(current);
+  }
+    
+#endif /* KEEP_BACK_PTRS */
 
 /* Store debugging info into p.  Return displaced pointer. */
 /* Assumes we don't hold allocation lock.                 */
@@ -105,6 +202,9 @@ word integer;
     /* But that's expensive.  And this way things should only appear   */
     /* inconsistent while we're in the handler.                                */
     LOCK();
+#   ifdef KEEP_BACK_PTRS
+      ((oh *)p) -> oh_back_ptr = 0;
+#   endif
     ((oh *)p) -> oh_string = string;
     ((oh *)p) -> oh_int = integer;
     ((oh *)p) -> oh_sz = sz;
@@ -115,7 +215,7 @@ word integer;
     return((ptr_t)result);
 }
 
-/* Check the object with debugging info at p           */
+/* Check the object with debugging info at ohdr                */
 /* return NIL if it's OK.  Else return clobbered       */
 /* address.                                            */
 ptr_t GC_check_annotated_obj(ohdr)
@@ -144,7 +244,7 @@ ptr_t p;
 {
     register oh * ohdr = (oh *)GC_base(p);
     
-    GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh));
+    GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
     GC_err_puts(ohdr -> oh_string);
     GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
                                      (unsigned long)(ohdr -> oh_sz));
@@ -171,7 +271,7 @@ ptr_t p, clobbered_addr;
     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
         || ohdr -> oh_string == 0) {
         GC_err_printf1("<smashed>, appr. sz = %ld)\n",
-                      GC_size((ptr_t)ohdr) - DEBUG_BYTES);
+                      (GC_size((ptr_t)ohdr) - DEBUG_BYTES));
     } else {
         if (ohdr -> oh_string[0] == '\0') {
             GC_err_puts("EMPTY(smashed?)");
@@ -205,16 +305,8 @@ void GC_start_debugging()
     GC_register_displacement((word)sizeof(oh) + offset);
 }
 
-# ifdef GC_ADD_CALLER
-#   define EXTRA_ARGS word ra, char * s, int i
-#   define OPT_RA ra,
-# else
-#   define EXTRA_ARGS char * s, int i
-#   define OPT_RA
-# endif
-
 # ifdef __STDC__
-    GC_PTR GC_debug_malloc(size_t lb, EXTRA_ARGS)
+    GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
 # else
     GC_PTR GC_debug_malloc(lb, s, i)
     size_t lb;
@@ -242,7 +334,7 @@ void GC_start_debugging()
 }
 
 # ifdef __STDC__
-    GC_PTR GC_debug_generic_malloc(size_t lb, int k, EXTRA_ARGS)
+    GC_PTR GC_debug_generic_malloc(size_t lb, int k, GC_EXTRA_PARAMS)
 # else
     GC_PTR GC_debug_malloc(lb, k, s, i)
     size_t lb;
@@ -272,7 +364,7 @@ void GC_start_debugging()
 
 #ifdef STUBBORN_ALLOC
 # ifdef __STDC__
-    GC_PTR GC_debug_malloc_stubborn(size_t lb, EXTRA_ARGS)
+    GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
 # else
     GC_PTR GC_debug_malloc_stubborn(lb, s, i)
     size_t lb;
@@ -336,10 +428,34 @@ GC_PTR p;
     GC_end_stubborn_change(q);
 }
 
-#endif /* STUBBORN_ALLOC */
+#else /* !STUBBORN_ALLOC */
 
 # ifdef __STDC__
-    GC_PTR GC_debug_malloc_atomic(size_t lb, EXTRA_ARGS)
+    GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
+# else
+    GC_PTR GC_debug_malloc_stubborn(lb, s, i)
+    size_t lb;
+    char * s;
+    int i;
+# endif
+{
+    return GC_debug_malloc(lb, OPT_RA s, i);
+}
+
+void GC_debug_change_stubborn(p)
+GC_PTR p;
+{
+}
+
+void GC_debug_end_stubborn_change(p)
+GC_PTR p;
+{
+}
+
+#endif /* !STUBBORN_ALLOC */
+
+# ifdef __STDC__
+    GC_PTR GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
 # else
     GC_PTR GC_debug_malloc_atomic(lb, s, i)
     size_t lb;
@@ -364,7 +480,7 @@ GC_PTR p;
 }
 
 # ifdef __STDC__
-    GC_PTR GC_debug_malloc_uncollectable(size_t lb, EXTRA_ARGS)
+    GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
 # else
     GC_PTR GC_debug_malloc_uncollectable(lb, s, i)
     size_t lb;
@@ -390,7 +506,7 @@ GC_PTR p;
 
 #ifdef ATOMIC_UNCOLLECTABLE
 # ifdef __STDC__
-    GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, EXTRA_ARGS)
+    GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
 # else
     GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i)
     size_t lb;
@@ -423,13 +539,15 @@ GC_PTR p;
     GC_PTR p;
 # endif
 {
-    register GC_PTR base = GC_base(p);
+    register GC_PTR base;
     register ptr_t clobbered;
     
+    if (0 == p) return;
+    base = GC_base(p);
     if (base == 0) {
         GC_err_printf1("Attempt to free invalid pointer %lx\n",
                       (unsigned long)p);
-        if (p != 0) ABORT("free(invalid pointer)");
+        ABORT("free(invalid pointer)");
     }
     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
         GC_err_printf1(
@@ -442,35 +560,33 @@ GC_PTR p;
             GC_err_printf0(
                   "GC_debug_free: found previously deallocated (?) object at ");
         } else {
-            GC_err_printf0("GC_debug_free: found smashed object at ");
+            GC_err_printf0("GC_debug_free: found smashed location at ");
         }
         GC_print_smashed_obj(p, clobbered);
       }
       /* Invalidate size */
       ((oh *)base) -> oh_sz = GC_size(base);
     }
-#   ifdef FIND_LEAK
+    if (GC_find_leak) {
         GC_free(base);
-#   else
-       {
-           register hdr * hhdr = HDR(p);
-           GC_bool uncollectable = FALSE;
+    } else {
+       register hdr * hhdr = HDR(p);
+       GC_bool uncollectable = FALSE;
 
-           if (hhdr ->  hb_obj_kind == UNCOLLECTABLE) {
-               uncollectable = TRUE;
-           }
-#          ifdef ATOMIC_UNCOLLECTABLE
-               if (hhdr ->  hb_obj_kind == AUNCOLLECTABLE) {
-                   uncollectable = TRUE;
-               }
-#          endif
-           if (uncollectable) GC_free(base);
+        if (hhdr ->  hb_obj_kind == UNCOLLECTABLE) {
+           uncollectable = TRUE;
        }
-#   endif
+#      ifdef ATOMIC_UNCOLLECTABLE
+           if (hhdr ->  hb_obj_kind == AUNCOLLECTABLE) {
+                   uncollectable = TRUE;
+           }
+#      endif
+       if (uncollectable) GC_free(base);
+    } /* !GC_find_leak */
 }
 
 # ifdef __STDC__
-    GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, EXTRA_ARGS)
+    GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, GC_EXTRA_PARAMS)
 # else
     GC_PTR GC_debug_realloc(p, lb, s, i)
     GC_PTR p;
@@ -525,7 +641,7 @@ GC_PTR p;
     }
     clobbered = GC_check_annotated_obj((oh *)base);
     if (clobbered != 0) {
-        GC_err_printf0("GC_debug_realloc: found smashed object at ");
+        GC_err_printf0("GC_debug_realloc: found smashed location at ");
         GC_print_smashed_obj(p, clobbered);
     }
     old_sz = ((oh *)base) -> oh_sz;
@@ -562,7 +678,7 @@ word dummy;
                
                if (clobbered != 0) {
                    GC_err_printf0(
-                       "GC_check_heap_block: found smashed object at ");
+                       "GC_check_heap_block: found smashed location at ");
                    GC_print_smashed_obj((ptr_t)p, clobbered);
                }
            }
@@ -643,12 +759,12 @@ struct closure {
 }
 
 # ifdef __STDC__
-    void GC_debug_register_finalizer_ignore_self
+    void GC_debug_register_finalizer_no_order
                                    (GC_PTR obj, GC_finalization_proc fn,
                                     GC_PTR cd, GC_finalization_proc *ofn,
                                     GC_PTR *ocd)
 # else
-    void GC_debug_register_finalizer_ignore_self
+    void GC_debug_register_finalizer_no_order
                                    (obj, fn, cd, ofn, ocd)
     GC_PTR obj;
     GC_finalization_proc fn;
@@ -660,20 +776,20 @@ struct closure {
     ptr_t base = GC_base(obj);
     if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
         GC_err_printf1(
-           "GC_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
-           obj);
+         "GC_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
+         obj);
     }
-    GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
-                                     GC_make_closure(fn,cd), ofn, ocd);
-}
+    GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
+                                     GC_make_closure(fn,cd), ofn, ocd);
+ }
 
 # ifdef __STDC__
-    void GC_debug_register_finalizer_no_order
+    void GC_debug_register_finalizer_ignore_self
                                    (GC_PTR obj, GC_finalization_proc fn,
                                     GC_PTR cd, GC_finalization_proc *ofn,
                                     GC_PTR *ocd)
 # else
-    void GC_debug_register_finalizer_no_order
+    void GC_debug_register_finalizer_ignore_self
                                    (obj, fn, cd, ofn, ocd)
     GC_PTR obj;
     GC_finalization_proc fn;
@@ -685,9 +801,9 @@ struct closure {
     ptr_t base = GC_base(obj);
     if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
         GC_err_printf1(
-           "GC_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
+           "GC_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
            obj);
     }
-    GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
+    GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
                                      GC_make_closure(fn,cd), ofn, ocd);
 }