12d81f045SAxel Dörfler /* 22d81f045SAxel Dörfler * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 32d81f045SAxel Dörfler * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. 42d81f045SAxel Dörfler * Distributed under the terms of the MIT License. 52d81f045SAxel Dörfler */ 62d81f045SAxel Dörfler 72d81f045SAxel Dörfler 8aa5d2a2dSAxel Dörfler #include <tracing.h> 9aa5d2a2dSAxel Dörfler 10f1047a1cSIngo Weinhold #include <stdarg.h> 11aa5d2a2dSAxel Dörfler #include <stdlib.h> 12aa5d2a2dSAxel Dörfler 1374652349SIngo Weinhold #include <debug.h> 148bd6d45dSIngo Weinhold #include <kernel.h> 152d81f045SAxel Dörfler #include <util/AutoLock.h> 162d81f045SAxel Dörfler 17aa5d2a2dSAxel Dörfler 18aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 19aa5d2a2dSAxel Dörfler 205276dad0SAxel Dörfler //#define TRACE_TRACING 215276dad0SAxel Dörfler #ifdef TRACE_TRACING 22*6d986c16SIngo Weinhold # define TRACE(x) dprintf_no_syslog x 235276dad0SAxel Dörfler #else 245276dad0SAxel Dörfler # define TRACE(x) ; 255276dad0SAxel Dörfler #endif 265276dad0SAxel Dörfler 275276dad0SAxel Dörfler 28aa5d2a2dSAxel Dörfler enum { 29aa5d2a2dSAxel Dörfler WRAP_ENTRY = 0x01, 308e43ece8SAxel Dörfler ENTRY_INITIALIZED = 0x02, 318e43ece8SAxel Dörfler BUFFER_ENTRY = 0x04 32aa5d2a2dSAxel Dörfler }; 33aa5d2a2dSAxel Dörfler 34aa5d2a2dSAxel Dörfler static const size_t kBufferSize = MAX_TRACE_SIZE / 4 - 1; 35aa5d2a2dSAxel Dörfler 36aa5d2a2dSAxel Dörfler static trace_entry* sBuffer; 37960f8f24SAxel Dörfler static trace_entry* sFirstEntry; 38960f8f24SAxel Dörfler static trace_entry* sAfterLastEntry; 39aa5d2a2dSAxel Dörfler static uint32 sEntries; 40f70280a7SAxel Dörfler static uint32 sWritten; 41aa5d2a2dSAxel Dörfler static spinlock sLock; 42aa5d2a2dSAxel Dörfler 43aa5d2a2dSAxel Dörfler 44aa5d2a2dSAxel Dörfler static trace_entry* 45aa5d2a2dSAxel Dörfler next_entry(trace_entry* entry) 46aa5d2a2dSAxel Dörfler { 47aa5d2a2dSAxel Dörfler entry += entry->size >> 2; 48aa5d2a2dSAxel Dörfler if ((entry->flags & WRAP_ENTRY) != 0) 49aa5d2a2dSAxel Dörfler entry = sBuffer; 50aa5d2a2dSAxel Dörfler 51960f8f24SAxel Dörfler if (entry == sAfterLastEntry) 52aa5d2a2dSAxel Dörfler return NULL; 53aa5d2a2dSAxel Dörfler 54aa5d2a2dSAxel Dörfler return entry; 55aa5d2a2dSAxel Dörfler } 56aa5d2a2dSAxel Dörfler 57aa5d2a2dSAxel Dörfler 58*6d986c16SIngo Weinhold static bool 59*6d986c16SIngo Weinhold free_first_entry() 60*6d986c16SIngo Weinhold { 61*6d986c16SIngo Weinhold TRACE((" skip start %p, %u bytes\n", sFirstEntry, sFirstEntry->size)); 62*6d986c16SIngo Weinhold 63*6d986c16SIngo Weinhold trace_entry* newFirst = next_entry(sFirstEntry); 64*6d986c16SIngo Weinhold 65*6d986c16SIngo Weinhold if (sFirstEntry->flags & BUFFER_ENTRY) { 66*6d986c16SIngo Weinhold // a buffer entry -- just skip it 67*6d986c16SIngo Weinhold } else if (sFirstEntry->flags & ENTRY_INITIALIZED) { 68*6d986c16SIngo Weinhold // fully initialized TraceEntry -- destroy it 69*6d986c16SIngo Weinhold ((TraceEntry*)sFirstEntry)->~TraceEntry(); 70*6d986c16SIngo Weinhold sEntries--; 71*6d986c16SIngo Weinhold } else { 72*6d986c16SIngo Weinhold // Not fully initialized TraceEntry. We can't free it, since 73*6d986c16SIngo Weinhold // then it's constructor might still write into the memory and 74*6d986c16SIngo Weinhold // overwrite data of the entry we're going to allocate. 75*6d986c16SIngo Weinhold // We can't do anything until this entry can be discarded. 76*6d986c16SIngo Weinhold return false; 77*6d986c16SIngo Weinhold } 78*6d986c16SIngo Weinhold 79*6d986c16SIngo Weinhold if (newFirst == NULL) { 80*6d986c16SIngo Weinhold // everything is freed -- that practically this can't happen, if 81*6d986c16SIngo Weinhold // the buffer is large enough to hold three max-sized entries 82*6d986c16SIngo Weinhold sFirstEntry = sAfterLastEntry = sBuffer; 83*6d986c16SIngo Weinhold TRACE(("free_first_entry(): all entries freed!\n")); 84*6d986c16SIngo Weinhold } else 85*6d986c16SIngo Weinhold sFirstEntry = newFirst; 86*6d986c16SIngo Weinhold 87*6d986c16SIngo Weinhold return true; 88*6d986c16SIngo Weinhold } 89*6d986c16SIngo Weinhold 90*6d986c16SIngo Weinhold 91*6d986c16SIngo Weinhold static bool 928e43ece8SAxel Dörfler make_space(size_t needed) 93aa5d2a2dSAxel Dörfler { 94*6d986c16SIngo Weinhold // we need space for sAfterLastEntry, too (in case we need to wrap around 95*6d986c16SIngo Weinhold // later) 96*6d986c16SIngo Weinhold needed += 4; 97*6d986c16SIngo Weinhold 98*6d986c16SIngo Weinhold // If there's not enough space (free or occupied) after sAfterLastEntry, 99*6d986c16SIngo Weinhold // we free all entries in that region and wrap around. 100*6d986c16SIngo Weinhold if (sAfterLastEntry + needed / 4 > sBuffer + kBufferSize) { 101*6d986c16SIngo Weinhold TRACE(("make_space(%lu), wrapping around: after last: %p\n", needed, 102*6d986c16SIngo Weinhold sAfterLastEntry)); 103*6d986c16SIngo Weinhold 104*6d986c16SIngo Weinhold // Free all entries after sAfterLastEntry and one more at the beginning 105*6d986c16SIngo Weinhold // of the buffer. 106*6d986c16SIngo Weinhold do { 107*6d986c16SIngo Weinhold if (!free_first_entry()) 108*6d986c16SIngo Weinhold return false; 109*6d986c16SIngo Weinhold } while (sFirstEntry > sAfterLastEntry); 110*6d986c16SIngo Weinhold 111*6d986c16SIngo Weinhold // just in case free_first_entry() freed the very last existing entry 112*6d986c16SIngo Weinhold if (sAfterLastEntry == sBuffer) 113*6d986c16SIngo Weinhold return true; 114*6d986c16SIngo Weinhold 115*6d986c16SIngo Weinhold // mark as wrap entry and actually wrap around 116960f8f24SAxel Dörfler sAfterLastEntry->size = 0; 117960f8f24SAxel Dörfler sAfterLastEntry->flags = WRAP_ENTRY; 118960f8f24SAxel Dörfler sAfterLastEntry = sBuffer; 119aa5d2a2dSAxel Dörfler } 120aa5d2a2dSAxel Dörfler 121*6d986c16SIngo Weinhold if (sFirstEntry <= sAfterLastEntry) { 122*6d986c16SIngo Weinhold // buffer is empty or the space after sAfterLastEntry is unoccupied 123*6d986c16SIngo Weinhold return true; 12474652349SIngo Weinhold } 125aa5d2a2dSAxel Dörfler 126*6d986c16SIngo Weinhold // free the first entries, until there's enough space 127*6d986c16SIngo Weinhold size_t space = (sFirstEntry - sAfterLastEntry) * 4; 128aa5d2a2dSAxel Dörfler 129*6d986c16SIngo Weinhold if (space < needed) { 130*6d986c16SIngo Weinhold TRACE(("make_space(%lu), left %ld\n", needed, space)); 131*6d986c16SIngo Weinhold } 132*6d986c16SIngo Weinhold 133*6d986c16SIngo Weinhold while (space < needed) { 134*6d986c16SIngo Weinhold space += sFirstEntry->size; 135*6d986c16SIngo Weinhold 136*6d986c16SIngo Weinhold if (!free_first_entry()) 137*6d986c16SIngo Weinhold return false; 138aa5d2a2dSAxel Dörfler } 1395276dad0SAxel Dörfler 140960f8f24SAxel Dörfler TRACE((" out: start %p, entries %ld\n", sFirstEntry, sEntries)); 141*6d986c16SIngo Weinhold 142*6d986c16SIngo Weinhold return true; 143aa5d2a2dSAxel Dörfler } 144aa5d2a2dSAxel Dörfler 145aa5d2a2dSAxel Dörfler 14674652349SIngo Weinhold static trace_entry* 14774652349SIngo Weinhold allocate_entry(size_t size, uint16 flags) 148aa5d2a2dSAxel Dörfler { 149*6d986c16SIngo Weinhold if (sBuffer == NULL || size == 0 || size >= 65532) 150aa5d2a2dSAxel Dörfler return NULL; 151aa5d2a2dSAxel Dörfler 152aa5d2a2dSAxel Dörfler InterruptsSpinLocker _(sLock); 153aa5d2a2dSAxel Dörfler 154aa5d2a2dSAxel Dörfler size = (size + 3) & ~3; 155aa5d2a2dSAxel Dörfler 1565276dad0SAxel Dörfler TRACE(("allocate_entry(%lu), start %p, end %p, buffer %p\n", size, 157960f8f24SAxel Dörfler sFirstEntry, sAfterLastEntry, sBuffer)); 1585276dad0SAxel Dörfler 159*6d986c16SIngo Weinhold if (!make_space(size)) 160*6d986c16SIngo Weinhold return NULL; 161aa5d2a2dSAxel Dörfler 162960f8f24SAxel Dörfler trace_entry* entry = sAfterLastEntry; 163aa5d2a2dSAxel Dörfler entry->size = size; 16474652349SIngo Weinhold entry->flags = flags; 165960f8f24SAxel Dörfler sAfterLastEntry += size >> 2; 16674652349SIngo Weinhold 16774652349SIngo Weinhold if (!(flags & BUFFER_ENTRY)) 168aa5d2a2dSAxel Dörfler sEntries++; 16974652349SIngo Weinhold 170*6d986c16SIngo Weinhold TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry, 171*6d986c16SIngo Weinhold sAfterLastEntry, sFirstEntry, sEntries)); 17274652349SIngo Weinhold 173aa5d2a2dSAxel Dörfler return entry; 1748e43ece8SAxel Dörfler } 1758e43ece8SAxel Dörfler 1768e43ece8SAxel Dörfler 1778e43ece8SAxel Dörfler #endif // ENABLE_TRACING 1788e43ece8SAxel Dörfler 1798e43ece8SAxel Dörfler 1808e43ece8SAxel Dörfler // #pragma mark - 1818e43ece8SAxel Dörfler 1828e43ece8SAxel Dörfler 183f1047a1cSIngo Weinhold TraceOutput::TraceOutput(char* buffer, size_t bufferSize) 184f1047a1cSIngo Weinhold : fBuffer(buffer), 185f7a5d9c5SIngo Weinhold fCapacity(bufferSize) 186f1047a1cSIngo Weinhold { 187f7a5d9c5SIngo Weinhold Clear(); 188f7a5d9c5SIngo Weinhold } 189f7a5d9c5SIngo Weinhold 190f7a5d9c5SIngo Weinhold 191f7a5d9c5SIngo Weinhold void 192f7a5d9c5SIngo Weinhold TraceOutput::Clear() 193f7a5d9c5SIngo Weinhold { 194f7a5d9c5SIngo Weinhold if (fCapacity > 0) 195f7a5d9c5SIngo Weinhold fBuffer[0] = '\0'; 196f7a5d9c5SIngo Weinhold fSize = 0; 197f1047a1cSIngo Weinhold } 198f1047a1cSIngo Weinhold 199f1047a1cSIngo Weinhold 200f1047a1cSIngo Weinhold void 201f1047a1cSIngo Weinhold TraceOutput::Print(const char* format,...) 202f1047a1cSIngo Weinhold { 203f1047a1cSIngo Weinhold if (IsFull()) 204f1047a1cSIngo Weinhold return; 205f1047a1cSIngo Weinhold 206f1047a1cSIngo Weinhold va_list args; 207f1047a1cSIngo Weinhold va_start(args, format); 208f1047a1cSIngo Weinhold fSize += vsnprintf(fBuffer + fSize, fCapacity - fSize, format, args); 209f1047a1cSIngo Weinhold va_end(args); 210f1047a1cSIngo Weinhold } 211f1047a1cSIngo Weinhold 212f1047a1cSIngo Weinhold 213f1047a1cSIngo Weinhold // #pragma mark - 214f1047a1cSIngo Weinhold 215f1047a1cSIngo Weinhold 2168e43ece8SAxel Dörfler TraceEntry::TraceEntry() 2178e43ece8SAxel Dörfler { 2188e43ece8SAxel Dörfler } 2198e43ece8SAxel Dörfler 2208e43ece8SAxel Dörfler 2218e43ece8SAxel Dörfler TraceEntry::~TraceEntry() 2228e43ece8SAxel Dörfler { 2238e43ece8SAxel Dörfler } 2248e43ece8SAxel Dörfler 2258e43ece8SAxel Dörfler 2268e43ece8SAxel Dörfler void 227f7a5d9c5SIngo Weinhold TraceEntry::Dump(TraceOutput& out) 2288e43ece8SAxel Dörfler { 2298e43ece8SAxel Dörfler #if ENABLE_TRACING 230f1047a1cSIngo Weinhold // to be overridden by subclasses 231f7a5d9c5SIngo Weinhold out.Print("ENTRY %p", this); 2328e43ece8SAxel Dörfler #endif 2338e43ece8SAxel Dörfler } 2348e43ece8SAxel Dörfler 2358e43ece8SAxel Dörfler 2368e43ece8SAxel Dörfler void 2378e43ece8SAxel Dörfler TraceEntry::Initialized() 2388e43ece8SAxel Dörfler { 2398e43ece8SAxel Dörfler #if ENABLE_TRACING 2408e43ece8SAxel Dörfler flags |= ENTRY_INITIALIZED; 241f70280a7SAxel Dörfler sWritten++; 2428e43ece8SAxel Dörfler #endif 2438e43ece8SAxel Dörfler } 2448e43ece8SAxel Dörfler 2458e43ece8SAxel Dörfler 2468e43ece8SAxel Dörfler void* 2478e43ece8SAxel Dörfler TraceEntry::operator new(size_t size, const std::nothrow_t&) throw() 2488e43ece8SAxel Dörfler { 2498e43ece8SAxel Dörfler #if ENABLE_TRACING 25074652349SIngo Weinhold return allocate_entry(size, 0); 2518e43ece8SAxel Dörfler #else 252aa5d2a2dSAxel Dörfler return NULL; 253aa5d2a2dSAxel Dörfler #endif 254aa5d2a2dSAxel Dörfler } 255aa5d2a2dSAxel Dörfler 256aa5d2a2dSAxel Dörfler 257aa5d2a2dSAxel Dörfler // #pragma mark - 258aa5d2a2dSAxel Dörfler 259aa5d2a2dSAxel Dörfler 260f1047a1cSIngo Weinhold AbstractTraceEntry::~AbstractTraceEntry() 261f1047a1cSIngo Weinhold { 262f1047a1cSIngo Weinhold } 263f1047a1cSIngo Weinhold 264f1047a1cSIngo Weinhold 265f1047a1cSIngo Weinhold void 266f7a5d9c5SIngo Weinhold AbstractTraceEntry::Dump(TraceOutput& out) 267f1047a1cSIngo Weinhold { 268f7a5d9c5SIngo Weinhold out.Print("[%6ld] %Ld: ", fThread, fTime); 269f1047a1cSIngo Weinhold AddDump(out); 270f1047a1cSIngo Weinhold } 271f1047a1cSIngo Weinhold 272f1047a1cSIngo Weinhold 273f1047a1cSIngo Weinhold void 274f1047a1cSIngo Weinhold AbstractTraceEntry::AddDump(TraceOutput& out) 275f1047a1cSIngo Weinhold { 276f1047a1cSIngo Weinhold } 277f1047a1cSIngo Weinhold 278f1047a1cSIngo Weinhold 2794c4b14c3SIngo Weinhold // #pragma mark - trace filters 2804c4b14c3SIngo Weinhold 2814c4b14c3SIngo Weinhold 2824c4b14c3SIngo Weinhold class LazyTraceOutput : public TraceOutput { 2834c4b14c3SIngo Weinhold public: 2844c4b14c3SIngo Weinhold LazyTraceOutput(char* buffer, size_t bufferSize) 2854c4b14c3SIngo Weinhold : TraceOutput(buffer, bufferSize) 2864c4b14c3SIngo Weinhold { 2874c4b14c3SIngo Weinhold } 2884c4b14c3SIngo Weinhold 2894c4b14c3SIngo Weinhold const char* DumpEntry(const TraceEntry* entry) 2904c4b14c3SIngo Weinhold { 2914c4b14c3SIngo Weinhold if (Size() == 0) { 2924c4b14c3SIngo Weinhold const_cast<TraceEntry*>(entry)->Dump(*this); 2934c4b14c3SIngo Weinhold // Dump() should probably be const 2944c4b14c3SIngo Weinhold } 2954c4b14c3SIngo Weinhold 2964c4b14c3SIngo Weinhold return Buffer(); 2974c4b14c3SIngo Weinhold } 2984c4b14c3SIngo Weinhold }; 2994c4b14c3SIngo Weinhold 3004c4b14c3SIngo Weinhold 3014c4b14c3SIngo Weinhold class TraceFilter { 3024c4b14c3SIngo Weinhold public: 3034c4b14c3SIngo Weinhold virtual ~TraceFilter() 3044c4b14c3SIngo Weinhold { 3054c4b14c3SIngo Weinhold } 3064c4b14c3SIngo Weinhold 3074c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 3084c4b14c3SIngo Weinhold { 3094c4b14c3SIngo Weinhold return false; 3104c4b14c3SIngo Weinhold } 3114c4b14c3SIngo Weinhold 3124c4b14c3SIngo Weinhold public: 3134c4b14c3SIngo Weinhold union { 3144c4b14c3SIngo Weinhold thread_id fThread; 3154c4b14c3SIngo Weinhold const char* fString; 3164c4b14c3SIngo Weinhold struct { 3174c4b14c3SIngo Weinhold TraceFilter* first; 3184c4b14c3SIngo Weinhold TraceFilter* second; 3194c4b14c3SIngo Weinhold } fSubFilters; 3204c4b14c3SIngo Weinhold }; 3214c4b14c3SIngo Weinhold }; 3224c4b14c3SIngo Weinhold 3234c4b14c3SIngo Weinhold 3244c4b14c3SIngo Weinhold class ThreadTraceFilter : public TraceFilter { 3254c4b14c3SIngo Weinhold public: 3264c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out) 3274c4b14c3SIngo Weinhold { 3284c4b14c3SIngo Weinhold const AbstractTraceEntry* entry 3294c4b14c3SIngo Weinhold = dynamic_cast<const AbstractTraceEntry*>(_entry); 3304c4b14c3SIngo Weinhold return (entry != NULL && entry->Thread() == fThread); 3314c4b14c3SIngo Weinhold } 3324c4b14c3SIngo Weinhold }; 3334c4b14c3SIngo Weinhold 3344c4b14c3SIngo Weinhold 3354c4b14c3SIngo Weinhold class PatternTraceFilter : public TraceFilter { 3364c4b14c3SIngo Weinhold public: 3374c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 3384c4b14c3SIngo Weinhold { 3394c4b14c3SIngo Weinhold return strstr(out.DumpEntry(entry), fString) != NULL; 3404c4b14c3SIngo Weinhold } 3414c4b14c3SIngo Weinhold }; 3424c4b14c3SIngo Weinhold 3434c4b14c3SIngo Weinhold 3444c4b14c3SIngo Weinhold class NotTraceFilter : public TraceFilter { 3454c4b14c3SIngo Weinhold public: 3464c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 3474c4b14c3SIngo Weinhold { 3484c4b14c3SIngo Weinhold return !fSubFilters.first->Filter(entry, out); 3494c4b14c3SIngo Weinhold } 3504c4b14c3SIngo Weinhold }; 3514c4b14c3SIngo Weinhold 3524c4b14c3SIngo Weinhold 3534c4b14c3SIngo Weinhold class AndTraceFilter : public TraceFilter { 3544c4b14c3SIngo Weinhold public: 3554c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 3564c4b14c3SIngo Weinhold { 3574c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out) 3584c4b14c3SIngo Weinhold && fSubFilters.second->Filter(entry, out); 3594c4b14c3SIngo Weinhold } 3604c4b14c3SIngo Weinhold }; 3614c4b14c3SIngo Weinhold 3624c4b14c3SIngo Weinhold 3634c4b14c3SIngo Weinhold class OrTraceFilter : public TraceFilter { 3644c4b14c3SIngo Weinhold public: 3654c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 3664c4b14c3SIngo Weinhold { 3674c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out) 3684c4b14c3SIngo Weinhold || fSubFilters.second->Filter(entry, out); 3694c4b14c3SIngo Weinhold } 3704c4b14c3SIngo Weinhold }; 3714c4b14c3SIngo Weinhold 3724c4b14c3SIngo Weinhold 3734c4b14c3SIngo Weinhold class TraceFilterParser { 3744c4b14c3SIngo Weinhold public: 3754c4b14c3SIngo Weinhold static TraceFilterParser* Default() 3764c4b14c3SIngo Weinhold { 3774c4b14c3SIngo Weinhold return &sParser; 3784c4b14c3SIngo Weinhold } 3794c4b14c3SIngo Weinhold 3804c4b14c3SIngo Weinhold bool Parse(int argc, const char* const* argv) 3814c4b14c3SIngo Weinhold { 3824c4b14c3SIngo Weinhold fTokens = argv; 3834c4b14c3SIngo Weinhold fTokenCount = argc; 3844c4b14c3SIngo Weinhold fTokenIndex = 0; 3854c4b14c3SIngo Weinhold fFilterCount = 0; 3864c4b14c3SIngo Weinhold 3874c4b14c3SIngo Weinhold TraceFilter* filter = _ParseExpression(); 3884c4b14c3SIngo Weinhold return fTokenIndex == fTokenCount && filter != NULL; 3894c4b14c3SIngo Weinhold } 3904c4b14c3SIngo Weinhold 3914c4b14c3SIngo Weinhold bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 3924c4b14c3SIngo Weinhold { 3934c4b14c3SIngo Weinhold return fFilters[0].Filter(entry, out); 3944c4b14c3SIngo Weinhold } 3954c4b14c3SIngo Weinhold 3964c4b14c3SIngo Weinhold private: 3974c4b14c3SIngo Weinhold TraceFilter* _ParseExpression() 3984c4b14c3SIngo Weinhold { 3994c4b14c3SIngo Weinhold const char* token = _NextToken(); 4004c4b14c3SIngo Weinhold if (!token) { 4014c4b14c3SIngo Weinhold // unexpected end of expression 4024c4b14c3SIngo Weinhold return NULL; 4034c4b14c3SIngo Weinhold } 4044c4b14c3SIngo Weinhold 4054c4b14c3SIngo Weinhold if (fFilterCount == MAX_FILTERS) { 4064c4b14c3SIngo Weinhold // too many filters 4074c4b14c3SIngo Weinhold return NULL; 4084c4b14c3SIngo Weinhold } 4094c4b14c3SIngo Weinhold 4104c4b14c3SIngo Weinhold if (token[0] == '#') { 4114c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 4124c4b14c3SIngo Weinhold PatternTraceFilter; 4134c4b14c3SIngo Weinhold filter->fString = token + 1; 4144c4b14c3SIngo Weinhold return filter; 4154c4b14c3SIngo Weinhold } else if (strcmp(token, "not") == 0) { 4164c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) NotTraceFilter; 4174c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL) 4184c4b14c3SIngo Weinhold return filter; 4194c4b14c3SIngo Weinhold return NULL; 4204c4b14c3SIngo Weinhold } else if (strcmp(token, "and") == 0) { 4214c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) AndTraceFilter; 4224c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL 4234c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) { 4244c4b14c3SIngo Weinhold return filter; 4254c4b14c3SIngo Weinhold } 4264c4b14c3SIngo Weinhold return NULL; 4274c4b14c3SIngo Weinhold } else if (strcmp(token, "or") == 0) { 4284c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) OrTraceFilter; 4294c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL 4304c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) { 4314c4b14c3SIngo Weinhold return filter; 4324c4b14c3SIngo Weinhold } 4334c4b14c3SIngo Weinhold return NULL; 4344c4b14c3SIngo Weinhold } else if (strcmp(token, "thread") == 0) { 4354c4b14c3SIngo Weinhold const char* arg = _NextToken(); 4364c4b14c3SIngo Weinhold if (arg == NULL) { 4374c4b14c3SIngo Weinhold // unexpected end of expression 4384c4b14c3SIngo Weinhold return NULL; 4394c4b14c3SIngo Weinhold } 4404c4b14c3SIngo Weinhold 4414c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 4424c4b14c3SIngo Weinhold ThreadTraceFilter; 4434c4b14c3SIngo Weinhold filter->fThread = strtol(arg, NULL, 0); 4444c4b14c3SIngo Weinhold return filter; 4454c4b14c3SIngo Weinhold } else { 4464c4b14c3SIngo Weinhold // invalid token 4474c4b14c3SIngo Weinhold return NULL; 4484c4b14c3SIngo Weinhold } 4494c4b14c3SIngo Weinhold } 4504c4b14c3SIngo Weinhold 4514c4b14c3SIngo Weinhold const char* _CurrentToken() const 4524c4b14c3SIngo Weinhold { 4534c4b14c3SIngo Weinhold if (fTokenIndex >= 1 && fTokenIndex <= fTokenCount) 4544c4b14c3SIngo Weinhold return fTokens[fTokenIndex - 1]; 4554c4b14c3SIngo Weinhold return NULL; 4564c4b14c3SIngo Weinhold } 4574c4b14c3SIngo Weinhold 4584c4b14c3SIngo Weinhold const char* _NextToken() 4594c4b14c3SIngo Weinhold { 4604c4b14c3SIngo Weinhold if (fTokenIndex >= fTokenCount) 4614c4b14c3SIngo Weinhold return NULL; 4624c4b14c3SIngo Weinhold return fTokens[fTokenIndex++]; 4634c4b14c3SIngo Weinhold } 4644c4b14c3SIngo Weinhold 4654c4b14c3SIngo Weinhold private: 4664c4b14c3SIngo Weinhold enum { MAX_FILTERS = 32 }; 4674c4b14c3SIngo Weinhold 4684c4b14c3SIngo Weinhold const char* const* fTokens; 4694c4b14c3SIngo Weinhold int fTokenCount; 4704c4b14c3SIngo Weinhold int fTokenIndex; 4714c4b14c3SIngo Weinhold TraceFilter fFilters[MAX_FILTERS]; 4724c4b14c3SIngo Weinhold int fFilterCount; 4734c4b14c3SIngo Weinhold 4744c4b14c3SIngo Weinhold static TraceFilterParser sParser; 4754c4b14c3SIngo Weinhold }; 4764c4b14c3SIngo Weinhold 4774c4b14c3SIngo Weinhold 4784c4b14c3SIngo Weinhold TraceFilterParser TraceFilterParser::sParser; 4794c4b14c3SIngo Weinhold 4804c4b14c3SIngo Weinhold 481f1047a1cSIngo Weinhold // #pragma mark - 482f1047a1cSIngo Weinhold 483f1047a1cSIngo Weinhold 484aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 485aa5d2a2dSAxel Dörfler 486aa5d2a2dSAxel Dörfler 487aa5d2a2dSAxel Dörfler int 488aa5d2a2dSAxel Dörfler dump_tracing(int argc, char** argv) 489aa5d2a2dSAxel Dörfler { 4904c4b14c3SIngo Weinhold int argi = 1; 4918e43ece8SAxel Dörfler 49274652349SIngo Weinhold // Note: start and index are Pascal-like indices (i.e. in [1, sEntries]). 493aa5d2a2dSAxel Dörfler int32 count = 30; 49474652349SIngo Weinhold int32 start = 0; // special index: print the last count entries 49574652349SIngo Weinhold int32 cont = 0; 496aa5d2a2dSAxel Dörfler 4974c4b14c3SIngo Weinhold bool hasFilter = false; 4984c4b14c3SIngo Weinhold 4994c4b14c3SIngo Weinhold if (argi < argc) { 5004c4b14c3SIngo Weinhold if (strcmp(argv[argi], "forward") == 0) { 50174652349SIngo Weinhold cont = 1; 5024c4b14c3SIngo Weinhold argi++; 5034c4b14c3SIngo Weinhold } else if (strcmp(argv[argi], "backward") == 0) { 50474652349SIngo Weinhold cont = -1; 5054c4b14c3SIngo Weinhold argi++; 5064c4b14c3SIngo Weinhold } 50774652349SIngo Weinhold } 5082d81f045SAxel Dörfler 5094c4b14c3SIngo Weinhold if (cont != 0 && argi < argc) { 510a7e979caSIngo Weinhold print_debugger_command_usage(argv[0]); 511aa5d2a2dSAxel Dörfler return 0; 512aa5d2a2dSAxel Dörfler } 513aa5d2a2dSAxel Dörfler 5144c4b14c3SIngo Weinhold // start 5154c4b14c3SIngo Weinhold if (argi < argc) { 5164c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) { 5174c4b14c3SIngo Weinhold hasFilter = true; 5184c4b14c3SIngo Weinhold argi++; 5194c4b14c3SIngo Weinhold } else if (argv[argi][0] == '#') { 5204c4b14c3SIngo Weinhold hasFilter = true; 5214c4b14c3SIngo Weinhold } else { 5224c4b14c3SIngo Weinhold start = parse_expression(argv[argi]); 5234c4b14c3SIngo Weinhold argi++; 5244c4b14c3SIngo Weinhold } 5254c4b14c3SIngo Weinhold } 5264c4b14c3SIngo Weinhold 5274c4b14c3SIngo Weinhold // count 5284c4b14c3SIngo Weinhold if (!hasFilter && argi < argc) { 5294c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) { 5304c4b14c3SIngo Weinhold hasFilter = true; 5314c4b14c3SIngo Weinhold argi++; 5324c4b14c3SIngo Weinhold } else if (argv[argi][0] == '#') { 5334c4b14c3SIngo Weinhold hasFilter = true; 5344c4b14c3SIngo Weinhold } else { 5354c4b14c3SIngo Weinhold count = parse_expression(argv[argi]); 5364c4b14c3SIngo Weinhold argi++; 5374c4b14c3SIngo Weinhold } 5384c4b14c3SIngo Weinhold } 5394c4b14c3SIngo Weinhold 5404c4b14c3SIngo Weinhold // filter specification 5414c4b14c3SIngo Weinhold if (argi < argc) { 5424c4b14c3SIngo Weinhold hasFilter = true; 5434c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) 5444c4b14c3SIngo Weinhold argi++; 5454c4b14c3SIngo Weinhold 5464c4b14c3SIngo Weinhold if (!TraceFilterParser::Default()->Parse(argc - argi, argv + argi)) { 5474c4b14c3SIngo Weinhold print_debugger_command_usage(argv[0]); 5484c4b14c3SIngo Weinhold return 0; 5494c4b14c3SIngo Weinhold } 5504c4b14c3SIngo Weinhold } 5514c4b14c3SIngo Weinhold 55274652349SIngo Weinhold if (cont != 0) { 55374652349SIngo Weinhold start = get_debug_variable("_tracingStart", start); 55474652349SIngo Weinhold count = get_debug_variable("_tracingCount", count); 55574652349SIngo Weinhold start = max_c(1, start + count * cont); 5564c4b14c3SIngo Weinhold hasFilter = get_debug_variable("_tracingFilter", count); 55774652349SIngo Weinhold } 558aa5d2a2dSAxel Dörfler 55974652349SIngo Weinhold if ((uint32)count > sEntries) 56074652349SIngo Weinhold count = sEntries; 56174652349SIngo Weinhold if (start <= 0) 56274652349SIngo Weinhold start = max_c(1, sEntries - count + 1); 56374652349SIngo Weinhold if (uint32(start + count) > sEntries) 56474652349SIngo Weinhold count = sEntries - start + 1; 56574652349SIngo Weinhold 56674652349SIngo Weinhold int32 index = 1; 5675276dad0SAxel Dörfler int32 dumped = 0; 568aa5d2a2dSAxel Dörfler 569960f8f24SAxel Dörfler for (trace_entry* current = sFirstEntry; current != NULL; 570aa5d2a2dSAxel Dörfler current = next_entry(current), index++) { 5715276dad0SAxel Dörfler if ((current->flags & BUFFER_ENTRY) != 0) { 5728e43ece8SAxel Dörfler // skip buffer entries 5738e43ece8SAxel Dörfler index--; 5748e43ece8SAxel Dörfler continue; 5758e43ece8SAxel Dörfler } 57674652349SIngo Weinhold if (index < start) 57774652349SIngo Weinhold continue; 57874652349SIngo Weinhold if (index >= start + count) 57974652349SIngo Weinhold break; 580aa5d2a2dSAxel Dörfler 5818e43ece8SAxel Dörfler if ((current->flags & ENTRY_INITIALIZED) != 0) { 5828e43ece8SAxel Dörfler char buffer[256]; 5834c4b14c3SIngo Weinhold LazyTraceOutput out(buffer, sizeof(buffer)); 584f7a5d9c5SIngo Weinhold 5854c4b14c3SIngo Weinhold TraceEntry* entry = (TraceEntry*)current; 5864c4b14c3SIngo Weinhold if (hasFilter && !TraceFilterParser::Default()->Filter(entry, out)) 5878e43ece8SAxel Dörfler continue; 5888e43ece8SAxel Dörfler 5894c4b14c3SIngo Weinhold kprintf("%5ld. %s\n", index, out.DumpEntry(entry)); 5908e43ece8SAxel Dörfler } else 5918e43ece8SAxel Dörfler kprintf("%5ld. ** uninitialized entry **\n", index); 59274652349SIngo Weinhold 59374652349SIngo Weinhold dumped++; 594aa5d2a2dSAxel Dörfler } 595aa5d2a2dSAxel Dörfler 596f70280a7SAxel Dörfler kprintf("entries %ld to %ld (%ld of %ld). %ld entries written\n", start, 597f70280a7SAxel Dörfler start + count - 1, dumped, sEntries, sWritten); 59874652349SIngo Weinhold 59974652349SIngo Weinhold set_debug_variable("_tracingStart", start); 60074652349SIngo Weinhold set_debug_variable("_tracingCount", count); 6014c4b14c3SIngo Weinhold set_debug_variable("_tracingFilter", hasFilter); 60274652349SIngo Weinhold 60374652349SIngo Weinhold return cont != 0 ? B_KDEBUG_CONT : 0; 604aa5d2a2dSAxel Dörfler } 605aa5d2a2dSAxel Dörfler 606aa5d2a2dSAxel Dörfler 607aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING 608aa5d2a2dSAxel Dörfler 6092d81f045SAxel Dörfler 6108e43ece8SAxel Dörfler extern "C" uint8* 6118e43ece8SAxel Dörfler alloc_tracing_buffer(size_t size) 6128e43ece8SAxel Dörfler { 6138e43ece8SAxel Dörfler #if ENABLE_TRACING 61474652349SIngo Weinhold trace_entry* entry = allocate_entry(size + sizeof(trace_entry), 61574652349SIngo Weinhold BUFFER_ENTRY); 6168e43ece8SAxel Dörfler if (entry == NULL) 6178e43ece8SAxel Dörfler return NULL; 6188e43ece8SAxel Dörfler 6198e43ece8SAxel Dörfler return (uint8*)(entry + 1); 6208e43ece8SAxel Dörfler #else 6218e43ece8SAxel Dörfler return NULL; 6228e43ece8SAxel Dörfler #endif 6238e43ece8SAxel Dörfler } 6248e43ece8SAxel Dörfler 625aa5d2a2dSAxel Dörfler 6260b60583fSIngo Weinhold uint8* 6270b60583fSIngo Weinhold alloc_tracing_buffer_memcpy(const void* source, size_t size, bool user) 6280b60583fSIngo Weinhold { 6298bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source)) 6308bd6d45dSIngo Weinhold return NULL; 6318bd6d45dSIngo Weinhold 6320b60583fSIngo Weinhold uint8* buffer = alloc_tracing_buffer(size); 6330b60583fSIngo Weinhold if (buffer == NULL) 6340b60583fSIngo Weinhold return NULL; 6350b60583fSIngo Weinhold 6360b60583fSIngo Weinhold if (user) { 6370b60583fSIngo Weinhold if (user_memcpy(buffer, source, size) != B_OK) 6380b60583fSIngo Weinhold return NULL; 6390b60583fSIngo Weinhold } else 6400b60583fSIngo Weinhold memcpy(buffer, source, size); 6410b60583fSIngo Weinhold 6420b60583fSIngo Weinhold return buffer; 6430b60583fSIngo Weinhold } 6440b60583fSIngo Weinhold 6450b60583fSIngo Weinhold 6460b60583fSIngo Weinhold char* 6470b60583fSIngo Weinhold alloc_tracing_buffer_strcpy(const char* source, size_t maxSize, bool user) 6480b60583fSIngo Weinhold { 6498bd6d45dSIngo Weinhold if (source == NULL || maxSize == 0) 6500b60583fSIngo Weinhold return NULL; 6510b60583fSIngo Weinhold 6528bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source)) 6538bd6d45dSIngo Weinhold return NULL; 6548bd6d45dSIngo Weinhold 6558bd6d45dSIngo Weinhold // limit maxSize to the actual source string len 6568bd6d45dSIngo Weinhold if (user) { 6578bd6d45dSIngo Weinhold ssize_t size = user_strlcpy(NULL, source, 0); 6588bd6d45dSIngo Weinhold // there's no user_strnlen() 6598bd6d45dSIngo Weinhold if (size < 0) 6608bd6d45dSIngo Weinhold return 0; 6618bd6d45dSIngo Weinhold maxSize = min_c(maxSize, (size_t)size + 1); 6628bd6d45dSIngo Weinhold } else 6630b60583fSIngo Weinhold maxSize = strnlen(source, maxSize - 1) + 1; 6640b60583fSIngo Weinhold 6650b60583fSIngo Weinhold char* buffer = (char*)alloc_tracing_buffer(maxSize); 6660b60583fSIngo Weinhold if (buffer == NULL) 6670b60583fSIngo Weinhold return NULL; 6680b60583fSIngo Weinhold 6690b60583fSIngo Weinhold if (user) { 6700b60583fSIngo Weinhold if (user_strlcpy(buffer, source, maxSize) < B_OK) 6710b60583fSIngo Weinhold return NULL; 6720b60583fSIngo Weinhold } else 6730b60583fSIngo Weinhold strlcpy(buffer, source, maxSize); 6740b60583fSIngo Weinhold 6750b60583fSIngo Weinhold return buffer; 6760b60583fSIngo Weinhold } 6770b60583fSIngo Weinhold 6780b60583fSIngo Weinhold 679aa5d2a2dSAxel Dörfler extern "C" status_t 680aa5d2a2dSAxel Dörfler tracing_init(void) 681aa5d2a2dSAxel Dörfler { 682aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 683aa5d2a2dSAxel Dörfler area_id area = create_area("tracing log", (void**)&sBuffer, 684aa5d2a2dSAxel Dörfler B_ANY_KERNEL_ADDRESS, MAX_TRACE_SIZE, B_FULL_LOCK, 685aa5d2a2dSAxel Dörfler B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 6865276dad0SAxel Dörfler if (area < B_OK) 687aa5d2a2dSAxel Dörfler return area; 688aa5d2a2dSAxel Dörfler 689960f8f24SAxel Dörfler sFirstEntry = sBuffer; 690960f8f24SAxel Dörfler sAfterLastEntry = sBuffer; 691aa5d2a2dSAxel Dörfler 69274652349SIngo Weinhold add_debugger_command_etc("traced", &dump_tracing, 69374652349SIngo Weinhold "Dump recorded trace entries", 69474652349SIngo Weinhold "(\"forward\" | \"backward\") | ([ <start> [ <count> ] ] " 6954c4b14c3SIngo Weinhold "[ #<pattern> | (\"filter\" <filter>) ])\n" 69674652349SIngo Weinhold "Prints recorded trace entries. If \"backward\" or \"forward\" is\n" 69774652349SIngo Weinhold "specified, the command continues where the previous invocation left\n" 69874652349SIngo Weinhold "off, i.e. printing the previous respectively next entries (as many\n" 69974652349SIngo Weinhold "as printed before). In this case the command is continuable, that is\n" 70074652349SIngo Weinhold "afterwards entering an empty line in the debugger will reinvoke it.\n" 70174652349SIngo Weinhold " <start> - The index of the first entry to print. The index of\n" 70274652349SIngo Weinhold " the first recorded entry is 1. If 0 is specified, the\n" 70374652349SIngo Weinhold " last <count> recorded entries are printed. Defaults \n" 70474652349SIngo Weinhold " to 0.\n" 70574652349SIngo Weinhold " <count> - The number of entries to be printed. Defaults to 30.\n" 70674652349SIngo Weinhold " <pattern> - If specified only entries containing this string are\n" 7074c4b14c3SIngo Weinhold " printed.\n" 7084c4b14c3SIngo Weinhold " <filter> - If specified only entries matching this filter\n" 7094c4b14c3SIngo Weinhold " expression are printed. The expression can consist of\n" 7104c4b14c3SIngo Weinhold " prefix operators \"not\", \"and\", \"or\", filters of\n" 7114c4b14c3SIngo Weinhold " the kind \"'thread' <thread>\" (matching entries\n" 7124c4b14c3SIngo Weinhold " with the given thread ID), or filter of the kind\n" 7134c4b14c3SIngo Weinhold " \"#<pattern>\" (matching entries containing the given\n" 7144c4b14c3SIngo Weinhold " string.\n", 0); 715aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING 716aa5d2a2dSAxel Dörfler return B_OK; 717aa5d2a2dSAxel Dörfler } 718aa5d2a2dSAxel Dörfler 719