From aa5d2a2df2ac48c3f9eba907e9f07b99f998aec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 12 Jan 2008 18:41:35 +0000 Subject: [PATCH] bonefish+axeld: * Implemented an optional tracing layer that can be used in the kernel. Nice to use if you don't have serial output or need something that doesn't slow down the system as much. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23447 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/tracing.h | 42 ++++++ src/system/kernel/debug/Jamfile | 1 + src/system/kernel/debug/debug.c | 2 + src/system/kernel/debug/tracing.cpp | 203 ++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+) create mode 100644 headers/private/kernel/tracing.h create mode 100644 src/system/kernel/debug/tracing.cpp diff --git a/headers/private/kernel/tracing.h b/headers/private/kernel/tracing.h new file mode 100644 index 0000000000..a96f28c9a0 --- /dev/null +++ b/headers/private/kernel/tracing.h @@ -0,0 +1,42 @@ +#ifndef KERNEL_UTIL_TRACING_H +#define KERNEL_UTIL_TRACING_H + + +#include + + +#define ENABLE_TRACING 0 +#define MAX_TRACE_SIZE 1024 * 1024 + +struct trace_entry { + uint16 size; + uint16 flags; +}; + +#ifdef __cplusplus + +#include + +class TraceEntry : trace_entry { + public: + TraceEntry(); + virtual ~TraceEntry(); + + virtual void Dump(); + + size_t Size() const { return size; } + uint16 Flags() const { return flags; } + + void Initialized(); + + void* operator new(size_t size); +}; + +#endif // __cplusplus + +#ifdef __cplusplus +extern "C" +#endif +status_t tracing_init(void); + +#endif /* KERNEL_UTIL_TRACING_H */ diff --git a/src/system/kernel/debug/Jamfile b/src/system/kernel/debug/Jamfile index 79e2216984..c55bb7d7eb 100644 --- a/src/system/kernel/debug/Jamfile +++ b/src/system/kernel/debug/Jamfile @@ -7,6 +7,7 @@ KernelMergeObject kernel_debug.o : debug.c frame_buffer_console.cpp gdb.c + tracing.cpp user_debugger.cpp : $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused diff --git a/src/system/kernel/debug/debug.c b/src/system/kernel/debug/debug.c index 3ac76c600a..e1ab5e41c5 100644 --- a/src/system/kernel/debug/debug.c +++ b/src/system/kernel/debug/debug.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -722,6 +723,7 @@ debug_init_post_vm(kernel_args *args) frame_buffer_console_init(args); arch_debug_console_init_settings(args); + tracing_init(); // get debug settings handle = load_driver_settings("kernel"); diff --git a/src/system/kernel/debug/tracing.cpp b/src/system/kernel/debug/tracing.cpp new file mode 100644 index 0000000000..b4e625c85c --- /dev/null +++ b/src/system/kernel/debug/tracing.cpp @@ -0,0 +1,203 @@ +#include + +#include + +#include + + +#if ENABLE_TRACING + +enum { + WRAP_ENTRY = 0x01, + ENTRY_INITIALIZED = 0x02 +}; + +static const size_t kBufferSize = MAX_TRACE_SIZE / 4 - 1; + +static trace_entry* sBuffer; +static trace_entry* sBufferStart; +static trace_entry* sBufferEnd; +static uint32 sEntries; +static spinlock sLock; + + +static trace_entry* +next_entry(trace_entry* entry) +{ + entry += entry->size >> 2; + if ((entry->flags & WRAP_ENTRY) != 0) + entry = sBuffer; + + if (entry == sBufferEnd) + return NULL; + + return entry; +} + + +static void +make_space(size_t size) +{ + if (sBufferEnd + size / 4 > sBuffer + kBufferSize - 1) { + sBufferEnd->size = 0; + sBufferEnd->flags = WRAP_ENTRY; + sBufferEnd = sBuffer; + } + + int32 diff = sBufferStart - sBufferEnd; + if (diff < 0) + sBufferEnd = sBuffer; + else + size -= diff; + + while (true) { + uint16 skip = sBufferStart->size; + sBufferStart = next_entry(sBufferStart); + if (sBufferStart == NULL) + sBufferStart = sBuffer; + sEntries--; + + if (size <= skip) + break; + + size -= skip; + } +} + + +#endif // ENABLE_TRACING + + +// #pragma mark - + + +TraceEntry::TraceEntry() +{ +} + + +TraceEntry::~TraceEntry() +{ +} + + +void +TraceEntry::Dump() +{ +#if ENABLE_TRACING + // to be overloaded by subclasses + kprintf("ENTRY %p\n", this); +#endif +} + + +void +TraceEntry::Initialized() +{ +#if ENABLE_TRACING + flags |= ENTRY_INITIALIZED; +#endif +} + + +void* +TraceEntry::operator new(size_t size) throw() +{ +#if ENABLE_TRACING + if (sBuffer == NULL) + return NULL; + + InterruptsSpinLocker _(sLock); + + size = (size + 3) & ~3; + + if (sBufferStart < sBufferEnd || sEntries == 0) { + // the buffer ahead of us is still empty + uint32 space = (sBuffer + kBufferSize - sBufferEnd) * 4; + if (space < size) + make_space(size); + } else { + // we need to overwrite existing entries + make_space(size); + } + + trace_entry* entry = sBufferEnd; + entry->size = size; + entry->flags = 0; + sBufferEnd += size >> 2; + sEntries++; + return entry; +#else // !ENABLE_TRACING + return NULL; +#endif +} + + +// #pragma mark - + + +#if ENABLE_TRACING + + +int +dump_tracing(int argc, char** argv) +{ + int32 count = 30; + int32 start = sEntries - count; + + if (argc == 2) { + count = strtol(argv[1], NULL, 0); + } else if (argc == 3) { + start = strtol(argv[1], NULL, 0); + count = strtol(argv[2], NULL, 0); + } else if (argc > 3) { + kprintf("usage: %s [start] [count]\n", argv[0]); + return 0; + } + + if (start < 0) + start = 0; + + int32 index = 0; + + for (trace_entry* current = sBufferStart; current != NULL; + current = next_entry(current), index++) { + if (index < start) + continue; + if (index > start + count) + break; + + if ((current->flags & ENTRY_INITIALIZED) != 0) + ((TraceEntry*)current)->Dump(); + else + kprintf("** uninitialized entry **\n"); + } + + return 0; +} + + +#endif // ENABLE_TRACING + + +extern "C" status_t +tracing_init(void) +{ +#if ENABLE_TRACING + area_id area = create_area("tracing log", (void**)&sBuffer, + B_ANY_KERNEL_ADDRESS, MAX_TRACE_SIZE, B_FULL_LOCK, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); + if (area < B_OK) { + panic("OH"); + return area; + } + + sBufferStart = sBuffer; + sBufferEnd = sBuffer; + + add_debugger_command("traced", &dump_tracing, + "Dump recorded trace entries"); +#endif // ENABLE_TRACING + return B_OK; +} +