1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17: #include <errno.h>
18: #include <string.h>
19: #include "private/dbg_mlc.h"
20:
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));
25:
26:
27: #ifndef SHORT_DBG_HDRS
28:
29:
30:
31:
32:
33:
34:
35:
36:
37: GC_bool GC_has_other_debug_info(p)
38: ptr_t p;
39: {
40: register oh * ohdr = (oh *)p;
41: register ptr_t body = (ptr_t)(ohdr + 1);
42: register word sz = GC_size((ptr_t) ohdr);
43:
44: if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
45: || sz < DEBUG_BYTES + EXTRA_BYTES) {
46: return(FALSE);
47: }
48: if (ohdr -> oh_sz == sz) {
49:
50: return(FALSE);
51: }
52: if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
53: if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
54: return(TRUE);
55: }
56: return(FALSE);
57: }
58: #endif
59:
60: #ifdef KEEP_BACK_PTRS
61:
62: # include <stdlib.h>
63:
64: # if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
65: || defined(HPUX) || defined(IRIX5) || defined(OSF1)
66: # define RANDOM() random()
67: # else
68: # define RANDOM() (long)rand()
69: # endif
70:
71:
72:
73:
74:
75:
76:
77: void GC_store_back_pointer(ptr_t source, ptr_t dest)
78: {
79: if (GC_HAS_DEBUG_INFO(dest)) {
80: ((oh *)dest) -> oh_back_ptr = HIDE_BACK_PTR(source);
81: }
82: }
83:
84: void GC_marked_for_finalization(ptr_t dest) {
85: GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
86: }
87:
88:
89:
90:
91:
92:
93:
94: GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p)
95: {
96: oh * hdr = (oh *)GC_base(dest);
97: ptr_t bp;
98: ptr_t bp_base;
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;
104: # if ALIGNMENT == 1
105:
106:
107: {
108: ptr_t alternate_ptr = bp + 1;
109: ptr_t target = *(ptr_t *)bp;
110: ptr_t alternate_target = *(ptr_t *)alternate_ptr;
111:
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)) {
116: bp = alternate_ptr;
117: }
118: }
119: # endif
120: bp_base = GC_base(bp);
121: if (0 == bp_base) {
122: *base_p = bp;
123: *offset_p = 0;
124: return GC_REFD_FROM_ROOT;
125: } else {
126: if (GC_HAS_DEBUG_INFO(bp_base)) bp_base += sizeof(oh);
127: *base_p = bp_base;
128: *offset_p = bp - bp_base;
129: return GC_REFD_FROM_HEAP;
130: }
131: }
132:
133:
134:
135:
136: void *GC_generate_random_heap_address(void)
137: {
138: int i;
139: long heap_offset = RANDOM();
140: if (GC_heapsize > RAND_MAX) {
141: heap_offset *= RAND_MAX;
142: heap_offset += RANDOM();
143: }
144: heap_offset %= GC_heapsize;
145:
146:
147:
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;
152: } else {
153: heap_offset -= size;
154: }
155: }
156: ABORT("GC_generate_random_heap_address: size inconsistency");
157:
158: return 0;
159: }
160:
161:
162: void *GC_generate_random_valid_address(void)
163: {
164: ptr_t result;
165: ptr_t base;
166: for (;;) {
167: result = GC_generate_random_heap_address();
168: base = GC_base(result);
169: if (0 == base) continue;
170: if (!GC_is_marked(base)) continue;
171: return result;
172: }
173: }
174:
175:
176: void GC_print_backtrace(void *p)
177: {
178: void *current = p;
179: int i;
180: GC_ref_kind source;
181: size_t offset;
182: void *base;
183:
184: GC_print_heap_obj(GC_base(current));
185: GC_err_printf0("\n");
186: for (i = 0; ; ++i) {
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");
190: goto out;
191: }
192: if (GC_NO_SPACE == source) {
193: GC_err_printf0("No debug info in object: Can't find reference\n");
194: goto out;
195: }
196: GC_err_printf1("Reachable via %d levels of pointers from ",
197: (unsigned long)i);
198: switch(source) {
199: case GC_REFD_FROM_ROOT:
200: GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base);
201: goto out;
202: case GC_REFD_FROM_REG:
203: GC_err_printf0("root in register\n\n");
204: goto out;
205: case GC_FINALIZER_REFD:
206: GC_err_printf0("list of finalizable objects\n\n");
207: goto out;
208: case GC_REFD_FROM_HEAP:
209: GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
210:
211: GC_print_heap_obj(GC_base(base));
212: GC_err_printf0("\n");
213: break;
214: }
215: current = base;
216: }
217: out:;
218: }
219:
220:
221:
222: void GC_generate_random_backtrace_no_gc(void)
223: {
224: void * current;
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);
228: }
229:
230: void GC_generate_random_backtrace(void)
231: {
232: GC_gcollect();
233: GC_generate_random_backtrace_no_gc();
234: }
235:
236: #endif
237:
238: # define CROSSES_HBLK(p, sz) \
239: (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
240:
241:
242: ptr_t GC_store_debug_info(p, sz, string, integer)
243: register ptr_t p;
244: word sz;
245: GC_CONST char * string;
246: word integer;
247: {
248: register word * result = (word *)((oh *)p + 1);
249: DCL_LOCK_STATE;
250:
251:
252:
253:
254: LOCK();
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);
259: # endif
260: # ifdef MAKE_BACK_GRAPH
261: ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
262: # endif
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;
270: # endif
271: UNLOCK();
272: return((ptr_t)result);
273: }
274:
275: #ifdef DBG_HDRS_ALL
276:
277:
278: ptr_t GC_store_debug_info_inner(p, sz, string, integer)
279: register ptr_t p;
280: word sz;
281: char * string;
282: word integer;
283: {
284: register word * result = (word *)((oh *)p + 1);
285:
286:
287:
288:
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);
293: # endif
294: # ifdef MAKE_BACK_GRAPH
295: ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
296: # endif
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;
304: # endif
305: return((ptr_t)result);
306: }
307: #endif
308:
309: #ifndef SHORT_DBG_HDRS
310:
311:
312:
313: ptr_t GC_check_annotated_obj(ohdr)
314: register oh * ohdr;
315: {
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)));
320: }
321: if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
322: return((ptr_t)(&(ohdr -> oh_sf)));
323: }
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));
326: }
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)));
330: }
331: return(0);
332: }
333: #endif
334:
335: static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
336:
337: void GC_register_describe_type_fn(kind, fn)
338: int kind;
339: GC_describe_type_fn fn;
340: {
341: GC_describe_type_fns[kind] = fn;
342: }
343:
344:
345:
346: void GC_print_type(p)
347: ptr_t p;
348: {
349: hdr * hhdr = GC_find_header(p);
350: char buffer[GC_TYPE_DESCR_LEN + 1];
351: int kind = hhdr -> hb_obj_kind;
352:
353: if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
354:
355:
356: buffer[GC_TYPE_DESCR_LEN] = 0;
357: (GC_describe_type_fns[kind])(p, buffer);
358: GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
359: GC_err_puts(buffer);
360: } else {
361: switch(kind) {
362: case PTRFREE:
363: GC_err_puts("PTRFREE");
364: break;
365: case NORMAL:
366: GC_err_puts("NORMAL");
367: break;
368: case UNCOLLECTABLE:
369: GC_err_puts("UNCOLLECTABLE");
370: break;
371: # ifdef ATOMIC_UNCOLLECTABLE
372: case AUNCOLLECTABLE:
373: GC_err_puts("ATOMIC UNCOLLECTABLE");
374: break;
375: # endif
376: case STUBBORN:
377: GC_err_puts("STUBBORN");
378: break;
379: default:
380: GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr);
381: }
382: }
383: }
384:
385:
386:
387: void GC_print_obj(p)
388: ptr_t p;
389: {
390: register oh * ohdr = (oh *)GC_base(p);
391:
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));
397: # else
398: GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
399: (unsigned long)(ohdr -> oh_sz));
400: # endif
401: GC_print_type((ptr_t)(ohdr + 1));
402: GC_err_puts(")\n");
403: PRINT_CALL_CHAIN(ohdr);
404: }
405:
406: # if defined(__STDC__) || defined(__cplusplus)
407: void GC_debug_print_heap_obj_proc(ptr_t p)
408: # else
409: void GC_debug_print_heap_obj_proc(p)
410: ptr_t p;
411: # endif
412: {
413: GC_ASSERT(!I_HOLD_LOCK());
414: if (GC_HAS_DEBUG_INFO(p)) {
415: GC_print_obj(p);
416: } else {
417: GC_default_print_heap_obj_proc(p);
418: }
419: }
420:
421: #ifndef SHORT_DBG_HDRS
422: void GC_print_smashed_obj(p, clobbered_addr)
423: ptr_t p, clobbered_addr;
424: {
425: register oh * ohdr = (oh *)GC_base(p);
426:
427: GC_ASSERT(!I_HOLD_LOCK());
428: GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
429: (unsigned long)p);
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));
434: } else {
435: if (ohdr -> oh_string[0] == '\0') {
436: GC_err_puts("EMPTY(smashed?)");
437: } else {
438: GC_err_puts(ohdr -> oh_string);
439: }
440: GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
441: (unsigned long)(ohdr -> oh_sz));
442: PRINT_CALL_CHAIN(ohdr);
443: }
444: }
445: #endif
446:
447: void GC_check_heap_proc GC_PROTO((void));
448:
449: void GC_print_all_smashed_proc GC_PROTO((void));
450:
451: void GC_do_nothing() {}
452:
453: void GC_start_debugging()
454: {
455: # ifndef SHORT_DBG_HDRS
456: GC_check_heap = GC_check_heap_proc;
457: GC_print_all_smashed = GC_print_all_smashed_proc;
458: # else
459: GC_check_heap = GC_do_nothing;
460: GC_print_all_smashed = GC_do_nothing;
461: # endif
462: GC_print_heap_obj = GC_debug_print_heap_obj_proc;
463: GC_debugging_started = TRUE;
464: GC_register_displacement((word)sizeof(oh));
465: }
466:
467: size_t GC_debug_header_size = sizeof(oh);
468:
469: # if defined(__STDC__) || defined(__cplusplus)
470: void GC_debug_register_displacement(GC_word offset)
471: # else
472: void GC_debug_register_displacement(offset)
473: GC_word offset;
474: # endif
475: {
476: GC_register_displacement(offset);
477: GC_register_displacement((word)sizeof(oh) + offset);
478: }
479:
480: # ifdef __STDC__
481: GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
482: # else
483: GC_PTR GC_debug_malloc(lb, s, i)
484: size_t lb;
485: char * s;
486: int i;
487: # ifdef GC_ADD_CALLER
488: --> GC_ADD_CALLER not implemented for K&R C
489: # endif
490: # endif
491: {
492: GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
493:
494: if (result == 0) {
495: GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
496: (unsigned long) lb);
497: GC_err_puts(s);
498: GC_err_printf1(":%ld)\n", (unsigned long)i);
499: return(0);
500: }
501: if (!GC_debugging_started) {
502: GC_start_debugging();
503: }
504: ADD_CALL_CHAIN(result, ra);
505: return (GC_store_debug_info(result, (word)lb, s, (word)i));
506: }
507:
508: # ifdef __STDC__
509: GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
510: # else
511: GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
512: size_t lb;
513: char * s;
514: int i;
515: # ifdef GC_ADD_CALLER
516: --> GC_ADD_CALLER not implemented for K&R C
517: # endif
518: # endif
519: {
520: GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
521:
522: if (result == 0) {
523: GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
524: (unsigned long) lb);
525: GC_err_puts(s);
526: GC_err_printf1(":%ld)\n", (unsigned long)i);
527: return(0);
528: }
529: if (!GC_debugging_started) {
530: GC_start_debugging();
531: }
532: ADD_CALL_CHAIN(result, ra);
533: return (GC_store_debug_info(result, (word)lb, s, (word)i));
534: }
535:
536: # ifdef __STDC__
537: GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
538: # else
539: GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
540: size_t lb;
541: char * s;
542: int i;
543: # ifdef GC_ADD_CALLER
544: --> GC_ADD_CALLER not implemented for K&R C
545: # endif
546: # endif
547: {
548: GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
549:
550: if (result == 0) {
551: GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
552: " returning NIL (", (unsigned long) lb);
553: GC_err_puts(s);
554: GC_err_printf1(":%ld)\n", (unsigned long)i);
555: return(0);
556: }
557: if (!GC_debugging_started) {