2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
6 #include <debug_paranoia.h>
15 #include <util/AutoLock.h>
18 #if ENABLE_PARANOIA_CHECKS
21 // #pragma mark - CRC-32
24 static const uint32 kCRC32Polynom
= 0x04c11db7;
25 static uint32 sCRC32Table
[256];
29 crc32_reflect(uint32 value
, int32 bits
)
32 for (int32 i
= 1; i
<= bits
; i
++) {
34 result
|= 1 << (bits
- i
);
45 for (int32 i
= 0; i
< 256; i
++) {
46 sCRC32Table
[i
] = crc32_reflect(i
, 8) << 24;
47 for (int32 k
= 0; k
< 8; k
++) {
48 sCRC32Table
[i
] = (sCRC32Table
[i
] << 1)
49 ^ (sCRC32Table
[i
] & (1 << 31) ? kCRC32Polynom
: 0);
51 sCRC32Table
[i
] = crc32_reflect(sCRC32Table
[i
], 32);
57 crc32(const void* _data
, size_t size
)
59 uint8
* data
= (uint8
*)_data
;
60 uint32 crc
= 0xffffffff;
63 crc
= (crc
>> 8) ^ sCRC32Table
[(crc
& 0xff) ^ *data
];
71 // #pragma mark - ParanoiaCheck[Set]
74 class ParanoiaCheckSet
;
78 ParanoiaCheck(const void* address
, size_t size
)
86 const void* Address() const { return fAddress
; }
87 size_t Size() const { return fSize
; }
91 fCheckSum
= crc32(fAddress
, fSize
);
96 return crc32(fAddress
, fSize
) == fCheckSum
;
100 const void* fAddress
;
103 ParanoiaCheck
* fNext
;
105 friend class ParanoiaCheckSet
;
109 class ParanoiaCheckSet
{
111 ParanoiaCheckSet(const void* object
, const char* description
)
114 fDescription(description
),
119 const void* Object() const { return fObject
; }
120 const char* Description() const { return fDescription
; }
122 ParanoiaCheck
* FirstCheck() const
127 ParanoiaCheck
* NextCheck(ParanoiaCheck
* check
) const
132 ParanoiaCheck
* FindCheck(const void* address
) const
134 ParanoiaCheck
* check
= fChecks
;
135 while (check
!= NULL
&& check
->Address() != address
)
136 check
= check
->fNext
;
140 void AddCheck(ParanoiaCheck
* check
)
142 check
->fNext
= fChecks
;
146 void RemoveCheck(ParanoiaCheck
* check
)
148 if (check
== fChecks
) {
149 fChecks
= check
->fNext
;
153 ParanoiaCheck
* previous
= fChecks
;
154 while (previous
!= NULL
&& previous
->fNext
!= check
)
155 previous
= previous
->fNext
;
157 // if previous is NULL (which it shouldn't be), just crash here
158 previous
->fNext
= check
->fNext
;
161 ParanoiaCheck
* RemoveFirstCheck()
163 ParanoiaCheck
* check
= fChecks
;
167 fChecks
= check
->fNext
;
171 void SetHashNext(ParanoiaCheckSet
* next
)
176 ParanoiaCheckSet
* HashNext() const
183 const char* fDescription
;
184 ParanoiaCheck
* fChecks
;
185 ParanoiaCheckSet
* fHashNext
;
189 union paranoia_slot
{
190 uint8 check
[sizeof(ParanoiaCheck
)];
191 uint8 checkSet
[sizeof(ParanoiaCheckSet
)];
192 paranoia_slot
* nextFree
;
196 // #pragma mark - Tracing
202 namespace ParanoiaTracing
{
204 class ParanoiaTraceEntry
: public AbstractTraceEntry
{
206 ParanoiaTraceEntry(const void* object
)
210 #if PARANOIA_TRACING_STACK_TRACE
211 fStackTrace
= capture_tracing_stack_trace(PARANOIA_TRACING_STACK_TRACE
,
216 #if PARANOIA_TRACING_STACK_TRACE
217 virtual void DumpStackTrace(TraceOutput
& out
)
219 out
.PrintStackTrace(fStackTrace
);
225 #if PARANOIA_TRACING_STACK_TRACE
226 tracing_stack_trace
* fStackTrace
;
231 class CreateCheckSet
: public ParanoiaTraceEntry
{
233 CreateCheckSet(const void* object
, const char* description
)
235 ParanoiaTraceEntry(object
)
237 fDescription
= alloc_tracing_buffer_strcpy(description
, 64, false);
241 virtual void AddDump(TraceOutput
& out
)
243 out
.Print("paranoia create check set: object: %p, "
244 "description: \"%s\"", fObject
, fDescription
);
248 const char* fDescription
;
252 class DeleteCheckSet
: public ParanoiaTraceEntry
{
254 DeleteCheckSet(const void* object
)
256 ParanoiaTraceEntry(object
)
261 virtual void AddDump(TraceOutput
& out
)
263 out
.Print("paranoia delete check set: object: %p", fObject
);
268 class SetCheck
: public ParanoiaTraceEntry
{
270 SetCheck(const void* object
, const void* address
, size_t size
,
271 paranoia_set_check_mode mode
)
273 ParanoiaTraceEntry(object
),
281 virtual void AddDump(TraceOutput
& out
)
283 const char* mode
= "??? op:";
285 case PARANOIA_DONT_FAIL
:
288 case PARANOIA_FAIL_IF_EXISTS
:
291 case PARANOIA_FAIL_IF_MISSING
:
295 out
.Print("paranoia check %s object: %p, address: %p, size: %lu",
296 mode
, fObject
, fAddress
, fSize
);
300 const void* fAddress
;
302 paranoia_set_check_mode fMode
;
306 class RemoveCheck
: public ParanoiaTraceEntry
{
308 RemoveCheck(const void* object
, const void* address
, size_t size
)
310 ParanoiaTraceEntry(object
),
317 virtual void AddDump(TraceOutput
& out
)
319 out
.Print("paranoia check remove: object: %p, address: %p, size: "
320 "%lu", fObject
, fAddress
, fSize
);
324 const void* fAddress
;
326 paranoia_set_check_mode fMode
;
330 } // namespace ParanoiaTracing
332 # define T(x) new(std::nothrow) ParanoiaTracing::x
336 #endif // PARANOIA_TRACING
342 #define PARANOIA_HASH_SIZE PARANOIA_SLOT_COUNT
344 static paranoia_slot sSlots
[PARANOIA_SLOT_COUNT
];
345 static paranoia_slot
* sSlotFreeList
;
346 static ParanoiaCheckSet
* sCheckSetHash
[PARANOIA_HASH_SIZE
];
347 static spinlock sParanoiaLock
;
350 static paranoia_slot
*
353 if (sSlotFreeList
== NULL
)
356 paranoia_slot
* slot
= sSlotFreeList
;
357 sSlotFreeList
= slot
->nextFree
;
363 free_slot(paranoia_slot
* slot
)
365 slot
->nextFree
= sSlotFreeList
;
366 sSlotFreeList
= slot
;
371 add_check_set(ParanoiaCheckSet
* set
)
373 int slot
= (addr_t
)set
->Object() % PARANOIA_HASH_SIZE
;
374 set
->SetHashNext(sCheckSetHash
[slot
]);
375 sCheckSetHash
[slot
] = set
;
380 remove_check_set(ParanoiaCheckSet
* set
)
382 int slot
= (addr_t
)set
->Object() % PARANOIA_HASH_SIZE
;
383 if (set
== sCheckSetHash
[slot
]) {
384 sCheckSetHash
[slot
] = set
->HashNext();
388 ParanoiaCheckSet
* previousSet
= sCheckSetHash
[slot
];
389 while (previousSet
!= NULL
&& previousSet
->HashNext() != set
)
390 previousSet
= previousSet
->HashNext();
392 // if previousSet is NULL (which it shouldn't be), just crash here
393 previousSet
->SetHashNext(set
->HashNext());
397 static ParanoiaCheckSet
*
398 lookup_check_set(const void* object
)
400 int slot
= (addr_t
)object
% PARANOIA_HASH_SIZE
;
401 ParanoiaCheckSet
* set
= sCheckSetHash
[slot
];
402 while (set
!= NULL
&& set
->Object() != object
)
403 set
= set
->HashNext();
408 // #pragma mark - public interface
412 create_paranoia_check_set(const void* object
, const char* description
)
414 T(CreateCheckSet(object
, description
));
416 if (object
== NULL
) {
417 panic("create_paranoia_check_set(): NULL object");
421 InterruptsSpinLocker
_(sParanoiaLock
);
423 // check, if object is already registered
424 ParanoiaCheckSet
* set
= lookup_check_set(object
);
426 panic("create_paranoia_check_set(): object %p already has a check set",
432 paranoia_slot
* slot
= allocate_slot();
434 panic("create_paranoia_check_set(): out of free slots");
438 set
= new(slot
) ParanoiaCheckSet(object
, description
);
446 delete_paranoia_check_set(const void* object
)
448 T(DeleteCheckSet(object
));
450 InterruptsSpinLocker
_(sParanoiaLock
);
453 ParanoiaCheckSet
* set
= lookup_check_set(object
);
455 panic("delete_paranoia_check_set(): object %p doesn't have a check set",
461 while (ParanoiaCheck
* check
= set
->RemoveFirstCheck())
462 free_slot((paranoia_slot
*)check
);
465 remove_check_set(set
);
466 free_slot((paranoia_slot
*)set
);
473 run_paranoia_checks(const void* object
)
475 InterruptsSpinLocker
_(sParanoiaLock
);
478 ParanoiaCheckSet
* set
= lookup_check_set(object
);
480 panic("run_paranoia_checks(): object %p doesn't have a check set",
485 status_t error
= B_OK
;
487 ParanoiaCheck
* check
= set
->FirstCheck();
488 while (check
!= NULL
) {
489 if (!check
->Check()) {
490 panic("paranoia check failed for object %p (%s), address: %p, "
491 "size: %lu", set
->Object(), set
->Description(),
492 check
->Address(), check
->Size());
496 check
= set
->NextCheck(check
);
504 set_paranoia_check(const void* object
, const void* address
, size_t size
,
505 paranoia_set_check_mode mode
)
507 T(SetCheck(object
, address
, size
, mode
));
509 InterruptsSpinLocker
_(sParanoiaLock
);
512 ParanoiaCheckSet
* set
= lookup_check_set(object
);
514 panic("set_paranoia_check(): object %p doesn't have a check set",
519 // update check, if already existing
520 ParanoiaCheck
* check
= set
->FindCheck(address
);
522 if (mode
== PARANOIA_FAIL_IF_EXISTS
) {
523 panic("set_paranoia_check(): object %p already has a check for "
524 "address %p", object
, address
);
528 if (check
->Size() != size
) {
529 panic("set_paranoia_check(): changing check sizes not supported");
537 if (mode
== PARANOIA_FAIL_IF_MISSING
) {
538 panic("set_paranoia_check(): object %p doesn't have a check for "
539 "address %p yet", object
, address
);
544 paranoia_slot
* slot
= allocate_slot();
546 panic("set_paranoia_check(): out of free slots");
550 check
= new(slot
) ParanoiaCheck(address
, size
);
551 set
->AddCheck(check
);
558 remove_paranoia_check(const void* object
, const void* address
, size_t size
)
560 T(RemoveCheck(object
, address
, size
));
562 InterruptsSpinLocker
_(sParanoiaLock
);
565 ParanoiaCheckSet
* set
= lookup_check_set(object
);
567 panic("remove_paranoia_check(): object %p doesn't have a check set",
573 ParanoiaCheck
* check
= set
->FindCheck(address
);
575 panic("remove_paranoia_check(): no check for address %p "
576 "(object %p (%s))", address
, object
, set
->Description());
580 if (check
->Size() != size
) {
581 panic("remove_paranoia_check(): changing check sizes not "
586 set
->RemoveCheck(check
);
591 #endif // ENABLE_PARANOIA_CHECKS
595 debug_paranoia_init()
597 #if ENABLE_PARANOIA_CHECKS
601 // init paranoia slot free list
602 for (int32 i
= 0; i
< PARANOIA_SLOT_COUNT
; i
++)
603 free_slot(&sSlots
[i
]);