Fix mysterious unremovable file part 2 ?
[cacao.git] / src / mm / boehm-gc / dbg_mlc.c
1 /* 
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
4  * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
5  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
6  *
7  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
9  *
10  * Permission is hereby granted to use or copy this program
11  * for any purpose,  provided the above notices are retained on all copies.
12  * Permission to modify the code and to distribute modified code is granted,
13  * provided the above notices are retained, and a notice that the code was
14  * modified is included with the above copyright notice.
15  */
16
17 #include "config.h"
18
19 #include <errno.h>
20 #include <string.h>
21 #include "private/dbg_mlc.h"
22
23 void GC_default_print_heap_obj_proc();
24 GC_API void GC_register_finalizer_no_order
25         GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
26                   GC_finalization_proc *ofn, GC_PTR *ocd));
27
28
29 #ifndef SHORT_DBG_HDRS
30 /* Check whether object with base pointer p has debugging info  */ 
31 /* p is assumed to point to a legitimate object in our part     */
32 /* of the heap.                                                 */
33 /* This excludes the check as to whether the back pointer is    */
34 /* odd, which is added by the GC_HAS_DEBUG_INFO macro.          */
35 /* Note that if DBG_HDRS_ALL is set, uncollectable objects      */
36 /* on free lists may not have debug information set.  Thus it's */
37 /* not always safe to return TRUE, even if the client does      */
38 /* its part.                                                    */
39 GC_bool GC_has_other_debug_info(p)
40 ptr_t p;
41 {
42     register oh * ohdr = (oh *)p;
43     register ptr_t body = (ptr_t)(ohdr + 1);
44     register word sz = GC_size((ptr_t) ohdr);
45     
46     if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
47         || sz < DEBUG_BYTES + EXTRA_BYTES) {
48         return(FALSE);
49     }
50     if (ohdr -> oh_sz == sz) {
51         /* Object may have had debug info, but has been deallocated     */
52         return(FALSE);
53     }
54     if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
55     if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
56         return(TRUE);
57     }
58     return(FALSE);
59 }
60 #endif
61
62 #ifdef KEEP_BACK_PTRS
63
64 # include <stdlib.h>
65
66 # if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
67      || defined(HPUX) || defined(IRIX5) || defined(OSF1)
68 #   define RANDOM() random()
69 # else
70 #   define RANDOM() (long)rand()
71 # endif
72
73   /* Store back pointer to source in dest, if that appears to be possible. */
74   /* This is not completely safe, since we may mistakenly conclude that    */
75   /* dest has a debugging wrapper.  But the error probability is very      */
76   /* small, and this shouldn't be used in production code.                 */
77   /* We assume that dest is the real base pointer.  Source will usually    */
78   /* be a pointer to the interior of an object.                            */
79   void GC_store_back_pointer(ptr_t source, ptr_t dest)
80   {
81     if (GC_HAS_DEBUG_INFO(dest)) {
82       ((oh *)dest) -> oh_back_ptr = HIDE_BACK_PTR(source);
83     }
84   }
85
86   void GC_marked_for_finalization(ptr_t dest) {
87     GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
88   }
89
90   /* Store information about the object referencing dest in *base_p     */
91   /* and *offset_p.                                                     */
92   /*   source is root ==> *base_p = address, *offset_p = 0              */
93   /*   source is heap object ==> *base_p != 0, *offset_p = offset       */
94   /*   Returns 1 on success, 0 if source couldn't be determined.        */
95   /* Dest can be any address within a heap object.                      */
96   GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p)
97   {
98     oh * hdr = (oh *)GC_base(dest);
99     ptr_t bp;
100     ptr_t bp_base;
101     if (!GC_HAS_DEBUG_INFO((ptr_t) hdr)) return GC_NO_SPACE;
102     bp = REVEAL_POINTER(hdr -> oh_back_ptr);
103     if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD;
104     if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG;
105     if (NOT_MARKED == bp) return GC_UNREFERENCED;
106 #   if ALIGNMENT == 1
107       /* Heuristically try to fix off by 1 errors we introduced by      */
108       /* insisting on even addresses.                                   */
109       {
110         ptr_t alternate_ptr = bp + 1;
111         ptr_t target = *(ptr_t *)bp;
112         ptr_t alternate_target = *(ptr_t *)alternate_ptr;
113
114         if (alternate_target >= GC_least_plausible_heap_addr
115             && alternate_target <= GC_greatest_plausible_heap_addr
116             && (target < GC_least_plausible_heap_addr
117                 || target > GC_greatest_plausible_heap_addr)) {
118             bp = alternate_ptr;
119         }
120       }
121 #   endif
122     bp_base = GC_base(bp);
123     if (0 == bp_base) {
124       *base_p = bp;
125       *offset_p = 0;
126       return GC_REFD_FROM_ROOT;
127     } else {
128       if (GC_HAS_DEBUG_INFO(bp_base)) bp_base += sizeof(oh);
129       *base_p = bp_base;
130       *offset_p = bp - bp_base;
131       return GC_REFD_FROM_HEAP;
132     }
133   }
134
135   /* Generate a random heap address.            */
136   /* The resulting address is in the heap, but  */
137   /* not necessarily inside a valid object.     */
138   void *GC_generate_random_heap_address(void)
139   {
140     int i;
141     long heap_offset = RANDOM();
142     if (GC_heapsize > RAND_MAX) {
143         heap_offset *= RAND_MAX;
144         heap_offset += RANDOM();
145     }
146     heap_offset %= GC_heapsize;
147         /* This doesn't yield a uniform distribution, especially if     */
148         /* e.g. RAND_MAX = 1.5* GC_heapsize.  But for typical cases,    */
149         /* it's not too bad.                                            */
150     for (i = 0; i < GC_n_heap_sects; ++ i) {
151         int size = GC_heap_sects[i].hs_bytes;
152         if (heap_offset < size) {
153             return GC_heap_sects[i].hs_start + heap_offset;
154         } else {
155             heap_offset -= size;
156         }
157     }
158     ABORT("GC_generate_random_heap_address: size inconsistency");
159     /*NOTREACHED*/
160     return 0;
161   }
162
163   /* Generate a random address inside a valid marked heap object. */
164   void *GC_generate_random_valid_address(void)
165   {
166     ptr_t result;
167     ptr_t base;
168     for (;;) {
169         result = GC_generate_random_heap_address();
170         base = GC_base(result);
171         if (0 == base) continue;
172         if (!GC_is_marked(base)) continue;
173         return result;
174     }
175   }
176
177   /* Print back trace for p */
178   void GC_print_backtrace(void *p)
179   {
180     void *current = p;
181     int i;
182     GC_ref_kind source;
183     size_t offset;
184     void *base;
185
186     GC_print_heap_obj(GC_base(current));
187     GC_err_printf0("\n");
188     for (i = 0; ; ++i) {
189       source = GC_get_back_ptr_info(current, &base, &offset);
190       if (GC_UNREFERENCED == source) {
191         GC_err_printf0("Reference could not be found\n");
192         goto out;
193       }
194       if (GC_NO_SPACE == source) {
195         GC_err_printf0("No debug info in object: Can't find reference\n");
196         goto out;
197       }
198       GC_err_printf1("Reachable via %d levels of pointers from ",
199                  (unsigned long)i);
200       switch(source) {
201         case GC_REFD_FROM_ROOT:
202           GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base);
203           goto out;
204         case GC_REFD_FROM_REG:
205           GC_err_printf0("root in register\n\n");
206           goto out;
207         case GC_FINALIZER_REFD:
208           GC_err_printf0("list of finalizable objects\n\n");
209           goto out;
210         case GC_REFD_FROM_HEAP:
211           GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
212           /* Take GC_base(base) to get real base, i.e. header. */
213           GC_print_heap_obj(GC_base(base));
214           GC_err_printf0("\n");
215           break;
216       }
217       current = base;
218     }
219     out:;
220   }
221
222   /* Force a garbage collection and generate a backtrace from a */
223   /* random heap address.                                       */
224   void GC_generate_random_backtrace_no_gc(void)
225   {
226     void * current;
227     current = GC_generate_random_valid_address();
228     GC_printf1("\n****Chose address 0x%lx in object\n", (unsigned long)current);
229     GC_print_backtrace(current);
230   }
231     
232   void GC_generate_random_backtrace(void)
233   {
234     GC_gcollect();
235     GC_generate_random_backtrace_no_gc();
236   }
237     
238 #endif /* KEEP_BACK_PTRS */
239
240 # define CROSSES_HBLK(p, sz) \
241         (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
242 /* Store debugging info into p.  Return displaced pointer. */
243 /* Assumes we don't hold allocation lock.                  */
244 ptr_t GC_store_debug_info(p, sz, string, integer)
245 register ptr_t p;       /* base pointer */
246 word sz;        /* bytes */
247 GC_CONST char * string;
248 word integer;
249 {
250     register word * result = (word *)((oh *)p + 1);
251     DCL_LOCK_STATE;
252     
253     /* There is some argument that we should dissble signals here.      */
254     /* But that's expensive.  And this way things should only appear    */
255     /* inconsistent while we're in the handler.                         */
256     LOCK();
257     GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
258     GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
259 #   ifdef KEEP_BACK_PTRS
260       ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
261 #   endif
262 #   ifdef MAKE_BACK_GRAPH
263       ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
264 #   endif
265     ((oh *)p) -> oh_string = string;
266     ((oh *)p) -> oh_int = integer;
267 #   ifndef SHORT_DBG_HDRS
268       ((oh *)p) -> oh_sz = sz;
269       ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
270       ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
271          result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
272 #   endif
273     UNLOCK();
274     return((ptr_t)result);
275 }
276
277 #ifdef DBG_HDRS_ALL
278 /* Store debugging info into p.  Return displaced pointer.         */
279 /* This version assumes we do hold the allocation lock.            */
280 ptr_t GC_store_debug_info_inner(p, sz, string, integer)
281 register ptr_t p;       /* base pointer */
282 word sz;        /* bytes */
283 char * string;
284 word integer;
285 {
286     register word * result = (word *)((oh *)p + 1);
287     
288     /* There is some argument that we should disable signals here.      */
289     /* But that's expensive.  And this way things should only appear    */
290     /* inconsistent while we're in the handler.                         */
291     GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
292     GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
293 #   ifdef KEEP_BACK_PTRS
294       ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
295 #   endif
296 #   ifdef MAKE_BACK_GRAPH
297       ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
298 #   endif
299     ((oh *)p) -> oh_string = string;
300     ((oh *)p) -> oh_int = integer;
301 #   ifndef SHORT_DBG_HDRS
302       ((oh *)p) -> oh_sz = sz;
303       ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
304       ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
305          result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
306 #   endif
307     return((ptr_t)result);
308 }
309 #endif
310
311 #ifndef SHORT_DBG_HDRS
312 /* Check the object with debugging info at ohdr         */
313 /* return NIL if it's OK.  Else return clobbered        */
314 /* address.                                             */
315 ptr_t GC_check_annotated_obj(ohdr)
316 register oh * ohdr;
317 {
318     register ptr_t body = (ptr_t)(ohdr + 1);
319     register word gc_sz = GC_size((ptr_t)ohdr);
320     if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
321         return((ptr_t)(&(ohdr -> oh_sz)));
322     }
323     if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
324         return((ptr_t)(&(ohdr -> oh_sf)));
325     }
326     if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
327         return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1));
328     }
329     if (((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)]
330         != (END_FLAG ^ (word)body)) {
331         return((ptr_t)((word *)body + SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)));
332     }
333     return(0);
334 }
335 #endif /* !SHORT_DBG_HDRS */
336
337 static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
338
339 void GC_register_describe_type_fn(kind, fn)
340 int kind;
341 GC_describe_type_fn fn;
342 {
343   GC_describe_type_fns[kind] = fn;
344 }
345
346 /* Print a type description for the object whose client-visible address */
347 /* is p.                                                                */
348 void GC_print_type(p)
349 ptr_t p;
350 {
351     hdr * hhdr = GC_find_header(p);
352     char buffer[GC_TYPE_DESCR_LEN + 1];
353     int kind = hhdr -> hb_obj_kind;
354
355     if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
356         /* This should preclude free list objects except with   */
357         /* thread-local allocation.                             */
358         buffer[GC_TYPE_DESCR_LEN] = 0;
359         (GC_describe_type_fns[kind])(p, buffer);
360         GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
361         GC_err_puts(buffer);
362     } else {
363         switch(kind) {
364           case PTRFREE:
365             GC_err_puts("PTRFREE");
366             break;
367           case NORMAL:
368             GC_err_puts("NORMAL");
369             break;
370           case UNCOLLECTABLE:
371             GC_err_puts("UNCOLLECTABLE");
372             break;
373 #         ifdef ATOMIC_UNCOLLECTABLE
374             case AUNCOLLECTABLE:
375               GC_err_puts("ATOMIC UNCOLLECTABLE");
376               break;
377 #         endif
378           case STUBBORN:
379             GC_err_puts("STUBBORN");
380             break;
381           default:
382             GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr);
383         }
384     }
385 }
386
387     
388
389 void GC_print_obj(p)
390 ptr_t p;
391 {
392     register oh * ohdr = (oh *)GC_base(p);
393     
394     GC_ASSERT(!I_HOLD_LOCK());
395     GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
396     GC_err_puts(ohdr -> oh_string);
397 #   ifdef SHORT_DBG_HDRS
398       GC_err_printf1(":%ld, ", (unsigned long)(ohdr -> oh_int));
399 #   else
400       GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
401                                         (unsigned long)(ohdr -> oh_sz));
402 #   endif
403     GC_print_type((ptr_t)(ohdr + 1));
404     GC_err_puts(")\n");
405     PRINT_CALL_CHAIN(ohdr);
406 }
407
408 # if defined(__STDC__) || defined(__cplusplus)
409     void GC_debug_print_heap_obj_proc(ptr_t p)
410 # else
411     void GC_debug_print_heap_obj_proc(p)
412     ptr_t p;
413 # endif
414 {
415     GC_ASSERT(!I_HOLD_LOCK());
416     if (GC_HAS_DEBUG_INFO(p)) {
417         GC_print_obj(p);
418     } else {
419         GC_default_print_heap_obj_proc(p);
420     }
421 }
422
423 #ifndef SHORT_DBG_HDRS
424 void GC_print_smashed_obj(p, clobbered_addr)
425 ptr_t p, clobbered_addr;
426 {
427     register oh * ohdr = (oh *)GC_base(p);
428     
429     GC_ASSERT(!I_HOLD_LOCK());
430     GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
431                                                 (unsigned long)p);
432     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
433         || ohdr -> oh_string == 0) {
434         GC_err_printf1("<smashed>, appr. sz = %ld)\n",
435                        (GC_size((ptr_t)ohdr) - DEBUG_BYTES));
436     } else {
437         if (ohdr -> oh_string[0] == '\0') {
438             GC_err_puts("EMPTY(smashed?)");
439         } else {
440             GC_err_puts(ohdr -> oh_string);
441         }
442         GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
443                                           (unsigned long)(ohdr -> oh_sz));
444         PRINT_CALL_CHAIN(ohdr);
445     }
446 }
447 #endif
448
449 void GC_check_heap_proc GC_PROTO((void));
450
451 void GC_print_all_smashed_proc GC_PROTO((void));
452
453 void GC_do_nothing() {}
454
455 void GC_start_debugging()
456 {
457 #   ifndef SHORT_DBG_HDRS
458       GC_check_heap = GC_check_heap_proc;
459       GC_print_all_smashed = GC_print_all_smashed_proc;
460 #   else
461       GC_check_heap = GC_do_nothing;
462       GC_print_all_smashed = GC_do_nothing;
463 #   endif
464     GC_print_heap_obj = GC_debug_print_heap_obj_proc;
465     GC_debugging_started = TRUE;
466     GC_register_displacement((word)sizeof(oh));
467 }
468
469 size_t GC_debug_header_size = sizeof(oh);
470
471 # if defined(__STDC__) || defined(__cplusplus)
472     void GC_debug_register_displacement(GC_word offset)
473 # else
474     void GC_debug_register_displacement(offset) 
475     GC_word offset;
476 # endif
477 {
478     GC_register_displacement(offset);
479     GC_register_displacement((word)sizeof(oh) + offset);
480 }
481
482 # ifdef __STDC__
483     GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
484 # else
485     GC_PTR GC_debug_malloc(lb, s, i)
486     size_t lb;
487     char * s;
488     int i;
489 #   ifdef GC_ADD_CALLER
490         --> GC_ADD_CALLER not implemented for K&R C
491 #   endif
492 # endif
493 {
494     GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
495     
496     if (result == 0) {
497         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
498                        (unsigned long) lb);
499         GC_err_puts(s);
500         GC_err_printf1(":%ld)\n", (unsigned long)i);
501         return(0);
502     }
503     if (!GC_debugging_started) {
504         GC_start_debugging();
505     }
506     ADD_CALL_CHAIN(result, ra);
507     return (GC_store_debug_info(result, (word)lb, s, (word)i));
508 }
509
510 # ifdef __STDC__
511     GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
512 # else
513     GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
514     size_t lb;
515     char * s;
516     int i;
517 #   ifdef GC_ADD_CALLER
518         --> GC_ADD_CALLER not implemented for K&R C
519 #   endif
520 # endif
521 {
522     GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
523     
524     if (result == 0) {
525         GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
526                        (unsigned long) lb);
527         GC_err_puts(s);
528         GC_err_printf1(":%ld)\n", (unsigned long)i);
529         return(0);
530     }
531     if (!GC_debugging_started) {
532         GC_start_debugging();
533     }
534     ADD_CALL_CHAIN(result, ra);
535     return (GC_store_debug_info(result, (word)lb, s, (word)i));
536 }
537
538 # ifdef __STDC__
539     GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
540 # else
541     GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
542     size_t lb;
543     char * s;
544     int i;
545 #   ifdef GC_ADD_CALLER
546         --> GC_ADD_CALLER not implemented for K&R C
547 #   endif
548 # endif
549 {
550     GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
551     
552     if (result == 0) {
553         GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
554                        " returning NIL (", (unsigned long) lb);
555         GC_err_puts(s);
556         GC_err_printf1(":%ld)\n", (unsigned long)i);
557         return(0);
558     }
559     if (!GC_debugging_started) {
560         GC_start_debugging();
561     }
562     ADD_CALL_CHAIN(result, ra);
563     return (GC_store_debug_info(result, (word)lb, s, (word)i));
564 }
565
566 # ifdef DBG_HDRS_ALL
567 /* 
568  * An allocation function for internal use.
569  * Normally internally allocated objects do not have debug information.
570  * But in this case, we need to make sure that all objects have debug
571  * headers.
572  * We assume debugging was started in collector initialization,
573  * and we already hold the GC lock.
574  */
575   GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k)
576   {
577     GC_PTR result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
578     
579     if (result == 0) {
580         GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
581                        (unsigned long) lb);
582         return(0);
583     }
584     ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
585     return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
586   }
587
588   GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, int k)
589   {
590     GC_PTR result = GC_generic_malloc_inner_ignore_off_page(
591                                                 lb + DEBUG_BYTES, k);
592     
593     if (result == 0) {
594         GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
595                        (unsigned long) lb);
596         return(0);
597     }
598     ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
599     return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
600   }
601 # endif
602
603 #ifdef STUBBORN_ALLOC
604 # ifdef __STDC__
605     GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
606 # else
607     GC_PTR GC_debug_malloc_stubborn(lb, s, i)
608     size_t lb;
609     char * s;
610     int i;
611 # endif
612 {
613     GC_PTR result = GC_malloc_stubborn(lb + DEBUG_BYTES);
614     
615     if (result == 0) {
616         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
617                        (unsigned long) lb);
618         GC_err_puts(s);
619         GC_err_printf1(":%ld)\n", (unsigned long)i);
620         return(0);
621     }
622     if (!GC_debugging_started) {
623         GC_start_debugging();
624     }
625     ADD_CALL_CHAIN(result, ra);
626     return (GC_store_debug_info(result, (word)lb, s, (word)i));
627 }
628
629 void GC_debug_change_stubborn(p)
630 GC_PTR p;
631 {
632     register GC_PTR q = GC_base(p);
633     register hdr * hhdr;
634     
635     if (q == 0) {
636         GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
637                        (unsigned long) p);
638         ABORT("GC_debug_change_stubborn: bad arg");
639     }
640     hhdr = HDR(q);
641     if (hhdr -> hb_obj_kind != STUBBORN) {
642         GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
643                        (unsigned long) p);
644         ABORT("GC_debug_change_stubborn: arg not stubborn");
645     }
646     GC_change_stubborn(q);
647 }
648
649 void GC_debug_end_stubborn_change(p)
650 GC_PTR p;
651 {
652     register GC_PTR q = GC_base(p);
653     register hdr * hhdr;
654     
655     if (q == 0) {
656         GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
657                        (unsigned long) p);
658         ABORT("GC_debug_end_stubborn_change: bad arg");
659     }
660     hhdr = HDR(q);
661     if (hhdr -> hb_obj_kind != STUBBORN) {
662         GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
663                        (unsigned long) p);
664         ABORT("GC_debug_end_stubborn_change: arg not stubborn");
665     }
666     GC_end_stubborn_change(q);
667 }
668
669 #else /* !STUBBORN_ALLOC */
670
671 # ifdef __STDC__
672     GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
673 # else
674     GC_PTR GC_debug_malloc_stubborn(lb, s, i)
675     size_t lb;
676     char * s;
677     int i;
678 # endif
679 {
680     return GC_debug_malloc(lb, OPT_RA s, i);
681 }
682
683 void GC_debug_change_stubborn(p)
684 GC_PTR p;
685 {
686 }
687
688 void GC_debug_end_stubborn_change(p)
689 GC_PTR p;
690 {
691 }
692
693 #endif /* !STUBBORN_ALLOC */
694
695 # ifdef __STDC__
696     GC_PTR GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
697 # else
698     GC_PTR GC_debug_malloc_atomic(lb, s, i)
699     size_t lb;
700     char * s;
701     int i;
702 # endif
703 {
704     GC_PTR result = GC_malloc_atomic(lb + DEBUG_BYTES);
705     
706     if (result == 0) {
707         GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
708                       (unsigned long) lb);
709         GC_err_puts(s);
710         GC_err_printf1(":%ld)\n", (unsigned long)i);
711         return(0);
712     }
713     if (!GC_debugging_started) {
714         GC_start_debugging();
715     }
716     ADD_CALL_CHAIN(result, ra);
717     return (GC_store_debug_info(result, (word)lb, s, (word)i));
718 }
719
720 # ifdef __STDC__
721     char *GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
722 #else
723     char *GC_debug_strdup(str, s, i)
724     char *str;
725     char *s;
726     int i;
727 #endif
728 {
729     char *copy;
730     if (str == NULL) return NULL;
731     copy = GC_debug_malloc_atomic(strlen(str) + 1, OPT_RA s, i);
732     if (copy == NULL) {
733       errno = ENOMEM;
734       return NULL;
735     }
736     strcpy(copy, str);
737     return copy;
738 }
739
740 # ifdef __STDC__
741     GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
742 # else
743     GC_PTR GC_debug_malloc_uncollectable(lb, s, i)
744     size_t lb;
745     char * s;
746     int i;
747 # endif
748 {
749     GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
750     
751     if (result == 0) {
752         GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
753                       (unsigned long) lb);
754         GC_err_puts(s);
755         GC_err_printf1(":%ld)\n", (unsigned long)i);
756         return(0);
757     }
758     if (!GC_debugging_started) {
759         GC_start_debugging();
760     }
761     ADD_CALL_CHAIN(result, ra);
762     return (GC_store_debug_info(result, (word)lb, s, (word)i));
763 }
764
765 #ifdef ATOMIC_UNCOLLECTABLE
766 # ifdef __STDC__
767     GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
768 # else
769     GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i)
770     size_t lb;
771     char * s;
772     int i;
773 # endif
774 {
775     GC_PTR result =
776         GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
777     
778     if (result == 0) {
779         GC_err_printf1(
780                 "GC_debug_malloc_atomic_uncollectable(%ld) returning NIL (",
781                 (unsigned long) lb);
782         GC_err_puts(s);
783         GC_err_printf1(":%ld)\n", (unsigned long)i);
784         return(0);
785     }
786     if (!GC_debugging_started) {
787         GC_start_debugging();
788     }
789     ADD_CALL_CHAIN(result, ra);
790     return (GC_store_debug_info(result, (word)lb, s, (word)i));
791 }
792 #endif /* ATOMIC_UNCOLLECTABLE */
793
794 # ifdef __STDC__
795     void GC_debug_free(GC_PTR p)
796 # else
797     void GC_debug_free(p)
798     GC_PTR p;
799 # endif
800 {
801     register GC_PTR base;
802     register ptr_t clobbered;
803     
804     if (0 == p) return;
805     base = GC_base(p);
806     if (base == 0) {
807         GC_err_printf1("Attempt to free invalid pointer %lx\n",
808                        (unsigned long)p);
809         ABORT("free(invalid pointer)");
810     }
811     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
812         GC_err_printf1(
813                   "GC_debug_free called on pointer %lx wo debugging info\n",
814                   (unsigned long)p);
815     } else {
816 #     ifndef SHORT_DBG_HDRS
817         clobbered = GC_check_annotated_obj((oh *)base);
818         if (clobbered != 0) {
819           if (((oh *)base) -> oh_sz == GC_size(base)) {
820             GC_err_printf0(
821                   "GC_debug_free: found previously deallocated (?) object at ");
822           } else {
823             GC_err_printf0("GC_debug_free: found smashed location at ");
824           }
825           GC_print_smashed_obj(p, clobbered);
826         }
827         /* Invalidate size */
828         ((oh *)base) -> oh_sz = GC_size(base);
829 #     endif /* SHORT_DBG_HDRS */
830     }
831     if (GC_find_leak) {
832         GC_free(base);
833     } else {
834         register hdr * hhdr = HDR(p);
835         GC_bool uncollectable = FALSE;
836
837         if (hhdr ->  hb_obj_kind == UNCOLLECTABLE) {
838             uncollectable = TRUE;
839         }
840 #       ifdef ATOMIC_UNCOLLECTABLE
841             if (hhdr ->  hb_obj_kind == AUNCOLLECTABLE) {
842                     uncollectable = TRUE;
843             }
844 #       endif
845         if (uncollectable) {
846             GC_free(base);
847         } else {
848             size_t i;
849             size_t obj_sz = hhdr -> hb_sz - BYTES_TO_WORDS(sizeof(oh));
850
851             for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef;
852             GC_ASSERT((word *)p + i == (word *)base + hhdr -> hb_sz);
853         }
854     } /* !GC_find_leak */
855 }
856
857 #ifdef THREADS
858
859 extern void GC_free_inner(GC_PTR p);
860
861 /* Used internally; we assume it's called correctly.    */
862 void GC_debug_free_inner(GC_PTR p)
863 {
864     GC_free_inner(GC_base(p));
865 }
866 #endif
867
868 # ifdef __STDC__
869     GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, GC_EXTRA_PARAMS)
870 # else
871     GC_PTR GC_debug_realloc(p, lb, s, i)
872     GC_PTR p;
873     size_t lb;
874     char *s;
875     int i;
876 # endif
877 {
878     register GC_PTR base = GC_base(p);
879     register ptr_t clobbered;
880     register GC_PTR result;
881     register size_t copy_sz = lb;
882     register size_t old_sz;
883     register hdr * hhdr;
884     
885     if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i));
886     if (base == 0) {
887         GC_err_printf1(
888               "Attempt to reallocate invalid pointer %lx\n", (unsigned long)p);
889         ABORT("realloc(invalid pointer)");
890     }
891     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
892         GC_err_printf1(
893                 "GC_debug_realloc called on pointer %lx wo debugging info\n",
894                 (unsigned long)p);
895         return(GC_realloc(p, lb));
896     }
897     hhdr = HDR(base);
898     switch (hhdr -> hb_obj_kind) {
899 #    ifdef STUBBORN_ALLOC
900       case STUBBORN:
901         result = GC_debug_malloc_stubborn(lb, OPT_RA s, i);
902         break;
903 #    endif
904       case NORMAL:
905         result = GC_debug_malloc(lb, OPT_RA s, i);
906         break;
907       case PTRFREE:
908         result = GC_debug_malloc_atomic(lb, OPT_RA s, i);
909         break;
910       case UNCOLLECTABLE:
911         result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
912         break;
913 #    ifdef ATOMIC_UNCOLLECTABLE
914       case AUNCOLLECTABLE:
915         result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
916         break;
917 #    endif
918       default:
919         GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
920         ABORT("bad kind");
921     }
922 #   ifdef SHORT_DBG_HDRS
923       old_sz = GC_size(base) - sizeof(oh);
924 #   else
925       clobbered = GC_check_annotated_obj((oh *)base);
926       if (clobbered != 0) {
927         GC_err_printf0("GC_debug_realloc: found smashed location at ");
928         GC_print_smashed_obj(p, clobbered);
929       }
930       old_sz = ((oh *)base) -> oh_sz;
931 #   endif
932     if (old_sz < copy_sz) copy_sz = old_sz;
933     if (result == 0) return(0);
934     BCOPY(p, result,  copy_sz);
935     GC_debug_free(p);
936     return(result);
937 }
938
939 #ifndef SHORT_DBG_HDRS
940
941 /* List of smashed objects.  We defer printing these, since we can't    */
942 /* always print them nicely with the allocation lock held.              */
943 /* We put them here instead of in GC_arrays, since it may be useful to  */
944 /* be able to look at them with the debugger.                           */
945 #define MAX_SMASHED 20
946 ptr_t GC_smashed[MAX_SMASHED];
947 unsigned GC_n_smashed = 0;
948
949 # if defined(__STDC__) || defined(__cplusplus)
950     void GC_add_smashed(ptr_t smashed)
951 # else
952     void GC_add_smashed(smashed)
953     ptr_t smashed;
954 #endif
955 {
956     GC_ASSERT(GC_is_marked(GC_base(smashed)));
957     GC_smashed[GC_n_smashed] = smashed;
958     if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
959       /* In case of overflow, we keep the first MAX_SMASHED-1   */
960       /* entries plus the last one.                             */
961     GC_have_errors = TRUE;
962 }
963
964 /* Print all objects on the list.  Clear the list.      */
965 void GC_print_all_smashed_proc ()
966 {
967     unsigned i;
968
969     GC_ASSERT(!I_HOLD_LOCK());
970     if (GC_n_smashed == 0) return;
971     GC_err_printf0("GC_check_heap_block: found smashed heap objects:\n");
972     for (i = 0; i < GC_n_smashed; ++i) {
973         GC_print_smashed_obj(GC_base(GC_smashed[i]), GC_smashed[i]);
974         GC_smashed[i] = 0;
975     }
976     GC_n_smashed = 0;
977 }
978
979 /* Check all marked objects in the given block for validity */
980 /*ARGSUSED*/
981 # if defined(__STDC__) || defined(__cplusplus)
982     void GC_check_heap_block(register struct hblk *hbp, word dummy)
983 # else
984     void GC_check_heap_block(hbp, dummy)
985     register struct hblk *hbp;  /* ptr to current heap block            */
986     word dummy;
987 # endif
988 {
989     register struct hblkhdr * hhdr = HDR(hbp);
990     register word sz = hhdr -> hb_sz;
991     register int word_no;
992     register word *p, *plim;
993     
994     p = (word *)(hbp->hb_body);
995     word_no = 0;
996     if (sz > MAXOBJSZ) {
997         plim = p;
998     } else {
999         plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz));
1000     }
1001     /* go through all words in block */
1002         while( p <= plim ) {
1003             if( mark_bit_from_hdr(hhdr, word_no)
1004                 && GC_HAS_DEBUG_INFO((ptr_t)p)) {
1005                 ptr_t clobbered = GC_check_annotated_obj((oh *)p);
1006                 
1007                 if (clobbered != 0) GC_add_smashed(clobbered);
1008             }
1009             word_no += sz;
1010             p += sz;
1011         }
1012 }
1013
1014
1015 /* This assumes that all accessible objects are marked, and that        */
1016 /* I hold the allocation lock.  Normally called by collector.           */
1017 void GC_check_heap_proc()
1018 {
1019 #   ifndef SMALL_CONFIG
1020 #     ifdef ALIGN_DOUBLE
1021         GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
1022 #     else
1023         GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
1024 #     endif
1025 #   endif
1026     GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
1027 }
1028
1029 #endif /* !SHORT_DBG_HDRS */
1030
1031 struct closure {
1032     GC_finalization_proc cl_fn;
1033     GC_PTR cl_data;
1034 };
1035
1036 # ifdef __STDC__
1037     void * GC_make_closure(GC_finalization_proc fn, void * data)
1038 # else
1039     GC_PTR GC_make_closure(fn, data)
1040     GC_finalization_proc fn;
1041     GC_PTR data;
1042 # endif
1043 {
1044     struct closure * result =
1045 #   ifdef DBG_HDRS_ALL
1046       (struct closure *) GC_debug_malloc(sizeof (struct closure),
1047                                          GC_EXTRAS);
1048 #   else
1049       (struct closure *) GC_malloc(sizeof (struct closure));
1050 #   endif
1051     
1052     result -> cl_fn = fn;
1053     result -> cl_data = data;
1054     return((GC_PTR)result);
1055 }
1056
1057 # ifdef __STDC__
1058     void GC_debug_invoke_finalizer(void * obj, void * data)
1059 # else
1060     void GC_debug_invoke_finalizer(obj, data)
1061     char * obj;
1062     char * data;
1063 # endif
1064 {
1065     register struct closure * cl = (struct closure *) data;
1066     
1067     (*(cl -> cl_fn))((GC_PTR)((char *)obj + sizeof(oh)), cl -> cl_data);
1068
1069
1070 /* Set ofn and ocd to reflect the values we got back.   */
1071 static void store_old (obj, my_old_fn, my_old_cd, ofn, ocd)
1072 GC_PTR obj;
1073 GC_finalization_proc my_old_fn;
1074 struct closure * my_old_cd;
1075 GC_finalization_proc *ofn;
1076 GC_PTR *ocd;
1077 {
1078     if (0 != my_old_fn) {
1079       if (my_old_fn != GC_debug_invoke_finalizer) {
1080         GC_err_printf1("Debuggable object at 0x%lx had non-debug finalizer.\n",
1081                        obj);
1082         /* This should probably be fatal. */
1083       } else {
1084         if (ofn) *ofn = my_old_cd -> cl_fn;
1085         if (ocd) *ocd = my_old_cd -> cl_data;
1086       }
1087     } else {
1088       if (ofn) *ofn = 0;
1089       if (ocd) *ocd = 0;
1090     }
1091 }
1092
1093 # ifdef __STDC__
1094     void GC_debug_register_finalizer(GC_PTR obj, GC_finalization_proc fn,
1095                                      GC_PTR cd, GC_finalization_proc *ofn,
1096                                      GC_PTR *ocd)
1097 # else
1098     void GC_debug_register_finalizer(obj, fn, cd, ofn, ocd)
1099     GC_PTR obj;
1100     GC_finalization_proc fn;
1101     GC_PTR cd;
1102     GC_finalization_proc *ofn;
1103     GC_PTR *ocd;
1104 # endif
1105 {
1106     GC_finalization_proc my_old_fn;
1107     GC_PTR my_old_cd;
1108     ptr_t base = GC_base(obj);
1109     if (0 == base) return;
1110     if ((ptr_t)obj - base != sizeof(oh)) {
1111         GC_err_printf1(
1112             "GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
1113             obj);
1114     }
1115     if (0 == fn) {
1116       GC_register_finalizer(base, 0, 0, &my_old_fn, &my_old_cd);
1117     } else {
1118       GC_register_finalizer(base, GC_debug_invoke_finalizer,
1119                             GC_make_closure(fn,cd), &my_old_fn, &my_old_cd);
1120     }
1121     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1122 }
1123
1124 # ifdef __STDC__
1125     void GC_debug_register_finalizer_no_order
1126                                     (GC_PTR obj, GC_finalization_proc fn,
1127                                      GC_PTR cd, GC_finalization_proc *ofn,
1128                                      GC_PTR *ocd)
1129 # else
1130     void GC_debug_register_finalizer_no_order
1131                                     (obj, fn, cd, ofn, ocd)
1132     GC_PTR obj;
1133     GC_finalization_proc fn;
1134     GC_PTR cd;
1135     GC_finalization_proc *ofn;
1136     GC_PTR *ocd;
1137 # endif
1138 {
1139     GC_finalization_proc my_old_fn;
1140     GC_PTR my_old_cd;
1141     ptr_t base = GC_base(obj);
1142     if (0 == base) return;
1143     if ((ptr_t)obj - base != sizeof(oh)) {
1144         GC_err_printf1(
1145           "GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
1146           obj);
1147     }
1148     if (0 == fn) {
1149       GC_register_finalizer_no_order(base, 0, 0, &my_old_fn, &my_old_cd);
1150     } else {
1151       GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
1152                                      GC_make_closure(fn,cd), &my_old_fn,
1153                                      &my_old_cd);
1154     }
1155     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1156  }
1157
1158 # ifdef __STDC__
1159     void GC_debug_register_finalizer_ignore_self
1160                                     (GC_PTR obj, GC_finalization_proc fn,
1161                                      GC_PTR cd, GC_finalization_proc *ofn,
1162                                      GC_PTR *ocd)
1163 # else
1164     void GC_debug_register_finalizer_ignore_self
1165                                     (obj, fn, cd, ofn, ocd)
1166     GC_PTR obj;
1167     GC_finalization_proc fn;
1168     GC_PTR cd;
1169     GC_finalization_proc *ofn;
1170     GC_PTR *ocd;
1171 # endif
1172 {
1173     GC_finalization_proc my_old_fn;
1174     GC_PTR my_old_cd;
1175     ptr_t base = GC_base(obj);
1176     if (0 == base) return;
1177     if ((ptr_t)obj - base != sizeof(oh)) {
1178         GC_err_printf1(
1179             "GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
1180             obj);
1181     }
1182     if (0 == fn) {
1183       GC_register_finalizer_ignore_self(base, 0, 0, &my_old_fn, &my_old_cd);
1184     } else {
1185       GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
1186                                      GC_make_closure(fn,cd), &my_old_fn,
1187                                      &my_old_cd);
1188     }
1189     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1190 }
1191
1192 #ifdef GC_ADD_CALLER
1193 # define RA GC_RETURN_ADDR,
1194 #else
1195 # define RA
1196 #endif
1197
1198 GC_PTR GC_debug_malloc_replacement(lb)
1199 size_t lb;
1200 {
1201     return GC_debug_malloc(lb, RA "unknown", 0);
1202 }
1203
1204 GC_PTR GC_debug_realloc_replacement(p, lb)
1205 GC_PTR p;
1206 size_t lb;
1207 {
1208     return GC_debug_realloc(p, lb, RA "unknown", 0);
1209 }