12d81f045SAxel Dörfler /* 24535495dSIngo Weinhold * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3093e0057SAxel Dörfler * Copyright 2008-2009, 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 133ce26345SIngo Weinhold #include <algorithm> 143ce26345SIngo Weinhold 1565f40152SIngo Weinhold #include <arch/debug.h> 1674652349SIngo Weinhold #include <debug.h> 1765f40152SIngo Weinhold #include <elf.h> 1865f40152SIngo Weinhold #include <int.h> 198bd6d45dSIngo Weinhold #include <kernel.h> 2064fe37eeSIngo Weinhold #include <team.h> 2164fe37eeSIngo Weinhold #include <thread.h> 222d81f045SAxel Dörfler #include <util/AutoLock.h> 23e50cf876SIngo Weinhold #include <vm/vm.h> 242d81f045SAxel Dörfler 25aa5d2a2dSAxel Dörfler 26b2d95c3cSIngo Weinhold struct tracing_stack_trace { 27b2d95c3cSIngo Weinhold int32 depth; 28b2d95c3cSIngo Weinhold addr_t return_addresses[0]; 29b2d95c3cSIngo Weinhold }; 30b2d95c3cSIngo Weinhold 31b2d95c3cSIngo Weinhold 32aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 33aa5d2a2dSAxel Dörfler 345276dad0SAxel Dörfler //#define TRACE_TRACING 355276dad0SAxel Dörfler #ifdef TRACE_TRACING 366d986c16SIngo Weinhold # define TRACE(x) dprintf_no_syslog x 375276dad0SAxel Dörfler #else 385276dad0SAxel Dörfler # define TRACE(x) ; 395276dad0SAxel Dörfler #endif 405276dad0SAxel Dörfler 415276dad0SAxel Dörfler 42aa5d2a2dSAxel Dörfler enum { 43aa5d2a2dSAxel Dörfler WRAP_ENTRY = 0x01, 448e43ece8SAxel Dörfler ENTRY_INITIALIZED = 0x02, 4556213ff4SIngo Weinhold BUFFER_ENTRY = 0x04, 463fccf067SIngo Weinhold FILTER_MATCH = 0x08, 473fccf067SIngo Weinhold INVALID_ENTRY = 0x10, 483fccf067SIngo Weinhold CHECK_ENTRY = 0x20, 49aa5d2a2dSAxel Dörfler }; 50aa5d2a2dSAxel Dörfler 5165f40152SIngo Weinhold 5265f40152SIngo Weinhold static const size_t kTraceOutputBufferSize = 10240; 533fccf067SIngo Weinhold static const size_t kBufferSize = MAX_TRACE_SIZE / sizeof(trace_entry); 54aa5d2a2dSAxel Dörfler 55ce50cdc3SIngo Weinhold static const uint32 kMaxRecoveringErrorCount = 100; 56d829579dSIngo Weinhold static const addr_t kMetaDataBaseAddress = 32 * 1024 * 1024; 57d829579dSIngo Weinhold static const addr_t kMetaDataBaseEndAddress = 128 * 1024 * 1024; 58d829579dSIngo Weinhold static const addr_t kMetaDataAddressIncrement = 8 * 1024 * 1024; 59d829579dSIngo Weinhold static const uint32 kMetaDataMagic1 = 'Vali'; 60d829579dSIngo Weinhold static const uint32 kMetaDataMagic2 = 'dTra'; 61d829579dSIngo Weinhold static const uint32 kMetaDataMagic3 = 'cing'; 62d829579dSIngo Weinhold 633fccf067SIngo Weinhold // the maximum we can address with the trace_entry::[previous_]size fields 64ce50cdc3SIngo Weinhold static const size_t kMaxTracingEntryByteSize 653fccf067SIngo Weinhold = ((1 << 13) - 1) * sizeof(trace_entry); 663fccf067SIngo Weinhold 67d829579dSIngo Weinhold 68d829579dSIngo Weinhold class TracingMetaData { 69d829579dSIngo Weinhold public: 703fccf067SIngo Weinhold static status_t Create(TracingMetaData*& _metaData); 71d829579dSIngo Weinhold 723fccf067SIngo Weinhold inline bool Lock(); 733fccf067SIngo Weinhold inline void Unlock(); 743fccf067SIngo Weinhold 753fccf067SIngo Weinhold inline trace_entry* FirstEntry() const; 763fccf067SIngo Weinhold inline trace_entry* AfterLastEntry() const; 773fccf067SIngo Weinhold 783fccf067SIngo Weinhold inline uint32 Entries() const; 793fccf067SIngo Weinhold inline uint32 EntriesEver() const; 803fccf067SIngo Weinhold 813fccf067SIngo Weinhold inline void IncrementEntriesEver(); 823fccf067SIngo Weinhold 833fccf067SIngo Weinhold inline char* TraceOutputBuffer() const; 843fccf067SIngo Weinhold 853fccf067SIngo Weinhold trace_entry* NextEntry(trace_entry* entry); 863fccf067SIngo Weinhold trace_entry* PreviousEntry(trace_entry* entry); 873fccf067SIngo Weinhold 883fccf067SIngo Weinhold trace_entry* AllocateEntry(size_t size, uint16 flags); 893fccf067SIngo Weinhold 903fccf067SIngo Weinhold private: 913fccf067SIngo Weinhold bool _FreeFirstEntry(); 923fccf067SIngo Weinhold bool _MakeSpace(size_t needed); 933fccf067SIngo Weinhold 943fccf067SIngo Weinhold static status_t _CreateMetaDataArea(bool findPrevious, 953fccf067SIngo Weinhold area_id& _area, 963fccf067SIngo Weinhold TracingMetaData*& _metaData); 97ce50cdc3SIngo Weinhold bool _InitPreviousTracingData(); 983fccf067SIngo Weinhold 993fccf067SIngo Weinhold private: 1003fccf067SIngo Weinhold uint32 fMagic1; 1013fccf067SIngo Weinhold trace_entry* fBuffer; 1023fccf067SIngo Weinhold trace_entry* fFirstEntry; 1033fccf067SIngo Weinhold trace_entry* fAfterLastEntry; 1043fccf067SIngo Weinhold uint32 fEntries; 1053fccf067SIngo Weinhold uint32 fMagic2; 1063fccf067SIngo Weinhold uint32 fEntriesEver; 1073fccf067SIngo Weinhold spinlock fLock; 1083fccf067SIngo Weinhold char* fTraceOutputBuffer; 10964d79effSIngo Weinhold phys_addr_t fPhysicalAddress; 1103fccf067SIngo Weinhold uint32 fMagic3; 1113fccf067SIngo Weinhold }; 1123fccf067SIngo Weinhold 1133fccf067SIngo Weinhold static TracingMetaData sDummyTracingMetaData; 1143fccf067SIngo Weinhold static TracingMetaData* sTracingMetaData = &sDummyTracingMetaData; 1153fccf067SIngo Weinhold static bool sTracingDataRecovered = false; 1163fccf067SIngo Weinhold 1173fccf067SIngo Weinhold 1183fccf067SIngo Weinhold // #pragma mark - 1193fccf067SIngo Weinhold 1203fccf067SIngo Weinhold 1213fccf067SIngo Weinhold // #pragma mark - TracingMetaData 1223fccf067SIngo Weinhold 1233fccf067SIngo Weinhold 1243fccf067SIngo Weinhold bool 1253fccf067SIngo Weinhold TracingMetaData::Lock() 1263fccf067SIngo Weinhold { 1273fccf067SIngo Weinhold acquire_spinlock(&fLock); 1283fccf067SIngo Weinhold return true; 1293fccf067SIngo Weinhold } 1303fccf067SIngo Weinhold 1313fccf067SIngo Weinhold 1323fccf067SIngo Weinhold void 1333fccf067SIngo Weinhold TracingMetaData::Unlock() 1343fccf067SIngo Weinhold { 1353fccf067SIngo Weinhold release_spinlock(&fLock); 1363fccf067SIngo Weinhold } 1373fccf067SIngo Weinhold 1383fccf067SIngo Weinhold 1393fccf067SIngo Weinhold trace_entry* 1403fccf067SIngo Weinhold TracingMetaData::FirstEntry() const 1413fccf067SIngo Weinhold { 1423fccf067SIngo Weinhold return fFirstEntry; 1433fccf067SIngo Weinhold } 1443fccf067SIngo Weinhold 1453fccf067SIngo Weinhold 1463fccf067SIngo Weinhold trace_entry* 1473fccf067SIngo Weinhold TracingMetaData::AfterLastEntry() const 1483fccf067SIngo Weinhold { 1493fccf067SIngo Weinhold return fAfterLastEntry; 1503fccf067SIngo Weinhold } 1513fccf067SIngo Weinhold 1523fccf067SIngo Weinhold 1533fccf067SIngo Weinhold uint32 1543fccf067SIngo Weinhold TracingMetaData::Entries() const 1553fccf067SIngo Weinhold { 1563fccf067SIngo Weinhold return fEntries; 1573fccf067SIngo Weinhold } 1583fccf067SIngo Weinhold 1593fccf067SIngo Weinhold 1603fccf067SIngo Weinhold uint32 1613fccf067SIngo Weinhold TracingMetaData::EntriesEver() const 1623fccf067SIngo Weinhold { 1633fccf067SIngo Weinhold return fEntriesEver; 1643fccf067SIngo Weinhold } 1653fccf067SIngo Weinhold 1663fccf067SIngo Weinhold 1673fccf067SIngo Weinhold void 1683fccf067SIngo Weinhold TracingMetaData::IncrementEntriesEver() 1693fccf067SIngo Weinhold { 1703fccf067SIngo Weinhold fEntriesEver++; 171ce50cdc3SIngo Weinhold // NOTE: Race condition on SMP machines! We should use atomic_add(), 172ce50cdc3SIngo Weinhold // though that costs some performance and the information is for 173ce50cdc3SIngo Weinhold // informational purpose anyway. 1743fccf067SIngo Weinhold } 1753fccf067SIngo Weinhold 1763fccf067SIngo Weinhold 1773fccf067SIngo Weinhold char* 1783fccf067SIngo Weinhold TracingMetaData::TraceOutputBuffer() const 1793fccf067SIngo Weinhold { 1803fccf067SIngo Weinhold return fTraceOutputBuffer; 1813fccf067SIngo Weinhold } 1823fccf067SIngo Weinhold 1833fccf067SIngo Weinhold 1843fccf067SIngo Weinhold trace_entry* 1853fccf067SIngo Weinhold TracingMetaData::NextEntry(trace_entry* entry) 1863fccf067SIngo Weinhold { 1873fccf067SIngo Weinhold entry += entry->size; 1883fccf067SIngo Weinhold if ((entry->flags & WRAP_ENTRY) != 0) 1893fccf067SIngo Weinhold entry = fBuffer; 1903fccf067SIngo Weinhold 1913fccf067SIngo Weinhold if (entry == fAfterLastEntry) 1923fccf067SIngo Weinhold return NULL; 1933fccf067SIngo Weinhold 1943fccf067SIngo Weinhold return entry; 1953fccf067SIngo Weinhold } 1963fccf067SIngo Weinhold 1973fccf067SIngo Weinhold 1983fccf067SIngo Weinhold trace_entry* 1993fccf067SIngo Weinhold TracingMetaData::PreviousEntry(trace_entry* entry) 2003fccf067SIngo Weinhold { 2013fccf067SIngo Weinhold if (entry == fFirstEntry) 2023fccf067SIngo Weinhold return NULL; 2033fccf067SIngo Weinhold 2043fccf067SIngo Weinhold if (entry == fBuffer) { 2053fccf067SIngo Weinhold // beginning of buffer -- previous entry is a wrap entry 2063fccf067SIngo Weinhold entry = fBuffer + kBufferSize - entry->previous_size; 2073fccf067SIngo Weinhold } 2083fccf067SIngo Weinhold 2093fccf067SIngo Weinhold return entry - entry->previous_size; 2103fccf067SIngo Weinhold } 2113fccf067SIngo Weinhold 2123fccf067SIngo Weinhold 2133fccf067SIngo Weinhold trace_entry* 2143fccf067SIngo Weinhold TracingMetaData::AllocateEntry(size_t size, uint16 flags) 2153fccf067SIngo Weinhold { 216ce50cdc3SIngo Weinhold if (fAfterLastEntry == NULL || size == 0 217ce50cdc3SIngo Weinhold || size >= kMaxTracingEntryByteSize) { 2183fccf067SIngo Weinhold return NULL; 219ce50cdc3SIngo Weinhold } 2203fccf067SIngo Weinhold 2213fccf067SIngo Weinhold InterruptsSpinLocker _(fLock); 2223fccf067SIngo Weinhold 2233fccf067SIngo Weinhold size = (size + 3) >> 2; 2243fccf067SIngo Weinhold // 4 byte aligned, don't store the lower 2 bits 2253fccf067SIngo Weinhold 2263fccf067SIngo Weinhold TRACE(("AllocateEntry(%lu), start %p, end %p, buffer %p\n", size * 4, 2273fccf067SIngo Weinhold fFirstEntry, fAfterLastEntry, fBuffer)); 2283fccf067SIngo Weinhold 2293fccf067SIngo Weinhold if (!_MakeSpace(size)) 2303fccf067SIngo Weinhold return NULL; 2313fccf067SIngo Weinhold 2323fccf067SIngo Weinhold trace_entry* entry = fAfterLastEntry; 2333fccf067SIngo Weinhold entry->size = size; 2343fccf067SIngo Weinhold entry->flags = flags; 2353fccf067SIngo Weinhold fAfterLastEntry += size; 2363fccf067SIngo Weinhold fAfterLastEntry->previous_size = size; 2373fccf067SIngo Weinhold 2383fccf067SIngo Weinhold if (!(flags & BUFFER_ENTRY)) 2393fccf067SIngo Weinhold fEntries++; 2403fccf067SIngo Weinhold 2413fccf067SIngo Weinhold TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry, 2423fccf067SIngo Weinhold fAfterLastEntry, fFirstEntry, fEntries)); 2433fccf067SIngo Weinhold 2443fccf067SIngo Weinhold return entry; 2453fccf067SIngo Weinhold } 2463fccf067SIngo Weinhold 2473fccf067SIngo Weinhold 2483fccf067SIngo Weinhold bool 2493fccf067SIngo Weinhold TracingMetaData::_FreeFirstEntry() 2503fccf067SIngo Weinhold { 2513fccf067SIngo Weinhold TRACE((" skip start %p, %lu*4 bytes\n", fFirstEntry, fFirstEntry->size)); 2523fccf067SIngo Weinhold 2533fccf067SIngo Weinhold trace_entry* newFirst = NextEntry(fFirstEntry); 2543fccf067SIngo Weinhold 2553fccf067SIngo Weinhold if (fFirstEntry->flags & BUFFER_ENTRY) { 2563fccf067SIngo Weinhold // a buffer entry -- just skip it 2573fccf067SIngo Weinhold } else if (fFirstEntry->flags & ENTRY_INITIALIZED) { 25837e6de5dSIngo Weinhold // Fully initialized TraceEntry: We could destroy it, but don't do so 25937e6de5dSIngo Weinhold // for sake of robustness. The destructors of tracing entry classes 26037e6de5dSIngo Weinhold // should be empty anyway. 2613fccf067SIngo Weinhold fEntries--; 2623fccf067SIngo Weinhold } else { 2633fccf067SIngo Weinhold // Not fully initialized TraceEntry. We can't free it, since 2643fccf067SIngo Weinhold // then it's constructor might still write into the memory and 2653fccf067SIngo Weinhold // overwrite data of the entry we're going to allocate. 2663fccf067SIngo Weinhold // We can't do anything until this entry can be discarded. 2673fccf067SIngo Weinhold return false; 2683fccf067SIngo Weinhold } 2693fccf067SIngo Weinhold 2703fccf067SIngo Weinhold if (newFirst == NULL) { 2713fccf067SIngo Weinhold // everything is freed -- practically this can't happen, if 2723fccf067SIngo Weinhold // the buffer is large enough to hold three max-sized entries 2733fccf067SIngo Weinhold fFirstEntry = fAfterLastEntry = fBuffer; 2743fccf067SIngo Weinhold TRACE(("_FreeFirstEntry(): all entries freed!\n")); 2753fccf067SIngo Weinhold } else 2763fccf067SIngo Weinhold fFirstEntry = newFirst; 2773fccf067SIngo Weinhold 2783fccf067SIngo Weinhold return true; 2793fccf067SIngo Weinhold } 2803fccf067SIngo Weinhold 2813fccf067SIngo Weinhold 2823fccf067SIngo Weinhold /*! Makes sure we have needed * 4 bytes of memory at fAfterLastEntry. 2833fccf067SIngo Weinhold Returns \c false, if unable to free that much. 2843fccf067SIngo Weinhold */ 2853fccf067SIngo Weinhold bool 2863fccf067SIngo Weinhold TracingMetaData::_MakeSpace(size_t needed) 2873fccf067SIngo Weinhold { 2883fccf067SIngo Weinhold // we need space for fAfterLastEntry, too (in case we need to wrap around 2893fccf067SIngo Weinhold // later) 2903fccf067SIngo Weinhold needed++; 2913fccf067SIngo Weinhold 2923fccf067SIngo Weinhold // If there's not enough space (free or occupied) after fAfterLastEntry, 2933fccf067SIngo Weinhold // we free all entries in that region and wrap around. 2943fccf067SIngo Weinhold if (fAfterLastEntry + needed > fBuffer + kBufferSize) { 2953fccf067SIngo Weinhold TRACE(("_MakeSpace(%lu), wrapping around: after last: %p\n", needed, 2963fccf067SIngo Weinhold fAfterLastEntry)); 2973fccf067SIngo Weinhold 2983fccf067SIngo Weinhold // Free all entries after fAfterLastEntry and one more at the beginning 2993fccf067SIngo Weinhold // of the buffer. 3003fccf067SIngo Weinhold while (fFirstEntry > fAfterLastEntry) { 3013fccf067SIngo Weinhold if (!_FreeFirstEntry()) 3023fccf067SIngo Weinhold return false; 3033fccf067SIngo Weinhold } 3043fccf067SIngo Weinhold if (fAfterLastEntry != fBuffer && !_FreeFirstEntry()) 3053fccf067SIngo Weinhold return false; 3063fccf067SIngo Weinhold 3073fccf067SIngo Weinhold // just in case _FreeFirstEntry() freed the very last existing entry 3083fccf067SIngo Weinhold if (fAfterLastEntry == fBuffer) 3093fccf067SIngo Weinhold return true; 3103fccf067SIngo Weinhold 3113fccf067SIngo Weinhold // mark as wrap entry and actually wrap around 3123fccf067SIngo Weinhold trace_entry* wrapEntry = fAfterLastEntry; 3133fccf067SIngo Weinhold wrapEntry->size = 0; 3143fccf067SIngo Weinhold wrapEntry->flags = WRAP_ENTRY; 3153fccf067SIngo Weinhold fAfterLastEntry = fBuffer; 3163fccf067SIngo Weinhold fAfterLastEntry->previous_size = fBuffer + kBufferSize - wrapEntry; 3173fccf067SIngo Weinhold } 3183fccf067SIngo Weinhold 3193fccf067SIngo Weinhold if (fFirstEntry <= fAfterLastEntry) { 3203fccf067SIngo Weinhold // buffer is empty or the space after fAfterLastEntry is unoccupied 3213fccf067SIngo Weinhold return true; 3223fccf067SIngo Weinhold } 3233fccf067SIngo Weinhold 3243fccf067SIngo Weinhold // free the first entries, until there's enough space 3253fccf067SIngo Weinhold size_t space = fFirstEntry - fAfterLastEntry; 3263fccf067SIngo Weinhold 3273fccf067SIngo Weinhold if (space < needed) { 3283fccf067SIngo Weinhold TRACE(("_MakeSpace(%lu), left %ld\n", needed, space)); 3293fccf067SIngo Weinhold } 3303fccf067SIngo Weinhold 3313fccf067SIngo Weinhold while (space < needed) { 3323fccf067SIngo Weinhold space += fFirstEntry->size; 3333fccf067SIngo Weinhold 3343fccf067SIngo Weinhold if (!_FreeFirstEntry()) 3353fccf067SIngo Weinhold return false; 3363fccf067SIngo Weinhold } 3373fccf067SIngo Weinhold 3383fccf067SIngo Weinhold TRACE((" out: start %p, entries %ld\n", fFirstEntry, fEntries)); 3393fccf067SIngo Weinhold 3403fccf067SIngo Weinhold return true; 3413fccf067SIngo Weinhold } 3423fccf067SIngo Weinhold 3433fccf067SIngo Weinhold 3443fccf067SIngo Weinhold /*static*/ status_t 3453fccf067SIngo Weinhold TracingMetaData::Create(TracingMetaData*& _metaData) 346d829579dSIngo Weinhold { 347d829579dSIngo Weinhold // search meta data in memory (from previous session) 348d829579dSIngo Weinhold area_id area; 349d829579dSIngo Weinhold TracingMetaData* metaData; 350d829579dSIngo Weinhold status_t error = _CreateMetaDataArea(true, area, metaData); 351d829579dSIngo Weinhold if (error == B_OK) { 352ce50cdc3SIngo Weinhold if (metaData->_InitPreviousTracingData()) { 353d829579dSIngo Weinhold _metaData = metaData; 354d829579dSIngo Weinhold return B_OK; 355d829579dSIngo Weinhold } 356d829579dSIngo Weinhold 357d829579dSIngo Weinhold dprintf("Found previous tracing meta data, but failed to init.\n"); 358d829579dSIngo Weinhold 359d829579dSIngo Weinhold // invalidate the meta data 3603fccf067SIngo Weinhold metaData->fMagic1 = 0; 3613fccf067SIngo Weinhold metaData->fMagic2 = 0; 3623fccf067SIngo Weinhold metaData->fMagic3 = 0; 363d829579dSIngo Weinhold delete_area(area); 364d829579dSIngo Weinhold } else 365d829579dSIngo Weinhold dprintf("No previous tracing meta data found.\n"); 366d829579dSIngo Weinhold 36755d903d2SAxel Dörfler // no previous tracing data found -- create new one 368d829579dSIngo Weinhold error = _CreateMetaDataArea(false, area, metaData); 369d829579dSIngo Weinhold if (error != B_OK) 370d829579dSIngo Weinhold return error; 371d829579dSIngo Weinhold 372a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {}; 373a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; 374a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {}; 3757198f765SAxel Dörfler area = create_area_etc(B_SYSTEM_TEAM, "tracing log", 376d829579dSIngo Weinhold kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS, 377a8ad734fSIngo Weinhold B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT, 378a8ad734fSIngo Weinhold &virtualRestrictions, &physicalRestrictions, 379a8ad734fSIngo Weinhold (void**)&metaData->fTraceOutputBuffer); 380d829579dSIngo Weinhold if (area < 0) 381d829579dSIngo Weinhold return area; 382d829579dSIngo Weinhold 383d829579dSIngo Weinhold // get the physical address 384d829579dSIngo Weinhold physical_entry physicalEntry; 3853fccf067SIngo Weinhold if (get_memory_map(metaData->fTraceOutputBuffer, B_PAGE_SIZE, 386d829579dSIngo Weinhold &physicalEntry, 1) == B_OK) { 38764d79effSIngo Weinhold metaData->fPhysicalAddress = physicalEntry.address; 388d829579dSIngo Weinhold } else { 389d829579dSIngo Weinhold dprintf("TracingMetaData::Create(): failed to get physical address " 390d829579dSIngo Weinhold "of tracing buffer\n"); 3913fccf067SIngo Weinhold metaData->fPhysicalAddress = 0; 392d829579dSIngo Weinhold } 393d829579dSIngo Weinhold 3943fccf067SIngo Weinhold metaData->fBuffer = (trace_entry*)(metaData->fTraceOutputBuffer 395d829579dSIngo Weinhold + kTraceOutputBufferSize); 3963fccf067SIngo Weinhold metaData->fFirstEntry = metaData->fBuffer; 3973fccf067SIngo Weinhold metaData->fAfterLastEntry = metaData->fBuffer; 398d829579dSIngo Weinhold 3993fccf067SIngo Weinhold metaData->fEntries = 0; 4003fccf067SIngo Weinhold metaData->fEntriesEver = 0; 4013fccf067SIngo Weinhold B_INITIALIZE_SPINLOCK(&metaData->fLock); 402d829579dSIngo Weinhold 4033fccf067SIngo Weinhold metaData->fMagic1 = kMetaDataMagic1; 4043fccf067SIngo Weinhold metaData->fMagic2 = kMetaDataMagic2; 4053fccf067SIngo Weinhold metaData->fMagic3 = kMetaDataMagic3; 406d829579dSIngo Weinhold 407d829579dSIngo Weinhold _metaData = metaData; 408d829579dSIngo Weinhold return B_OK; 409d829579dSIngo Weinhold } 410d829579dSIngo Weinhold 4113fccf067SIngo Weinhold 4123fccf067SIngo Weinhold /*static*/ status_t 4133fccf067SIngo Weinhold TracingMetaData::_CreateMetaDataArea(bool findPrevious, area_id& _area, 4143fccf067SIngo Weinhold TracingMetaData*& _metaData) 415d829579dSIngo Weinhold { 416d829579dSIngo Weinhold // search meta data in memory (from previous session) 417d829579dSIngo Weinhold TracingMetaData* metaData; 418a8ad734fSIngo Weinhold phys_addr_t metaDataAddress = kMetaDataBaseAddress; 419d829579dSIngo Weinhold for (; metaDataAddress <= kMetaDataBaseEndAddress; 420d829579dSIngo Weinhold metaDataAddress += kMetaDataAddressIncrement) { 421a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {}; 422a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; 423a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {}; 424a8ad734fSIngo Weinhold physicalRestrictions.low_address = metaDataAddress; 425a8ad734fSIngo Weinhold physicalRestrictions.high_address = metaDataAddress + B_PAGE_SIZE; 426cdb638a8SAxel Dörfler area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing metadata", 427cdb638a8SAxel Dörfler B_PAGE_SIZE, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 428a8ad734fSIngo Weinhold CREATE_AREA_DONT_CLEAR, &virtualRestrictions, &physicalRestrictions, 429a8ad734fSIngo Weinhold (void**)&metaData); 430d829579dSIngo Weinhold if (area < 0) 431d829579dSIngo Weinhold continue; 432d829579dSIngo Weinhold 433d829579dSIngo Weinhold if (!findPrevious) { 434d829579dSIngo Weinhold _area = area; 435d829579dSIngo Weinhold _metaData = metaData; 436d829579dSIngo Weinhold return B_OK; 437d829579dSIngo Weinhold } 438d829579dSIngo Weinhold 4393fccf067SIngo Weinhold if (metaData->fMagic1 == kMetaDataMagic1 4403fccf067SIngo Weinhold && metaData->fMagic2 == kMetaDataMagic2 4413fccf067SIngo Weinhold && metaData->fMagic3 == kMetaDataMagic3) { 442d829579dSIngo Weinhold _area = area; 443d829579dSIngo Weinhold _metaData = metaData; 444d829579dSIngo Weinhold return B_OK; 445d829579dSIngo Weinhold } 446d829579dSIngo Weinhold 447d829579dSIngo Weinhold delete_area(area); 448d829579dSIngo Weinhold } 449d829579dSIngo Weinhold 450d829579dSIngo Weinhold return B_ENTRY_NOT_FOUND; 451d829579dSIngo Weinhold } 452d829579dSIngo Weinhold 4533fccf067SIngo Weinhold 454ce50cdc3SIngo Weinhold bool 455ce50cdc3SIngo Weinhold TracingMetaData::_InitPreviousTracingData() 456d829579dSIngo Weinhold { 457b0eaa06cSIngo Weinhold // TODO: ATM re-attaching the previous tracing buffer doesn't work very 458b0eaa06cSIngo Weinhold // well. The entries should checked more thoroughly for validity -- e.g. the 459b0eaa06cSIngo Weinhold // pointers to the entries' vtable pointers could be invalid, which can 460b0eaa06cSIngo Weinhold // make the "traced" command quite unusable. The validity of the entries 461b0eaa06cSIngo Weinhold // could be checked in a safe environment (i.e. with a fault handler) with 462b0eaa06cSIngo Weinhold // typeid() and call of a virtual function. 463b0eaa06cSIngo Weinhold return false; 464b0eaa06cSIngo Weinhold 465d829579dSIngo Weinhold addr_t bufferStart 466ce50cdc3SIngo Weinhold = (addr_t)fTraceOutputBuffer + kTraceOutputBufferSize; 467d829579dSIngo Weinhold addr_t bufferEnd = bufferStart + MAX_TRACE_SIZE; 468d829579dSIngo Weinhold 469ce50cdc3SIngo Weinhold if (bufferStart > bufferEnd || (addr_t)fBuffer != bufferStart 470ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry % sizeof(trace_entry) != 0 471ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry < bufferStart 472ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry + sizeof(trace_entry) >= bufferEnd 473ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry % sizeof(trace_entry) != 0 474ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry < bufferStart 475ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry > bufferEnd 476ce50cdc3SIngo Weinhold || fPhysicalAddress == 0) { 477d829579dSIngo Weinhold dprintf("Failed to init tracing meta data: Sanity checks " 478d829579dSIngo Weinhold "failed.\n"); 479d829579dSIngo Weinhold return false; 480d829579dSIngo Weinhold } 481d829579dSIngo Weinhold 482d829579dSIngo Weinhold // re-map the previous tracing buffer 483a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {}; 484a8ad734fSIngo Weinhold virtualRestrictions.address = fTraceOutputBuffer; 485a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_EXACT_ADDRESS; 486a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {}; 487a8ad734fSIngo Weinhold physicalRestrictions.low_address = fPhysicalAddress; 488a8ad734fSIngo Weinhold physicalRestrictions.high_address = fPhysicalAddress 489cdb638a8SAxel Dörfler + ROUNDUP(kTraceOutputBufferSize + MAX_TRACE_SIZE, B_PAGE_SIZE); 490d829579dSIngo Weinhold area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing log", 491a8ad734fSIngo Weinhold kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS, 492a8ad734fSIngo Weinhold B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_CLEAR, 493a8ad734fSIngo Weinhold &virtualRestrictions, &physicalRestrictions, NULL); 494d829579dSIngo Weinhold if (area < 0) { 495d829579dSIngo Weinhold dprintf("Failed to init tracing meta data: Mapping tracing log " 496d829579dSIngo Weinhold "buffer failed: %s\n", strerror(area)); 497d829579dSIngo Weinhold return false; 498d829579dSIngo Weinhold } 499d829579dSIngo Weinhold 5001aed2639SIngo Weinhold dprintf("ktrace: Remapped tracing buffer at %p, size: %" B_PRIuSIZE "\n", 501a8ad734fSIngo Weinhold fTraceOutputBuffer, kTraceOutputBufferSize + MAX_TRACE_SIZE); 5021aed2639SIngo Weinhold 5033fccf067SIngo Weinhold // verify/repair the tracing entry list 504ce50cdc3SIngo Weinhold uint32 errorCount = 0; 505ce50cdc3SIngo Weinhold uint32 entryCount = 0; 506ce50cdc3SIngo Weinhold uint32 nonBufferEntryCount = 0; 507ce50cdc3SIngo Weinhold uint32 previousEntrySize = 0; 508ce50cdc3SIngo Weinhold trace_entry* entry = fFirstEntry; 509ce50cdc3SIngo Weinhold while (errorCount <= kMaxRecoveringErrorCount) { 510ce50cdc3SIngo Weinhold // check previous entry size 511ce50cdc3SIngo Weinhold if (entry->previous_size != previousEntrySize) { 512ce50cdc3SIngo Weinhold if (entry != fFirstEntry) { 513ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: fixing previous_size " 514ce50cdc3SIngo Weinhold "size: %lu (should be %lu)\n", entry, entry->previous_size, 515ce50cdc3SIngo Weinhold previousEntrySize); 5161aed2639SIngo Weinhold errorCount++; 517d829579dSIngo Weinhold } 518ce50cdc3SIngo Weinhold entry->previous_size = previousEntrySize; 519ce50cdc3SIngo Weinhold } 520aa5d2a2dSAxel Dörfler 5213fccf067SIngo Weinhold if (entry == fAfterLastEntry) 522ce50cdc3SIngo Weinhold break; 523aa5d2a2dSAxel Dörfler 524ce50cdc3SIngo Weinhold // check size field 525ce50cdc3SIngo Weinhold if ((entry->flags & WRAP_ENTRY) == 0 && entry->size == 0) { 526ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: non-wrap entry size is 0\n", 527ce50cdc3SIngo Weinhold entry); 5281aed2639SIngo Weinhold errorCount++; 529ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 530ce50cdc3SIngo Weinhold break; 531aa5d2a2dSAxel Dörfler } 532aa5d2a2dSAxel Dörfler 533ce50cdc3SIngo Weinhold if (entry->size > uint32(fBuffer + kBufferSize - entry)) { 534ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: size too big: %lu\n", entry, 535ce50cdc3SIngo Weinhold entry->size); 5361aed2639SIngo Weinhold errorCount++; 537ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 538ce50cdc3SIngo Weinhold break; 5396d369966SIngo Weinhold } 5406d369966SIngo Weinhold 541ce50cdc3SIngo Weinhold if (entry < fAfterLastEntry && entry + entry->size > fAfterLastEntry) { 542ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: entry crosses " 543ce50cdc3SIngo Weinhold "fAfterLastEntry (%p)\n", entry, fAfterLastEntry); 5441aed2639SIngo Weinhold errorCount++; 545ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 546ce50cdc3SIngo Weinhold break; 5476d369966SIngo Weinhold } 5486d369966SIngo Weinhold 549ce50cdc3SIngo Weinhold // check for wrap entry 550ce50cdc3SIngo Weinhold if ((entry->flags & WRAP_ENTRY) != 0) { 551ce50cdc3SIngo Weinhold if ((uint32)(fBuffer + kBufferSize - entry) 552ce50cdc3SIngo Weinhold > kMaxTracingEntryByteSize / sizeof(trace_entry)) { 553ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: wrap entry at invalid " 554ce50cdc3SIngo Weinhold "buffer location\n", entry); 5551aed2639SIngo Weinhold errorCount++; 556ce50cdc3SIngo Weinhold } 5576d369966SIngo Weinhold 558ce50cdc3SIngo Weinhold if (entry->size != 0) { 559ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: invalid wrap entry " 560ce50cdc3SIngo Weinhold "size: %lu\n", entry, entry->size); 5611aed2639SIngo Weinhold errorCount++; 562ce50cdc3SIngo Weinhold entry->size = 0; 563ce50cdc3SIngo Weinhold } 5646d986c16SIngo Weinhold 565ce50cdc3SIngo Weinhold previousEntrySize = fBuffer + kBufferSize - entry; 566ce50cdc3SIngo Weinhold entry = fBuffer; 567ce50cdc3SIngo Weinhold continue; 568ce50cdc3SIngo Weinhold } 569ce50cdc3SIngo Weinhold 570ce50cdc3SIngo Weinhold if ((entry->flags & BUFFER_ENTRY) == 0) { 571ce50cdc3SIngo Weinhold entry->flags |= CHECK_ENTRY; 572ce50cdc3SIngo Weinhold nonBufferEntryCount++; 573ce50cdc3SIngo Weinhold } 574ce50cdc3SIngo Weinhold 575ce50cdc3SIngo Weinhold entryCount++; 576ce50cdc3SIngo Weinhold previousEntrySize = entry->size; 577ce50cdc3SIngo Weinhold 578ce50cdc3SIngo Weinhold entry += entry->size; 579ce50cdc3SIngo Weinhold } 580ce50cdc3SIngo Weinhold 581ce50cdc3SIngo Weinhold if (errorCount > kMaxRecoveringErrorCount) { 582ce50cdc3SIngo Weinhold dprintf("ktrace recovering: Too many errors.\n"); 583ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 584ce50cdc3SIngo Weinhold fAfterLastEntry->previous_size = previousEntrySize; 585ce50cdc3SIngo Weinhold } 586ce50cdc3SIngo Weinhold 587ce50cdc3SIngo Weinhold dprintf("ktrace recovering: Recovered %lu entries + %lu buffer entries " 588ce50cdc3SIngo Weinhold "from previous session. Expected %lu entries.\n", nonBufferEntryCount, 589ce50cdc3SIngo Weinhold entryCount - nonBufferEntryCount, fEntries); 590ce50cdc3SIngo Weinhold fEntries = nonBufferEntryCount; 591ce50cdc3SIngo Weinhold 592ce50cdc3SIngo Weinhold B_INITIALIZE_SPINLOCK(&fLock); 593ce50cdc3SIngo Weinhold 594ce50cdc3SIngo Weinhold // TODO: Actually check the entries! Do that when first accessing the 595ce50cdc3SIngo Weinhold // tracing buffer from the kernel debugger (when sTracingDataRecovered is 596ce50cdc3SIngo Weinhold // true). 5973fccf067SIngo Weinhold sTracingDataRecovered = true; 5986d986c16SIngo Weinhold return true; 5996d986c16SIngo Weinhold } 6006d986c16SIngo Weinhold 6016d986c16SIngo Weinhold 6028e43ece8SAxel Dörfler #endif // ENABLE_TRACING 6038e43ece8SAxel Dörfler 6048e43ece8SAxel Dörfler 6058e43ece8SAxel Dörfler // #pragma mark - 6068e43ece8SAxel Dörfler 6078e43ece8SAxel Dörfler 608350b6dbcSIngo Weinhold TraceOutput::TraceOutput(char* buffer, size_t bufferSize, uint32 flags) 609f1047a1cSIngo Weinhold : fBuffer(buffer), 610350b6dbcSIngo Weinhold fCapacity(bufferSize), 611350b6dbcSIngo Weinhold fFlags(flags) 612f1047a1cSIngo Weinhold { 613f7a5d9c5SIngo Weinhold Clear(); 614f7a5d9c5SIngo Weinhold } 615f7a5d9c5SIngo Weinhold 616f7a5d9c5SIngo Weinhold 617f7a5d9c5SIngo Weinhold void 618f7a5d9c5SIngo Weinhold TraceOutput::Clear() 619f7a5d9c5SIngo Weinhold { 620f7a5d9c5SIngo Weinhold if (fCapacity > 0) 621f7a5d9c5SIngo Weinhold fBuffer[0] = '\0'; 622f7a5d9c5SIngo Weinhold fSize = 0; 623f1047a1cSIngo Weinhold } 624f1047a1cSIngo Weinhold 625f1047a1cSIngo Weinhold 626f1047a1cSIngo Weinhold void 627f1047a1cSIngo Weinhold TraceOutput::Print(const char* format,...) 628f1047a1cSIngo Weinhold { 629b2d95c3cSIngo Weinhold #if ENABLE_TRACING 630f1047a1cSIngo Weinhold if (IsFull()) 631f1047a1cSIngo Weinhold return; 632f1047a1cSIngo Weinhold 6333ce26345SIngo Weinhold if (fSize < fCapacity) { 634f1047a1cSIngo Weinhold va_list args; 635f1047a1cSIngo Weinhold va_start(args, format); 6363ce26345SIngo Weinhold size_t length = vsnprintf(fBuffer + fSize, fCapacity - fSize, format, 6373ce26345SIngo Weinhold args); 6383ce26345SIngo Weinhold fSize += std::min(length, fCapacity - fSize - 1); 639f1047a1cSIngo Weinhold va_end(args); 6403ce26345SIngo Weinhold } 641b2d95c3cSIngo Weinhold #endif 642f1047a1cSIngo Weinhold } 643f1047a1cSIngo Weinhold 644f1047a1cSIngo Weinhold 645350b6dbcSIngo Weinhold void 64665f40152SIngo Weinhold TraceOutput::PrintStackTrace(tracing_stack_trace* stackTrace) 64765f40152SIngo Weinhold { 648b2d95c3cSIngo Weinhold #if ENABLE_TRACING 64965f40152SIngo Weinhold if (stackTrace == NULL || stackTrace->depth <= 0) 65065f40152SIngo Weinhold return; 65165f40152SIngo Weinhold 65265f40152SIngo Weinhold for (int32 i = 0; i < stackTrace->depth; i++) { 65365f40152SIngo Weinhold addr_t address = stackTrace->return_addresses[i]; 65465f40152SIngo Weinhold 65565f40152SIngo Weinhold const char* symbol; 65665f40152SIngo Weinhold const char* imageName; 65765f40152SIngo Weinhold bool exactMatch; 65865f40152SIngo Weinhold addr_t baseAddress; 65965f40152SIngo Weinhold 66065f40152SIngo Weinhold if (elf_debug_lookup_symbol_address(address, &baseAddress, &symbol, 66165f40152SIngo Weinhold &imageName, &exactMatch) == B_OK) { 66265f40152SIngo Weinhold Print(" %p %s + 0x%lx (%s)%s\n", (void*)address, symbol, 66365f40152SIngo Weinhold address - baseAddress, imageName, 66465f40152SIngo Weinhold exactMatch ? "" : " (nearest)"); 66565f40152SIngo Weinhold } else 66665f40152SIngo Weinhold Print(" %p\n", (void*)address); 66765f40152SIngo Weinhold } 668b2d95c3cSIngo Weinhold #endif 66965f40152SIngo Weinhold } 67065f40152SIngo Weinhold 67165f40152SIngo Weinhold 67265f40152SIngo Weinhold void 673350b6dbcSIngo Weinhold TraceOutput::SetLastEntryTime(bigtime_t time) 674350b6dbcSIngo Weinhold { 675350b6dbcSIngo Weinhold fLastEntryTime = time; 676350b6dbcSIngo Weinhold } 677350b6dbcSIngo Weinhold 678350b6dbcSIngo Weinhold 679350b6dbcSIngo Weinhold bigtime_t 680350b6dbcSIngo Weinhold TraceOutput::LastEntryTime() const 681350b6dbcSIngo Weinhold { 682350b6dbcSIngo Weinhold return fLastEntryTime; 683350b6dbcSIngo Weinhold } 684350b6dbcSIngo Weinhold 685350b6dbcSIngo Weinhold 686f1047a1cSIngo Weinhold // #pragma mark - 687f1047a1cSIngo Weinhold 688f1047a1cSIngo Weinhold 6898e43ece8SAxel Dörfler TraceEntry::TraceEntry() 6908e43ece8SAxel Dörfler { 6918e43ece8SAxel Dörfler } 6928e43ece8SAxel Dörfler 6938e43ece8SAxel Dörfler 6948e43ece8SAxel Dörfler TraceEntry::~TraceEntry() 6958e43ece8SAxel Dörfler { 6968e43ece8SAxel Dörfler } 6978e43ece8SAxel Dörfler 6988e43ece8SAxel Dörfler 6998e43ece8SAxel Dörfler void 700f7a5d9c5SIngo Weinhold TraceEntry::Dump(TraceOutput& out) 7018e43ece8SAxel Dörfler { 7028e43ece8SAxel Dörfler #if ENABLE_TRACING 703f1047a1cSIngo Weinhold // to be overridden by subclasses 704f7a5d9c5SIngo Weinhold out.Print("ENTRY %p", this); 7058e43ece8SAxel Dörfler #endif 7068e43ece8SAxel Dörfler } 7078e43ece8SAxel Dörfler 7088e43ece8SAxel Dörfler 7098e43ece8SAxel Dörfler void 71065f40152SIngo Weinhold TraceEntry::DumpStackTrace(TraceOutput& out) 71165f40152SIngo Weinhold { 71265f40152SIngo Weinhold } 71365f40152SIngo Weinhold 71465f40152SIngo Weinhold 71565f40152SIngo Weinhold void 7168e43ece8SAxel Dörfler TraceEntry::Initialized() 7178e43ece8SAxel Dörfler { 7188e43ece8SAxel Dörfler #if ENABLE_TRACING 719b3d6c12dSIngo Weinhold ToTraceEntry()->flags |= ENTRY_INITIALIZED; 7203fccf067SIngo Weinhold sTracingMetaData->IncrementEntriesEver(); 7218e43ece8SAxel Dörfler #endif 7228e43ece8SAxel Dörfler } 7238e43ece8SAxel Dörfler 7248e43ece8SAxel Dörfler 7258e43ece8SAxel Dörfler void* 7268e43ece8SAxel Dörfler TraceEntry::operator new(size_t size, const std::nothrow_t&) throw() 7278e43ece8SAxel Dörfler { 7288e43ece8SAxel Dörfler #if ENABLE_TRACING 7293fccf067SIngo Weinhold trace_entry* entry = sTracingMetaData->AllocateEntry( 7303fccf067SIngo Weinhold size + sizeof(trace_entry), 0); 731b3d6c12dSIngo Weinhold return entry != NULL ? entry + 1 : NULL; 732aa5d2a2dSAxel Dörfler #endif 733989a6e05SIngo Weinhold return NULL; 734aa5d2a2dSAxel Dörfler } 735aa5d2a2dSAxel Dörfler 736aa5d2a2dSAxel Dörfler 737aa5d2a2dSAxel Dörfler // #pragma mark - 738aa5d2a2dSAxel Dörfler 739aa5d2a2dSAxel Dörfler 740f1047a1cSIngo Weinhold AbstractTraceEntry::~AbstractTraceEntry() 741f1047a1cSIngo Weinhold { 742f1047a1cSIngo Weinhold } 743f1047a1cSIngo Weinhold 744f1047a1cSIngo Weinhold 745f1047a1cSIngo Weinhold void 746f7a5d9c5SIngo Weinhold AbstractTraceEntry::Dump(TraceOutput& out) 747f1047a1cSIngo Weinhold { 748350b6dbcSIngo Weinhold bigtime_t time = (out.Flags() & TRACE_OUTPUT_DIFF_TIME) 749350b6dbcSIngo Weinhold ? fTime - out.LastEntryTime() 750350b6dbcSIngo Weinhold : fTime; 751350b6dbcSIngo Weinhold 752350b6dbcSIngo Weinhold if (out.Flags() & TRACE_OUTPUT_TEAM_ID) 753350b6dbcSIngo Weinhold out.Print("[%6ld:%6ld] %10Ld: ", fThread, fTeam, time); 75464fe37eeSIngo Weinhold else 755350b6dbcSIngo Weinhold out.Print("[%6ld] %10Ld: ", fThread, time); 756350b6dbcSIngo Weinhold 757f1047a1cSIngo Weinhold AddDump(out); 758350b6dbcSIngo Weinhold 759350b6dbcSIngo Weinhold out.SetLastEntryTime(fTime); 760f1047a1cSIngo Weinhold } 761f1047a1cSIngo Weinhold 762f1047a1cSIngo Weinhold 763f1047a1cSIngo Weinhold void 764f1047a1cSIngo Weinhold AbstractTraceEntry::AddDump(TraceOutput& out) 765f1047a1cSIngo Weinhold { 766f1047a1cSIngo Weinhold } 767f1047a1cSIngo Weinhold 768f1047a1cSIngo Weinhold 769*fe8f0f46SMichael Lotz void 770*fe8f0f46SMichael Lotz AbstractTraceEntry::_Init() 771*fe8f0f46SMichael Lotz { 772*fe8f0f46SMichael Lotz Thread* thread = thread_get_current_thread(); 773*fe8f0f46SMichael Lotz if (thread != NULL) { 774*fe8f0f46SMichael Lotz fThread = thread->id; 775*fe8f0f46SMichael Lotz if (thread->team) 776*fe8f0f46SMichael Lotz fTeam = thread->team->id; 777*fe8f0f46SMichael Lotz } 778*fe8f0f46SMichael Lotz fTime = system_time(); 779*fe8f0f46SMichael Lotz } 780*fe8f0f46SMichael Lotz 781*fe8f0f46SMichael Lotz 782*fe8f0f46SMichael Lotz // #pragma mark - AbstractTraceEntryWithStackTrace 783*fe8f0f46SMichael Lotz 784*fe8f0f46SMichael Lotz 785*fe8f0f46SMichael Lotz 786*fe8f0f46SMichael Lotz AbstractTraceEntryWithStackTrace::AbstractTraceEntryWithStackTrace( 787*fe8f0f46SMichael Lotz size_t stackTraceDepth, size_t skipFrames, bool kernelOnly) 788*fe8f0f46SMichael Lotz { 789*fe8f0f46SMichael Lotz fStackTrace = capture_tracing_stack_trace(stackTraceDepth, skipFrames + 1, 790*fe8f0f46SMichael Lotz kernelOnly); 791*fe8f0f46SMichael Lotz } 792*fe8f0f46SMichael Lotz 793*fe8f0f46SMichael Lotz 794*fe8f0f46SMichael Lotz void 795*fe8f0f46SMichael Lotz AbstractTraceEntryWithStackTrace::DumpStackTrace(TraceOutput& out) 796*fe8f0f46SMichael Lotz { 797*fe8f0f46SMichael Lotz out.PrintStackTrace(fStackTrace); 798*fe8f0f46SMichael Lotz } 799*fe8f0f46SMichael Lotz 800*fe8f0f46SMichael Lotz 801a54c125eSIngo Weinhold // #pragma mark - 802a54c125eSIngo Weinhold 803a54c125eSIngo Weinhold 804a54c125eSIngo Weinhold #if ENABLE_TRACING 805a54c125eSIngo Weinhold 8067d2d758dSIngo Weinhold class KernelTraceEntry : public AbstractTraceEntry { 8077d2d758dSIngo Weinhold public: 8087d2d758dSIngo Weinhold KernelTraceEntry(const char* message) 8097d2d758dSIngo Weinhold { 8107d2d758dSIngo Weinhold fMessage = alloc_tracing_buffer_strcpy(message, 256, false); 8117d2d758dSIngo Weinhold 812b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE 813b3d6c12dSIngo Weinhold fStackTrace = capture_tracing_stack_trace( 814b3d6c12dSIngo Weinhold KTRACE_PRINTF_STACK_TRACE, 1, false); 815b3d6c12dSIngo Weinhold #endif 8167d2d758dSIngo Weinhold Initialized(); 8177d2d758dSIngo Weinhold } 8187d2d758dSIngo Weinhold 8197d2d758dSIngo Weinhold virtual void AddDump(TraceOutput& out) 8207d2d758dSIngo Weinhold { 8217d2d758dSIngo Weinhold out.Print("kern: %s", fMessage); 8227d2d758dSIngo Weinhold } 8237d2d758dSIngo Weinhold 824b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE 825b3d6c12dSIngo Weinhold virtual void DumpStackTrace(TraceOutput& out) 826b3d6c12dSIngo Weinhold { 827b3d6c12dSIngo Weinhold out.PrintStackTrace(fStackTrace); 828b3d6c12dSIngo Weinhold } 829b3d6c12dSIngo Weinhold #endif 830b3d6c12dSIngo Weinhold 8317d2d758dSIngo Weinhold private: 8327d2d758dSIngo Weinhold char* fMessage; 833b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE 834b3d6c12dSIngo Weinhold tracing_stack_trace* fStackTrace; 835b3d6c12dSIngo Weinhold #endif 8367d2d758dSIngo Weinhold }; 8377d2d758dSIngo Weinhold 8387d2d758dSIngo Weinhold 839a54c125eSIngo Weinhold class UserTraceEntry : public AbstractTraceEntry { 840a54c125eSIngo Weinhold public: 841a54c125eSIngo Weinhold UserTraceEntry(const char* message) 842a54c125eSIngo Weinhold { 843a54c125eSIngo Weinhold fMessage = alloc_tracing_buffer_strcpy(message, 256, true); 844a54c125eSIngo Weinhold 845bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE 846bc6a5f86SOliver Tappe fStackTrace = capture_tracing_stack_trace( 847bc6a5f86SOliver Tappe KTRACE_PRINTF_STACK_TRACE, 1, false); 848bc6a5f86SOliver Tappe #endif 849a54c125eSIngo Weinhold Initialized(); 850a54c125eSIngo Weinhold } 851a54c125eSIngo Weinhold 852a54c125eSIngo Weinhold virtual void AddDump(TraceOutput& out) 853a54c125eSIngo Weinhold { 854a54c125eSIngo Weinhold out.Print("user: %s", fMessage); 855a54c125eSIngo Weinhold } 856a54c125eSIngo Weinhold 857bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE 858bc6a5f86SOliver Tappe virtual void DumpStackTrace(TraceOutput& out) 859bc6a5f86SOliver Tappe { 860bc6a5f86SOliver Tappe out.PrintStackTrace(fStackTrace); 861bc6a5f86SOliver Tappe } 862bc6a5f86SOliver Tappe #endif 863bc6a5f86SOliver Tappe 864a54c125eSIngo Weinhold private: 865a54c125eSIngo Weinhold char* fMessage; 866bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE 867bc6a5f86SOliver Tappe tracing_stack_trace* fStackTrace; 868bc6a5f86SOliver Tappe #endif 869a54c125eSIngo Weinhold }; 870a54c125eSIngo Weinhold 871d829579dSIngo Weinhold 872d829579dSIngo Weinhold class TracingLogStartEntry : public AbstractTraceEntry { 873d829579dSIngo Weinhold public: 874d829579dSIngo Weinhold TracingLogStartEntry() 875d829579dSIngo Weinhold { 876d829579dSIngo Weinhold Initialized(); 877d829579dSIngo Weinhold } 878d829579dSIngo Weinhold 879d829579dSIngo Weinhold virtual void AddDump(TraceOutput& out) 880d829579dSIngo Weinhold { 881d829579dSIngo Weinhold out.Print("ktrace start"); 882d829579dSIngo Weinhold } 883d829579dSIngo Weinhold }; 884d829579dSIngo Weinhold 885a54c125eSIngo Weinhold #endif // ENABLE_TRACING 886a54c125eSIngo Weinhold 887a54c125eSIngo Weinhold 8884c4b14c3SIngo Weinhold // #pragma mark - trace filters 8894c4b14c3SIngo Weinhold 8904c4b14c3SIngo Weinhold 891f97199edSIngo Weinhold TraceFilter::~TraceFilter() 8924c4b14c3SIngo Weinhold { 8934c4b14c3SIngo Weinhold } 8944c4b14c3SIngo Weinhold 8954c4b14c3SIngo Weinhold 896f97199edSIngo Weinhold bool 897f97199edSIngo Weinhold TraceFilter::Filter(const TraceEntry* entry, LazyTraceOutput& out) 8984c4b14c3SIngo Weinhold { 8994c4b14c3SIngo Weinhold return false; 9004c4b14c3SIngo Weinhold } 9014c4b14c3SIngo Weinhold 9024c4b14c3SIngo Weinhold 9034c4b14c3SIngo Weinhold 9044c4b14c3SIngo Weinhold class ThreadTraceFilter : public TraceFilter { 9054c4b14c3SIngo Weinhold public: 9064c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out) 9074c4b14c3SIngo Weinhold { 9084c4b14c3SIngo Weinhold const AbstractTraceEntry* entry 9094c4b14c3SIngo Weinhold = dynamic_cast<const AbstractTraceEntry*>(_entry); 9104535495dSIngo Weinhold return (entry != NULL && entry->ThreadID() == fThread); 9114c4b14c3SIngo Weinhold } 9124c4b14c3SIngo Weinhold }; 9134c4b14c3SIngo Weinhold 9144c4b14c3SIngo Weinhold 91564fe37eeSIngo Weinhold class TeamTraceFilter : public TraceFilter { 91664fe37eeSIngo Weinhold public: 91764fe37eeSIngo Weinhold virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out) 91864fe37eeSIngo Weinhold { 91964fe37eeSIngo Weinhold const AbstractTraceEntry* entry 92064fe37eeSIngo Weinhold = dynamic_cast<const AbstractTraceEntry*>(_entry); 9214535495dSIngo Weinhold return (entry != NULL && entry->TeamID() == fTeam); 92264fe37eeSIngo Weinhold } 92364fe37eeSIngo Weinhold }; 92464fe37eeSIngo Weinhold 92564fe37eeSIngo Weinhold 9264c4b14c3SIngo Weinhold class PatternTraceFilter : public TraceFilter { 9274c4b14c3SIngo Weinhold public: 9284c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9294c4b14c3SIngo Weinhold { 9304c4b14c3SIngo Weinhold return strstr(out.DumpEntry(entry), fString) != NULL; 9314c4b14c3SIngo Weinhold } 9324c4b14c3SIngo Weinhold }; 9334c4b14c3SIngo Weinhold 9344c4b14c3SIngo Weinhold 935dc1a7867SAxel Dörfler class DecimalPatternTraceFilter : public TraceFilter { 936dc1a7867SAxel Dörfler public: 937dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 938dc1a7867SAxel Dörfler { 939dc1a7867SAxel Dörfler // TODO: this is *very* slow 940dc1a7867SAxel Dörfler char buffer[64]; 941dc1a7867SAxel Dörfler snprintf(buffer, sizeof(buffer), "%Ld", fValue); 942dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL; 943dc1a7867SAxel Dörfler } 944dc1a7867SAxel Dörfler }; 945dc1a7867SAxel Dörfler 946dc1a7867SAxel Dörfler class HexPatternTraceFilter : public TraceFilter { 947dc1a7867SAxel Dörfler public: 948dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 949dc1a7867SAxel Dörfler { 950dc1a7867SAxel Dörfler // TODO: this is *very* slow 951dc1a7867SAxel Dörfler char buffer[64]; 952dc1a7867SAxel Dörfler snprintf(buffer, sizeof(buffer), "%Lx", fValue); 953dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL; 954dc1a7867SAxel Dörfler } 955dc1a7867SAxel Dörfler }; 956dc1a7867SAxel Dörfler 957dc1a7867SAxel Dörfler class StringPatternTraceFilter : public TraceFilter { 958dc1a7867SAxel Dörfler public: 959dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 960dc1a7867SAxel Dörfler { 961dc1a7867SAxel Dörfler if (IS_KERNEL_ADDRESS(fValue)) 962dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), (const char*)fValue) != NULL; 963dc1a7867SAxel Dörfler 964dc1a7867SAxel Dörfler // TODO: this is *very* slow 965dc1a7867SAxel Dörfler char buffer[64]; 966dc1a7867SAxel Dörfler user_strlcpy(buffer, (const char*)fValue, sizeof(buffer)); 967dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL; 968dc1a7867SAxel Dörfler } 969dc1a7867SAxel Dörfler }; 970dc1a7867SAxel Dörfler 9714c4b14c3SIngo Weinhold class NotTraceFilter : public TraceFilter { 9724c4b14c3SIngo Weinhold public: 9734c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9744c4b14c3SIngo Weinhold { 9754c4b14c3SIngo Weinhold return !fSubFilters.first->Filter(entry, out); 9764c4b14c3SIngo Weinhold } 9774c4b14c3SIngo Weinhold }; 9784c4b14c3SIngo Weinhold 9794c4b14c3SIngo Weinhold 9804c4b14c3SIngo Weinhold class AndTraceFilter : public TraceFilter { 9814c4b14c3SIngo Weinhold public: 9824c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9834c4b14c3SIngo Weinhold { 9844c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out) 9854c4b14c3SIngo Weinhold && fSubFilters.second->Filter(entry, out); 9864c4b14c3SIngo Weinhold } 9874c4b14c3SIngo Weinhold }; 9884c4b14c3SIngo Weinhold 9894c4b14c3SIngo Weinhold 9904c4b14c3SIngo Weinhold class OrTraceFilter : public TraceFilter { 9914c4b14c3SIngo Weinhold public: 9924c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9934c4b14c3SIngo Weinhold { 9944c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out) 9954c4b14c3SIngo Weinhold || fSubFilters.second->Filter(entry, out); 9964c4b14c3SIngo Weinhold } 9974c4b14c3SIngo Weinhold }; 9984c4b14c3SIngo Weinhold 9994c4b14c3SIngo Weinhold 10004c4b14c3SIngo Weinhold class TraceFilterParser { 10014c4b14c3SIngo Weinhold public: 10024c4b14c3SIngo Weinhold static TraceFilterParser* Default() 10034c4b14c3SIngo Weinhold { 10044c4b14c3SIngo Weinhold return &sParser; 10054c4b14c3SIngo Weinhold } 10064c4b14c3SIngo Weinhold 10074c4b14c3SIngo Weinhold bool Parse(int argc, const char* const* argv) 10084c4b14c3SIngo Weinhold { 10094c4b14c3SIngo Weinhold fTokens = argv; 10104c4b14c3SIngo Weinhold fTokenCount = argc; 10114c4b14c3SIngo Weinhold fTokenIndex = 0; 10124c4b14c3SIngo Weinhold fFilterCount = 0; 10134c4b14c3SIngo Weinhold 10144c4b14c3SIngo Weinhold TraceFilter* filter = _ParseExpression(); 10154c4b14c3SIngo Weinhold return fTokenIndex == fTokenCount && filter != NULL; 10164c4b14c3SIngo Weinhold } 10174c4b14c3SIngo Weinhold 1018f97199edSIngo Weinhold TraceFilter* Filter() 10194c4b14c3SIngo Weinhold { 1020f97199edSIngo Weinhold return &fFilters[0]; 10214c4b14c3SIngo Weinhold } 10224c4b14c3SIngo Weinhold 10234c4b14c3SIngo Weinhold private: 10244c4b14c3SIngo Weinhold TraceFilter* _ParseExpression() 10254c4b14c3SIngo Weinhold { 10264c4b14c3SIngo Weinhold const char* token = _NextToken(); 10274c4b14c3SIngo Weinhold if (!token) { 10284c4b14c3SIngo Weinhold // unexpected end of expression 10294c4b14c3SIngo Weinhold return NULL; 10304c4b14c3SIngo Weinhold } 10314c4b14c3SIngo Weinhold 10324c4b14c3SIngo Weinhold if (fFilterCount == MAX_FILTERS) { 10334c4b14c3SIngo Weinhold // too many filters 10344c4b14c3SIngo Weinhold return NULL; 10354c4b14c3SIngo Weinhold } 10364c4b14c3SIngo Weinhold 10374c4b14c3SIngo Weinhold if (token[0] == '#') { 10384c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 10394c4b14c3SIngo Weinhold PatternTraceFilter; 10404c4b14c3SIngo Weinhold filter->fString = token + 1; 10414c4b14c3SIngo Weinhold return filter; 1042dc1a7867SAxel Dörfler } else if (token[0] == 'd' && token[1] == '#') { 1043dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++]) 1044dc1a7867SAxel Dörfler DecimalPatternTraceFilter; 1045dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2); 1046dc1a7867SAxel Dörfler return filter; 1047dc1a7867SAxel Dörfler } else if (token[0] == 'x' && token[1] == '#') { 1048dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++]) 1049dc1a7867SAxel Dörfler HexPatternTraceFilter; 1050dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2); 1051dc1a7867SAxel Dörfler return filter; 1052dc1a7867SAxel Dörfler } else if (token[0] == 's' && token[1] == '#') { 1053dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++]) 1054dc1a7867SAxel Dörfler StringPatternTraceFilter; 1055dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2); 1056dc1a7867SAxel Dörfler return filter; 10574c4b14c3SIngo Weinhold } else if (strcmp(token, "not") == 0) { 10584c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) NotTraceFilter; 10594c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL) 10604c4b14c3SIngo Weinhold return filter; 10614c4b14c3SIngo Weinhold return NULL; 10624c4b14c3SIngo Weinhold } else if (strcmp(token, "and") == 0) { 10634c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) AndTraceFilter; 10644c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL 10654c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) { 10664c4b14c3SIngo Weinhold return filter; 10674c4b14c3SIngo Weinhold } 10684c4b14c3SIngo Weinhold return NULL; 10694c4b14c3SIngo Weinhold } else if (strcmp(token, "or") == 0) { 10704c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) OrTraceFilter; 10714c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL 10724c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) { 10734c4b14c3SIngo Weinhold return filter; 10744c4b14c3SIngo Weinhold } 10754c4b14c3SIngo Weinhold return NULL; 10764c4b14c3SIngo Weinhold } else if (strcmp(token, "thread") == 0) { 10774c4b14c3SIngo Weinhold const char* arg = _NextToken(); 10784c4b14c3SIngo Weinhold if (arg == NULL) { 10794c4b14c3SIngo Weinhold // unexpected end of expression 10804c4b14c3SIngo Weinhold return NULL; 10814c4b14c3SIngo Weinhold } 10824c4b14c3SIngo Weinhold 10834c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 10844c4b14c3SIngo Weinhold ThreadTraceFilter; 10854c4b14c3SIngo Weinhold filter->fThread = strtol(arg, NULL, 0); 10864c4b14c3SIngo Weinhold return filter; 108764fe37eeSIngo Weinhold } else if (strcmp(token, "team") == 0) { 108864fe37eeSIngo Weinhold const char* arg = _NextToken(); 108964fe37eeSIngo Weinhold if (arg == NULL) { 109064fe37eeSIngo Weinhold // unexpected end of expression 109164fe37eeSIngo Weinhold return NULL; 109264fe37eeSIngo Weinhold } 109364fe37eeSIngo Weinhold 109464fe37eeSIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 109564fe37eeSIngo Weinhold TeamTraceFilter; 109664fe37eeSIngo Weinhold filter->fTeam = strtol(arg, NULL, 0); 109764fe37eeSIngo Weinhold return filter; 10984c4b14c3SIngo Weinhold } else { 10994c4b14c3SIngo Weinhold // invalid token 11004c4b14c3SIngo Weinhold return NULL; 11014c4b14c3SIngo Weinhold } 11024c4b14c3SIngo Weinhold } 11034c4b14c3SIngo Weinhold 11044c4b14c3SIngo Weinhold const char* _CurrentToken() const 11054c4b14c3SIngo Weinhold { 11064c4b14c3SIngo Weinhold if (fTokenIndex >= 1 && fTokenIndex <= fTokenCount) 11074c4b14c3SIngo Weinhold return fTokens[fTokenIndex - 1]; 11084c4b14c3SIngo Weinhold return NULL; 11094c4b14c3SIngo Weinhold } 11104c4b14c3SIngo Weinhold 11114c4b14c3SIngo Weinhold const char* _NextToken() 11124c4b14c3SIngo Weinhold { 11134c4b14c3SIngo Weinhold if (fTokenIndex >= fTokenCount) 11144c4b14c3SIngo Weinhold return NULL; 11154c4b14c3SIngo Weinhold return fTokens[fTokenIndex++]; 11164c4b14c3SIngo Weinhold } 11174c4b14c3SIngo Weinhold 11184c4b14c3SIngo Weinhold private: 11194c4b14c3SIngo Weinhold enum { MAX_FILTERS = 32 }; 11204c4b14c3SIngo Weinhold 11214c4b14c3SIngo Weinhold const char* const* fTokens; 11224c4b14c3SIngo Weinhold int fTokenCount; 11234c4b14c3SIngo Weinhold int fTokenIndex; 11244c4b14c3SIngo Weinhold TraceFilter fFilters[MAX_FILTERS]; 11254c4b14c3SIngo Weinhold int fFilterCount; 11264c4b14c3SIngo Weinhold 11274c4b14c3SIngo Weinhold static TraceFilterParser sParser; 11284c4b14c3SIngo Weinhold }; 11294c4b14c3SIngo Weinhold 11304c4b14c3SIngo Weinhold 11314c4b14c3SIngo Weinhold TraceFilterParser TraceFilterParser::sParser; 11324c4b14c3SIngo Weinhold 11334c4b14c3SIngo Weinhold 1134f1047a1cSIngo Weinhold // #pragma mark - 1135f1047a1cSIngo Weinhold 1136f1047a1cSIngo Weinhold 1137aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 1138aa5d2a2dSAxel Dörfler 1139aa5d2a2dSAxel Dörfler 1140ef7102faSIngo Weinhold TraceEntry* 1141ef7102faSIngo Weinhold TraceEntryIterator::Next() 11426d369966SIngo Weinhold { 11436d369966SIngo Weinhold if (fIndex == 0) { 11443fccf067SIngo Weinhold fEntry = _NextNonBufferEntry(sTracingMetaData->FirstEntry()); 11456d369966SIngo Weinhold fIndex = 1; 11466d369966SIngo Weinhold } else if (fEntry != NULL) { 11473fccf067SIngo Weinhold fEntry = _NextNonBufferEntry(sTracingMetaData->NextEntry(fEntry)); 11486d369966SIngo Weinhold fIndex++; 11496d369966SIngo Weinhold } 11506d369966SIngo Weinhold 11516d369966SIngo Weinhold return Current(); 11526d369966SIngo Weinhold } 11536d369966SIngo Weinhold 1154ef7102faSIngo Weinhold 1155ef7102faSIngo Weinhold TraceEntry* 1156ef7102faSIngo Weinhold TraceEntryIterator::Previous() 11576d369966SIngo Weinhold { 11583fccf067SIngo Weinhold if (fIndex == (int32)sTracingMetaData->Entries() + 1) 11593fccf067SIngo Weinhold fEntry = sTracingMetaData->AfterLastEntry(); 11606d369966SIngo Weinhold 11616d369966SIngo Weinhold if (fEntry != NULL) { 11623fccf067SIngo Weinhold fEntry = _PreviousNonBufferEntry( 11633fccf067SIngo Weinhold sTracingMetaData->PreviousEntry(fEntry)); 11646d369966SIngo Weinhold fIndex--; 11656d369966SIngo Weinhold } 11666d369966SIngo Weinhold 11676d369966SIngo Weinhold return Current(); 11686d369966SIngo Weinhold } 11696d369966SIngo Weinhold 1170ef7102faSIngo Weinhold 1171ef7102faSIngo Weinhold TraceEntry* 1172ef7102faSIngo Weinhold TraceEntryIterator::MoveTo(int32 index) 11736d369966SIngo Weinhold { 11746d369966SIngo Weinhold if (index == fIndex) 11756d369966SIngo Weinhold return Current(); 11766d369966SIngo Weinhold 11773fccf067SIngo Weinhold if (index <= 0 || index > (int32)sTracingMetaData->Entries()) { 11783fccf067SIngo Weinhold fIndex = (index <= 0 ? 0 : sTracingMetaData->Entries() + 1); 11796d369966SIngo Weinhold fEntry = NULL; 11806d369966SIngo Weinhold return NULL; 11816d369966SIngo Weinhold } 11826d369966SIngo Weinhold 11836d369966SIngo Weinhold // get the shortest iteration path 11846d369966SIngo Weinhold int32 distance = index - fIndex; 11856d369966SIngo Weinhold int32 direction = distance < 0 ? -1 : 1; 11866d369966SIngo Weinhold distance *= direction; 11876d369966SIngo Weinhold 11886d369966SIngo Weinhold if (index < distance) { 11896d369966SIngo Weinhold distance = index; 11906d369966SIngo Weinhold direction = 1; 11916d369966SIngo Weinhold fEntry = NULL; 11926d369966SIngo Weinhold fIndex = 0; 11936d369966SIngo Weinhold } 11943fccf067SIngo Weinhold if ((int32)sTracingMetaData->Entries() + 1 - fIndex < distance) { 11953fccf067SIngo Weinhold distance = sTracingMetaData->Entries() + 1 - fIndex; 11966d369966SIngo Weinhold direction = -1; 11976d369966SIngo Weinhold fEntry = NULL; 11983fccf067SIngo Weinhold fIndex = sTracingMetaData->Entries() + 1; 11996d369966SIngo Weinhold } 12006d369966SIngo Weinhold 12016d369966SIngo Weinhold // iterate to the index 12026d369966SIngo Weinhold if (direction < 0) { 12036d369966SIngo Weinhold while (fIndex != index) 12046d369966SIngo Weinhold Previous(); 12056d369966SIngo Weinhold } else { 12066d369966SIngo Weinhold while (fIndex != index) 12076d369966SIngo Weinhold Next(); 12086d369966SIngo Weinhold } 12096d369966SIngo Weinhold 12106d369966SIngo Weinhold return Current(); 12116d369966SIngo Weinhold } 12126d369966SIngo Weinhold 1213ef7102faSIngo Weinhold 1214ef7102faSIngo Weinhold trace_entry* 1215ef7102faSIngo Weinhold TraceEntryIterator::_NextNonBufferEntry(trace_entry* entry) 12166d369966SIngo Weinhold { 12176d369966SIngo Weinhold while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0) 12183fccf067SIngo Weinhold entry = sTracingMetaData->NextEntry(entry); 12196d369966SIngo Weinhold 12206d369966SIngo Weinhold return entry; 12216d369966SIngo Weinhold } 12226d369966SIngo Weinhold 1223ef7102faSIngo Weinhold 1224ef7102faSIngo Weinhold trace_entry* 1225ef7102faSIngo Weinhold TraceEntryIterator::_PreviousNonBufferEntry(trace_entry* entry) 12266d369966SIngo Weinhold { 12276d369966SIngo Weinhold while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0) 12283fccf067SIngo Weinhold entry = sTracingMetaData->PreviousEntry(entry); 12296d369966SIngo Weinhold 12306d369966SIngo Weinhold return entry; 12316d369966SIngo Weinhold } 12326d369966SIngo Weinhold 12336d369966SIngo Weinhold 1234aa5d2a2dSAxel Dörfler int 1235f97199edSIngo Weinhold dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter) 1236aa5d2a2dSAxel Dörfler { 12374c4b14c3SIngo Weinhold int argi = 1; 12388e43ece8SAxel Dörfler 12396d369966SIngo Weinhold // variables in which we store our state to be continuable 12406d369966SIngo Weinhold static int32 _previousCount = 0; 12416d369966SIngo Weinhold static bool _previousHasFilter = false; 124265f40152SIngo Weinhold static bool _previousPrintStackTrace = false; 12436d369966SIngo Weinhold static int32 _previousMaxToCheck = 0; 12446d369966SIngo Weinhold static int32 _previousFirstChecked = 1; 12456d369966SIngo Weinhold static int32 _previousLastChecked = -1; 12465fa74667SIngo Weinhold static int32 _previousDirection = 1; 12473fccf067SIngo Weinhold static uint32 _previousEntriesEver = 0; 124856213ff4SIngo Weinhold static uint32 _previousEntries = 0; 1249350b6dbcSIngo Weinhold static uint32 _previousOutputFlags = 0; 125056213ff4SIngo Weinhold static TraceEntryIterator iterator; 125156213ff4SIngo Weinhold 12523fccf067SIngo Weinhold uint32 entriesEver = sTracingMetaData->EntriesEver(); 12533fccf067SIngo Weinhold 1254d829579dSIngo Weinhold // Note: start and index are Pascal-like indices (i.e. in [1, Entries()]). 125574652349SIngo Weinhold int32 start = 0; // special index: print the last count entries 12566d369966SIngo Weinhold int32 count = 0; 12576d369966SIngo Weinhold int32 maxToCheck = 0; 125874652349SIngo Weinhold int32 cont = 0; 1259aa5d2a2dSAxel Dörfler 12604c4b14c3SIngo Weinhold bool hasFilter = false; 126165f40152SIngo Weinhold bool printStackTrace = false; 12624c4b14c3SIngo Weinhold 1263350b6dbcSIngo Weinhold uint32 outputFlags = 0; 1264350b6dbcSIngo Weinhold while (argi < argc) { 126565f40152SIngo Weinhold if (strcmp(argv[argi], "--difftime") == 0) { 126665f40152SIngo Weinhold outputFlags |= TRACE_OUTPUT_DIFF_TIME; 126765f40152SIngo Weinhold argi++; 126865f40152SIngo Weinhold } else if (strcmp(argv[argi], "--printteam") == 0) { 1269350b6dbcSIngo Weinhold outputFlags |= TRACE_OUTPUT_TEAM_ID; 127064fe37eeSIngo Weinhold argi++; 127165f40152SIngo Weinhold } else if (strcmp(argv[argi], "--stacktrace") == 0) { 127265f40152SIngo Weinhold printStackTrace = true; 1273350b6dbcSIngo Weinhold argi++; 1274350b6dbcSIngo Weinhold } else 1275350b6dbcSIngo Weinhold break; 127664fe37eeSIngo Weinhold } 127764fe37eeSIngo Weinhold 12784c4b14c3SIngo Weinhold if (argi < argc) { 12794c4b14c3SIngo Weinhold if (strcmp(argv[argi], "forward") == 0) { 128074652349SIngo Weinhold cont = 1; 12814c4b14c3SIngo Weinhold argi++; 12824c4b14c3SIngo Weinhold } else if (strcmp(argv[argi], "backward") == 0) { 128374652349SIngo Weinhold cont = -1; 12844c4b14c3SIngo Weinhold argi++; 12854c4b14c3SIngo Weinhold } 12865fa74667SIngo Weinhold } else 12875fa74667SIngo Weinhold cont = _previousDirection; 12882d81f045SAxel Dörfler 12896d369966SIngo Weinhold if (cont != 0) { 12906d369966SIngo Weinhold if (argi < argc) { 1291a7e979caSIngo Weinhold print_debugger_command_usage(argv[0]); 1292aa5d2a2dSAxel Dörfler return 0; 1293aa5d2a2dSAxel Dörfler } 12943fccf067SIngo Weinhold if (entriesEver == 0 || entriesEver != _previousEntriesEver 12953fccf067SIngo Weinhold || sTracingMetaData->Entries() != _previousEntries) { 12966d369966SIngo Weinhold kprintf("Can't continue iteration. \"%s\" has not been invoked " 12976d369966SIngo Weinhold "before, or there were new entries written since the last " 12986d369966SIngo Weinhold "invocation.\n", argv[0]); 12996d369966SIngo Weinhold return 0; 13006d369966SIngo Weinhold } 13016d369966SIngo Weinhold } 1302aa5d2a2dSAxel Dörfler 13036d369966SIngo Weinhold // get start, count, maxToCheck 13046d369966SIngo Weinhold int32* params[3] = { &start, &count, &maxToCheck }; 13056d369966SIngo Weinhold for (int i = 0; i < 3 && !hasFilter && argi < argc; i++) { 13064c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) { 13074c4b14c3SIngo Weinhold hasFilter = true; 13084c4b14c3SIngo Weinhold argi++; 13094c4b14c3SIngo Weinhold } else if (argv[argi][0] == '#') { 13104c4b14c3SIngo Weinhold hasFilter = true; 13114c4b14c3SIngo Weinhold } else { 13126d369966SIngo Weinhold *params[i] = parse_expression(argv[argi]); 13134c4b14c3SIngo Weinhold argi++; 13144c4b14c3SIngo Weinhold } 13154c4b14c3SIngo Weinhold } 13164c4b14c3SIngo Weinhold 13174c4b14c3SIngo Weinhold // filter specification 13184c4b14c3SIngo Weinhold if (argi < argc) { 13194c4b14c3SIngo Weinhold hasFilter = true; 13204c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) 13214c4b14c3SIngo Weinhold argi++; 13224c4b14c3SIngo Weinhold 13234c4b14c3SIngo Weinhold if (!TraceFilterParser::Default()->Parse(argc - argi, argv + argi)) { 13244c4b14c3SIngo Weinhold print_debugger_command_usage(argv[0]); 13254c4b14c3SIngo Weinhold return 0; 13264c4b14c3SIngo Weinhold } 13274c4b14c3SIngo Weinhold } 13284c4b14c3SIngo Weinhold 13296d369966SIngo Weinhold int32 direction; 13306d369966SIngo Weinhold int32 firstToCheck; 13316d369966SIngo Weinhold int32 lastToCheck; 13326d369966SIngo Weinhold 133374652349SIngo Weinhold if (cont != 0) { 13346d369966SIngo Weinhold // get values from the previous iteration 13356d369966SIngo Weinhold direction = cont; 13366d369966SIngo Weinhold count = _previousCount; 13376d369966SIngo Weinhold maxToCheck = _previousMaxToCheck; 13386d369966SIngo Weinhold hasFilter = _previousHasFilter; 1339350b6dbcSIngo Weinhold outputFlags = _previousOutputFlags; 134065f40152SIngo Weinhold printStackTrace = _previousPrintStackTrace; 13416d369966SIngo Weinhold 13426d369966SIngo Weinhold if (direction < 0) 13436d369966SIngo Weinhold start = _previousFirstChecked - 1; 13446d369966SIngo Weinhold else 13456d369966SIngo Weinhold start = _previousLastChecked + 1; 13466d369966SIngo Weinhold } else { 13476d369966SIngo Weinhold // defaults for count and maxToCheck 13486d369966SIngo Weinhold if (count == 0) 13496d369966SIngo Weinhold count = 30; 13506d369966SIngo Weinhold if (maxToCheck == 0 || !hasFilter) 13516d369966SIngo Weinhold maxToCheck = count; 13526d369966SIngo Weinhold else if (maxToCheck < 0) 13533fccf067SIngo Weinhold maxToCheck = sTracingMetaData->Entries(); 13546d369966SIngo Weinhold 13556d369966SIngo Weinhold // determine iteration direction 13566d369966SIngo Weinhold direction = (start <= 0 || count < 0 ? -1 : 1); 13576d369966SIngo Weinhold 13586d369966SIngo Weinhold // validate count and maxToCheck 13596d369966SIngo Weinhold if (count < 0) 13606d369966SIngo Weinhold count = -count; 13616d369966SIngo Weinhold if (maxToCheck < 0) 13626d369966SIngo Weinhold maxToCheck = -maxToCheck; 13633fccf067SIngo Weinhold if (maxToCheck > (int32)sTracingMetaData->Entries()) 13643fccf067SIngo Weinhold maxToCheck = sTracingMetaData->Entries(); 13656d369966SIngo Weinhold if (count > maxToCheck) 13666d369966SIngo Weinhold count = maxToCheck; 13676d369966SIngo Weinhold 13686d369966SIngo Weinhold // validate start 13693fccf067SIngo Weinhold if (start <= 0 || start > (int32)sTracingMetaData->Entries()) 13703fccf067SIngo Weinhold start = max_c(1, sTracingMetaData->Entries()); 137174652349SIngo Weinhold } 1372aa5d2a2dSAxel Dörfler 13736d369966SIngo Weinhold if (direction < 0) { 13746d369966SIngo Weinhold firstToCheck = max_c(1, start - maxToCheck + 1); 13756d369966SIngo Weinhold lastToCheck = start; 13766d369966SIngo Weinhold } else { 13776d369966SIngo Weinhold firstToCheck = start; 13783fccf067SIngo Weinhold lastToCheck = min_c((int32)sTracingMetaData->Entries(), 13793fccf067SIngo Weinhold start + maxToCheck - 1); 13808e43ece8SAxel Dörfler } 1381aa5d2a2dSAxel Dörfler 138256213ff4SIngo Weinhold // reset the iterator, if something changed in the meantime 13833fccf067SIngo Weinhold if (entriesEver == 0 || entriesEver != _previousEntriesEver 13843fccf067SIngo Weinhold || sTracingMetaData->Entries() != _previousEntries) { 138556213ff4SIngo Weinhold iterator.Reset(); 138656213ff4SIngo Weinhold } 13876d369966SIngo Weinhold 13883fccf067SIngo Weinhold LazyTraceOutput out(sTracingMetaData->TraceOutputBuffer(), 1389d829579dSIngo Weinhold kTraceOutputBufferSize, outputFlags); 1390f7a5d9c5SIngo Weinhold 139156213ff4SIngo Weinhold bool markedMatching = false; 139256213ff4SIngo Weinhold int32 firstToDump = firstToCheck; 139356213ff4SIngo Weinhold int32 lastToDump = lastToCheck; 139456213ff4SIngo Weinhold 1395f97199edSIngo Weinhold TraceFilter* filter = NULL; 1396f97199edSIngo Weinhold if (hasFilter) 1397f97199edSIngo Weinhold filter = TraceFilterParser::Default()->Filter(); 1398f97199edSIngo Weinhold 1399f97199edSIngo Weinhold if (wrapperFilter != NULL) { 1400f97199edSIngo Weinhold wrapperFilter->Init(filter, direction, cont != 0); 1401f97199edSIngo Weinhold filter = wrapperFilter; 1402f97199edSIngo Weinhold } 1403f97199edSIngo Weinhold 1404f97199edSIngo Weinhold if (direction < 0 && filter && lastToCheck - firstToCheck >= count) { 14056d369966SIngo Weinhold // iteration direction is backwards 140656213ff4SIngo Weinhold markedMatching = true; 14076d369966SIngo Weinhold 14086d369966SIngo Weinhold // From the last entry to check iterate backwards to check filter 14096d369966SIngo Weinhold // matches. 14106d369966SIngo Weinhold int32 matching = 0; 14116d369966SIngo Weinhold 14126d369966SIngo Weinhold // move to the entry after the last entry to check 14136d369966SIngo Weinhold iterator.MoveTo(lastToCheck + 1); 14146d369966SIngo Weinhold 14156d369966SIngo Weinhold // iterate backwards 141656213ff4SIngo Weinhold firstToDump = -1; 141756213ff4SIngo Weinhold lastToDump = -1; 14186d369966SIngo Weinhold while (iterator.Index() > firstToCheck) { 14196d369966SIngo Weinhold TraceEntry* entry = iterator.Previous(); 1420b3d6c12dSIngo Weinhold if ((entry->Flags() & ENTRY_INITIALIZED) != 0) { 14216d369966SIngo Weinhold out.Clear(); 1422f97199edSIngo Weinhold if (filter->Filter(entry, out)) { 1423b3d6c12dSIngo Weinhold entry->ToTraceEntry()->flags |= FILTER_MATCH; 142456213ff4SIngo Weinhold if (lastToDump == -1) 142556213ff4SIngo Weinhold lastToDump = iterator.Index(); 142656213ff4SIngo Weinhold firstToDump = iterator.Index(); 142756213ff4SIngo Weinhold 14286d369966SIngo Weinhold matching++; 14296d369966SIngo Weinhold if (matching >= count) 14306d369966SIngo Weinhold break; 143156213ff4SIngo Weinhold } else 1432b3d6c12dSIngo Weinhold entry->ToTraceEntry()->flags &= ~FILTER_MATCH; 14336d369966SIngo Weinhold } 14346d369966SIngo Weinhold } 14356d369966SIngo Weinhold 14366d369966SIngo Weinhold firstToCheck = iterator.Index(); 14376d369966SIngo Weinhold 14386d369966SIngo Weinhold // iterate to the previous entry, so that the next loop starts at the 14396d369966SIngo Weinhold // right one 14406d369966SIngo Weinhold iterator.Previous(); 14416d369966SIngo Weinhold } 14426d369966SIngo Weinhold 1443350b6dbcSIngo Weinhold out.SetLastEntryTime(0); 1444350b6dbcSIngo Weinhold 144556213ff4SIngo Weinhold // set the iterator to the entry before the first one to dump 144656213ff4SIngo Weinhold iterator.MoveTo(firstToDump - 1); 144756213ff4SIngo Weinhold 144856213ff4SIngo Weinhold // dump the entries matching the filter in the range 144956213ff4SIngo Weinhold // [firstToDump, lastToDump] 14506d369966SIngo Weinhold int32 dumped = 0; 14516d369966SIngo Weinhold 14526d369966SIngo Weinhold while (TraceEntry* entry = iterator.Next()) { 14536d369966SIngo Weinhold int32 index = iterator.Index(); 145456213ff4SIngo Weinhold if (index < firstToDump) 14556d369966SIngo Weinhold continue; 145656213ff4SIngo Weinhold if (index > lastToDump || dumped >= count) { 14576d369966SIngo Weinhold if (direction > 0) 14586d369966SIngo Weinhold lastToCheck = index - 1; 14596d369966SIngo Weinhold break; 14606d369966SIngo Weinhold } 14616d369966SIngo Weinhold 1462b3d6c12dSIngo Weinhold if ((entry->Flags() & ENTRY_INITIALIZED) != 0) { 14636d369966SIngo Weinhold out.Clear(); 1464f97199edSIngo Weinhold if (filter && (markedMatching 1465b3d6c12dSIngo Weinhold ? (entry->Flags() & FILTER_MATCH) == 0 1466f97199edSIngo Weinhold : !filter->Filter(entry, out))) { 14678e43ece8SAxel Dörfler continue; 146856213ff4SIngo Weinhold } 14698e43ece8SAxel Dörfler 14700c45a120SIngo Weinhold // don't print trailing new line 14710c45a120SIngo Weinhold const char* dump = out.DumpEntry(entry); 14720c45a120SIngo Weinhold int len = strlen(dump); 14730c45a120SIngo Weinhold if (len > 0 && dump[len - 1] == '\n') 14740c45a120SIngo Weinhold len--; 14750c45a120SIngo Weinhold 14760c45a120SIngo Weinhold kprintf("%5ld. %.*s\n", index, len, dump); 147765f40152SIngo Weinhold 147865f40152SIngo Weinhold if (printStackTrace) { 147965f40152SIngo Weinhold out.Clear(); 148065f40152SIngo Weinhold entry->DumpStackTrace(out); 148165f40152SIngo Weinhold if (out.Size() > 0) 148265f40152SIngo Weinhold kputs(out.Buffer()); 148365f40152SIngo Weinhold } 1484f97199edSIngo Weinhold } else if (!filter) 14858e43ece8SAxel Dörfler kprintf("%5ld. ** uninitialized entry **\n", index); 148674652349SIngo Weinhold 148774652349SIngo Weinhold dumped++; 1488aa5d2a2dSAxel Dörfler } 1489aa5d2a2dSAxel Dörfler 14906d369966SIngo Weinhold kprintf("printed %ld entries within range %ld to %ld (%ld of %ld total, " 14916d369966SIngo Weinhold "%ld ever)\n", dumped, firstToCheck, lastToCheck, 14923fccf067SIngo Weinhold lastToCheck - firstToCheck + 1, sTracingMetaData->Entries(), 14933fccf067SIngo Weinhold entriesEver); 149474652349SIngo Weinhold 14956d369966SIngo Weinhold // store iteration state 14966d369966SIngo Weinhold _previousCount = count; 14976d369966SIngo Weinhold _previousMaxToCheck = maxToCheck; 14986d369966SIngo Weinhold _previousHasFilter = hasFilter; 149965f40152SIngo Weinhold _previousPrintStackTrace = printStackTrace; 15006d369966SIngo Weinhold _previousFirstChecked = firstToCheck; 15016d369966SIngo Weinhold _previousLastChecked = lastToCheck; 15025fa74667SIngo Weinhold _previousDirection = direction; 15033fccf067SIngo Weinhold _previousEntriesEver = entriesEver; 15043fccf067SIngo Weinhold _previousEntries = sTracingMetaData->Entries(); 1505350b6dbcSIngo Weinhold _previousOutputFlags = outputFlags; 150674652349SIngo Weinhold 150774652349SIngo Weinhold return cont != 0 ? B_KDEBUG_CONT : 0; 1508aa5d2a2dSAxel Dörfler } 1509aa5d2a2dSAxel Dörfler 1510aa5d2a2dSAxel Dörfler 1511f97199edSIngo Weinhold static int 1512f97199edSIngo Weinhold dump_tracing_command(int argc, char** argv) 1513f97199edSIngo Weinhold { 1514f97199edSIngo Weinhold return dump_tracing_internal(argc, argv, NULL); 1515f97199edSIngo Weinhold } 1516f97199edSIngo Weinhold 1517f97199edSIngo Weinhold 1518aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING 1519aa5d2a2dSAxel Dörfler 15202d81f045SAxel Dörfler 15218e43ece8SAxel Dörfler extern "C" uint8* 15228e43ece8SAxel Dörfler alloc_tracing_buffer(size_t size) 15238e43ece8SAxel Dörfler { 15248e43ece8SAxel Dörfler #if ENABLE_TRACING 15253fccf067SIngo Weinhold trace_entry* entry = sTracingMetaData->AllocateEntry( 15263fccf067SIngo Weinhold size + sizeof(trace_entry), BUFFER_ENTRY); 15278e43ece8SAxel Dörfler if (entry == NULL) 15288e43ece8SAxel Dörfler return NULL; 15298e43ece8SAxel Dörfler 15308e43ece8SAxel Dörfler return (uint8*)(entry + 1); 15318e43ece8SAxel Dörfler #else 15328e43ece8SAxel Dörfler return NULL; 15338e43ece8SAxel Dörfler #endif 15348e43ece8SAxel Dörfler } 15358e43ece8SAxel Dörfler 1536aa5d2a2dSAxel Dörfler 15370b60583fSIngo Weinhold uint8* 15380b60583fSIngo Weinhold alloc_tracing_buffer_memcpy(const void* source, size_t size, bool user) 15390b60583fSIngo Weinhold { 15408bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source)) 15418bd6d45dSIngo Weinhold return NULL; 15428bd6d45dSIngo Weinhold 15430b60583fSIngo Weinhold uint8* buffer = alloc_tracing_buffer(size); 15440b60583fSIngo Weinhold if (buffer == NULL) 15450b60583fSIngo Weinhold return NULL; 15460b60583fSIngo Weinhold 15470b60583fSIngo Weinhold if (user) { 15480b60583fSIngo Weinhold if (user_memcpy(buffer, source, size) != B_OK) 15490b60583fSIngo Weinhold return NULL; 15500b60583fSIngo Weinhold } else 15510b60583fSIngo Weinhold memcpy(buffer, source, size); 15520b60583fSIngo Weinhold 15530b60583fSIngo Weinhold return buffer; 15540b60583fSIngo Weinhold } 15550b60583fSIngo Weinhold 15560b60583fSIngo Weinhold 15570b60583fSIngo Weinhold char* 15580b60583fSIngo Weinhold alloc_tracing_buffer_strcpy(const char* source, size_t maxSize, bool user) 15590b60583fSIngo Weinhold { 15608bd6d45dSIngo Weinhold if (source == NULL || maxSize == 0) 15610b60583fSIngo Weinhold return NULL; 15620b60583fSIngo Weinhold 15638bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source)) 15648bd6d45dSIngo Weinhold return NULL; 15658bd6d45dSIngo Weinhold 15668bd6d45dSIngo Weinhold // limit maxSize to the actual source string len 15678bd6d45dSIngo Weinhold if (user) { 15688bd6d45dSIngo Weinhold ssize_t size = user_strlcpy(NULL, source, 0); 15698bd6d45dSIngo Weinhold // there's no user_strnlen() 15708bd6d45dSIngo Weinhold if (size < 0) 15718bd6d45dSIngo Weinhold return 0; 15728bd6d45dSIngo Weinhold maxSize = min_c(maxSize, (size_t)size + 1); 15738bd6d45dSIngo Weinhold } else 15740b60583fSIngo Weinhold maxSize = strnlen(source, maxSize - 1) + 1; 15750b60583fSIngo Weinhold 15760b60583fSIngo Weinhold char* buffer = (char*)alloc_tracing_buffer(maxSize); 15770b60583fSIngo Weinhold if (buffer == NULL) 15780b60583fSIngo Weinhold return NULL; 15790b60583fSIngo Weinhold 15800b60583fSIngo Weinhold if (user) { 15810b60583fSIngo Weinhold if (user_strlcpy(buffer, source, maxSize) < B_OK) 15820b60583fSIngo Weinhold return NULL; 15830b60583fSIngo Weinhold } else 15840b60583fSIngo Weinhold strlcpy(buffer, source, maxSize); 15850b60583fSIngo Weinhold 15860b60583fSIngo Weinhold return buffer; 15870b60583fSIngo Weinhold } 15880b60583fSIngo Weinhold 15890b60583fSIngo Weinhold 159065f40152SIngo Weinhold tracing_stack_trace* 1591a38f8503SIngo Weinhold capture_tracing_stack_trace(int32 maxCount, int32 skipFrames, bool kernelOnly) 159265f40152SIngo Weinhold { 159365f40152SIngo Weinhold #if ENABLE_TRACING 15944502d80dSIngo Weinhold // page_fault_exception() doesn't allow us to gracefully handle a bad 15954502d80dSIngo Weinhold // address in the stack trace, if interrupts are disabled, so we always 15964502d80dSIngo Weinhold // restrict the stack traces to the kernel only in this case. A bad address 15974502d80dSIngo Weinhold // in the kernel stack trace would still cause a panic(), but this is 15984502d80dSIngo Weinhold // probably even desired. 159965f40152SIngo Weinhold if (!are_interrupts_enabled()) 16004502d80dSIngo Weinhold kernelOnly = true; 160165f40152SIngo Weinhold 160265f40152SIngo Weinhold tracing_stack_trace* stackTrace 160365f40152SIngo Weinhold = (tracing_stack_trace*)alloc_tracing_buffer( 160465f40152SIngo Weinhold sizeof(tracing_stack_trace) + maxCount * sizeof(addr_t)); 160565f40152SIngo Weinhold 160665f40152SIngo Weinhold if (stackTrace != NULL) { 160765f40152SIngo Weinhold stackTrace->depth = arch_debug_get_stack_trace( 1608e670fc6fSIngo Weinhold stackTrace->return_addresses, maxCount, 0, skipFrames + 1, 16094502d80dSIngo Weinhold STACK_TRACE_KERNEL | (kernelOnly ? 0 : STACK_TRACE_USER)); 161065f40152SIngo Weinhold } 161165f40152SIngo Weinhold 161265f40152SIngo Weinhold return stackTrace; 161365f40152SIngo Weinhold #else 161465f40152SIngo Weinhold return NULL; 161565f40152SIngo Weinhold #endif 161665f40152SIngo Weinhold } 161765f40152SIngo Weinhold 161865f40152SIngo Weinhold 1619f97199edSIngo Weinhold int 1620f97199edSIngo Weinhold dump_tracing(int argc, char** argv, WrapperTraceFilter* wrapperFilter) 1621f97199edSIngo Weinhold { 1622f97199edSIngo Weinhold #if ENABLE_TRACING 1623f97199edSIngo Weinhold return dump_tracing_internal(argc, argv, wrapperFilter); 1624f97199edSIngo Weinhold #else 1625f97199edSIngo Weinhold return 0; 1626f97199edSIngo Weinhold #endif 1627f97199edSIngo Weinhold } 1628f97199edSIngo Weinhold 1629f97199edSIngo Weinhold 1630aa1a64f3SIngo Weinhold void 1631aa1a64f3SIngo Weinhold lock_tracing_buffer() 1632aa1a64f3SIngo Weinhold { 1633aa1a64f3SIngo Weinhold #if ENABLE_TRACING 16343fccf067SIngo Weinhold sTracingMetaData->Lock(); 1635aa1a64f3SIngo Weinhold #endif 1636aa1a64f3SIngo Weinhold } 1637aa1a64f3SIngo Weinhold 1638aa1a64f3SIngo Weinhold 1639aa1a64f3SIngo Weinhold void 1640aa1a64f3SIngo Weinhold unlock_tracing_buffer() 1641aa1a64f3SIngo Weinhold { 1642aa1a64f3SIngo Weinhold #if ENABLE_TRACING 16433fccf067SIngo Weinhold sTracingMetaData->Unlock(); 1644aa1a64f3SIngo Weinhold #endif 1645aa1a64f3SIngo Weinhold } 1646aa1a64f3SIngo Weinhold 1647aa1a64f3SIngo Weinhold 1648aa5d2a2dSAxel Dörfler extern "C" status_t 1649aa5d2a2dSAxel Dörfler tracing_init(void) 1650aa5d2a2dSAxel Dörfler { 1651aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 1652d829579dSIngo Weinhold status_t result = TracingMetaData::Create(sTracingMetaData); 1653d829579dSIngo Weinhold if (result != B_OK) { 1654d829579dSIngo Weinhold sTracingMetaData = &sDummyTracingMetaData; 1655d829579dSIngo Weinhold return result; 1656d829579dSIngo Weinhold } 1657aa5d2a2dSAxel Dörfler 1658d829579dSIngo Weinhold new(nothrow) TracingLogStartEntry(); 1659aa5d2a2dSAxel Dörfler 1660f97199edSIngo Weinhold add_debugger_command_etc("traced", &dump_tracing_command, 166174652349SIngo Weinhold "Dump recorded trace entries", 1662093e0057SAxel Dörfler "[ --printteam ] [ --difftime ] [ --stacktrace ] " 1663093e0057SAxel Dörfler "(\"forward\" | \"backward\") " 166464fe37eeSIngo Weinhold "| ([ <start> [ <count> [ <range> ] ] ] " 16654c4b14c3SIngo Weinhold "[ #<pattern> | (\"filter\" <filter>) ])\n" 166674652349SIngo Weinhold "Prints recorded trace entries. If \"backward\" or \"forward\" is\n" 166774652349SIngo Weinhold "specified, the command continues where the previous invocation left\n" 166874652349SIngo Weinhold "off, i.e. printing the previous respectively next entries (as many\n" 166974652349SIngo Weinhold "as printed before). In this case the command is continuable, that is\n" 167074652349SIngo Weinhold "afterwards entering an empty line in the debugger will reinvoke it.\n" 16715fa74667SIngo Weinhold "If no arguments are given, the command continues in the direction\n" 16725fa74667SIngo Weinhold "of the last invocation.\n" 1673093e0057SAxel Dörfler "--printteam - enables printing the entries' team IDs.\n" 1674093e0057SAxel Dörfler "--difftime - print difference times for all but the first entry.\n" 1675093e0057SAxel Dörfler "--stacktrace - print stack traces for entries that captured one.\n" 16766d369966SIngo Weinhold " <start> - The base index of the entries to print. Depending on\n" 16776d369966SIngo Weinhold " whether the iteration direction is forward or\n" 16786d369966SIngo Weinhold " backward this will be the first or last entry printed\n" 16796d369966SIngo Weinhold " (potentially, if a filter is specified). The index of\n" 16806d369966SIngo Weinhold " the first entry in the trace buffer is 1. If 0 is\n" 16816d369966SIngo Weinhold " specified, the last <count> recorded entries are\n" 16826d369966SIngo Weinhold " printed (iteration direction is backward). Defaults \n" 168374652349SIngo Weinhold " to 0.\n" 168474652349SIngo Weinhold " <count> - The number of entries to be printed. Defaults to 30.\n" 16856d369966SIngo Weinhold " If negative, the -<count> entries before and\n" 16866d369966SIngo Weinhold " including <start> will be printed.\n" 16876d369966SIngo Weinhold " <range> - Only relevant if a filter is specified. Specifies the\n" 16886d369966SIngo Weinhold " number of entries to be filtered -- depending on the\n" 16896d369966SIngo Weinhold " iteration direction the entries before or after\n" 16906d369966SIngo Weinhold " <start>. If more than <count> entries match the\n" 16916d369966SIngo Weinhold " filter, only the first (forward) or last (backward)\n" 16926d369966SIngo Weinhold " <count> matching entries will be printed. If 0 is\n" 16936d369966SIngo Weinhold " specified <range> will be set to <count>. If -1,\n" 16946d369966SIngo Weinhold " <range> will be set to the number of recorded\n" 16956d369966SIngo Weinhold " entries.\n" 169674652349SIngo Weinhold " <pattern> - If specified only entries containing this string are\n" 16974c4b14c3SIngo Weinhold " printed.\n" 16984c4b14c3SIngo Weinhold " <filter> - If specified only entries matching this filter\n" 16994c4b14c3SIngo Weinhold " expression are printed. The expression can consist of\n" 170064fe37eeSIngo Weinhold " prefix operators \"not\", \"and\", \"or\", and\n" 170164fe37eeSIngo Weinhold " filters \"'thread' <thread>\" (matching entries\n" 170264fe37eeSIngo Weinhold " with the given thread ID), \"'team' <team>\"\n" 170364fe37eeSIngo Weinhold "(matching entries with the given team ID), and\n" 17044c4b14c3SIngo Weinhold " \"#<pattern>\" (matching entries containing the given\n" 170564fe37eeSIngo Weinhold " string).\n", 0); 1706aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING 1707aa5d2a2dSAxel Dörfler return B_OK; 1708aa5d2a2dSAxel Dörfler } 1709aa5d2a2dSAxel Dörfler 1710a54c125eSIngo Weinhold 1711a54c125eSIngo Weinhold void 17127d2d758dSIngo Weinhold ktrace_printf(const char *format, ...) 17137d2d758dSIngo Weinhold { 17147d2d758dSIngo Weinhold #if ENABLE_TRACING 17157d2d758dSIngo Weinhold va_list list; 17167d2d758dSIngo Weinhold va_start(list, format); 17177d2d758dSIngo Weinhold 17187d2d758dSIngo Weinhold char buffer[256]; 17197d2d758dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 17207d2d758dSIngo Weinhold 17217d2d758dSIngo Weinhold va_end(list); 17227d2d758dSIngo Weinhold 17237d2d758dSIngo Weinhold new(nothrow) KernelTraceEntry(buffer); 17247d2d758dSIngo Weinhold #endif // ENABLE_TRACING 17257d2d758dSIngo Weinhold } 17267d2d758dSIngo Weinhold 17277d2d758dSIngo Weinhold 17287d2d758dSIngo Weinhold void 1729a54c125eSIngo Weinhold _user_ktrace_output(const char *message) 1730a54c125eSIngo Weinhold { 1731a54c125eSIngo Weinhold #if ENABLE_TRACING 1732a54c125eSIngo Weinhold new(nothrow) UserTraceEntry(message); 1733a54c125eSIngo Weinhold #endif // ENABLE_TRACING 1734a54c125eSIngo Weinhold } 1735a54c125eSIngo Weinhold 1736