Back to index

plt-scheme  4.2.1
dbg_mlc.c
Go to the documentation of this file.
00001 /* 
00002  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00003  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
00004  * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
00005  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
00006  *
00007  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00008  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00009  *
00010  * Permission is hereby granted to use or copy this program
00011  * for any purpose,  provided the above notices are retained on all copies.
00012  * Permission to modify the code and to distribute modified code is granted,
00013  * provided the above notices are retained, and a notice that the code was
00014  * modified is included with the above copyright notice.
00015  */
00016 
00017 #include <errno.h>
00018 #include <string.h>
00019 #include "private/dbg_mlc.h"
00020 
00021 void GC_default_print_heap_obj_proc();
00022 GC_API void GC_register_finalizer_no_order
00023        GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
00024                 GC_finalization_proc *ofn, GC_PTR *ocd));
00025 
00026 
00027 #ifndef SHORT_DBG_HDRS
00028 /* Check whether object with base pointer p has debugging info */ 
00029 /* p is assumed to point to a legitimate object in our part    */
00030 /* of the heap.                                                */
00031 /* This excludes the check as to whether the back pointer is   */
00032 /* odd, which is added by the GC_HAS_DEBUG_INFO macro.         */
00033 /* Note that if DBG_HDRS_ALL is set, uncollectable objects     */
00034 /* on free lists may not have debug information set.  Thus it's       */
00035 /* not always safe to return TRUE, even if the client does     */
00036 /* its part.                                            */
00037 GC_bool GC_has_other_debug_info(p)
00038 ptr_t p;
00039 {
00040     register oh * ohdr = (oh *)p;
00041     register ptr_t body = (ptr_t)(ohdr + 1);
00042     register word sz = GC_size((ptr_t) ohdr);
00043     
00044     if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
00045         || sz < DEBUG_BYTES + EXTRA_BYTES) {
00046         return(FALSE);
00047     }
00048     if (ohdr -> oh_sz == sz) {
00049        /* Object may have had debug info, but has been deallocated    */
00050        return(FALSE);
00051     }
00052     if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
00053     if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
00054         return(TRUE);
00055     }
00056     return(FALSE);
00057 }
00058 #endif
00059 
00060 #ifdef KEEP_BACK_PTRS
00061 
00062 # include <stdlib.h>
00063 
00064 # if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
00065      || defined(HPUX) || defined(IRIX5) || defined(OSF1)
00066 #   define RANDOM() random()
00067 # else
00068 #   define RANDOM() (long)rand()
00069 # endif
00070 
00071   /* Store back pointer to source in dest, if that appears to be possible. */
00072   /* This is not completely safe, since we may mistakenly conclude that         */
00073   /* dest has a debugging wrapper.  But the error probability is very    */
00074   /* small, and this shouldn't be used in production code.               */
00075   /* We assume that dest is the real base pointer.  Source will usually    */
00076   /* be a pointer to the interior of an object.                          */
00077   void GC_store_back_pointer(ptr_t source, ptr_t dest)
00078   {
00079     if (GC_HAS_DEBUG_INFO(dest)) {
00080       ((oh *)dest) -> oh_back_ptr = HIDE_BACK_PTR(source);
00081     }
00082   }
00083 
00084   void GC_marked_for_finalization(ptr_t dest) {
00085     GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
00086   }
00087 
00088   /* Store information about the object referencing dest in *base_p   */
00089   /* and *offset_p.                                            */
00090   /*   source is root ==> *base_p = address, *offset_p = 0            */
00091   /*   source is heap object ==> *base_p != 0, *offset_p = offset     */
00092   /*   Returns 1 on success, 0 if source couldn't be determined.      */
00093   /* Dest can be any address within a heap object.                    */
00094   GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p)
00095   {
00096     oh * hdr = (oh *)GC_base(dest);
00097     ptr_t bp;
00098     ptr_t bp_base;
00099     if (!GC_HAS_DEBUG_INFO((ptr_t) hdr)) return GC_NO_SPACE;
00100     bp = REVEAL_POINTER(hdr -> oh_back_ptr);
00101     if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD;
00102     if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG;
00103     if (NOT_MARKED == bp) return GC_UNREFERENCED;
00104 #   if ALIGNMENT == 1
00105       /* Heuristically try to fix off by 1 errors we introduced by    */
00106       /* insisting on even addresses.                                 */
00107       {
00108        ptr_t alternate_ptr = bp + 1;
00109        ptr_t target = *(ptr_t *)bp;
00110        ptr_t alternate_target = *(ptr_t *)alternate_ptr;
00111 
00112        if (alternate_target >= GC_least_plausible_heap_addr
00113            && alternate_target <= GC_greatest_plausible_heap_addr
00114            && (target < GC_least_plausible_heap_addr
00115               || target > GC_greatest_plausible_heap_addr)) {
00116            bp = alternate_ptr;
00117        }
00118       }
00119 #   endif
00120     bp_base = GC_base(bp);
00121     if (0 == bp_base) {
00122       *base_p = bp;
00123       *offset_p = 0;
00124       return GC_REFD_FROM_ROOT;
00125     } else {
00126       if (GC_HAS_DEBUG_INFO(bp_base)) bp_base += sizeof(oh);
00127       *base_p = bp_base;
00128       *offset_p = bp - bp_base;
00129       return GC_REFD_FROM_HEAP;
00130     }
00131   }
00132 
00133   /* Generate a random heap address.             */
00134   /* The resulting address is in the heap, but   */
00135   /* not necessarily inside a valid object.      */
00136   void *GC_generate_random_heap_address(void)
00137   {
00138     int i;
00139     long heap_offset = RANDOM();
00140     if (GC_heapsize > RAND_MAX) {
00141        heap_offset *= RAND_MAX;
00142        heap_offset += RANDOM();
00143     }
00144     heap_offset %= GC_heapsize;
00145        /* This doesn't yield a uniform distribution, especially if    */
00146         /* e.g. RAND_MAX = 1.5* GC_heapsize.  But for typical cases,  */
00147         /* it's not too bad.                                          */
00148     for (i = 0; i < GC_n_heap_sects; ++ i) {
00149        int size = GC_heap_sects[i].hs_bytes;
00150        if (heap_offset < size) {
00151            return GC_heap_sects[i].hs_start + heap_offset;
00152        } else {
00153            heap_offset -= size;
00154        }
00155     }
00156     ABORT("GC_generate_random_heap_address: size inconsistency");
00157     /*NOTREACHED*/
00158     return 0;
00159   }
00160 
00161   /* Generate a random address inside a valid marked heap object. */
00162   void *GC_generate_random_valid_address(void)
00163   {
00164     ptr_t result;
00165     ptr_t base;
00166     for (;;) {
00167        result = GC_generate_random_heap_address();
00168        base = GC_base(result);
00169        if (0 == base) continue;
00170        if (!GC_is_marked(base)) continue;
00171        return result;
00172     }
00173   }
00174 
00175   /* Print back trace for p */
00176   void GC_print_backtrace(void *p)
00177   {
00178     void *current = p;
00179     int i;
00180     GC_ref_kind source;
00181     size_t offset;
00182     void *base;
00183 
00184     GC_print_heap_obj(GC_base(current));
00185     GC_err_printf0("\n");
00186     for (i = 0; ; ++i) {
00187       source = GC_get_back_ptr_info(current, &base, &offset);
00188       if (GC_UNREFERENCED == source) {
00189        GC_err_printf0("Reference could not be found\n");
00190        goto out;
00191       }
00192       if (GC_NO_SPACE == source) {
00193        GC_err_printf0("No debug info in object: Can't find reference\n");
00194        goto out;
00195       }
00196       GC_err_printf1("Reachable via %d levels of pointers from ",
00197                (unsigned long)i);
00198       switch(source) {
00199        case GC_REFD_FROM_ROOT:
00200          GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base);
00201          goto out;
00202        case GC_REFD_FROM_REG:
00203          GC_err_printf0("root in register\n\n");
00204          goto out;
00205        case GC_FINALIZER_REFD:
00206          GC_err_printf0("list of finalizable objects\n\n");
00207          goto out;
00208        case GC_REFD_FROM_HEAP:
00209          GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
00210          /* Take GC_base(base) to get real base, i.e. header. */
00211          GC_print_heap_obj(GC_base(base));
00212          GC_err_printf0("\n");
00213          break;
00214       }
00215       current = base;
00216     }
00217     out:;
00218   }
00219 
00220   /* Force a garbage collection and generate a backtrace from a       */
00221   /* random heap address.                               */
00222   void GC_generate_random_backtrace_no_gc(void)
00223   {
00224     void * current;
00225     current = GC_generate_random_valid_address();
00226     GC_printf1("\n****Chose address 0x%lx in object\n", (unsigned long)current);
00227     GC_print_backtrace(current);
00228   }
00229     
00230   void GC_generate_random_backtrace(void)
00231   {
00232     GC_gcollect();
00233     GC_generate_random_backtrace_no_gc();
00234   }
00235     
00236 #endif /* KEEP_BACK_PTRS */
00237 
00238 # define CROSSES_HBLK(p, sz) \
00239        (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
00240 /* Store debugging info into p.  Return displaced pointer. */
00241 /* Assumes we don't hold allocation lock.           */
00242 ptr_t GC_store_debug_info(p, sz, string, integer)
00243 register ptr_t p;    /* base pointer */
00244 word sz;      /* bytes */
00245 GC_CONST char * string;
00246 word integer;
00247 {
00248     register word * result = (word *)((oh *)p + 1);
00249     DCL_LOCK_STATE;
00250     
00251     /* There is some argument that we should dissble signals here.    */
00252     /* But that's expensive.  And this way things should only appear  */
00253     /* inconsistent while we're in the handler.                       */
00254     LOCK();
00255     GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
00256     GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
00257 #   ifdef KEEP_BACK_PTRS
00258       ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
00259 #   endif
00260 #   ifdef MAKE_BACK_GRAPH
00261       ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
00262 #   endif
00263     ((oh *)p) -> oh_string = string;
00264     ((oh *)p) -> oh_int = integer;
00265 #   ifndef SHORT_DBG_HDRS
00266       ((oh *)p) -> oh_sz = sz;
00267       ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
00268       ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
00269          result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
00270 #   endif
00271     UNLOCK();
00272     return((ptr_t)result);
00273 }
00274 
00275 #ifdef DBG_HDRS_ALL
00276 /* Store debugging info into p.  Return displaced pointer.        */
00277 /* This version assumes we do hold the allocation lock.           */
00278 ptr_t GC_store_debug_info_inner(p, sz, string, integer)
00279 register ptr_t p;    /* base pointer */
00280 word sz;      /* bytes */
00281 char * string;
00282 word integer;
00283 {
00284     register word * result = (word *)((oh *)p + 1);
00285     
00286     /* There is some argument that we should disable signals here.    */
00287     /* But that's expensive.  And this way things should only appear  */
00288     /* inconsistent while we're in the handler.                       */
00289     GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
00290     GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
00291 #   ifdef KEEP_BACK_PTRS
00292       ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
00293 #   endif
00294 #   ifdef MAKE_BACK_GRAPH
00295       ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
00296 #   endif
00297     ((oh *)p) -> oh_string = string;
00298     ((oh *)p) -> oh_int = integer;
00299 #   ifndef SHORT_DBG_HDRS
00300       ((oh *)p) -> oh_sz = sz;
00301       ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
00302       ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
00303          result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
00304 #   endif
00305     return((ptr_t)result);
00306 }
00307 #endif
00308 
00309 #ifndef SHORT_DBG_HDRS
00310 /* Check the object with debugging info at ohdr         */
00311 /* return NIL if it's OK.  Else return clobbered */
00312 /* address.                                      */
00313 ptr_t GC_check_annotated_obj(ohdr)
00314 register oh * ohdr;
00315 {
00316     register ptr_t body = (ptr_t)(ohdr + 1);
00317     register word gc_sz = GC_size((ptr_t)ohdr);
00318     if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
00319         return((ptr_t)(&(ohdr -> oh_sz)));
00320     }
00321     if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
00322         return((ptr_t)(&(ohdr -> oh_sf)));
00323     }
00324     if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
00325         return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1));
00326     }
00327     if (((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)]
00328         != (END_FLAG ^ (word)body)) {
00329         return((ptr_t)((word *)body + SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)));
00330     }
00331     return(0);
00332 }
00333 #endif /* !SHORT_DBG_HDRS */
00334 
00335 static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
00336 
00337 void GC_register_describe_type_fn(kind, fn)
00338 int kind;
00339 GC_describe_type_fn fn;
00340 {
00341   GC_describe_type_fns[kind] = fn;
00342 }
00343 
00344 /* Print a type description for the object whose client-visible address      */
00345 /* is p.                                                       */
00346 void GC_print_type(p)
00347 ptr_t p;
00348 {
00349     hdr * hhdr = GC_find_header(p);
00350     char buffer[GC_TYPE_DESCR_LEN + 1];
00351     int kind = hhdr -> hb_obj_kind;
00352 
00353     if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
00354        /* This should preclude free list objects except with   */
00355        /* thread-local allocation.                      */
00356        buffer[GC_TYPE_DESCR_LEN] = 0;
00357        (GC_describe_type_fns[kind])(p, buffer);
00358        GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
00359        GC_err_puts(buffer);
00360     } else {
00361        switch(kind) {
00362          case PTRFREE:
00363            GC_err_puts("PTRFREE");
00364            break;
00365          case NORMAL:
00366            GC_err_puts("NORMAL");
00367            break;
00368          case UNCOLLECTABLE:
00369            GC_err_puts("UNCOLLECTABLE");
00370            break;
00371 #        ifdef ATOMIC_UNCOLLECTABLE
00372            case AUNCOLLECTABLE:
00373              GC_err_puts("ATOMIC UNCOLLECTABLE");
00374              break;
00375 #        endif
00376          case STUBBORN:
00377            GC_err_puts("STUBBORN");
00378            break;
00379          default:
00380            GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr);
00381        }
00382     }
00383 }
00384 
00385     
00386 
00387 void GC_print_obj(p)
00388 ptr_t p;
00389 {
00390     register oh * ohdr = (oh *)GC_base(p);
00391     
00392     GC_ASSERT(!I_HOLD_LOCK());
00393     GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
00394     GC_err_puts(ohdr -> oh_string);
00395 #   ifdef SHORT_DBG_HDRS
00396       GC_err_printf1(":%ld, ", (unsigned long)(ohdr -> oh_int));
00397 #   else
00398       GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
00399                                     (unsigned long)(ohdr -> oh_sz));
00400 #   endif
00401     GC_print_type((ptr_t)(ohdr + 1));
00402     GC_err_puts(")\n");
00403     PRINT_CALL_CHAIN(ohdr);
00404 }
00405 
00406 # if defined(__STDC__) || defined(__cplusplus)
00407     void GC_debug_print_heap_obj_proc(ptr_t p)
00408 # else
00409     void GC_debug_print_heap_obj_proc(p)
00410     ptr_t p;
00411 # endif
00412 {
00413     GC_ASSERT(!I_HOLD_LOCK());
00414     if (GC_HAS_DEBUG_INFO(p)) {
00415        GC_print_obj(p);
00416     } else {
00417        GC_default_print_heap_obj_proc(p);
00418     }
00419 }
00420 
00421 #ifndef SHORT_DBG_HDRS
00422 void GC_print_smashed_obj(p, clobbered_addr)
00423 ptr_t p, clobbered_addr;
00424 {
00425     register oh * ohdr = (oh *)GC_base(p);
00426     
00427     GC_ASSERT(!I_HOLD_LOCK());
00428     GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
00429                                            (unsigned long)p);
00430     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
00431         || ohdr -> oh_string == 0) {
00432         GC_err_printf1("<smashed>, appr. sz = %ld)\n",
00433                      (GC_size((ptr_t)ohdr) - DEBUG_BYTES));
00434     } else {
00435         if (ohdr -> oh_string[0] == '\0') {
00436             GC_err_puts("EMPTY(smashed?)");
00437         } else {
00438             GC_err_puts(ohdr -> oh_string);
00439         }
00440         GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
00441                                       (unsigned long)(ohdr -> oh_sz));
00442         PRINT_CALL_CHAIN(ohdr);
00443     }
00444 }
00445 #endif
00446 
00447 void GC_check_heap_proc GC_PROTO((void));
00448 
00449 void GC_print_all_smashed_proc GC_PROTO((void));
00450 
00451 void GC_do_nothing() {}
00452 
00453 void GC_start_debugging()
00454 {
00455 #   ifndef SHORT_DBG_HDRS
00456       GC_check_heap = GC_check_heap_proc;
00457       GC_print_all_smashed = GC_print_all_smashed_proc;
00458 #   else
00459       GC_check_heap = GC_do_nothing;
00460       GC_print_all_smashed = GC_do_nothing;
00461 #   endif
00462     GC_print_heap_obj = GC_debug_print_heap_obj_proc;
00463     GC_debugging_started = TRUE;
00464     GC_register_displacement((word)sizeof(oh));
00465 }
00466 
00467 size_t GC_debug_header_size = sizeof(oh);
00468 
00469 # if defined(__STDC__) || defined(__cplusplus)
00470     void GC_debug_register_displacement(GC_word offset)
00471 # else
00472     void GC_debug_register_displacement(offset) 
00473     GC_word offset;
00474 # endif
00475 {
00476     GC_register_displacement(offset);
00477     GC_register_displacement((word)sizeof(oh) + offset);
00478 }
00479 
00480 # ifdef __STDC__
00481     GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
00482 # else
00483     GC_PTR GC_debug_malloc(lb, s, i)
00484     size_t lb;
00485     char * s;
00486     int i;
00487 #   ifdef GC_ADD_CALLER
00488        --> GC_ADD_CALLER not implemented for K&R C
00489 #   endif
00490 # endif
00491 {
00492     GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
00493     
00494     if (result == 0) {
00495         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
00496                      (unsigned long) lb);
00497         GC_err_puts(s);
00498         GC_err_printf1(":%ld)\n", (unsigned long)i);
00499         return(0);
00500     }
00501     if (!GC_debugging_started) {
00502        GC_start_debugging();
00503     }
00504     ADD_CALL_CHAIN(result, ra);
00505     return (GC_store_debug_info(result, (word)lb, s, (word)i));
00506 }
00507 
00508 # ifdef __STDC__
00509     GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
00510 # else
00511     GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
00512     size_t lb;
00513     char * s;
00514     int i;
00515 #   ifdef GC_ADD_CALLER
00516        --> GC_ADD_CALLER not implemented for K&R C
00517 #   endif
00518 # endif
00519 {
00520     GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
00521     
00522     if (result == 0) {
00523         GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
00524                      (unsigned long) lb);
00525         GC_err_puts(s);
00526         GC_err_printf1(":%ld)\n", (unsigned long)i);
00527         return(0);
00528     }
00529     if (!GC_debugging_started) {
00530        GC_start_debugging();
00531     }
00532     ADD_CALL_CHAIN(result, ra);
00533     return (GC_store_debug_info(result, (word)lb, s, (word)i));
00534 }
00535 
00536 # ifdef __STDC__
00537     GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
00538 # else
00539     GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
00540     size_t lb;
00541     char * s;
00542     int i;
00543 #   ifdef GC_ADD_CALLER
00544        --> GC_ADD_CALLER not implemented for K&R C
00545 #   endif
00546 # endif
00547 {
00548     GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
00549     
00550     if (result == 0) {
00551         GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
00552                      " returning NIL (", (unsigned long) lb);
00553         GC_err_puts(s);
00554         GC_err_printf1(":%ld)\n", (unsigned long)i);
00555         return(0);
00556     }
00557     if (!GC_debugging_started) {
00558        GC_start_debugging();
00559     }
00560     ADD_CALL_CHAIN(result, ra);
00561     return (GC_store_debug_info(result, (word)lb, s, (word)i));
00562 }
00563 
00564 # ifdef DBG_HDRS_ALL
00565 /* 
00566  * An allocation function for internal use.
00567  * Normally internally allocated objects do not have debug information.
00568  * But in this case, we need to make sure that all objects have debug
00569  * headers.
00570  * We assume debugging was started in collector initialization,
00571  * and we already hold the GC lock.
00572  */
00573   GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k)
00574   {
00575     GC_PTR result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
00576     
00577     if (result == 0) {
00578         GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
00579                      (unsigned long) lb);
00580         return(0);
00581     }
00582     ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
00583     return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
00584   }
00585 
00586   GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, int k)
00587   {
00588     GC_PTR result = GC_generic_malloc_inner_ignore_off_page(
00589                                            lb + DEBUG_BYTES, k);
00590     
00591     if (result == 0) {
00592         GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
00593                      (unsigned long) lb);
00594         return(0);
00595     }
00596     ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
00597     return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
00598   }
00599 # endif
00600 
00601 #ifdef STUBBORN_ALLOC
00602 # ifdef __STDC__
00603     GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
00604 # else
00605     GC_PTR GC_debug_malloc_stubborn(lb, s, i)
00606     size_t lb;
00607     char * s;
00608     int i;
00609 # endif
00610 {
00611     GC_PTR result = GC_malloc_stubborn(lb + DEBUG_BYTES);
00612     
00613     if (result == 0) {
00614         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
00615                      (unsigned long) lb);
00616         GC_err_puts(s);
00617         GC_err_printf1(":%ld)\n", (unsigned long)i);
00618         return(0);
00619     }
00620     if (!GC_debugging_started) {
00621        GC_start_debugging();
00622     }
00623     ADD_CALL_CHAIN(result, ra);
00624     return (GC_store_debug_info(result, (word)lb, s, (word)i));
00625 }
00626 
00627 void GC_debug_change_stubborn(p)
00628 GC_PTR p;
00629 {
00630     register GC_PTR q = GC_base(p);
00631     register hdr * hhdr;
00632     
00633     if (q == 0) {
00634         GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
00635                      (unsigned long) p);
00636         ABORT("GC_debug_change_stubborn: bad arg");
00637     }
00638     hhdr = HDR(q);
00639     if (hhdr -> hb_obj_kind != STUBBORN) {
00640         GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
00641                      (unsigned long) p);
00642         ABORT("GC_debug_change_stubborn: arg not stubborn");
00643     }
00644     GC_change_stubborn(q);
00645 }
00646 
00647 void GC_debug_end_stubborn_change(p)
00648 GC_PTR p;
00649 {
00650     register GC_PTR q = GC_base(p);
00651     register hdr * hhdr;
00652     
00653     if (q == 0) {
00654         GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
00655                      (unsigned long) p);
00656         ABORT("GC_debug_end_stubborn_change: bad arg");
00657     }
00658     hhdr = HDR(q);
00659     if (hhdr -> hb_obj_kind != STUBBORN) {
00660         GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
00661                      (unsigned long) p);
00662         ABORT("GC_debug_end_stubborn_change: arg not stubborn");
00663     }
00664     GC_end_stubborn_change(q);
00665 }
00666 
00667 #else /* !STUBBORN_ALLOC */
00668 
00669 # ifdef __STDC__
00670     GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
00671 # else
00672     GC_PTR GC_debug_malloc_stubborn(lb, s, i)
00673     size_t lb;
00674     char * s;
00675     int i;
00676 # endif
00677 {
00678     return GC_debug_malloc(lb, OPT_RA s, i);
00679 }
00680 
00681 void GC_debug_change_stubborn(p)
00682 GC_PTR p;
00683 {
00684 }
00685 
00686 void GC_debug_end_stubborn_change(p)
00687 GC_PTR p;
00688 {
00689 }
00690 
00691 #endif /* !STUBBORN_ALLOC */
00692 
00693 # ifdef __STDC__
00694     GC_PTR GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
00695 # else
00696     GC_PTR GC_debug_malloc_atomic(lb, s, i)
00697     size_t lb;
00698     char * s;
00699     int i;
00700 # endif
00701 {
00702     GC_PTR result = GC_malloc_atomic(lb + DEBUG_BYTES);
00703     
00704     if (result == 0) {
00705         GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
00706                     (unsigned long) lb);
00707         GC_err_puts(s);
00708         GC_err_printf1(":%ld)\n", (unsigned long)i);
00709         return(0);
00710     }
00711     if (!GC_debugging_started) {
00712         GC_start_debugging();
00713     }
00714     ADD_CALL_CHAIN(result, ra);
00715     return (GC_store_debug_info(result, (word)lb, s, (word)i));
00716 }
00717 
00718 # ifdef __STDC__
00719     char *GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
00720 #else
00721     char *GC_debug_strdup(str, s, i)
00722     char *str;
00723     char *s;
00724     int i;
00725 #endif
00726 {
00727     char *copy;
00728     if (str == NULL) return NULL;
00729     copy = GC_debug_malloc_atomic(strlen(str) + 1, OPT_RA s, i);
00730     if (copy == NULL) {
00731       errno = ENOMEM;
00732       return NULL;
00733     }
00734     strcpy(copy, str);
00735     return copy;
00736 }
00737 
00738 # ifdef __STDC__
00739     GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
00740 # else
00741     GC_PTR GC_debug_malloc_uncollectable(lb, s, i)
00742     size_t lb;
00743     char * s;
00744     int i;
00745 # endif
00746 {
00747     GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
00748     
00749     if (result == 0) {
00750         GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
00751                     (unsigned long) lb);
00752         GC_err_puts(s);
00753         GC_err_printf1(":%ld)\n", (unsigned long)i);
00754         return(0);
00755     }
00756     if (!GC_debugging_started) {
00757         GC_start_debugging();
00758     }
00759     ADD_CALL_CHAIN(result, ra);
00760     return (GC_store_debug_info(result, (word)lb, s, (word)i));
00761 }
00762 
00763 #ifdef ATOMIC_UNCOLLECTABLE
00764 # ifdef __STDC__
00765     GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
00766 # else
00767     GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i)
00768     size_t lb;
00769     char * s;
00770     int i;
00771 # endif
00772 {
00773     GC_PTR result =
00774        GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
00775     
00776     if (result == 0) {
00777         GC_err_printf1(
00778               "GC_debug_malloc_atomic_uncollectable(%ld) returning NIL (",
00779                 (unsigned long) lb);
00780         GC_err_puts(s);
00781         GC_err_printf1(":%ld)\n", (unsigned long)i);
00782         return(0);
00783     }
00784     if (!GC_debugging_started) {
00785         GC_start_debugging();
00786     }
00787     ADD_CALL_CHAIN(result, ra);
00788     return (GC_store_debug_info(result, (word)lb, s, (word)i));
00789 }
00790 #endif /* ATOMIC_UNCOLLECTABLE */
00791 
00792 # ifdef __STDC__
00793     void GC_debug_free(GC_PTR p)
00794 # else
00795     void GC_debug_free(p)
00796     GC_PTR p;
00797 # endif
00798 {
00799     register GC_PTR base;
00800     register ptr_t clobbered;
00801     
00802     if (0 == p) return;
00803     base = GC_base(p);
00804     if (base == 0) {
00805         GC_err_printf1("Attempt to free invalid pointer %lx\n",
00806                      (unsigned long)p);
00807         ABORT("free(invalid pointer)");
00808     }
00809     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
00810         GC_err_printf1(
00811                 "GC_debug_free called on pointer %lx wo debugging info\n",
00812                 (unsigned long)p);
00813     } else {
00814 #     ifndef SHORT_DBG_HDRS
00815         clobbered = GC_check_annotated_obj((oh *)base);
00816         if (clobbered != 0) {
00817           if (((oh *)base) -> oh_sz == GC_size(base)) {
00818             GC_err_printf0(
00819                   "GC_debug_free: found previously deallocated (?) object at ");
00820           } else {
00821             GC_err_printf0("GC_debug_free: found smashed location at ");
00822           }
00823           GC_print_smashed_obj(p, clobbered);
00824         }
00825         /* Invalidate size */
00826         ((oh *)base) -> oh_sz = GC_size(base);
00827 #     endif /* SHORT_DBG_HDRS */
00828     }
00829     if (GC_find_leak) {
00830         GC_free(base);
00831     } else {
00832        register hdr * hhdr = HDR(p);
00833        GC_bool uncollectable = FALSE;
00834 
00835         if (hhdr ->  hb_obj_kind == UNCOLLECTABLE) {
00836            uncollectable = TRUE;
00837        }
00838 #      ifdef ATOMIC_UNCOLLECTABLE
00839            if (hhdr ->  hb_obj_kind == AUNCOLLECTABLE) {
00840                   uncollectable = TRUE;
00841            }
00842 #      endif
00843        if (uncollectable) {
00844            GC_free(base);
00845        } else {
00846            size_t i;
00847            size_t obj_sz = hhdr -> hb_sz - BYTES_TO_WORDS(sizeof(oh));
00848 
00849            for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef;
00850            GC_ASSERT((word *)p + i == (word *)base + hhdr -> hb_sz);
00851        }
00852     } /* !GC_find_leak */
00853 }
00854 
00855 #ifdef THREADS
00856 
00857 extern void GC_free_inner(GC_PTR p);
00858 
00859 /* Used internally; we assume it's called correctly.    */
00860 void GC_debug_free_inner(GC_PTR p)
00861 {
00862     GC_free_inner(GC_base(p));
00863 }
00864 #endif
00865 
00866 # ifdef __STDC__
00867     GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, GC_EXTRA_PARAMS)
00868 # else
00869     GC_PTR GC_debug_realloc(p, lb, s, i)
00870     GC_PTR p;
00871     size_t lb;
00872     char *s;
00873     int i;
00874 # endif
00875 {
00876     register GC_PTR base = GC_base(p);
00877     register ptr_t clobbered;
00878     register GC_PTR result;
00879     register size_t copy_sz = lb;
00880     register size_t old_sz;
00881     register hdr * hhdr;
00882     
00883     if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i));
00884     if (base == 0) {
00885         GC_err_printf1(
00886               "Attempt to reallocate invalid pointer %lx\n", (unsigned long)p);
00887         ABORT("realloc(invalid pointer)");
00888     }
00889     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
00890         GC_err_printf1(
00891               "GC_debug_realloc called on pointer %lx wo debugging info\n",
00892               (unsigned long)p);
00893         return(GC_realloc(p, lb));
00894     }
00895     hhdr = HDR(base);
00896     switch (hhdr -> hb_obj_kind) {
00897 #    ifdef STUBBORN_ALLOC
00898       case STUBBORN:
00899         result = GC_debug_malloc_stubborn(lb, OPT_RA s, i);
00900         break;
00901 #    endif
00902       case NORMAL:
00903         result = GC_debug_malloc(lb, OPT_RA s, i);
00904         break;
00905       case PTRFREE:
00906         result = GC_debug_malloc_atomic(lb, OPT_RA s, i);
00907         break;
00908       case UNCOLLECTABLE:
00909        result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
00910        break;
00911 #    ifdef ATOMIC_UNCOLLECTABLE
00912       case AUNCOLLECTABLE:
00913        result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
00914        break;
00915 #    endif
00916       default:
00917         GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
00918         ABORT("bad kind");
00919     }
00920 #   ifdef SHORT_DBG_HDRS
00921       old_sz = GC_size(base) - sizeof(oh);
00922 #   else
00923       clobbered = GC_check_annotated_obj((oh *)base);
00924       if (clobbered != 0) {
00925         GC_err_printf0("GC_debug_realloc: found smashed location at ");
00926         GC_print_smashed_obj(p, clobbered);
00927       }
00928       old_sz = ((oh *)base) -> oh_sz;
00929 #   endif
00930     if (old_sz < copy_sz) copy_sz = old_sz;
00931     if (result == 0) return(0);
00932     BCOPY(p, result,  copy_sz);
00933     GC_debug_free(p);
00934     return(result);
00935 }
00936 
00937 #ifndef SHORT_DBG_HDRS
00938 
00939 /* List of smashed objects.  We defer printing these, since we can't  */
00940 /* always print them nicely with the allocation lock held.            */
00941 /* We put them here instead of in GC_arrays, since it may be useful to       */
00942 /* be able to look at them with the debugger.                         */
00943 #define MAX_SMASHED 20
00944 ptr_t GC_smashed[MAX_SMASHED];
00945 unsigned GC_n_smashed = 0;
00946 
00947 # if defined(__STDC__) || defined(__cplusplus)
00948     void GC_add_smashed(ptr_t smashed)
00949 # else
00950     void GC_add_smashed(smashed)
00951     ptr_t smashed;
00952 #endif
00953 {
00954     GC_ASSERT(GC_is_marked(GC_base(smashed)));
00955     GC_smashed[GC_n_smashed] = smashed;
00956     if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
00957       /* In case of overflow, we keep the first MAX_SMASHED-1  */
00958       /* entries plus the last one.                            */
00959     GC_have_errors = TRUE;
00960 }
00961 
00962 /* Print all objects on the list.  Clear the list.      */
00963 void GC_print_all_smashed_proc ()
00964 {
00965     unsigned i;
00966 
00967     GC_ASSERT(!I_HOLD_LOCK());
00968     if (GC_n_smashed == 0) return;
00969     GC_err_printf0("GC_check_heap_block: found smashed heap objects:\n");
00970     for (i = 0; i < GC_n_smashed; ++i) {
00971         GC_print_smashed_obj(GC_base(GC_smashed[i]), GC_smashed[i]);
00972        GC_smashed[i] = 0;
00973     }
00974     GC_n_smashed = 0;
00975 }
00976 
00977 /* Check all marked objects in the given block for validity */
00978 /*ARGSUSED*/
00979 # if defined(__STDC__) || defined(__cplusplus)
00980     void GC_check_heap_block(register struct hblk *hbp, word dummy)
00981 # else
00982     void GC_check_heap_block(hbp, dummy)
00983     register struct hblk *hbp;     /* ptr to current heap block              */
00984     word dummy;
00985 # endif
00986 {
00987     register struct hblkhdr * hhdr = HDR(hbp);
00988     register word sz = hhdr -> hb_sz;
00989     register int word_no;
00990     register word *p, *plim;
00991     
00992     p = (word *)(hbp->hb_body);
00993     word_no = 0;
00994     if (sz > MAXOBJSZ) {
00995        plim = p;
00996     } else {
00997        plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz));
00998     }
00999     /* go through all words in block */
01000        while( p <= plim ) {
01001            if( mark_bit_from_hdr(hhdr, word_no)
01002                && GC_HAS_DEBUG_INFO((ptr_t)p)) {
01003                ptr_t clobbered = GC_check_annotated_obj((oh *)p);
01004                
01005                if (clobbered != 0) GC_add_smashed(clobbered);
01006            }
01007            word_no += sz;
01008            p += sz;
01009        }
01010 }
01011 
01012 
01013 /* This assumes that all accessible objects are marked, and that      */
01014 /* I hold the allocation lock.     Normally called by collector.             */
01015 void GC_check_heap_proc()
01016 {
01017 #   ifndef SMALL_CONFIG
01018 #     ifdef ALIGN_DOUBLE
01019         GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
01020 #     else
01021         GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
01022 #     endif
01023 #   endif
01024     GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
01025 }
01026 
01027 #endif /* !SHORT_DBG_HDRS */
01028 
01029 struct closure {
01030     GC_finalization_proc cl_fn;
01031     GC_PTR cl_data;
01032 };
01033 
01034 # ifdef __STDC__
01035     void * GC_make_closure(GC_finalization_proc fn, void * data)
01036 # else
01037     GC_PTR GC_make_closure(fn, data)
01038     GC_finalization_proc fn;
01039     GC_PTR data;
01040 # endif
01041 {
01042     struct closure * result =
01043 #   ifdef DBG_HDRS_ALL
01044       (struct closure *) GC_debug_malloc(sizeof (struct closure),
01045                                      GC_EXTRAS);
01046 #   else
01047       (struct closure *) GC_malloc(sizeof (struct closure));
01048 #   endif
01049     
01050     result -> cl_fn = fn;
01051     result -> cl_data = data;
01052     return((GC_PTR)result);
01053 }
01054 
01055 # ifdef __STDC__
01056     void GC_debug_invoke_finalizer(void * obj, void * data)
01057 # else
01058     void GC_debug_invoke_finalizer(obj, data)
01059     char * obj;
01060     char * data;
01061 # endif
01062 {
01063     register struct closure * cl = (struct closure *) data;
01064     
01065     (*(cl -> cl_fn))((GC_PTR)((char *)obj + sizeof(oh)), cl -> cl_data);
01066 } 
01067 
01068 /* Set ofn and ocd to reflect the values we got back.   */
01069 static void store_old (obj, my_old_fn, my_old_cd, ofn, ocd)
01070 GC_PTR obj;
01071 GC_finalization_proc my_old_fn;
01072 struct closure * my_old_cd;
01073 GC_finalization_proc *ofn;
01074 GC_PTR *ocd;
01075 {
01076     if (0 != my_old_fn) {
01077       if (my_old_fn != GC_debug_invoke_finalizer) {
01078         GC_err_printf1("Debuggable object at 0x%lx had non-debug finalizer.\n",
01079                      obj);
01080         /* This should probably be fatal. */
01081       } else {
01082         if (ofn) *ofn = my_old_cd -> cl_fn;
01083         if (ocd) *ocd = my_old_cd -> cl_data;
01084       }
01085     } else {
01086       if (ofn) *ofn = 0;
01087       if (ocd) *ocd = 0;
01088     }
01089 }
01090 
01091 # ifdef __STDC__
01092     void GC_debug_register_finalizer(GC_PTR obj, GC_finalization_proc fn,
01093                                  GC_PTR cd, GC_finalization_proc *ofn,
01094                                  GC_PTR *ocd)
01095 # else
01096     void GC_debug_register_finalizer(obj, fn, cd, ofn, ocd)
01097     GC_PTR obj;
01098     GC_finalization_proc fn;
01099     GC_PTR cd;
01100     GC_finalization_proc *ofn;
01101     GC_PTR *ocd;
01102 # endif
01103 {
01104     GC_finalization_proc my_old_fn;
01105     GC_PTR my_old_cd;
01106     ptr_t base = GC_base(obj);
01107     if (0 == base) return;
01108     if ((ptr_t)obj - base != sizeof(oh)) {
01109         GC_err_printf1(
01110            "GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
01111            obj);
01112     }
01113     if (0 == fn) {
01114       GC_register_finalizer(base, 0, 0, &my_old_fn, &my_old_cd);
01115     } else {
01116       GC_register_finalizer(base, GC_debug_invoke_finalizer,
01117                          GC_make_closure(fn,cd), &my_old_fn, &my_old_cd);
01118     }
01119     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
01120 }
01121 
01122 # ifdef __STDC__
01123     void GC_debug_register_finalizer_no_order
01124                                 (GC_PTR obj, GC_finalization_proc fn,
01125                                  GC_PTR cd, GC_finalization_proc *ofn,
01126                                  GC_PTR *ocd)
01127 # else
01128     void GC_debug_register_finalizer_no_order
01129                                 (obj, fn, cd, ofn, ocd)
01130     GC_PTR obj;
01131     GC_finalization_proc fn;
01132     GC_PTR cd;
01133     GC_finalization_proc *ofn;
01134     GC_PTR *ocd;
01135 # endif
01136 {
01137     GC_finalization_proc my_old_fn;
01138     GC_PTR my_old_cd;
01139     ptr_t base = GC_base(obj);
01140     if (0 == base) return;
01141     if ((ptr_t)obj - base != sizeof(oh)) {
01142         GC_err_printf1(
01143          "GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
01144          obj);
01145     }
01146     if (0 == fn) {
01147       GC_register_finalizer_no_order(base, 0, 0, &my_old_fn, &my_old_cd);
01148     } else {
01149       GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
01150                                  GC_make_closure(fn,cd), &my_old_fn,
01151                                  &my_old_cd);
01152     }
01153     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
01154  }
01155 
01156 # ifdef __STDC__
01157     void GC_debug_register_finalizer_ignore_self
01158                                 (GC_PTR obj, GC_finalization_proc fn,
01159                                  GC_PTR cd, GC_finalization_proc *ofn,
01160                                  GC_PTR *ocd)
01161 # else
01162     void GC_debug_register_finalizer_ignore_self
01163                                 (obj, fn, cd, ofn, ocd)
01164     GC_PTR obj;
01165     GC_finalization_proc fn;
01166     GC_PTR cd;
01167     GC_finalization_proc *ofn;
01168     GC_PTR *ocd;
01169 # endif
01170 {
01171     GC_finalization_proc my_old_fn;
01172     GC_PTR my_old_cd;
01173     ptr_t base = GC_base(obj);
01174     if (0 == base) return;
01175     if ((ptr_t)obj - base != sizeof(oh)) {
01176         GC_err_printf1(
01177            "GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
01178            obj);
01179     }
01180     if (0 == fn) {
01181       GC_register_finalizer_ignore_self(base, 0, 0, &my_old_fn, &my_old_cd);
01182     } else {
01183       GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
01184                                  GC_make_closure(fn,cd), &my_old_fn,
01185                                  &my_old_cd);
01186     }
01187     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
01188 }
01189 
01190 #ifdef GC_ADD_CALLER
01191 # define RA GC_RETURN_ADDR,
01192 #else
01193 # define RA
01194 #endif
01195 
01196 GC_PTR GC_debug_malloc_replacement(lb)
01197 size_t lb;
01198 {
01199     return GC_debug_malloc(lb, RA "unknown", 0);
01200 }
01201 
01202 GC_PTR GC_debug_realloc_replacement(p, lb)
01203 GC_PTR p;
01204 size_t lb;
01205 {
01206     return GC_debug_realloc(p, lb, RA "unknown", 0);
01207 }