checksums.c raw

   1  /*
   2   * Copyright (c) 1992-1994 by Xerox Corporation.  All rights reserved.
   3   *
   4   * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
   5   * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
   6   *
   7   * Permission is hereby granted to use or copy this program
   8   * for any purpose, provided the above notices are retained on all copies.
   9   * Permission to modify the code and to distribute modified code is granted,
  10   * provided the above notices are retained, and a notice that the code was
  11   * modified is included with the above copyright notice.
  12   */
  13  
  14  #include "private/gc_priv.h"
  15  
  16  #ifdef CHECKSUMS
  17  
  18  /*
  19   * This is debugging code intended to verify the results of dirty bit
  20   * computations.  Currently works only in a single-threaded environment.
  21   */
  22  
  23  #  define NSUMS 10000
  24  #  define OFFSET 0x10000
  25  
  26  typedef struct {
  27    GC_bool new_valid;
  28    word old_sum;
  29    word new_sum;
  30  
  31    /*
  32     * Block to which this refers plus `OFFSET` to hide it from the
  33     * garbage collector.
  34     */
  35    struct hblk *block;
  36  } page_entry;
  37  
  38  page_entry GC_sums[NSUMS];
  39  
  40  /* Record of pages on which we saw a write fault. */
  41  STATIC word GC_faulted[NSUMS] = { 0 };
  42  
  43  STATIC size_t GC_n_faulted = 0;
  44  
  45  #  ifdef MPROTECT_VDB
  46  void
  47  GC_record_fault(struct hblk *h)
  48  {
  49    GC_ASSERT(GC_page_size != 0);
  50    if (GC_n_faulted >= NSUMS)
  51      ABORT("write fault log overflowed");
  52    GC_faulted[GC_n_faulted++] = ADDR(HBLK_PAGE_ALIGNED(h));
  53  }
  54  #  endif
  55  
  56  STATIC GC_bool
  57  GC_was_faulted(struct hblk *h)
  58  {
  59    size_t i;
  60    word page = ADDR(HBLK_PAGE_ALIGNED(h));
  61  
  62    for (i = 0; i < GC_n_faulted; ++i) {
  63      if (GC_faulted[i] == page)
  64        return TRUE;
  65    }
  66    return FALSE;
  67  }
  68  
  69  STATIC word
  70  GC_checksum(struct hblk *h)
  71  {
  72    word *p;
  73    word *lim = (word *)(h + 1);
  74    word result = 0;
  75  
  76    for (p = (word *)h; ADDR_LT((ptr_t)p, (ptr_t)lim); p++) {
  77      result += *p;
  78    }
  79    return result | SIGNB; /*< does not look like pointer */
  80  }
  81  
  82  int GC_n_dirty_errors = 0;
  83  int GC_n_faulted_dirty_errors = 0;
  84  unsigned long GC_n_clean = 0;
  85  unsigned long GC_n_dirty = 0;
  86  
  87  STATIC void
  88  GC_update_check_page(struct hblk *h, int index)
  89  {
  90    page_entry *pe = GC_sums + index;
  91    hdr *hhdr = HDR(h);
  92  
  93    if (pe->block != 0 && pe->block != h + OFFSET)
  94      ABORT("goofed");
  95    pe->old_sum = pe->new_sum;
  96    pe->new_sum = GC_checksum(h);
  97  #  if !defined(MSWIN32) && !defined(MSWINCE)
  98    if (pe->new_sum != SIGNB && !GC_page_was_ever_dirty(h)) {
  99      GC_err_printf("GC_page_was_ever_dirty(%p) is wrong\n", (void *)h);
 100    }
 101  #  endif
 102    if (GC_page_was_dirty(h)) {
 103      GC_n_dirty++;
 104    } else {
 105      GC_n_clean++;
 106    }
 107    if (hhdr != NULL) {
 108      (void)GC_find_starting_hblk(h, &hhdr);
 109      if (pe->new_valid
 110  #  ifdef SOFT_VDB
 111          && !HBLK_IS_FREE(hhdr)
 112  #  endif
 113          && !IS_PTRFREE(hhdr) && pe->old_sum != pe->new_sum) {
 114        if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
 115          GC_bool was_faulted = GC_was_faulted(h);
 116  
 117          GC_n_dirty_errors++; /*< set breakpoint here */
 118          if (was_faulted)
 119            GC_n_faulted_dirty_errors++;
 120        }
 121      }
 122    }
 123    pe->new_valid = TRUE;
 124    pe->block = h + OFFSET;
 125  }
 126  
 127  /* Should be called immediately after `GC_read_dirty`. */
 128  void
 129  GC_check_dirty(void)
 130  {
 131    int index;
 132    size_t i;
 133  
 134    GC_n_dirty_errors = 0;
 135    GC_n_faulted_dirty_errors = 0;
 136    GC_n_clean = 0;
 137    GC_n_dirty = 0;
 138  
 139    index = 0;
 140    for (i = 0; i < GC_n_heap_sects; i++) {
 141      ptr_t start = GC_heap_sects[i].hs_start;
 142      struct hblk *h;
 143  
 144      for (h = (struct hblk *)start;
 145           ADDR_LT((ptr_t)h, start + GC_heap_sects[i].hs_bytes); h++) {
 146        GC_update_check_page(h, index);
 147        index++;
 148        if (index >= NSUMS) {
 149          i = GC_n_heap_sects;
 150          break;
 151        }
 152      }
 153    }
 154  
 155    GC_COND_LOG_PRINTF("Checked %lu clean and %lu dirty pages\n", GC_n_clean,
 156                       GC_n_dirty);
 157    if (GC_n_dirty_errors > 0) {
 158      GC_err_printf("Found %d dirty bit errors (%d were faulted)\n",
 159                    GC_n_dirty_errors, GC_n_faulted_dirty_errors);
 160    }
 161    for (i = 0; i < GC_n_faulted; ++i) {
 162      /* Do not expose block addresses to the garbage collector. */
 163      GC_faulted[i] = 0;
 164    }
 165    GC_n_faulted = 0;
 166  }
 167  
 168  #endif /* CHECKSUMS */
 169