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; +} +