1 /* -----------------------------------------------------------------------------
2 * $Id: Sanity.c,v 1.2 1998/12/02 13:28:43 simonm Exp $
4 * Sanity checking code for the heap and stack.
6 * Used when debugging: check that the stack looks reasonable.
8 * - All things that are supposed to be pointers look like pointers.
10 * - Objects in text space are marked as static closures, those
11 * in the heap are dynamic.
13 * ---------------------------------------------------------------------------*/
21 #include "BlockAlloc.h"
26 #define LOOKS_LIKE_PTR(r) \
27 (IS_DATA_PTR(r) || ((IS_USER_PTR(r) && Bdescr((P_)r)->step == heap_step)))
29 /* -----------------------------------------------------------------------------
31 -------------------------------------------------------------------------- */
33 StgOffset checkStackClosure( StgClosure* c );
35 StgOffset checkStackObject( StgPtr sp );
37 void checkStackChunk( StgPtr sp, StgPtr stack_end );
39 static StgOffset checkSmallBitmap( StgPtr payload, StgNat32 bitmap );
41 static StgOffset checkLargeBitmap( StgPtr payload,
42 StgLargeBitmap* large_bitmap );
44 void checkClosureShallow( StgClosure* p );
47 checkSmallBitmap( StgPtr payload, StgNat32 bitmap )
52 for(; bitmap != 0; ++i, bitmap >>= 1 ) {
53 if ((bitmap & 1) == 0) {
54 checkClosure(stgCast(StgClosure*,payload[i]));
62 checkLargeBitmap( StgPtr payload, StgLargeBitmap* large_bitmap )
68 for (bmp=0; bmp<large_bitmap->size; bmp++) {
69 StgNat32 bitmap = large_bitmap->bitmap[bmp];
70 for(; bitmap != 0; ++i, bitmap >>= 1 ) {
71 if ((bitmap & 1) == 0) {
72 checkClosure(stgCast(StgClosure*,payload[i]));
80 checkStackClosure( StgClosure* c )
82 const StgInfoTable* info = get_itbl(c);
84 /* All activation records have 'bitmap' style layout info. */
86 case RET_DYN: /* Dynamic bitmap: the mask is stored on the stack */
88 StgRetDyn* r = stgCast(StgRetDyn*,c);
89 return sizeofW(StgRetDyn) +
90 checkSmallBitmap(r->payload,r->liveness);
92 case RET_BCO: /* small bitmap (<= 32 entries) */
99 return sizeofW(StgClosure) +
100 checkSmallBitmap((StgPtr)c->payload,info->layout.bitmap);
101 case RET_BIG: /* large bitmap (> 32 entries) */
103 return sizeofW(StgClosure) +
104 checkLargeBitmap((StgPtr)c->payload,
105 info->layout.large_bitmap);
107 case FUN_STATIC: /* probably a slow-entry point return address: */
110 /* if none of the above, maybe it's a closure which looks a
111 * little like an infotable
113 checkClosureShallow(*stgCast(StgClosure**,c));
115 /* barf("checkStackClosure: weird activation record found on stack (%p).",c); */
120 * check that it looks like a valid closure - without checking its payload
121 * used to avoid recursion between checking PAPs and checking stack
126 checkClosureShallow( StgClosure* p )
128 ASSERT(LOOKS_LIKE_GHC_INFO(p->header.info));
130 /* Is it a static closure (i.e. in the data segment)? */
131 if (LOOKS_LIKE_STATIC(p)) {
132 ASSERT(closure_STATIC(p));
134 ASSERT(!closure_STATIC(p));
135 ASSERT(LOOKS_LIKE_PTR(p));
139 /* check an individual stack object */
141 checkStackObject( StgPtr sp )
143 if (IS_ARG_TAG(*sp)) {
144 /* Tagged words might be "stubbed" pointers, so there's no
145 * point checking to see whether they look like pointers or
146 * not (some of them will).
148 return ARG_SIZE(*sp) + 1;
149 } else if (LOOKS_LIKE_GHC_INFO(*stgCast(StgPtr*,sp))) {
150 return checkStackClosure(stgCast(StgClosure*,sp));
151 } else { /* must be an untagged closure pointer in the stack */
152 checkClosureShallow(*stgCast(StgClosure**,sp));
157 /* check sections of stack between update frames */
159 checkStackChunk( StgPtr sp, StgPtr stack_end )
164 while (p < stack_end) {
165 p += checkStackObject( p );
167 ASSERT( p == stack_end );
171 checkClosure( StgClosure* p )
173 const StgInfoTable *info;
176 ASSERT(LOOKS_LIKE_GHC_INFO(p->header.info));
179 /* Is it a static closure (i.e. in the data segment)? */
180 if (LOOKS_LIKE_STATIC(p)) {
181 ASSERT(closure_STATIC(p));
183 ASSERT(!closure_STATIC(p));
184 ASSERT(LOOKS_LIKE_PTR(p));
188 switch (info->type) {
191 StgBCO* bco = stgCast(StgBCO*,p);
193 for(i=0; i < bco->n_ptrs; ++i) {
194 ASSERT(LOOKS_LIKE_PTR(bcoConstPtr(bco,i)));
196 return bco_sizeW(bco);
202 case IND_OLDGEN_PERM:
211 case CONSTR_CHARLIKE:
213 case CONSTR_NOCAF_STATIC:
219 for (i = 0; i < info->layout.payload.ptrs; i++) {
220 ASSERT(LOOKS_LIKE_PTR(payloadPtr(p,i)));
222 return sizeW_fromITBL(info);
226 /* deal with these specially - the info table isn't
227 * representative of the actual layout.
229 { StgWeak *w = (StgWeak *)p;
230 ASSERT(LOOKS_LIKE_PTR(w->key));
231 ASSERT(LOOKS_LIKE_PTR(w->value));
232 ASSERT(LOOKS_LIKE_PTR(w->finaliser));
234 ASSERT(LOOKS_LIKE_PTR(w->link));
236 return sizeW_fromITBL(info);
240 ASSERT(LOOKS_LIKE_PTR(stgCast(StgSelector*,p)->selectee));
241 return sizeofW(StgHeader) + MIN_UPD_SIZE;
246 /* we don't expect to see any of these after GC
247 * but they might appear during execution
249 StgInd *ind = stgCast(StgInd*,p);
250 ASSERT(LOOKS_LIKE_PTR(ind->indirectee));
251 return sizeofW(StgInd);
264 barf("checkClosure: stack frame");
266 case AP_UPD: /* we can treat this as being the same as a PAP */
269 StgPAP *pap = stgCast(StgPAP*,p);
270 ASSERT(LOOKS_LIKE_PTR(pap->fun));
271 checkStackChunk((StgPtr)pap->payload,
272 (StgPtr)pap->payload + pap->n_args
274 return pap_sizeW(pap);
279 return arr_words_sizeW(stgCast(StgArrWords*,p));
283 case MUT_ARR_PTRS_FROZEN:
285 StgArrPtrs* a = stgCast(StgArrPtrs*,p);
287 for (i = 0; i < a->ptrs; i++) {
288 ASSERT(LOOKS_LIKE_PTR(payloadPtr(a,i)));
290 return arr_ptrs_sizeW(a);
294 checkTSO((StgTSO *)p, heap_step);
295 return tso_sizeW((StgTSO *)p);
300 barf("checkClosure: unimplemented/strange closure type");
302 barf("checkClosure");
304 #undef LOOKS_LIKE_PTR
307 /* -----------------------------------------------------------------------------
310 After garbage collection, the live heap is in a state where we can
311 run through and check that all the pointers point to the right
313 -------------------------------------------------------------------------- */
316 checkHeap(bdescr *bd, nat step)
324 while (p < bd->free) {
325 nat size = checkClosure(stgCast(StgClosure*,p));
326 /* This is the smallest size of closure that can live in the heap. */
327 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
334 /* check stack - making sure that update frames are linked correctly */
336 checkStack(StgPtr sp, StgPtr stack_end, StgUpdateFrame* su )
338 /* check everything down to the first update frame */
339 checkStackChunk( sp, stgCast(StgPtr,su) );
340 while ( stgCast(StgPtr,su) < stack_end) {
341 sp = stgCast(StgPtr,su);
342 switch (get_itbl(su)->type) {
347 su = stgCast(StgSeqFrame*,su)->link;
350 su = stgCast(StgCatchFrame*,su)->link;
353 /* not quite: ASSERT(stgCast(StgPtr,su) == stack_end); */
356 barf("checkStack: weird record found on update frame list.");
358 checkStackChunk( sp, stgCast(StgPtr,su) );
360 ASSERT(stgCast(StgPtr,su) == stack_end);
364 checkTSO(StgTSO *tso, nat step)
367 StgPtr stack = tso->stack;
368 StgUpdateFrame* su = tso->su;
369 StgOffset stack_size = tso->stack_size;
370 StgPtr stack_end = stack + stack_size;
374 ASSERT(stack <= sp && sp < stack_end);
375 ASSERT(sp <= stgCast(StgPtr,su));
377 checkStack(sp, stack_end, su);
380 /* -----------------------------------------------------------------------------
381 Check Blackhole Sanity
383 Test whether an object is already on the update list.
384 It isn't necessarily an rts error if it is - it might be a programming
387 Future versions might be able to test for a blackhole without traversing
388 the update frame list.
390 -------------------------------------------------------------------------- */
391 rtsBool isBlackhole( StgTSO* tso, StgClosure* p )
393 StgUpdateFrame* su = tso->su;
395 switch (get_itbl(su)->type) {
397 if (su->updatee == p) {
404 su = stgCast(StgSeqFrame*,su)->link;
407 su = stgCast(StgCatchFrame*,su)->link;
412 barf("isBlackhole: weird record found on update frame list.");