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