OSDN Git Service

079e43be7cb45317f577f2e6a5d6d1c29711a8e2
[pf3gnuchains/gcc-fork.git] / 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  *
6  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
8  *
9  * Permission is hereby granted to use or copy this program
10  * for any purpose,  provided the above notices are retained on all copies.
11  * Permission to modify the code and to distribute modified code is granted,
12  * provided the above notices are retained, and a notice that the code was
13  * modified is included with the above copyright notice.
14  */
15 /* Boehm, October 9, 1995 1:16 pm PDT */
16 # include "gc_priv.h"
17
18 /* Do we want to and know how to save the call stack at the time of     */
19 /* an allocation?  How much space do we want to use in each object?     */
20
21 # define START_FLAG ((word)0xfedcedcb)
22 # define END_FLAG ((word)0xbcdecdef)
23         /* Stored both one past the end of user object, and one before  */
24         /* the end of the object as seen by the allocator.              */
25
26
27 /* Object header */
28 typedef struct {
29     char * oh_string;           /* object descriptor string     */
30     word oh_int;                /* object descriptor integers   */
31 #   ifdef NEED_CALLINFO
32       struct callinfo oh_ci[NFRAMES];
33 #   endif
34     word oh_sz;                 /* Original malloc arg.         */
35     word oh_sf;                 /* start flag */
36 } oh;
37 /* The size of the above structure is assumed not to dealign things,    */
38 /* and to be a multiple of the word length.                             */
39
40 #define DEBUG_BYTES (sizeof (oh) + sizeof (word))
41 #undef ROUNDED_UP_WORDS
42 #define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
43
44
45 #ifdef SAVE_CALL_CHAIN
46 #   define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
47 #   define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
48 #else
49 # ifdef GC_ADD_CALLER
50 #   define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
51 #   define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
52 # else
53 #   define ADD_CALL_CHAIN(base, ra)
54 #   define PRINT_CALL_CHAIN(base)
55 # endif
56 #endif
57
58 /* Check whether object with base pointer p has debugging info  */ 
59 /* p is assumed to point to a legitimate object in our part     */
60 /* of the heap.                                                 */
61 GC_bool GC_has_debug_info(p)
62 ptr_t p;
63 {
64     register oh * ohdr = (oh *)p;
65     register ptr_t body = (ptr_t)(ohdr + 1);
66     register word sz = GC_size((ptr_t) ohdr);
67     
68     if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
69         || sz < sizeof (oh)) {
70         return(FALSE);
71     }
72     if (ohdr -> oh_sz == sz) {
73         /* Object may have had debug info, but has been deallocated     */
74         return(FALSE);
75     }
76     if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
77     if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
78         return(TRUE);
79     }
80     return(FALSE);
81 }
82
83 /* Return start of object that might have debugging info.  */
84 ptr_t GC_debug_object_start(p)
85 ptr_t p;
86 {
87     register word * result = (word *)((oh *)p + 1);
88     if (! GC_has_debug_info(p))
89         return(p);
90     return((ptr_t)result);
91 }
92
93 /* Store debugging info into p.  Return displaced pointer. */
94 /* Assumes we don't hold allocation lock.                  */
95 ptr_t GC_store_debug_info(p, sz, string, integer)
96 register ptr_t p;       /* base pointer */
97 word sz;        /* bytes */
98 char * string;
99 word integer;
100 {
101     register word * result = (word *)((oh *)p + 1);
102     DCL_LOCK_STATE;
103     
104     /* There is some argument that we should dissble signals here.      */
105     /* But that's expensive.  And this way things should only appear    */
106     /* inconsistent while we're in the handler.                         */
107     LOCK();
108     ((oh *)p) -> oh_string = string;
109     ((oh *)p) -> oh_int = integer;
110     ((oh *)p) -> oh_sz = sz;
111     ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
112     ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
113          result[ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
114     UNLOCK();
115     return((ptr_t)result);
116 }
117
118 /* Check the object with debugging info at p            */
119 /* return NIL if it's OK.  Else return clobbered        */
120 /* address.                                             */
121 ptr_t GC_check_annotated_obj(ohdr)
122 register oh * ohdr;
123 {
124     register ptr_t body = (ptr_t)(ohdr + 1);
125     register word gc_sz = GC_size((ptr_t)ohdr);
126     if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
127         return((ptr_t)(&(ohdr -> oh_sz)));
128     }
129     if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
130         return((ptr_t)(&(ohdr -> oh_sf)));
131     }
132     if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
133         return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1));
134     }
135     if (((word *)body)[ROUNDED_UP_WORDS(ohdr -> oh_sz)]
136         != (END_FLAG ^ (word)body)) {
137         return((ptr_t)((word *)body + ROUNDED_UP_WORDS(ohdr -> oh_sz)));
138     }
139     return(0);
140 }
141
142 void GC_print_obj(p)
143 ptr_t p;
144 {
145     register oh * ohdr = (oh *)GC_base(p);
146     
147     GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh));
148     GC_err_puts(ohdr -> oh_string);
149     GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
150                                       (unsigned long)(ohdr -> oh_sz));
151     PRINT_CALL_CHAIN(ohdr);
152 }
153
154 void GC_debug_print_heap_obj_proc(p)
155 ptr_t p;
156 {
157     if (GC_has_debug_info(p)) {
158         GC_print_obj(p);
159     } else {
160         GC_default_print_heap_obj_proc(p);
161     }
162 }
163
164 void GC_print_smashed_obj(p, clobbered_addr)
165 ptr_t p, clobbered_addr;
166 {
167     register oh * ohdr = (oh *)GC_base(p);
168     
169     GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
170                                                 (unsigned long)p);
171     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
172         || ohdr -> oh_string == 0) {
173         GC_err_printf1("<smashed>, appr. sz = %ld)\n",
174                        GC_size((ptr_t)ohdr) - DEBUG_BYTES);
175     } else {
176         if (ohdr -> oh_string[0] == '\0') {
177             GC_err_puts("EMPTY(smashed?)");
178         } else {
179             GC_err_puts(ohdr -> oh_string);
180         }
181         GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
182                                           (unsigned long)(ohdr -> oh_sz));
183         PRINT_CALL_CHAIN(ohdr);
184     }
185 }
186
187 void GC_check_heap_proc();
188
189 void GC_start_debugging()
190 {
191     GC_check_heap = GC_check_heap_proc;
192     GC_print_heap_obj = GC_debug_print_heap_obj_proc;
193     GC_debugging_started = TRUE;
194     GC_register_displacement((word)sizeof(oh));
195 }
196
197 # if defined(__STDC__) || defined(__cplusplus)
198     void GC_debug_register_displacement(GC_word offset)
199 # else
200     void GC_debug_register_displacement(offset) 
201     GC_word offset;
202 # endif
203 {
204     GC_register_displacement(offset);
205     GC_register_displacement((word)sizeof(oh) + offset);
206 }
207
208 # ifdef GC_ADD_CALLER
209 #   define EXTRA_ARGS word ra, char * s, int i
210 #   define OPT_RA ra,
211 # else
212 #   define EXTRA_ARGS char * s, int i
213 #   define OPT_RA
214 # endif
215
216 # ifdef __STDC__
217     GC_PTR GC_debug_malloc(size_t lb, EXTRA_ARGS)
218 # else
219     GC_PTR GC_debug_malloc(lb, s, i)
220     size_t lb;
221     char * s;
222     int i;
223 #   ifdef GC_ADD_CALLER
224         --> GC_ADD_CALLER not implemented for K&R C
225 #   endif
226 # endif
227 {
228     GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
229     
230     if (result == 0) {
231         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
232                        (unsigned long) lb);
233         GC_err_puts(s);
234         GC_err_printf1(":%ld)\n", (unsigned long)i);
235         return(0);
236     }
237     if (!GC_debugging_started) {
238         GC_start_debugging();
239     }
240     ADD_CALL_CHAIN(result, ra);
241     return (GC_store_debug_info(result, (word)lb, s, (word)i));
242 }
243
244 # ifdef __STDC__
245     GC_PTR GC_debug_generic_malloc(size_t lb, int k, EXTRA_ARGS)
246 # else
247     GC_PTR GC_debug_malloc(lb, k, s, i)
248     size_t lb;
249     int k;
250     char * s;
251     int i;
252 #   ifdef GC_ADD_CALLER
253         --> GC_ADD_CALLER not implemented for K&R C
254 #   endif
255 # endif
256 {
257     GC_PTR result = GC_generic_malloc(lb + DEBUG_BYTES, k);
258     
259     if (result == 0) {
260         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
261                        (unsigned long) lb);
262         GC_err_puts(s);
263         GC_err_printf1(":%ld)\n", (unsigned long)i);
264         return(0);
265     }
266     if (!GC_debugging_started) {
267         GC_start_debugging();
268     }
269     ADD_CALL_CHAIN(result, ra);
270     return (GC_store_debug_info(result, (word)lb, s, (word)i));
271 }
272
273 #ifdef STUBBORN_ALLOC
274 # ifdef __STDC__
275     GC_PTR GC_debug_malloc_stubborn(size_t lb, EXTRA_ARGS)
276 # else
277     GC_PTR GC_debug_malloc_stubborn(lb, s, i)
278     size_t lb;
279     char * s;
280     int i;
281 # endif
282 {
283     GC_PTR result = GC_malloc_stubborn(lb + DEBUG_BYTES);
284     
285     if (result == 0) {
286         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
287                        (unsigned long) lb);
288         GC_err_puts(s);
289         GC_err_printf1(":%ld)\n", (unsigned long)i);
290         return(0);
291     }
292     if (!GC_debugging_started) {
293         GC_start_debugging();
294     }
295     ADD_CALL_CHAIN(result, ra);
296     return (GC_store_debug_info(result, (word)lb, s, (word)i));
297 }
298
299 void GC_debug_change_stubborn(p)
300 GC_PTR p;
301 {
302     register GC_PTR q = GC_base(p);
303     register hdr * hhdr;
304     
305     if (q == 0) {
306         GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
307                        (unsigned long) p);
308         ABORT("GC_debug_change_stubborn: bad arg");
309     }
310     hhdr = HDR(q);
311     if (hhdr -> hb_obj_kind != STUBBORN) {
312         GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
313                        (unsigned long) p);
314         ABORT("GC_debug_change_stubborn: arg not stubborn");
315     }
316     GC_change_stubborn(q);
317 }
318
319 void GC_debug_end_stubborn_change(p)
320 GC_PTR p;
321 {
322     register GC_PTR q = GC_base(p);
323     register hdr * hhdr;
324     
325     if (q == 0) {
326         GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
327                        (unsigned long) p);
328         ABORT("GC_debug_end_stubborn_change: bad arg");
329     }
330     hhdr = HDR(q);
331     if (hhdr -> hb_obj_kind != STUBBORN) {
332         GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
333                        (unsigned long) p);
334         ABORT("GC_debug_end_stubborn_change: arg not stubborn");
335     }
336     GC_end_stubborn_change(q);
337 }
338
339 #endif /* STUBBORN_ALLOC */
340
341 # ifdef __STDC__
342     GC_PTR GC_debug_malloc_atomic(size_t lb, EXTRA_ARGS)
343 # else
344     GC_PTR GC_debug_malloc_atomic(lb, s, i)
345     size_t lb;
346     char * s;
347     int i;
348 # endif
349 {
350     GC_PTR result = GC_malloc_atomic(lb + DEBUG_BYTES);
351     
352     if (result == 0) {
353         GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
354                       (unsigned long) lb);
355         GC_err_puts(s);
356         GC_err_printf1(":%ld)\n", (unsigned long)i);
357         return(0);
358     }
359     if (!GC_debugging_started) {
360         GC_start_debugging();
361     }
362     ADD_CALL_CHAIN(result, ra);
363     return (GC_store_debug_info(result, (word)lb, s, (word)i));
364 }
365
366 # ifdef __STDC__
367     GC_PTR GC_debug_malloc_uncollectable(size_t lb, EXTRA_ARGS)
368 # else
369     GC_PTR GC_debug_malloc_uncollectable(lb, s, i)
370     size_t lb;
371     char * s;
372     int i;
373 # endif
374 {
375     GC_PTR result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
376     
377     if (result == 0) {
378         GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
379                       (unsigned long) lb);
380         GC_err_puts(s);
381         GC_err_printf1(":%ld)\n", (unsigned long)i);
382         return(0);
383     }
384     if (!GC_debugging_started) {
385         GC_start_debugging();
386     }
387     ADD_CALL_CHAIN(result, ra);
388     return (GC_store_debug_info(result, (word)lb, s, (word)i));
389 }
390
391 #ifdef ATOMIC_UNCOLLECTABLE
392 # ifdef __STDC__
393     GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, EXTRA_ARGS)
394 # else
395     GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i)
396     size_t lb;
397     char * s;
398     int i;
399 # endif
400 {
401     GC_PTR result = GC_malloc_atomic_uncollectable(lb + DEBUG_BYTES);
402     
403     if (result == 0) {
404         GC_err_printf1(
405                 "GC_debug_malloc_atomic_uncollectable(%ld) returning NIL (",
406                 (unsigned long) lb);
407         GC_err_puts(s);
408         GC_err_printf1(":%ld)\n", (unsigned long)i);
409         return(0);
410     }
411     if (!GC_debugging_started) {
412         GC_start_debugging();
413     }
414     ADD_CALL_CHAIN(result, ra);
415     return (GC_store_debug_info(result, (word)lb, s, (word)i));
416 }
417 #endif /* ATOMIC_UNCOLLECTABLE */
418
419 # ifdef __STDC__
420     void GC_debug_free(GC_PTR p)
421 # else
422     void GC_debug_free(p)
423     GC_PTR p;
424 # endif
425 {
426     register GC_PTR base = GC_base(p);
427     register ptr_t clobbered;
428     
429     if (base == 0) {
430         GC_err_printf1("Attempt to free invalid pointer %lx\n",
431                        (unsigned long)p);
432         if (p != 0) ABORT("free(invalid pointer)");
433     }
434     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
435         GC_err_printf1(
436                   "GC_debug_free called on pointer %lx wo debugging info\n",
437                   (unsigned long)p);
438     } else {
439       clobbered = GC_check_annotated_obj((oh *)base);
440       if (clobbered != 0) {
441         if (((oh *)base) -> oh_sz == GC_size(base)) {
442             GC_err_printf0(
443                   "GC_debug_free: found previously deallocated (?) object at ");
444         } else {
445             GC_err_printf0("GC_debug_free: found smashed object at ");
446         }
447         GC_print_smashed_obj(p, clobbered);
448       }
449       /* Invalidate size */
450       ((oh *)base) -> oh_sz = GC_size(base);
451     }
452 #   ifdef FIND_LEAK
453         GC_free(base);
454 #   else
455         {
456             register hdr * hhdr = HDR(p);
457             GC_bool uncollectable = FALSE;
458
459             if (hhdr ->  hb_obj_kind == UNCOLLECTABLE) {
460                 uncollectable = TRUE;
461             }
462 #           ifdef ATOMIC_UNCOLLECTABLE
463                 if (hhdr ->  hb_obj_kind == AUNCOLLECTABLE) {
464                     uncollectable = TRUE;
465                 }
466 #           endif
467             if (uncollectable) GC_free(base);
468         }
469 #   endif
470 }
471
472 # ifdef __STDC__
473     GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, EXTRA_ARGS)
474 # else
475     GC_PTR GC_debug_realloc(p, lb, s, i)
476     GC_PTR p;
477     size_t lb;
478     char *s;
479     int i;
480 # endif
481 {
482     register GC_PTR base = GC_base(p);
483     register ptr_t clobbered;
484     register GC_PTR result;
485     register size_t copy_sz = lb;
486     register size_t old_sz;
487     register hdr * hhdr;
488     
489     if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i));
490     if (base == 0) {
491         GC_err_printf1(
492               "Attempt to reallocate invalid pointer %lx\n", (unsigned long)p);
493         ABORT("realloc(invalid pointer)");
494     }
495     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
496         GC_err_printf1(
497                 "GC_debug_realloc called on pointer %lx wo debugging info\n",
498                 (unsigned long)p);
499         return(GC_realloc(p, lb));
500     }
501     hhdr = HDR(base);
502     switch (hhdr -> hb_obj_kind) {
503 #    ifdef STUBBORN_ALLOC
504       case STUBBORN:
505         result = GC_debug_malloc_stubborn(lb, OPT_RA s, i);
506         break;
507 #    endif
508       case NORMAL:
509         result = GC_debug_malloc(lb, OPT_RA s, i);
510         break;
511       case PTRFREE:
512         result = GC_debug_malloc_atomic(lb, OPT_RA s, i);
513         break;
514       case UNCOLLECTABLE:
515         result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
516         break;
517 #    ifdef ATOMIC_UNCOLLECTABLE
518       case AUNCOLLECTABLE:
519         result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
520         break;
521 #    endif
522       default:
523         GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
524         ABORT("bad kind");
525     }
526     clobbered = GC_check_annotated_obj((oh *)base);
527     if (clobbered != 0) {
528         GC_err_printf0("GC_debug_realloc: found smashed object at ");
529         GC_print_smashed_obj(p, clobbered);
530     }
531     old_sz = ((oh *)base) -> oh_sz;
532     if (old_sz < copy_sz) copy_sz = old_sz;
533     if (result == 0) return(0);
534     BCOPY(p, result,  copy_sz);
535     GC_debug_free(p);
536     return(result);
537 }
538
539 /* Check all marked objects in the given block for validity */
540 /*ARGSUSED*/
541 void GC_check_heap_block(hbp, dummy)
542 register struct hblk *hbp;      /* ptr to current heap block            */
543 word dummy;
544 {
545     register struct hblkhdr * hhdr = HDR(hbp);
546     register word sz = hhdr -> hb_sz;
547     register int word_no;
548     register word *p, *plim;
549     
550     p = (word *)(hbp->hb_body);
551     word_no = HDR_WORDS;
552     if (sz > MAXOBJSZ) {
553         plim = p;
554     } else {
555         plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz));
556     }
557     /* go through all words in block */
558         while( p <= plim ) {
559             if( mark_bit_from_hdr(hhdr, word_no)
560                 && GC_has_debug_info((ptr_t)p)) {
561                 ptr_t clobbered = GC_check_annotated_obj((oh *)p);
562                 
563                 if (clobbered != 0) {
564                     GC_err_printf0(
565                         "GC_check_heap_block: found smashed object at ");
566                     GC_print_smashed_obj((ptr_t)p, clobbered);
567                 }
568             }
569             word_no += sz;
570             p += sz;
571         }
572 }
573
574
575 /* This assumes that all accessible objects are marked, and that        */
576 /* I hold the allocation lock.  Normally called by collector.           */
577 void GC_check_heap_proc()
578 {
579 #   ifndef SMALL_CONFIG
580         if (sizeof(oh) & (2 * sizeof(word) - 1) != 0) {
581             ABORT("Alignment problem: object header has inappropriate size\n");
582         }
583 #   endif
584     GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
585 }
586
587 struct closure {
588     GC_finalization_proc cl_fn;
589     GC_PTR cl_data;
590 };
591
592 # ifdef __STDC__
593     void * GC_make_closure(GC_finalization_proc fn, void * data)
594 # else
595     GC_PTR GC_make_closure(fn, data)
596     GC_finalization_proc fn;
597     GC_PTR data;
598 # endif
599 {
600     struct closure * result =
601                 (struct closure *) GC_malloc(sizeof (struct closure));
602     
603     result -> cl_fn = fn;
604     result -> cl_data = data;
605     return((GC_PTR)result);
606 }
607
608 # ifdef __STDC__
609     void GC_debug_invoke_finalizer(void * obj, void * data)
610 # else
611     void GC_debug_invoke_finalizer(obj, data)
612     char * obj;
613     char * data;
614 # endif
615 {
616     register struct closure * cl = (struct closure *) data;
617     
618     (*(cl -> cl_fn))((GC_PTR)((char *)obj + sizeof(oh)), cl -> cl_data);
619
620
621
622 # ifdef __STDC__
623     void GC_debug_register_finalizer(GC_PTR obj, GC_finalization_proc fn,
624                                      GC_PTR cd, GC_finalization_proc *ofn,
625                                      GC_PTR *ocd)
626 # else
627     void GC_debug_register_finalizer(obj, fn, cd, ofn, ocd)
628     GC_PTR obj;
629     GC_finalization_proc fn;
630     GC_PTR cd;
631     GC_finalization_proc *ofn;
632     GC_PTR *ocd;
633 # endif
634 {
635     ptr_t base = GC_base(obj);
636     if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
637         GC_err_printf1(
638             "GC_register_finalizer called with non-base-pointer 0x%lx\n",
639             obj);
640     }
641     GC_register_finalizer(base, GC_debug_invoke_finalizer,
642                           GC_make_closure(fn,cd), ofn, ocd);
643 }
644
645 # ifdef __STDC__
646     void GC_debug_register_finalizer_ignore_self
647                                     (GC_PTR obj, GC_finalization_proc fn,
648                                      GC_PTR cd, GC_finalization_proc *ofn,
649                                      GC_PTR *ocd)
650 # else
651     void GC_debug_register_finalizer_ignore_self
652                                     (obj, fn, cd, ofn, ocd)
653     GC_PTR obj;
654     GC_finalization_proc fn;
655     GC_PTR cd;
656     GC_finalization_proc *ofn;
657     GC_PTR *ocd;
658 # endif
659 {
660     ptr_t base = GC_base(obj);
661     if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
662         GC_err_printf1(
663             "GC_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
664             obj);
665     }
666     GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
667                                       GC_make_closure(fn,cd), ofn, ocd);
668 }
669
670 # ifdef __STDC__
671     void GC_debug_register_finalizer_no_order
672                                     (GC_PTR obj, GC_finalization_proc fn,
673                                      GC_PTR cd, GC_finalization_proc *ofn,
674                                      GC_PTR *ocd)
675 # else
676     void GC_debug_register_finalizer_no_order
677                                     (obj, fn, cd, ofn, ocd)
678     GC_PTR obj;
679     GC_finalization_proc fn;
680     GC_PTR cd;
681     GC_finalization_proc *ofn;
682     GC_PTR *ocd;
683 # endif
684 {
685     ptr_t base = GC_base(obj);
686     if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
687         GC_err_printf1(
688             "GC_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
689             obj);
690     }
691     GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
692                                       GC_make_closure(fn,cd), ofn, ocd);
693 }