From 2b8ae28a150f72c0afac406d6c9bf12d66d88d84 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 27 Apr 2008 03:14:36 +0000 Subject: [PATCH] * Added kernel tracing. Even with optional stack traces. * Added "mode" parameter to set_paranoia_check(), which specifies whether the check is supposed to already exist/not exist yet. This allows for, as it turns out, very useful additional tests. Added {ADD,UPDATE}_PARANOIA_CHECK macros that imply the used "mode" parameter. * PARANOIA_SLOT_COUNT was accidentally redefined in the source file. * Fixed remove_paranoia_check(). It didn't remove anything. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25207 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/config_headers/tracing_config.h | 2 + headers/private/kernel/debug_paranoia.h | 18 +- src/system/kernel/debug/debug_paranoia.cpp | 185 +++++++++++++++++++-- 3 files changed, 193 insertions(+), 12 deletions(-) diff --git a/build/config_headers/tracing_config.h b/build/config_headers/tracing_config.h index f29516df20..653c31374a 100644 --- a/build/config_headers/tracing_config.h +++ b/build/config_headers/tracing_config.h @@ -20,6 +20,8 @@ //#define BLOCK_CACHE_TRANSACTION_TRACING //#define KERNEL_HEAP_TRACING //#define PAGE_ALLOCATION_TRACING +//#define PARANOIA_TRACING +//#define PARANOIA_TRACING_STACK_TRACE 0 //#define OBJECT_CACHE_TRACING //#define RUNTIME_LOADER_TRACING //#define SIGNAL_TRACING diff --git a/headers/private/kernel/debug_paranoia.h b/headers/private/kernel/debug_paranoia.h index 1dfe3d9a0e..6d7d176dc8 100644 --- a/headers/private/kernel/debug_paranoia.h +++ b/headers/private/kernel/debug_paranoia.h @@ -17,6 +17,13 @@ // defined below and the ParanoiaChecker class. +enum paranoia_set_check_mode { + PARANOIA_DONT_FAIL, + PARANOIA_FAIL_IF_EXISTS, + PARANOIA_FAIL_IF_MISSING +}; + + __BEGIN_DECLS #if ENABLE_PARANOIA_CHECKS @@ -27,7 +34,7 @@ status_t delete_paranoia_check_set(const void* object); status_t run_paranoia_checks(const void* object); status_t set_paranoia_check(const void* object, const void* address, - size_t size); + size_t size, paranoia_set_check_mode mode); status_t remove_paranoia_check(const void* object, const void* address, size_t size); @@ -50,8 +57,15 @@ __END_DECLS PARANOIA_ONLY(delete_paranoia_check_set((object))) #define RUN_PARANOIA_CHECKS(object) \ PARANOIA_ONLY(run_paranoia_checks((object))) +#define ADD_PARANOIA_CHECK(object, address, size) \ + PARANOIA_ONLY(set_paranoia_check((object), (address), (size), \ + PARANOIA_FAIL_IF_EXISTS)) +#define UPDATE_PARANOIA_CHECK(object, address, size) \ + PARANOIA_ONLY(set_paranoia_check((object), (address), (size), \ + PARANOIA_FAIL_IF_MISSING)) #define SET_PARANOIA_CHECK(object, address, size) \ - PARANOIA_ONLY(set_paranoia_check((object), (address), (size))) + PARANOIA_ONLY(set_paranoia_check((object), (address), (size), \ + PARANOIA_DONT_FAIL)) #define REMOVE_PARANOIA_CHECK(object, address, size) \ PARANOIA_ONLY(remove_paranoia_check((object), (address), (size))) diff --git a/src/system/kernel/debug/debug_paranoia.cpp b/src/system/kernel/debug/debug_paranoia.cpp index 80c9d6bef0..ecd3629fd5 100644 --- a/src/system/kernel/debug/debug_paranoia.cpp +++ b/src/system/kernel/debug/debug_paranoia.cpp @@ -11,6 +11,7 @@ #include +#include #include @@ -192,10 +193,152 @@ union paranoia_slot { }; +// #pragma mark - Tracing + + +#ifdef PARANOIA_TRACING + + +namespace ParanoiaTracing { + +class ParanoiaTraceEntry : public AbstractTraceEntry { + public: + ParanoiaTraceEntry(const void* object) + : + fObject(object) + { +#if PARANOIA_TRACING_STACK_TRACE + fStackTrace = capture_tracing_stack_trace(PARANOIA_TRACING_STACK_TRACE, + 1, false); +#endif + } + +#if PARANOIA_TRACING_STACK_TRACE + virtual void DumpStackTrace(TraceOutput& out) + { + out.PrintStackTrace(fStackTrace); + } +#endif + + protected: + const void* fObject; +#if PARANOIA_TRACING_STACK_TRACE + tracing_stack_trace* fStackTrace; +#endif +}; + + +class CreateCheckSet : public ParanoiaTraceEntry { + public: + CreateCheckSet(const void* object, const char* description) + : + ParanoiaTraceEntry(object) + { + fDescription = alloc_tracing_buffer_strcpy(description, 64, false); + Initialized(); + } + + virtual void AddDump(TraceOutput& out) + { + out.Print("paranoia create check set: object: %p, " + "description: \"%s\"", fObject, fDescription); + } + + private: + const char* fDescription; +}; + + +class DeleteCheckSet : public ParanoiaTraceEntry { + public: + DeleteCheckSet(const void* object) + : + ParanoiaTraceEntry(object) + { + Initialized(); + } + + virtual void AddDump(TraceOutput& out) + { + out.Print("paranoia delete check set: object: %p", fObject); + } +}; + + +class SetCheck : public ParanoiaTraceEntry { + public: + SetCheck(const void* object, const void* address, size_t size, + paranoia_set_check_mode mode) + : + ParanoiaTraceEntry(object), + fAddress(address), + fSize(size), + fMode(mode) + { + Initialized(); + } + + virtual void AddDump(TraceOutput& out) + { + const char* mode = "??? op:"; + switch (fMode) { + case PARANOIA_DONT_FAIL: + mode = "set: "; + break; + case PARANOIA_FAIL_IF_EXISTS: + mode = "add: "; + break; + case PARANOIA_FAIL_IF_MISSING: + mode = "update:"; + break; + } + out.Print("paranoia check %s object: %p, address: %p, size: %lu", + mode, fObject, fAddress, fSize); + } + + private: + const void* fAddress; + size_t fSize; + paranoia_set_check_mode fMode; +}; + + +class RemoveCheck : public ParanoiaTraceEntry { + public: + RemoveCheck(const void* object, const void* address, size_t size) + : + ParanoiaTraceEntry(object), + fAddress(address), + fSize(size) + { + Initialized(); + } + + virtual void AddDump(TraceOutput& out) + { + out.Print("paranoia check remove: object: %p, address: %p, size: " + "%lu", fObject, fAddress, fSize); + } + + private: + const void* fAddress; + size_t fSize; + paranoia_set_check_mode fMode; +}; + + +} // namespace ParanoiaTracing + +# define T(x) new(std::nothrow) ParanoiaTracing::x + +#else +# define T(x) +#endif // PARANOIA_TRACING + + // #pragma mark - -#define PARANOIA_SLOT_COUNT 1024 #define PARANOIA_HASH_SIZE PARANOIA_SLOT_COUNT static paranoia_slot sSlots[PARANOIA_SLOT_COUNT]; @@ -268,6 +411,8 @@ lookup_check_set(const void* object) status_t create_paranoia_check_set(const void* object, const char* description) { + T(CreateCheckSet(object, description)); + if (object == NULL) { panic("create_paranoia_check_set(): NULL object"); return B_BAD_VALUE; @@ -300,6 +445,8 @@ create_paranoia_check_set(const void* object, const char* description) status_t delete_paranoia_check_set(const void* object) { + T(DeleteCheckSet(object)); + InterruptsSpinLocker _(sParanoiaLock); // get check set @@ -354,8 +501,11 @@ run_paranoia_checks(const void* object) status_t -set_paranoia_check(const void* object, const void* address, size_t size) +set_paranoia_check(const void* object, const void* address, size_t size, + paranoia_set_check_mode mode) { + T(SetCheck(object, address, size, mode)); + InterruptsSpinLocker _(sParanoiaLock); // get check set @@ -369,6 +519,12 @@ set_paranoia_check(const void* object, const void* address, size_t size) // update check, if already existing ParanoiaCheck* check = set->FindCheck(address); if (check != NULL) { + if (mode == PARANOIA_FAIL_IF_EXISTS) { + panic("set_paranoia_check(): object %p already has a check for " + "address %p", object, address); + return B_BAD_VALUE; + } + if (check->Size() != size) { panic("set_paranoia_check(): changing check sizes not supported"); return B_BAD_VALUE; @@ -378,6 +534,12 @@ set_paranoia_check(const void* object, const void* address, size_t size) return B_OK; } + if (mode == PARANOIA_FAIL_IF_MISSING) { + panic("set_paranoia_check(): object %p doesn't have a check for " + "address %p yet", object, address); + return B_BAD_VALUE; + } + // allocate slot paranoia_slot* slot = allocate_slot(); if (slot == NULL) { @@ -395,6 +557,8 @@ set_paranoia_check(const void* object, const void* address, size_t size) status_t remove_paranoia_check(const void* object, const void* address, size_t size) { + T(RemoveCheck(object, address, size)); + InterruptsSpinLocker _(sParanoiaLock); // get check set @@ -407,15 +571,16 @@ remove_paranoia_check(const void* object, const void* address, size_t size) // get check ParanoiaCheck* check = set->FindCheck(address); - if (check != NULL) { - if (check->Size() != size) { - panic("remove_paranoia_check(): changing check sizes not " - "supported"); - return B_BAD_VALUE; - } + if (check == NULL) { + panic("remove_paranoia_check(): no check for address %p " + "(object %p (%s))", address, object, set->Description()); + return B_BAD_VALUE; + } - check->Update(); - return B_OK; + if (check->Size() != size) { + panic("remove_paranoia_check(): changing check sizes not " + "supported"); + return B_BAD_VALUE; } set->RemoveCheck(check);