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