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.
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
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.
19 #include "private/dbg_mlc.h"
21 void GC_default_print_heap_obj_proc();
22 GC_API void GC_register_finalizer_no_order
23 GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
24 GC_finalization_proc *ofn, GC_PTR *ocd));
27 #ifndef SHORT_DBG_HDRS
28 /* Check whether object with base pointer p has debugging info */
29 /* p is assumed to point to a legitimate object in our part */
31 /* This excludes the check as to whether the back pointer is */
32 /* odd, which is added by the GC_HAS_DEBUG_INFO macro. */
33 /* Note that if DBG_HDRS_ALL is set, uncollectable objects */
34 /* on free lists may not have debug information set. Thus it's */
35 /* not always safe to return TRUE, even if the client does */
37 GC_bool GC_has_other_debug_info(p)
40 register oh * ohdr = (oh *)p;
41 register ptr_t body = (ptr_t)(ohdr + 1);
42 register word sz = GC_size((ptr_t) ohdr);
44 if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
45 || sz < DEBUG_BYTES + EXTRA_BYTES) {
48 if (ohdr -> oh_sz == sz) {
49 /* Object may have had debug info, but has been deallocated */
52 if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
53 if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
64 # if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
65 || defined(HPUX) || defined(IRIX5) || defined(OSF1)
66 # define RANDOM() random()
68 # define RANDOM() (long)rand()
71 /* Store back pointer to source in dest, if that appears to be possible. */
72 /* This is not completely safe, since we may mistakenly conclude that */
73 /* dest has a debugging wrapper. But the error probability is very */
74 /* small, and this shouldn't be used in production code. */
75 /* We assume that dest is the real base pointer. Source will usually */
76 /* be a pointer to the interior of an object. */
77 void GC_store_back_pointer(ptr_t source, ptr_t dest)
79 if (GC_HAS_DEBUG_INFO(dest)) {
80 ((oh *)dest) -> oh_back_ptr = HIDE_BACK_PTR(source);
84 void GC_marked_for_finalization(ptr_t dest) {
85 GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
88 /* Store information about the object referencing dest in *base_p */
90 /* source is root ==> *base_p = address, *offset_p = 0 */
91 /* source is heap object ==> *base_p != 0, *offset_p = offset */
92 /* Returns 1 on success, 0 if source couldn't be determined. */
93 /* Dest can be any address within a heap object. */
94 GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p)
96 oh * hdr = (oh *)GC_base(dest);
99 if (!GC_HAS_DEBUG_INFO((ptr_t) hdr)) return GC_NO_SPACE;
100 bp = REVEAL_POINTER(hdr -> oh_back_ptr);
101 if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD;
102 if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG;
103 if (NOT_MARKED == bp) return GC_UNREFERENCED;
105 /* Heuristically try to fix off by 1 errors we introduced by */
106 /* insisting on even addresses. */
108 ptr_t alternate_ptr = bp + 1;
109 ptr_t target = *(ptr_t *)bp;
110 ptr_t alternate_target = *(ptr_t *)alternate_ptr;
112 if (alternate_target >= GC_least_plausible_heap_addr
113 && alternate_target <= GC_greatest_plausible_heap_addr
114 && (target < GC_least_plausible_heap_addr
115 || target > GC_greatest_plausible_heap_addr)) {
120 bp_base = GC_base(bp);
124 return GC_REFD_FROM_ROOT;
126 if (GC_HAS_DEBUG_INFO(bp_base)) bp_base += sizeof(oh);
128 *offset_p = bp - bp_base;
129 return GC_REFD_FROM_HEAP;
133 /* Generate a random heap address. */
134 /* The resulting address is in the heap, but */
135 /* not necessarily inside a valid object. */
136 void *GC_generate_random_heap_address(void)
139 long heap_offset = RANDOM();
140 if (GC_heapsize > RAND_MAX) {
141 heap_offset *= RAND_MAX;
142 heap_offset += RANDOM();
144 heap_offset %= GC_heapsize;
145 /* This doesn't yield a uniform distribution, especially if */
146 /* e.g. RAND_MAX = 1.5* GC_heapsize. But for typical cases, */
147 /* it's not too bad. */
148 for (i = 0; i < GC_n_heap_sects; ++ i) {
149 int size = GC_heap_sects[i].hs_bytes;
150 if (heap_offset < size) {
151 return GC_heap_sects[i].hs_start + heap_offset;
156 ABORT("GC_generate_random_heap_address: size inconsistency");
161 /* Generate a random address inside a valid marked heap object. */
162 void *GC_generate_random_valid_address(void)
167 result = GC_generate_random_heap_address();
168 base = GC_base(result);
169 if (0 == base) continue;
170 if (!GC_is_marked(base)) continue;
175 /* Print back trace for p */
176 void GC_print_backtrace(void *p)
184 GC_print_heap_obj(GC_base(current));
185 GC_err_printf0("\n");
187 source = GC_get_back_ptr_info(current, &base, &offset);
188 if (GC_UNREFERENCED == source) {
189 GC_err_printf0("Reference could not be found\n");
192 if (GC_NO_SPACE == source) {
193 GC_err_printf0("No debug info in object: Can't find reference\n");
196 GC_err_printf1("Reachable via %d levels of pointers from ",
199 case GC_REFD_FROM_ROOT:
200 GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base);
202 case GC_REFD_FROM_REG:
203 GC_err_printf0("root in register\n\n");
205 case GC_FINALIZER_REFD:
206 GC_err_printf0("list of finalizable objects\n\n");
208 case GC_REFD_FROM_HEAP:
209 GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
210 /* Take GC_base(base) to get real base, i.e. header. */
211 GC_print_heap_obj(GC_base(base));
212 GC_err_printf0("\n");
220 /* Force a garbage collection and generate a backtrace from a */
221 /* random heap address. */
222 void GC_generate_random_backtrace_no_gc(void)
225 current = GC_generate_random_valid_address();
226 GC_printf1("\n****Chose address 0x%lx in object\n", (unsigned long)current);
227 GC_print_backtrace(current);
230 void GC_generate_random_backtrace(void)
233 GC_generate_random_backtrace_no_gc();
236 #endif /* KEEP_BACK_PTRS */
238 # define CROSSES_HBLK(p, sz) \
239 (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
240 /* Store debugging info into p. Return displaced pointer. */
241 /* Assumes we don't hold allocation lock. */
242 ptr_t GC_store_debug_info(p, sz, string, integer)
243 register ptr_t p; /* base pointer */
245 GC_CONST char * string;
248 register word * result = (word *)((oh *)p + 1);
251 /* There is some argument that we should dissble signals here. */
252 /* But that's expensive. And this way things should only appear */
253 /* inconsistent while we're in the handler. */
255 GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
256 GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
257 # ifdef KEEP_BACK_PTRS
258 ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
260 # ifdef MAKE_BACK_GRAPH
261 ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
263 ((oh *)p) -> oh_string = string;
264 ((oh *)p) -> oh_int = integer;
265 # ifndef SHORT_DBG_HDRS
266 ((oh *)p) -> oh_sz = sz;
267 ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
268 ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
269 result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
272 return((ptr_t)result);
276 /* Store debugging info into p. Return displaced pointer. */
277 /* This version assumes we do hold the allocation lock. */
278 ptr_t GC_store_debug_info_inner(p, sz, string, integer)
279 register ptr_t p; /* base pointer */
284 register word * result = (word *)((oh *)p + 1);
286 /* There is some argument that we should disable signals here. */
287 /* But that's expensive. And this way things should only appear */
288 /* inconsistent while we're in the handler. */
289 GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
290 GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
291 # ifdef KEEP_BACK_PTRS
292 ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
294 # ifdef MAKE_BACK_GRAPH
295 ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
297 ((oh *)p) -> oh_string = string;
298 ((oh *)p) -> oh_int = integer;
299 # ifndef SHORT_DBG_HDRS
300 ((oh *)p) -> oh_sz = sz;
301 ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
302 ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
303 result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
305 return((ptr_t)result);
309 #ifndef SHORT_DBG_HDRS
310 /* Check the object with debugging info at ohdr */
311 /* return NIL if it's OK. Else return clobbered */
313 ptr_t GC_check_annotated_obj(ohdr)
316 register ptr_t body = (ptr_t)(ohdr + 1);
317 register word gc_sz = GC_size((ptr_t)ohdr);
318 if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
319 return((ptr_t)(&(ohdr -> oh_sz)));
321 if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
322 return((ptr_t)(&(ohdr -> oh_sf)));
324 if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
325 return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1));
327 if (((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)]
328 != (END_FLAG ^ (word)body)) {
329 return((ptr_t)((word *)body + SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)));
333 #endif /* !SHORT_DBG_HDRS */
335 static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
337 void GC_register_describe_type_fn(kind, fn)
339 GC_describe_type_fn fn;
341 GC_describe_type_fns[kind] = fn;
344 /* Print a type description for the object whose client-visible address */
346 void GC_print_type(p)
349 hdr * hhdr = GC_find_header(p);
350 char buffer[GC_TYPE_DESCR_LEN + 1];
351 int kind = hhdr -> hb_obj_kind;
353 if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
354 /* This should preclude free list objects except with */
355 /* thread-local allocation. */
356 buffer[GC_TYPE_DESCR_LEN] = 0;
357 (GC_describe_type_fns[kind])(p, buffer);
358 GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
363 GC_err_puts("PTRFREE");
366 GC_err_puts("NORMAL");
369 GC_err_puts("UNCOLLECTABLE");
371 # ifdef ATOMIC_UNCOLLECTABLE
373 GC_err_puts("ATOMIC UNCOLLECTABLE");
377 GC_err_puts("STUBBORN");
380 GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr);
390 register oh * ohdr = (oh *)GC_base(p);
392 GC_ASSERT(!I_HOLD_LOCK());
393 GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
394 GC_err_puts(ohdr -> oh_string);
395 # ifdef SHORT_DBG_HDRS
396 GC_err_printf1(":%ld, ", (unsigned long)(ohdr -> oh_int));
398 GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
399 (unsigned long)(ohdr -> oh_sz));
401 GC_print_type((ptr_t)(ohdr + 1));
403 PRINT_CALL_CHAIN(ohdr);
406 # if defined(__STDC__) || defined(__cplusplus)
407 void GC_debug_print_heap_obj_proc(ptr_t p)
409 void GC_debug_print_heap_obj_proc(p)
413 GC_ASSERT(!I_HOLD_LOCK());
414 if (GC_HAS_DEBUG_INFO(p)) {
417 GC_default_print_heap_obj_proc(p);
421 #ifndef SHORT_DBG_HDRS
422 void GC_print_smashed_obj(p, clobbered_addr)
423 ptr_t p, clobbered_addr;
425 register oh * ohdr = (oh *)GC_base(p);
427 GC_ASSERT(!I_HOLD_LOCK());
428 GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
430 if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
431 || ohdr -> oh_string == 0) {
432 GC_err_printf1("<smashed>, appr. sz = %ld)\n",
433 (GC_size((ptr_t)ohdr) - DEBUG_BYTES));
435 if (ohdr -> oh_string[0] == '\0') {
436 GC_err_puts("EMPTY(smashed?)");
438 GC_err_puts(ohdr -> oh_string);
440 GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
441 (unsigned long)(ohdr -> oh_sz));
442 PRINT_CALL_CHAIN(ohdr);
447 void GC_check_heap_proc GC_PROTO((void));
449 void GC_print_all_smashed_proc GC_PROTO((void));
451 void GC_do_nothing() {}
453 void GC_start_debugging()
455 # ifndef SHORT_DBG_HDRS
456 GC_check_heap = GC_check_heap_proc;
457 GC_print_all_smashed = GC_print_all_smashed_proc;
459 GC_check_heap = GC_do_nothing;
460 GC_print_all_smashed = GC_do_nothing;
462 GC_print_heap_obj = GC_debug_print_heap_obj_proc;
463 GC_debugging_started = TRUE;
464 GC_register_displacement((word)sizeof(oh));
467 size_t GC_debug_header_size = sizeof(oh);
469 # if defined(__STDC__) || defined(__cplusplus)
470 void GC_debug_register_displacement(GC_word offset)
472 void GC_debug_register_displacement(offset)
476 GC_register_displacement(offset);
477 GC_register_displacement((word)sizeof(oh) + offset);
481 GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
483 GC_PTR GC_debug_malloc(lb, s, i)
487 # ifdef GC_ADD_CALLER
488 --> GC_ADD_CALLER not implemented for K&R C
492 GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
495 GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
498 GC_err_printf1(":%ld)\n", (unsigned long)i);
501 if (!GC_debugging_started) {
502 GC_start_debugging();
504 ADD_CALL_CHAIN(result, ra);
505 return (GC_store_debug_info(result, (word)lb, s, (word)i));
509 GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
511 GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
515 # ifdef GC_ADD_CALLER
516 --> GC_ADD_CALLER not implemented for K&R C
520 GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
523 GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
526 GC_err_printf1(":%ld)\n", (unsigned long)i);
529 if (!GC_debugging_started) {
530 GC_start_debugging();
532 ADD_CALL_CHAIN(result, ra);
533 return (GC_store_debug_info(result, (word)lb, s, (word)i));
537 GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
539 GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
543 # ifdef GC_ADD_CALLER
544 --> GC_ADD_CALLER not implemented for K&R C
548 GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
551 GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
552 " returning NIL (", (unsigned long) lb);
554 GC_err_printf1(":%ld)\n", (unsigned long)i);
557 if (!GC_debugging_started) {
558 GC_start_debugging();
560 ADD_CALL_CHAIN(result, ra);
561 return (GC_store_debug_info(result, (word)lb, s, (word)i));
566 * An allocation function for internal use.
567 * Normally internally allocated objects do not have debug information.
568 * But in this case, we need to make sure that all objects have debug
570 * We assume debugging was started in collector initialization,
571 * and we already hold the GC lock.
573 GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k)
575 GC_PTR result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
578 GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
582 ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
583 return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
586 GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, int k)
588 GC_PTR result = GC_generic_malloc_inner_ignore_off_page(
589 lb + DEBUG_BYTES, k);
592 GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
596 ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
597 return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
601 #ifdef STUBBORN_ALLOC
603 GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
605 GC_PTR GC_debug_malloc_stubborn(lb, s, i)
611 GC_PTR result = GC_malloc_stubborn(lb + DEBUG_BYTES);
614 GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
617 GC_err_printf1(":%ld)\n", (unsigned long)i);
620 if (!GC_debugging_started) {
621 GC_start_debugging();
623 ADD_CALL_CHAIN(result, ra);
624 return (GC_store_debug_info(result, (word)lb, s, (word)i));
627 void GC_debug_change_stubborn(p)
630 register GC_PTR q = GC_base(p);
634 GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
636 ABORT("GC_debug_change_stubborn: bad arg");
639 if (hhdr -> hb_obj_kind != STUBBORN) {
640 GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
642 ABORT("GC_debug_change_stubborn: arg not stubborn");
644 GC_change_stubborn(q);
647 void GC_debug_end_stubborn_change(p)
650 register GC_PTR q = GC_base(p);
654 GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
656 ABORT("GC_debug_end_stubborn_change: bad arg");
659 if (hhdr -> hb_obj_kind != STUBBORN) {
660 GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
662 ABORT("GC_debug_end_stubborn_change: arg not stubborn");
664 GC_end_stubborn_change(q);
667 #else /* !STUBBORN_ALLOC */
670 GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
672 GC_PTR GC_debug_malloc_stubborn(lb, s, i)
678 return GC_debug_malloc(lb, OPT_RA s, i);
681 void GC_debug_change_stubborn(p)
686 void GC_debug_end_stubborn_change(p)
691 #endif /* !STUBBORN_ALLOC */
694 GC_PTR GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
696 GC_PTR GC_debug_malloc_atomic(lb, s, i)
702 GC_PTR result = GC_malloc_atomic(lb + DEBUG_BYTES);
705 GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
708 GC_err_printf1(":%ld)\n", (unsigned long)i);
711 if (!GC_debugging_started) {
712 GC_start_debugging();
714 ADD_CALL_CHAIN(result, ra);
715 return (GC_store_debug_info(result, (word)lb, s, (word)i));
719 GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
721 GC_PTR GC_debug_malloc_uncollectable(lb, s, i)
727 GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
730 GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
733 GC_err_printf1(":%ld)\n", (unsigned long)i);
736 if (!GC_debugging_started) {
737 GC_start_debugging();
739 ADD_CALL_CHAIN(result, ra);
740 return (GC_store_debug_info(result, (word)lb, s, (word)i));
743 #ifdef ATOMIC_UNCOLLECTABLE
745 GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
747 GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i)
754 GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
758 "GC_debug_malloc_atomic_uncollectable(%ld) returning NIL (",
761 GC_err_printf1(":%ld)\n", (unsigned long)i);
764 if (!GC_debugging_started) {
765 GC_start_debugging();
767 ADD_CALL_CHAIN(result, ra);
768 return (GC_store_debug_info(result, (word)lb, s, (word)i));
770 #endif /* ATOMIC_UNCOLLECTABLE */
773 void GC_debug_free(GC_PTR p)
775 void GC_debug_free(p)
779 register GC_PTR base;
780 register ptr_t clobbered;
785 GC_err_printf1("Attempt to free invalid pointer %lx\n",
787 ABORT("free(invalid pointer)");
789 if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
791 "GC_debug_free called on pointer %lx wo debugging info\n",
794 # ifndef SHORT_DBG_HDRS
795 clobbered = GC_check_annotated_obj((oh *)base);
796 if (clobbered != 0) {
797 if (((oh *)base) -> oh_sz == GC_size(base)) {
799 "GC_debug_free: found previously deallocated (?) object at ");
801 GC_err_printf0("GC_debug_free: found smashed location at ");
803 GC_print_smashed_obj(p, clobbered);
805 /* Invalidate size */
806 ((oh *)base) -> oh_sz = GC_size(base);
807 # endif /* SHORT_DBG_HDRS */
812 register hdr * hhdr = HDR(p);
813 GC_bool uncollectable = FALSE;
815 if (hhdr -> hb_obj_kind == UNCOLLECTABLE) {
816 uncollectable = TRUE;
818 # ifdef ATOMIC_UNCOLLECTABLE
819 if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) {
820 uncollectable = TRUE;
827 size_t obj_sz = hhdr -> hb_sz - BYTES_TO_WORDS(sizeof(oh));
829 for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef;
830 GC_ASSERT((word *)p + i == (word *)base + hhdr -> hb_sz);
832 } /* !GC_find_leak */
837 extern void GC_free_inner(GC_PTR p);
839 /* Used internally; we assume it's called correctly. */
840 void GC_debug_free_inner(GC_PTR p)
842 GC_free_inner(GC_base(p));
847 GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, GC_EXTRA_PARAMS)
849 GC_PTR GC_debug_realloc(p, lb, s, i)
856 register GC_PTR base = GC_base(p);
857 register ptr_t clobbered;
858 register GC_PTR result;
859 register size_t copy_sz = lb;
860 register size_t old_sz;
863 if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i));
866 "Attempt to reallocate invalid pointer %lx\n", (unsigned long)p);
867 ABORT("realloc(invalid pointer)");
869 if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
871 "GC_debug_realloc called on pointer %lx wo debugging info\n",
873 return(GC_realloc(p, lb));
876 switch (hhdr -> hb_obj_kind) {
877 # ifdef STUBBORN_ALLOC
879 result = GC_debug_malloc_stubborn(lb, OPT_RA s, i);
883 result = GC_debug_malloc(lb, OPT_RA s, i);
886 result = GC_debug_malloc_atomic(lb, OPT_RA s, i);
889 result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
891 # ifdef ATOMIC_UNCOLLECTABLE
893 result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
897 GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
900 # ifdef SHORT_DBG_HDRS
901 old_sz = GC_size(base) - sizeof(oh);
903 clobbered = GC_check_annotated_obj((oh *)base);
904 if (clobbered != 0) {
905 GC_err_printf0("GC_debug_realloc: found smashed location at ");
906 GC_print_smashed_obj(p, clobbered);
908 old_sz = ((oh *)base) -> oh_sz;
910 if (old_sz < copy_sz) copy_sz = old_sz;
911 if (result == 0) return(0);
912 BCOPY(p, result, copy_sz);
917 #ifndef SHORT_DBG_HDRS
919 /* List of smashed objects. We defer printing these, since we can't */
920 /* always print them nicely with the allocation lock held. */
921 /* We put them here instead of in GC_arrays, since it may be useful to */
922 /* be able to look at them with the debugger. */
923 #define MAX_SMASHED 20
924 ptr_t GC_smashed[MAX_SMASHED];
925 unsigned GC_n_smashed = 0;
927 # if defined(__STDC__) || defined(__cplusplus)
928 void GC_add_smashed(ptr_t smashed)
930 void GC_add_smashed(smashed)
934 GC_ASSERT(GC_is_marked(GC_base(smashed)));
935 GC_smashed[GC_n_smashed] = smashed;
936 if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
937 /* In case of overflow, we keep the first MAX_SMASHED-1 */
938 /* entries plus the last one. */
939 GC_have_errors = TRUE;
942 /* Print all objects on the list. Clear the list. */
943 void GC_print_all_smashed_proc ()
947 GC_ASSERT(!I_HOLD_LOCK());
948 if (GC_n_smashed == 0) return;
949 GC_err_printf0("GC_check_heap_block: found smashed heap objects:\n");
950 for (i = 0; i < GC_n_smashed; ++i) {
951 GC_print_smashed_obj(GC_base(GC_smashed[i]), GC_smashed[i]);
957 /* Check all marked objects in the given block for validity */
959 # if defined(__STDC__) || defined(__cplusplus)
960 void GC_check_heap_block(register struct hblk *hbp, word dummy)
962 void GC_check_heap_block(hbp, dummy)
963 register struct hblk *hbp; /* ptr to current heap block */
967 register struct hblkhdr * hhdr = HDR(hbp);
968 register word sz = hhdr -> hb_sz;
969 register int word_no;
970 register word *p, *plim;
972 p = (word *)(hbp->hb_body);
977 plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz));
979 /* go through all words in block */
981 if( mark_bit_from_hdr(hhdr, word_no)
982 && GC_HAS_DEBUG_INFO((ptr_t)p)) {
983 ptr_t clobbered = GC_check_annotated_obj((oh *)p);
985 if (clobbered != 0) GC_add_smashed(clobbered);
993 /* This assumes that all accessible objects are marked, and that */
994 /* I hold the allocation lock. Normally called by collector. */
995 void GC_check_heap_proc()
997 # ifndef SMALL_CONFIG
999 GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
1001 GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
1004 GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
1007 #endif /* !SHORT_DBG_HDRS */
1010 GC_finalization_proc cl_fn;
1015 void * GC_make_closure(GC_finalization_proc fn, void * data)
1017 GC_PTR GC_make_closure(fn, data)
1018 GC_finalization_proc fn;
1022 struct closure * result =
1023 # ifdef DBG_HDRS_ALL
1024 (struct closure *) GC_debug_malloc(sizeof (struct closure),
1027 (struct closure *) GC_malloc(sizeof (struct closure));
1030 result -> cl_fn = fn;
1031 result -> cl_data = data;
1032 return((GC_PTR)result);
1036 void GC_debug_invoke_finalizer(void * obj, void * data)
1038 void GC_debug_invoke_finalizer(obj, data)
1043 register struct closure * cl = (struct closure *) data;
1045 (*(cl -> cl_fn))((GC_PTR)((char *)obj + sizeof(oh)), cl -> cl_data);
1048 /* Set ofn and ocd to reflect the values we got back. */
1049 static void store_old (obj, my_old_fn, my_old_cd, ofn, ocd)
1051 GC_finalization_proc my_old_fn;
1052 struct closure * my_old_cd;
1053 GC_finalization_proc *ofn;
1056 if (0 != my_old_fn) {
1057 if (my_old_fn != GC_debug_invoke_finalizer) {
1058 GC_err_printf1("Debuggable object at 0x%lx had non-debug finalizer.\n",
1060 /* This should probably be fatal. */
1062 if (ofn) *ofn = my_old_cd -> cl_fn;
1063 if (ocd) *ocd = my_old_cd -> cl_data;
1072 void GC_debug_register_finalizer(GC_PTR obj, GC_finalization_proc fn,
1073 GC_PTR cd, GC_finalization_proc *ofn,
1076 void GC_debug_register_finalizer(obj, fn, cd, ofn, ocd)
1078 GC_finalization_proc fn;
1080 GC_finalization_proc *ofn;
1084 GC_finalization_proc my_old_fn;
1086 ptr_t base = GC_base(obj);
1087 if (0 == base) return;
1088 if ((ptr_t)obj - base != sizeof(oh)) {
1090 "GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
1094 GC_register_finalizer(base, 0, 0, &my_old_fn, &my_old_cd);
1096 GC_register_finalizer(base, GC_debug_invoke_finalizer,
1097 GC_make_closure(fn,cd), &my_old_fn, &my_old_cd);
1099 store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1103 void GC_debug_register_finalizer_no_order
1104 (GC_PTR obj, GC_finalization_proc fn,
1105 GC_PTR cd, GC_finalization_proc *ofn,
1108 void GC_debug_register_finalizer_no_order
1109 (obj, fn, cd, ofn, ocd)
1111 GC_finalization_proc fn;
1113 GC_finalization_proc *ofn;
1117 GC_finalization_proc my_old_fn;
1119 ptr_t base = GC_base(obj);
1120 if (0 == base) return;
1121 if ((ptr_t)obj - base != sizeof(oh)) {
1123 "GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
1127 GC_register_finalizer_no_order(base, 0, 0, &my_old_fn, &my_old_cd);
1129 GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
1130 GC_make_closure(fn,cd), &my_old_fn,
1133 store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1137 void GC_debug_register_finalizer_ignore_self
1138 (GC_PTR obj, GC_finalization_proc fn,
1139 GC_PTR cd, GC_finalization_proc *ofn,
1142 void GC_debug_register_finalizer_ignore_self
1143 (obj, fn, cd, ofn, ocd)
1145 GC_finalization_proc fn;
1147 GC_finalization_proc *ofn;
1151 GC_finalization_proc my_old_fn;
1153 ptr_t base = GC_base(obj);
1154 if (0 == base) return;
1155 if ((ptr_t)obj - base != sizeof(oh)) {
1157 "GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
1161 GC_register_finalizer_ignore_self(base, 0, 0, &my_old_fn, &my_old_cd);
1163 GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
1164 GC_make_closure(fn,cd), &my_old_fn,
1167 store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1170 #ifdef GC_ADD_CALLER
1171 # define RA GC_RETURN_ADDR,
1176 GC_PTR GC_debug_malloc_replacement(lb)
1179 return GC_debug_malloc(lb, RA "unknown", 0);
1182 GC_PTR GC_debug_realloc_replacement(p, lb)
1186 return GC_debug_realloc(p, lb, RA "unknown", 0);