home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / SYSTEM / GC / DBG_MLC.C < prev    next >
C/C++ Source or Header  |  1994-10-27  |  14KB  |  495 lines

  1. /* 
  2.  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3.  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  4.  *
  5.  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6.  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  7.  *
  8.  * Permission is hereby granted to use or copy this program
  9.  * for any purpose,  provided the above notices are retained on all copies.
  10.  * Permission to modify the code and to distribute modified code is granted,
  11.  * provided the above notices are retained, and a notice that the code was
  12.  * modified is included with the above copyright notice.
  13.  */
  14. /* Boehm, October 27, 1994 9:57 am PDT */
  15. # include "gc_priv.h"
  16.  
  17. /* Do we want to and know how to save the call stack at the time of    */
  18. /* an allocation?  How much space do we want to use in each object?    */
  19.  
  20. # define START_FLAG ((word)0xfedcedcb)
  21. # define END_FLAG ((word)0xbcdecdef)
  22.     /* Stored both one past the end of user object, and one before    */
  23.     /* the end of the object as seen by the allocator.        */
  24.  
  25.  
  26. /* Object header */
  27. typedef struct {
  28.     char * oh_string;        /* object descriptor string    */
  29.     word oh_int;        /* object descriptor integers    */
  30. #   ifdef SAVE_CALL_CHAIN
  31.       struct callinfo oh_ci[NFRAMES];
  32. #   endif
  33.     word oh_sz;            /* Original malloc arg.        */
  34.     word oh_sf;            /* start flag */
  35. } oh;
  36. /* The size of the above structure is assumed not to dealign things,    */
  37. /* and to be a multiple of the word length.                */
  38.  
  39. #define DEBUG_BYTES (sizeof (oh) + sizeof (word))
  40. #undef ROUNDED_UP_WORDS
  41. #define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
  42.  
  43.  
  44. #ifdef SAVE_CALL_CHAIN
  45. #   define ADD_CALL_CHAIN(base) GC_save_callers(((oh *)(base)) -> oh_ci)
  46. #   define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
  47. #else
  48. #   define ADD_CALL_CHAIN(base)
  49. #   define PRINT_CALL_CHAIN(base)
  50. #endif
  51.  
  52. /* Check whether object with base pointer p has debugging info    */ 
  53. /* p is assumed to point to a legitimate object in our part    */
  54. /* of the heap.                            */
  55. bool GC_has_debug_info(p)
  56. ptr_t p;
  57. {
  58.     register oh * ohdr = (oh *)p;
  59.     register ptr_t body = (ptr_t)(ohdr + 1);
  60.     register word sz = GC_size((ptr_t) ohdr);
  61.     
  62.     if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
  63.         || sz < sizeof (oh)) {
  64.         return(FALSE);
  65.     }
  66.     if (ohdr -> oh_sz == sz) {
  67.         /* Object may have had debug info, but has been deallocated    */
  68.         return(FALSE);
  69.     }
  70.     if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
  71.     if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
  72.         return(TRUE);
  73.     }
  74.     return(FALSE);
  75. }
  76.  
  77. /* Store debugging info into p.  Return displaced pointer. */
  78. /* Assumes we don't hold allocation lock.           */
  79. ptr_t GC_store_debug_info(p, sz, string, integer)
  80. register ptr_t p;    /* base pointer */
  81. word sz;     /* bytes */
  82. char * string;
  83. word integer;
  84. {
  85.     register word * result = (word *)((oh *)p + 1);
  86.     DCL_LOCK_STATE;
  87.     
  88.     /* There is some argument that we should dissble signals here.    */
  89.     /* But that's expensive.  And this way things should only appear    */
  90.     /* inconsistent while we're in the handler.                */
  91.     LOCK();
  92.     ((oh *)p) -> oh_string = string;
  93.     ((oh *)p) -> oh_int = integer;
  94.     ((oh *)p) -> oh_sz = sz;
  95.     ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
  96.     ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
  97.          result[ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
  98.     UNLOCK();
  99.     return((ptr_t)result);
  100. }
  101.  
  102. /* Check the object with debugging info at p         */
  103. /* return NIL if it's OK.  Else return clobbered    */
  104. /* address.                        */
  105. ptr_t GC_check_annotated_obj(ohdr)
  106. register oh * ohdr;
  107. {
  108.     register ptr_t body = (ptr_t)(ohdr + 1);
  109.     register word gc_sz = GC_size((ptr_t)ohdr);
  110.     if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
  111.         return((ptr_t)(&(ohdr -> oh_sz)));
  112.     }
  113.     if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
  114.         return((ptr_t)(&(ohdr -> oh_sf)));
  115.     }
  116.     if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
  117.         return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1));
  118.     }
  119.     if (((word *)body)[ROUNDED_UP_WORDS(ohdr -> oh_sz)]
  120.         != (END_FLAG ^ (word)body)) {
  121.         return((ptr_t)((word *)body + ROUNDED_UP_WORDS(ohdr -> oh_sz)));
  122.     }
  123.     return(0);
  124. }
  125.  
  126. void GC_print_obj(p)
  127. ptr_t p;
  128. {
  129.     register oh * ohdr = (oh *)GC_base(p);
  130.     
  131.     GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh));
  132.     GC_err_puts(ohdr -> oh_string);
  133.     GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
  134.                           (unsigned long)(ohdr -> oh_sz));
  135.     PRINT_CALL_CHAIN(ohdr);
  136. }
  137. void GC_print_smashed_obj(p, clobbered_addr)
  138. ptr_t p, clobbered_addr;
  139. {
  140.     register oh * ohdr = (oh *)GC_base(p);
  141.     
  142.     GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
  143.                                 (unsigned long)p);
  144.     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
  145.         || ohdr -> oh_string == 0) {
  146.         GC_err_printf1("<smashed>, appr. sz = %ld)\n",
  147.                    GC_size((ptr_t)ohdr) - DEBUG_BYTES);
  148.     } else {
  149.         if (ohdr -> oh_string[0] == '\0') {
  150.             GC_err_puts("EMPTY(smashed?)");
  151.         } else {
  152.             GC_err_puts(ohdr -> oh_string);
  153.         }
  154.         GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
  155.                               (unsigned long)(ohdr -> oh_sz));
  156.     }
  157. }
  158.  
  159. void GC_check_heap_proc();
  160.  
  161. void GC_start_debugging()
  162. {
  163.     GC_check_heap = GC_check_heap_proc;
  164.     GC_debugging_started = TRUE;
  165.     GC_register_displacement((word)sizeof(oh));
  166. }
  167.  
  168. void GC_debug_register_displacement(n)
  169. word n;
  170. {
  171.     GC_register_displacement(n);
  172.     GC_register_displacement((word)sizeof(oh) + n);
  173. }
  174.  
  175. # ifdef __STDC__
  176.     extern_ptr_t GC_debug_malloc(size_t lb, char * s, int i)
  177. # else
  178.     extern_ptr_t GC_debug_malloc(lb, s, i)
  179.     size_t lb;
  180.     char * s;
  181.     int i;
  182. # endif
  183. {
  184.     extern_ptr_t result = GC_malloc(lb + DEBUG_BYTES);
  185.     
  186.     if (result == 0) {
  187.         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
  188.                    (unsigned long) lb);
  189.         GC_err_puts(s);
  190.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  191.         return(0);
  192.     }
  193.     if (!GC_debugging_started) {
  194.         GC_start_debugging();
  195.     }
  196.     ADD_CALL_CHAIN(result);
  197.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  198. }
  199.  
  200. #ifdef STUBBORN_ALLOC
  201. # ifdef __STDC__
  202.     extern_ptr_t GC_debug_malloc_stubborn(size_t lb, char * s, int i)
  203. # else
  204.     extern_ptr_t GC_debug_malloc_stubborn(lb, s, i)
  205.     size_t lb;
  206.     char * s;
  207.     int i;
  208. # endif
  209. {
  210.     extern_ptr_t result = GC_malloc_stubborn(lb + DEBUG_BYTES);
  211.     
  212.     if (result == 0) {
  213.         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
  214.                    (unsigned long) lb);
  215.         GC_err_puts(s);
  216.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  217.         return(0);
  218.     }
  219.     if (!GC_debugging_started) {
  220.         GC_start_debugging();
  221.     }
  222.     ADD_CALL_CHAIN(result);
  223.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  224. }
  225.  
  226. void GC_debug_change_stubborn(p)
  227. extern_ptr_t p;
  228. {
  229.     register extern_ptr_t q = GC_base(p);
  230.     register hdr * hhdr;
  231.     
  232.     if (q == 0) {
  233.         GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
  234.                    (unsigned long) p);
  235.         ABORT("GC_debug_change_stubborn: bad arg");
  236.     }
  237.     hhdr = HDR(q);
  238.     if (hhdr -> hb_obj_kind != STUBBORN) {
  239.         GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
  240.                    (unsigned long) p);
  241.         ABORT("GC_debug_change_stubborn: arg not stubborn");
  242.     }
  243.     GC_change_stubborn(q);
  244. }
  245.  
  246. void GC_debug_end_stubborn_change(p)
  247. extern_ptr_t p;
  248. {
  249.     register extern_ptr_t q = GC_base(p);
  250.     register hdr * hhdr;
  251.     
  252.     if (q == 0) {
  253.         GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
  254.                    (unsigned long) p);
  255.         ABORT("GC_debug_end_stubborn_change: bad arg");
  256.     }
  257.     hhdr = HDR(q);
  258.     if (hhdr -> hb_obj_kind != STUBBORN) {
  259.         GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
  260.                    (unsigned long) p);
  261.         ABORT("GC_debug_end_stubborn_change: arg not stubborn");
  262.     }
  263.     GC_end_stubborn_change(q);
  264. }
  265.  
  266. #endif /* STUBBORN_ALLOC */
  267.  
  268. # ifdef __STDC__
  269.     extern_ptr_t GC_debug_malloc_atomic(size_t lb, char * s, int i)
  270. # else
  271.     extern_ptr_t GC_debug_malloc_atomic(lb, s, i)
  272.     size_t lb;
  273.     char * s;
  274.     int i;
  275. # endif
  276. {
  277.     extern_ptr_t result = GC_malloc_atomic(lb + DEBUG_BYTES);
  278.     
  279.     if (result == 0) {
  280.         GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
  281.                   (unsigned long) lb);
  282.         GC_err_puts(s);
  283.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  284.         return(0);
  285.     }
  286.     if (!GC_debugging_started) {
  287.         GC_start_debugging();
  288.     }
  289.     ADD_CALL_CHAIN(result);
  290.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  291. }
  292.  
  293. # ifdef __STDC__
  294.     extern_ptr_t GC_debug_malloc_uncollectable(size_t lb, char * s, int i)
  295. # else
  296.     extern_ptr_t GC_debug_malloc_uncollectable(lb, s, i)
  297.     size_t lb;
  298.     char * s;
  299.     int i;
  300. # endif
  301. {
  302.     extern_ptr_t result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
  303.     
  304.     if (result == 0) {
  305.         GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
  306.                   (unsigned long) lb);
  307.         GC_err_puts(s);
  308.         GC_err_printf1(":%ld)\n", (unsigned long)i);
  309.         return(0);
  310.     }
  311.     if (!GC_debugging_started) {
  312.         GC_start_debugging();
  313.     }
  314.     ADD_CALL_CHAIN(result);
  315.     return (GC_store_debug_info(result, (word)lb, s, (word)i));
  316. }
  317.  
  318.  
  319. # ifdef __STDC__
  320.     void GC_debug_free(extern_ptr_t p)
  321. # else
  322.     void GC_debug_free(p)
  323.     extern_ptr_t p;
  324. # endif
  325. {
  326.     register extern_ptr_t base = GC_base(p);
  327.     register ptr_t clobbered;
  328.     
  329.     if (base == 0) {
  330.         GC_err_printf1("Attempt to free invalid pointer %lx\n",
  331.                    (unsigned long)p);
  332.         if (p != 0) ABORT("free(invalid pointer)");
  333.     }
  334.     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
  335.         GC_err_printf1(
  336.               "GC_debug_free called on pointer %lx wo debugging info\n",
  337.               (unsigned long)p);
  338.     } else {
  339.       clobbered = GC_check_annotated_obj((oh *)base);
  340.       if (clobbered != 0) {
  341.         if (((oh *)base) -> oh_sz == GC_size(base)) {
  342.             GC_err_printf0(
  343.                   "GC_debug_free: found previously deallocated (?) object at ");
  344.         } else {
  345.             GC_err_printf0("GC_debug_free: found smashed object at ");
  346.         }
  347.         GC_print_smashed_obj(p, clobbered);
  348.       }
  349.       /* Invalidate size */
  350.       ((oh *)base) -> oh_sz = GC_size(base);
  351.     }
  352. #   ifdef FIND_LEAK
  353.         GC_free(base);
  354. #   endif
  355. }
  356.  
  357. # ifdef __STDC__
  358.     extern_ptr_t GC_debug_realloc(extern_ptr_t p, size_t lb, char *s, int i)
  359. # else
  360.     extern_ptr_t GC_debug_realloc(p, lb, s, i)
  361.     extern_ptr_t p;
  362.     size_t lb;
  363.     char *s;
  364.     int i;
  365. # endif
  366. {
  367.     register extern_ptr_t base = GC_base(p);
  368.     register ptr_t clobbered;
  369.     register extern_ptr_t result = GC_debug_malloc(lb, s, i);
  370.     register size_t copy_sz = lb;
  371.     register size_t old_sz;
  372.     register hdr * hhdr;
  373.     
  374.     if (p == 0) return(GC_debug_malloc(lb, s, i));
  375.     if (base == 0) {
  376.         GC_err_printf1(
  377.               "Attempt to free invalid pointer %lx\n", (unsigned long)p);
  378.         ABORT("realloc(invalid pointer)");
  379.     }
  380.     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
  381.         GC_err_printf1(
  382.             "GC_debug_realloc called on pointer %lx wo debugging info\n",
  383.             (unsigned long)p);
  384.         return(GC_realloc(p, lb));
  385.     }
  386.     hhdr = HDR(base);
  387.     switch (hhdr -> hb_obj_kind) {
  388. #    ifdef STUBBORN_ALLOC
  389.       case STUBBORN:
  390.         result = GC_debug_malloc_stubborn(lb, s, i);
  391.         break;
  392. #    endif
  393.       case NORMAL:
  394.         result = GC_debug_malloc(lb, s, i);
  395.         break;
  396.       case PTRFREE:
  397.         result = GC_debug_malloc_atomic(lb, s, i);
  398.         break;
  399.       default:
  400.         GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
  401.         ABORT("bad kind");
  402.     }
  403.     clobbered = GC_check_annotated_obj((oh *)base);
  404.     if (clobbered != 0) {
  405.         GC_err_printf0("GC_debug_realloc: found smashed object at ");
  406.         GC_print_smashed_obj(p, clobbered);
  407.     }
  408.     old_sz = ((oh *)base) -> oh_sz;
  409.     if (old_sz < copy_sz) copy_sz = old_sz;
  410.     if (result == 0) return(0);
  411.     BCOPY(p, result,  copy_sz);
  412.     return(result);
  413. }
  414.  
  415. /* Check all marked objects in the given block for validity */
  416. /*ARGSUSED*/
  417. void GC_check_heap_block(hbp, dummy)
  418. register struct hblk *hbp;    /* ptr to current heap block        */
  419. word dummy;
  420. {
  421.     register struct hblkhdr * hhdr = HDR(hbp);
  422.     register word sz = hhdr -> hb_sz;
  423.     register int word_no;
  424.     register word *p, *plim;
  425.     
  426.     p = (word *)(hbp->hb_body);
  427.     word_no = HDR_WORDS;
  428.     plim = (word *)((((word)hbp) + HBLKSIZE)
  429.            - WORDS_TO_BYTES(sz));
  430.  
  431.     /* go through all words in block */
  432.     do {
  433.         if( mark_bit_from_hdr(hhdr, word_no)
  434.             && GC_has_debug_info((ptr_t)p)) {
  435.             ptr_t clobbered = GC_check_annotated_obj((oh *)p);
  436.             
  437.             if (clobbered != 0) {
  438.                 GC_err_printf0(
  439.                     "GC_check_heap_block: found smashed object at ");
  440.                 GC_print_smashed_obj((ptr_t)p, clobbered);
  441.             }
  442.         }
  443.         word_no += sz;
  444.         p += sz;
  445.     } while( p <= plim );
  446. }
  447.  
  448.  
  449. /* This assumes that all accessible objects are marked, and that    */
  450. /* I hold the allocation lock.    Normally called by collector.        */
  451. void GC_check_heap_proc()
  452. {
  453. #   ifndef SMALL_CONFIG
  454.     if (sizeof(oh) & (2 * sizeof(word) - 1) != 0) {
  455.         ABORT("Alignment problem: object header has inappropriate size\n");
  456.     }
  457. #   endif
  458.     GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
  459. }
  460.  
  461. struct closure {
  462.     GC_finalization_proc cl_fn;
  463.     extern_ptr_t cl_data;
  464. };
  465.  
  466. # ifdef __STDC__
  467.     void * GC_make_closure(GC_finalization_proc fn, void * data)
  468. # else
  469.     extern_ptr_t GC_make_closure(fn, data)
  470.     GC_finalization_proc fn;
  471.     extern_ptr_t data;
  472. # endif
  473. {
  474.     struct closure * result =
  475.             (struct closure *) GC_malloc(sizeof (struct closure));
  476.     
  477.     result -> cl_fn = fn;
  478.     result -> cl_data = data;
  479.     return((extern_ptr_t)result);
  480. }
  481.  
  482. # ifdef __STDC__
  483.     void GC_debug_invoke_finalizer(void * obj, void * data)
  484. # else
  485.     void GC_debug_invoke_finalizer(obj, data)
  486.     char * obj;
  487.     char * data;
  488. # endif
  489. {
  490.     register struct closure * cl = (struct closure *) data;
  491.     
  492.     (*(cl -> cl_fn))((extern_ptr_t)((char *)obj + sizeof(oh)), cl -> cl_data);
  493.  
  494.