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 26aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 27aa5d2a2dSAxel Dörfler 285276dad0SAxel Dörfler //#define TRACE_TRACING 295276dad0SAxel Dörfler #ifdef TRACE_TRACING 306d986c16SIngo Weinhold # define TRACE(x) dprintf_no_syslog x 315276dad0SAxel Dörfler #else 325276dad0SAxel Dörfler # define TRACE(x) ; 335276dad0SAxel Dörfler #endif 345276dad0SAxel Dörfler 355276dad0SAxel Dörfler 36aa5d2a2dSAxel Dörfler enum { 37aa5d2a2dSAxel Dörfler WRAP_ENTRY = 0x01, 388e43ece8SAxel Dörfler ENTRY_INITIALIZED = 0x02, 3956213ff4SIngo Weinhold BUFFER_ENTRY = 0x04, 403fccf067SIngo Weinhold FILTER_MATCH = 0x08, 413fccf067SIngo Weinhold INVALID_ENTRY = 0x10, 423fccf067SIngo Weinhold CHECK_ENTRY = 0x20, 43aa5d2a2dSAxel Dörfler }; 44aa5d2a2dSAxel Dörfler 4565f40152SIngo Weinhold 4665f40152SIngo Weinhold static const size_t kTraceOutputBufferSize = 10240; 473fccf067SIngo Weinhold static const size_t kBufferSize = MAX_TRACE_SIZE / sizeof(trace_entry); 48aa5d2a2dSAxel Dörfler 49ce50cdc3SIngo Weinhold static const uint32 kMaxRecoveringErrorCount = 100; 50d829579dSIngo Weinhold static const addr_t kMetaDataBaseAddress = 32 * 1024 * 1024; 51d829579dSIngo Weinhold static const addr_t kMetaDataBaseEndAddress = 128 * 1024 * 1024; 52d829579dSIngo Weinhold static const addr_t kMetaDataAddressIncrement = 8 * 1024 * 1024; 53d829579dSIngo Weinhold static const uint32 kMetaDataMagic1 = 'Vali'; 54d829579dSIngo Weinhold static const uint32 kMetaDataMagic2 = 'dTra'; 55d829579dSIngo Weinhold static const uint32 kMetaDataMagic3 = 'cing'; 56d829579dSIngo Weinhold 573fccf067SIngo Weinhold // the maximum we can address with the trace_entry::[previous_]size fields 58ce50cdc3SIngo Weinhold static const size_t kMaxTracingEntryByteSize 593fccf067SIngo Weinhold = ((1 << 13) - 1) * sizeof(trace_entry); 603fccf067SIngo Weinhold 61d829579dSIngo Weinhold 62d829579dSIngo Weinhold class TracingMetaData { 63d829579dSIngo Weinhold public: 643fccf067SIngo Weinhold static status_t Create(TracingMetaData*& _metaData); 65d829579dSIngo Weinhold 663fccf067SIngo Weinhold inline bool Lock(); 673fccf067SIngo Weinhold inline void Unlock(); 683fccf067SIngo Weinhold 693fccf067SIngo Weinhold inline trace_entry* FirstEntry() const; 703fccf067SIngo Weinhold inline trace_entry* AfterLastEntry() const; 713fccf067SIngo Weinhold 723fccf067SIngo Weinhold inline uint32 Entries() const; 733fccf067SIngo Weinhold inline uint32 EntriesEver() const; 743fccf067SIngo Weinhold 753fccf067SIngo Weinhold inline void IncrementEntriesEver(); 763fccf067SIngo Weinhold 773fccf067SIngo Weinhold inline char* TraceOutputBuffer() const; 783fccf067SIngo Weinhold 793fccf067SIngo Weinhold trace_entry* NextEntry(trace_entry* entry); 803fccf067SIngo Weinhold trace_entry* PreviousEntry(trace_entry* entry); 813fccf067SIngo Weinhold 823fccf067SIngo Weinhold trace_entry* AllocateEntry(size_t size, uint16 flags); 833fccf067SIngo Weinhold 843fccf067SIngo Weinhold private: 853fccf067SIngo Weinhold bool _FreeFirstEntry(); 863fccf067SIngo Weinhold bool _MakeSpace(size_t needed); 873fccf067SIngo Weinhold 883fccf067SIngo Weinhold static status_t _CreateMetaDataArea(bool findPrevious, 893fccf067SIngo Weinhold area_id& _area, 903fccf067SIngo Weinhold TracingMetaData*& _metaData); 91ce50cdc3SIngo Weinhold bool _InitPreviousTracingData(); 923fccf067SIngo Weinhold 933fccf067SIngo Weinhold private: 943fccf067SIngo Weinhold uint32 fMagic1; 953fccf067SIngo Weinhold trace_entry* fBuffer; 963fccf067SIngo Weinhold trace_entry* fFirstEntry; 973fccf067SIngo Weinhold trace_entry* fAfterLastEntry; 983fccf067SIngo Weinhold uint32 fEntries; 993fccf067SIngo Weinhold uint32 fMagic2; 1003fccf067SIngo Weinhold uint32 fEntriesEver; 1013fccf067SIngo Weinhold spinlock fLock; 1023fccf067SIngo Weinhold char* fTraceOutputBuffer; 10364d79effSIngo Weinhold phys_addr_t fPhysicalAddress; 1043fccf067SIngo Weinhold uint32 fMagic3; 1053fccf067SIngo Weinhold }; 1063fccf067SIngo Weinhold 1073fccf067SIngo Weinhold static TracingMetaData sDummyTracingMetaData; 1083fccf067SIngo Weinhold static TracingMetaData* sTracingMetaData = &sDummyTracingMetaData; 1093fccf067SIngo Weinhold static bool sTracingDataRecovered = false; 1103fccf067SIngo Weinhold 1113fccf067SIngo Weinhold 1123fccf067SIngo Weinhold // #pragma mark - 1133fccf067SIngo Weinhold 1143fccf067SIngo Weinhold 1153fccf067SIngo Weinhold // #pragma mark - TracingMetaData 1163fccf067SIngo Weinhold 1173fccf067SIngo Weinhold 1183fccf067SIngo Weinhold bool 1193fccf067SIngo Weinhold TracingMetaData::Lock() 1203fccf067SIngo Weinhold { 1213fccf067SIngo Weinhold acquire_spinlock(&fLock); 1223fccf067SIngo Weinhold return true; 1233fccf067SIngo Weinhold } 1243fccf067SIngo Weinhold 1253fccf067SIngo Weinhold 1263fccf067SIngo Weinhold void 1273fccf067SIngo Weinhold TracingMetaData::Unlock() 1283fccf067SIngo Weinhold { 1293fccf067SIngo Weinhold release_spinlock(&fLock); 1303fccf067SIngo Weinhold } 1313fccf067SIngo Weinhold 1323fccf067SIngo Weinhold 1333fccf067SIngo Weinhold trace_entry* 1343fccf067SIngo Weinhold TracingMetaData::FirstEntry() const 1353fccf067SIngo Weinhold { 1363fccf067SIngo Weinhold return fFirstEntry; 1373fccf067SIngo Weinhold } 1383fccf067SIngo Weinhold 1393fccf067SIngo Weinhold 1403fccf067SIngo Weinhold trace_entry* 1413fccf067SIngo Weinhold TracingMetaData::AfterLastEntry() const 1423fccf067SIngo Weinhold { 1433fccf067SIngo Weinhold return fAfterLastEntry; 1443fccf067SIngo Weinhold } 1453fccf067SIngo Weinhold 1463fccf067SIngo Weinhold 1473fccf067SIngo Weinhold uint32 1483fccf067SIngo Weinhold TracingMetaData::Entries() const 1493fccf067SIngo Weinhold { 1503fccf067SIngo Weinhold return fEntries; 1513fccf067SIngo Weinhold } 1523fccf067SIngo Weinhold 1533fccf067SIngo Weinhold 1543fccf067SIngo Weinhold uint32 1553fccf067SIngo Weinhold TracingMetaData::EntriesEver() const 1563fccf067SIngo Weinhold { 1573fccf067SIngo Weinhold return fEntriesEver; 1583fccf067SIngo Weinhold } 1593fccf067SIngo Weinhold 1603fccf067SIngo Weinhold 1613fccf067SIngo Weinhold void 1623fccf067SIngo Weinhold TracingMetaData::IncrementEntriesEver() 1633fccf067SIngo Weinhold { 1643fccf067SIngo Weinhold fEntriesEver++; 165ce50cdc3SIngo Weinhold // NOTE: Race condition on SMP machines! We should use atomic_add(), 166ce50cdc3SIngo Weinhold // though that costs some performance and the information is for 167ce50cdc3SIngo Weinhold // informational purpose anyway. 1683fccf067SIngo Weinhold } 1693fccf067SIngo Weinhold 1703fccf067SIngo Weinhold 1713fccf067SIngo Weinhold char* 1723fccf067SIngo Weinhold TracingMetaData::TraceOutputBuffer() const 1733fccf067SIngo Weinhold { 1743fccf067SIngo Weinhold return fTraceOutputBuffer; 1753fccf067SIngo Weinhold } 1763fccf067SIngo Weinhold 1773fccf067SIngo Weinhold 1783fccf067SIngo Weinhold trace_entry* 1793fccf067SIngo Weinhold TracingMetaData::NextEntry(trace_entry* entry) 1803fccf067SIngo Weinhold { 1813fccf067SIngo Weinhold entry += entry->size; 1823fccf067SIngo Weinhold if ((entry->flags & WRAP_ENTRY) != 0) 1833fccf067SIngo Weinhold entry = fBuffer; 1843fccf067SIngo Weinhold 1853fccf067SIngo Weinhold if (entry == fAfterLastEntry) 1863fccf067SIngo Weinhold return NULL; 1873fccf067SIngo Weinhold 1883fccf067SIngo Weinhold return entry; 1893fccf067SIngo Weinhold } 1903fccf067SIngo Weinhold 1913fccf067SIngo Weinhold 1923fccf067SIngo Weinhold trace_entry* 1933fccf067SIngo Weinhold TracingMetaData::PreviousEntry(trace_entry* entry) 1943fccf067SIngo Weinhold { 1953fccf067SIngo Weinhold if (entry == fFirstEntry) 1963fccf067SIngo Weinhold return NULL; 1973fccf067SIngo Weinhold 1983fccf067SIngo Weinhold if (entry == fBuffer) { 1993fccf067SIngo Weinhold // beginning of buffer -- previous entry is a wrap entry 2003fccf067SIngo Weinhold entry = fBuffer + kBufferSize - entry->previous_size; 2013fccf067SIngo Weinhold } 2023fccf067SIngo Weinhold 2033fccf067SIngo Weinhold return entry - entry->previous_size; 2043fccf067SIngo Weinhold } 2053fccf067SIngo Weinhold 2063fccf067SIngo Weinhold 2073fccf067SIngo Weinhold trace_entry* 2083fccf067SIngo Weinhold TracingMetaData::AllocateEntry(size_t size, uint16 flags) 2093fccf067SIngo Weinhold { 210ce50cdc3SIngo Weinhold if (fAfterLastEntry == NULL || size == 0 211ce50cdc3SIngo Weinhold || size >= kMaxTracingEntryByteSize) { 2123fccf067SIngo Weinhold return NULL; 213ce50cdc3SIngo Weinhold } 2143fccf067SIngo Weinhold 2153fccf067SIngo Weinhold InterruptsSpinLocker _(fLock); 2163fccf067SIngo Weinhold 2173fccf067SIngo Weinhold size = (size + 3) >> 2; 2183fccf067SIngo Weinhold // 4 byte aligned, don't store the lower 2 bits 2193fccf067SIngo Weinhold 2203fccf067SIngo Weinhold TRACE(("AllocateEntry(%lu), start %p, end %p, buffer %p\n", size * 4, 2213fccf067SIngo Weinhold fFirstEntry, fAfterLastEntry, fBuffer)); 2223fccf067SIngo Weinhold 2233fccf067SIngo Weinhold if (!_MakeSpace(size)) 2243fccf067SIngo Weinhold return NULL; 2253fccf067SIngo Weinhold 2263fccf067SIngo Weinhold trace_entry* entry = fAfterLastEntry; 2273fccf067SIngo Weinhold entry->size = size; 2283fccf067SIngo Weinhold entry->flags = flags; 2293fccf067SIngo Weinhold fAfterLastEntry += size; 2303fccf067SIngo Weinhold fAfterLastEntry->previous_size = size; 2313fccf067SIngo Weinhold 2323fccf067SIngo Weinhold if (!(flags & BUFFER_ENTRY)) 2333fccf067SIngo Weinhold fEntries++; 2343fccf067SIngo Weinhold 2353fccf067SIngo Weinhold TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry, 2363fccf067SIngo Weinhold fAfterLastEntry, fFirstEntry, fEntries)); 2373fccf067SIngo Weinhold 2383fccf067SIngo Weinhold return entry; 2393fccf067SIngo Weinhold } 2403fccf067SIngo Weinhold 2413fccf067SIngo Weinhold 2423fccf067SIngo Weinhold bool 2433fccf067SIngo Weinhold TracingMetaData::_FreeFirstEntry() 2443fccf067SIngo Weinhold { 2453fccf067SIngo Weinhold TRACE((" skip start %p, %lu*4 bytes\n", fFirstEntry, fFirstEntry->size)); 2463fccf067SIngo Weinhold 2473fccf067SIngo Weinhold trace_entry* newFirst = NextEntry(fFirstEntry); 2483fccf067SIngo Weinhold 2493fccf067SIngo Weinhold if (fFirstEntry->flags & BUFFER_ENTRY) { 2503fccf067SIngo Weinhold // a buffer entry -- just skip it 2513fccf067SIngo Weinhold } else if (fFirstEntry->flags & ENTRY_INITIALIZED) { 25237e6de5dSIngo Weinhold // Fully initialized TraceEntry: We could destroy it, but don't do so 25337e6de5dSIngo Weinhold // for sake of robustness. The destructors of tracing entry classes 25437e6de5dSIngo Weinhold // should be empty anyway. 2553fccf067SIngo Weinhold fEntries--; 2563fccf067SIngo Weinhold } else { 2573fccf067SIngo Weinhold // Not fully initialized TraceEntry. We can't free it, since 2583fccf067SIngo Weinhold // then it's constructor might still write into the memory and 2593fccf067SIngo Weinhold // overwrite data of the entry we're going to allocate. 2603fccf067SIngo Weinhold // We can't do anything until this entry can be discarded. 2613fccf067SIngo Weinhold return false; 2623fccf067SIngo Weinhold } 2633fccf067SIngo Weinhold 2643fccf067SIngo Weinhold if (newFirst == NULL) { 2653fccf067SIngo Weinhold // everything is freed -- practically this can't happen, if 2663fccf067SIngo Weinhold // the buffer is large enough to hold three max-sized entries 2673fccf067SIngo Weinhold fFirstEntry = fAfterLastEntry = fBuffer; 2683fccf067SIngo Weinhold TRACE(("_FreeFirstEntry(): all entries freed!\n")); 2693fccf067SIngo Weinhold } else 2703fccf067SIngo Weinhold fFirstEntry = newFirst; 2713fccf067SIngo Weinhold 2723fccf067SIngo Weinhold return true; 2733fccf067SIngo Weinhold } 2743fccf067SIngo Weinhold 2753fccf067SIngo Weinhold 2763fccf067SIngo Weinhold /*! Makes sure we have needed * 4 bytes of memory at fAfterLastEntry. 2773fccf067SIngo Weinhold Returns \c false, if unable to free that much. 2783fccf067SIngo Weinhold */ 2793fccf067SIngo Weinhold bool 2803fccf067SIngo Weinhold TracingMetaData::_MakeSpace(size_t needed) 2813fccf067SIngo Weinhold { 2823fccf067SIngo Weinhold // we need space for fAfterLastEntry, too (in case we need to wrap around 2833fccf067SIngo Weinhold // later) 2843fccf067SIngo Weinhold needed++; 2853fccf067SIngo Weinhold 2863fccf067SIngo Weinhold // If there's not enough space (free or occupied) after fAfterLastEntry, 2873fccf067SIngo Weinhold // we free all entries in that region and wrap around. 2883fccf067SIngo Weinhold if (fAfterLastEntry + needed > fBuffer + kBufferSize) { 2893fccf067SIngo Weinhold TRACE(("_MakeSpace(%lu), wrapping around: after last: %p\n", needed, 2903fccf067SIngo Weinhold fAfterLastEntry)); 2913fccf067SIngo Weinhold 2923fccf067SIngo Weinhold // Free all entries after fAfterLastEntry and one more at the beginning 2933fccf067SIngo Weinhold // of the buffer. 2943fccf067SIngo Weinhold while (fFirstEntry > fAfterLastEntry) { 2953fccf067SIngo Weinhold if (!_FreeFirstEntry()) 2963fccf067SIngo Weinhold return false; 2973fccf067SIngo Weinhold } 2983fccf067SIngo Weinhold if (fAfterLastEntry != fBuffer && !_FreeFirstEntry()) 2993fccf067SIngo Weinhold return false; 3003fccf067SIngo Weinhold 3013fccf067SIngo Weinhold // just in case _FreeFirstEntry() freed the very last existing entry 3023fccf067SIngo Weinhold if (fAfterLastEntry == fBuffer) 3033fccf067SIngo Weinhold return true; 3043fccf067SIngo Weinhold 3053fccf067SIngo Weinhold // mark as wrap entry and actually wrap around 3063fccf067SIngo Weinhold trace_entry* wrapEntry = fAfterLastEntry; 3073fccf067SIngo Weinhold wrapEntry->size = 0; 3083fccf067SIngo Weinhold wrapEntry->flags = WRAP_ENTRY; 3093fccf067SIngo Weinhold fAfterLastEntry = fBuffer; 3103fccf067SIngo Weinhold fAfterLastEntry->previous_size = fBuffer + kBufferSize - wrapEntry; 3113fccf067SIngo Weinhold } 3123fccf067SIngo Weinhold 3133fccf067SIngo Weinhold if (fFirstEntry <= fAfterLastEntry) { 3143fccf067SIngo Weinhold // buffer is empty or the space after fAfterLastEntry is unoccupied 3153fccf067SIngo Weinhold return true; 3163fccf067SIngo Weinhold } 3173fccf067SIngo Weinhold 3183fccf067SIngo Weinhold // free the first entries, until there's enough space 3193fccf067SIngo Weinhold size_t space = fFirstEntry - fAfterLastEntry; 3203fccf067SIngo Weinhold 3213fccf067SIngo Weinhold if (space < needed) { 3223fccf067SIngo Weinhold TRACE(("_MakeSpace(%lu), left %ld\n", needed, space)); 3233fccf067SIngo Weinhold } 3243fccf067SIngo Weinhold 3253fccf067SIngo Weinhold while (space < needed) { 3263fccf067SIngo Weinhold space += fFirstEntry->size; 3273fccf067SIngo Weinhold 3283fccf067SIngo Weinhold if (!_FreeFirstEntry()) 3293fccf067SIngo Weinhold return false; 3303fccf067SIngo Weinhold } 3313fccf067SIngo Weinhold 3323fccf067SIngo Weinhold TRACE((" out: start %p, entries %ld\n", fFirstEntry, fEntries)); 3333fccf067SIngo Weinhold 3343fccf067SIngo Weinhold return true; 3353fccf067SIngo Weinhold } 3363fccf067SIngo Weinhold 3373fccf067SIngo Weinhold 3383fccf067SIngo Weinhold /*static*/ status_t 3393fccf067SIngo Weinhold TracingMetaData::Create(TracingMetaData*& _metaData) 340d829579dSIngo Weinhold { 341d829579dSIngo Weinhold // search meta data in memory (from previous session) 342d829579dSIngo Weinhold area_id area; 343d829579dSIngo Weinhold TracingMetaData* metaData; 344d829579dSIngo Weinhold status_t error = _CreateMetaDataArea(true, area, metaData); 345d829579dSIngo Weinhold if (error == B_OK) { 346ce50cdc3SIngo Weinhold if (metaData->_InitPreviousTracingData()) { 347d829579dSIngo Weinhold _metaData = metaData; 348d829579dSIngo Weinhold return B_OK; 349d829579dSIngo Weinhold } 350d829579dSIngo Weinhold 351d829579dSIngo Weinhold dprintf("Found previous tracing meta data, but failed to init.\n"); 352d829579dSIngo Weinhold 353d829579dSIngo Weinhold // invalidate the meta data 3543fccf067SIngo Weinhold metaData->fMagic1 = 0; 3553fccf067SIngo Weinhold metaData->fMagic2 = 0; 3563fccf067SIngo Weinhold metaData->fMagic3 = 0; 357d829579dSIngo Weinhold delete_area(area); 358d829579dSIngo Weinhold } else 359d829579dSIngo Weinhold dprintf("No previous tracing meta data found.\n"); 360d829579dSIngo Weinhold 36155d903d2SAxel Dörfler // no previous tracing data found -- create new one 362d829579dSIngo Weinhold error = _CreateMetaDataArea(false, area, metaData); 363d829579dSIngo Weinhold if (error != B_OK) 364d829579dSIngo Weinhold return error; 365d829579dSIngo Weinhold 366a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {}; 367a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; 368a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {}; 3697198f765SAxel Dörfler area = create_area_etc(B_SYSTEM_TEAM, "tracing log", 370d829579dSIngo Weinhold kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS, 371a8ad734fSIngo Weinhold B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT, 372a8ad734fSIngo Weinhold &virtualRestrictions, &physicalRestrictions, 373a8ad734fSIngo Weinhold (void**)&metaData->fTraceOutputBuffer); 374d829579dSIngo Weinhold if (area < 0) 375d829579dSIngo Weinhold return area; 376d829579dSIngo Weinhold 377d829579dSIngo Weinhold // get the physical address 378d829579dSIngo Weinhold physical_entry physicalEntry; 3793fccf067SIngo Weinhold if (get_memory_map(metaData->fTraceOutputBuffer, B_PAGE_SIZE, 380d829579dSIngo Weinhold &physicalEntry, 1) == B_OK) { 38164d79effSIngo Weinhold metaData->fPhysicalAddress = physicalEntry.address; 382d829579dSIngo Weinhold } else { 383d829579dSIngo Weinhold dprintf("TracingMetaData::Create(): failed to get physical address " 384d829579dSIngo Weinhold "of tracing buffer\n"); 3853fccf067SIngo Weinhold metaData->fPhysicalAddress = 0; 386d829579dSIngo Weinhold } 387d829579dSIngo Weinhold 3883fccf067SIngo Weinhold metaData->fBuffer = (trace_entry*)(metaData->fTraceOutputBuffer 389d829579dSIngo Weinhold + kTraceOutputBufferSize); 3903fccf067SIngo Weinhold metaData->fFirstEntry = metaData->fBuffer; 3913fccf067SIngo Weinhold metaData->fAfterLastEntry = metaData->fBuffer; 392d829579dSIngo Weinhold 3933fccf067SIngo Weinhold metaData->fEntries = 0; 3943fccf067SIngo Weinhold metaData->fEntriesEver = 0; 3953fccf067SIngo Weinhold B_INITIALIZE_SPINLOCK(&metaData->fLock); 396d829579dSIngo Weinhold 3973fccf067SIngo Weinhold metaData->fMagic1 = kMetaDataMagic1; 3983fccf067SIngo Weinhold metaData->fMagic2 = kMetaDataMagic2; 3993fccf067SIngo Weinhold metaData->fMagic3 = kMetaDataMagic3; 400d829579dSIngo Weinhold 401d829579dSIngo Weinhold _metaData = metaData; 402d829579dSIngo Weinhold return B_OK; 403d829579dSIngo Weinhold } 404d829579dSIngo Weinhold 4053fccf067SIngo Weinhold 4063fccf067SIngo Weinhold /*static*/ status_t 4073fccf067SIngo Weinhold TracingMetaData::_CreateMetaDataArea(bool findPrevious, area_id& _area, 4083fccf067SIngo Weinhold TracingMetaData*& _metaData) 409d829579dSIngo Weinhold { 410d829579dSIngo Weinhold // search meta data in memory (from previous session) 411d829579dSIngo Weinhold TracingMetaData* metaData; 412a8ad734fSIngo Weinhold phys_addr_t metaDataAddress = kMetaDataBaseAddress; 413d829579dSIngo Weinhold for (; metaDataAddress <= kMetaDataBaseEndAddress; 414d829579dSIngo Weinhold metaDataAddress += kMetaDataAddressIncrement) { 415a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {}; 416a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; 417a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {}; 418a8ad734fSIngo Weinhold physicalRestrictions.low_address = metaDataAddress; 419a8ad734fSIngo Weinhold physicalRestrictions.high_address = metaDataAddress + B_PAGE_SIZE; 420cdb638a8SAxel Dörfler area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing metadata", 421cdb638a8SAxel Dörfler B_PAGE_SIZE, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 422a8ad734fSIngo Weinhold CREATE_AREA_DONT_CLEAR, &virtualRestrictions, &physicalRestrictions, 423a8ad734fSIngo Weinhold (void**)&metaData); 424d829579dSIngo Weinhold if (area < 0) 425d829579dSIngo Weinhold continue; 426d829579dSIngo Weinhold 427d829579dSIngo Weinhold if (!findPrevious) { 428d829579dSIngo Weinhold _area = area; 429d829579dSIngo Weinhold _metaData = metaData; 430d829579dSIngo Weinhold return B_OK; 431d829579dSIngo Weinhold } 432d829579dSIngo Weinhold 4333fccf067SIngo Weinhold if (metaData->fMagic1 == kMetaDataMagic1 4343fccf067SIngo Weinhold && metaData->fMagic2 == kMetaDataMagic2 4353fccf067SIngo Weinhold && metaData->fMagic3 == kMetaDataMagic3) { 436d829579dSIngo Weinhold _area = area; 437d829579dSIngo Weinhold _metaData = metaData; 438d829579dSIngo Weinhold return B_OK; 439d829579dSIngo Weinhold } 440d829579dSIngo Weinhold 441d829579dSIngo Weinhold delete_area(area); 442d829579dSIngo Weinhold } 443d829579dSIngo Weinhold 444d829579dSIngo Weinhold return B_ENTRY_NOT_FOUND; 445d829579dSIngo Weinhold } 446d829579dSIngo Weinhold 4473fccf067SIngo Weinhold 448ce50cdc3SIngo Weinhold bool 449ce50cdc3SIngo Weinhold TracingMetaData::_InitPreviousTracingData() 450d829579dSIngo Weinhold { 451b0eaa06cSIngo Weinhold // TODO: ATM re-attaching the previous tracing buffer doesn't work very 452b0eaa06cSIngo Weinhold // well. The entries should checked more thoroughly for validity -- e.g. the 453b0eaa06cSIngo Weinhold // pointers to the entries' vtable pointers could be invalid, which can 454b0eaa06cSIngo Weinhold // make the "traced" command quite unusable. The validity of the entries 455b0eaa06cSIngo Weinhold // could be checked in a safe environment (i.e. with a fault handler) with 456b0eaa06cSIngo Weinhold // typeid() and call of a virtual function. 457b0eaa06cSIngo Weinhold return false; 458b0eaa06cSIngo Weinhold 459d829579dSIngo Weinhold addr_t bufferStart 460ce50cdc3SIngo Weinhold = (addr_t)fTraceOutputBuffer + kTraceOutputBufferSize; 461d829579dSIngo Weinhold addr_t bufferEnd = bufferStart + MAX_TRACE_SIZE; 462d829579dSIngo Weinhold 463ce50cdc3SIngo Weinhold if (bufferStart > bufferEnd || (addr_t)fBuffer != bufferStart 464ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry % sizeof(trace_entry) != 0 465ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry < bufferStart 466ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry + sizeof(trace_entry) >= bufferEnd 467ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry % sizeof(trace_entry) != 0 468ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry < bufferStart 469ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry > bufferEnd 470ce50cdc3SIngo Weinhold || fPhysicalAddress == 0) { 471d829579dSIngo Weinhold dprintf("Failed to init tracing meta data: Sanity checks " 472d829579dSIngo Weinhold "failed.\n"); 473d829579dSIngo Weinhold return false; 474d829579dSIngo Weinhold } 475d829579dSIngo Weinhold 476d829579dSIngo Weinhold // re-map the previous tracing buffer 477a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {}; 478a8ad734fSIngo Weinhold virtualRestrictions.address = fTraceOutputBuffer; 479a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_EXACT_ADDRESS; 480a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {}; 481a8ad734fSIngo Weinhold physicalRestrictions.low_address = fPhysicalAddress; 482a8ad734fSIngo Weinhold physicalRestrictions.high_address = fPhysicalAddress 483cdb638a8SAxel Dörfler + ROUNDUP(kTraceOutputBufferSize + MAX_TRACE_SIZE, B_PAGE_SIZE); 484d829579dSIngo Weinhold area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing log", 485a8ad734fSIngo Weinhold kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS, 486a8ad734fSIngo Weinhold B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_CLEAR, 487a8ad734fSIngo Weinhold &virtualRestrictions, &physicalRestrictions, NULL); 488d829579dSIngo Weinhold if (area < 0) { 489d829579dSIngo Weinhold dprintf("Failed to init tracing meta data: Mapping tracing log " 490d829579dSIngo Weinhold "buffer failed: %s\n", strerror(area)); 491d829579dSIngo Weinhold return false; 492d829579dSIngo Weinhold } 493d829579dSIngo Weinhold 4941aed2639SIngo Weinhold dprintf("ktrace: Remapped tracing buffer at %p, size: %" B_PRIuSIZE "\n", 495a8ad734fSIngo Weinhold fTraceOutputBuffer, kTraceOutputBufferSize + MAX_TRACE_SIZE); 4961aed2639SIngo Weinhold 4973fccf067SIngo Weinhold // verify/repair the tracing entry list 498ce50cdc3SIngo Weinhold uint32 errorCount = 0; 499ce50cdc3SIngo Weinhold uint32 entryCount = 0; 500ce50cdc3SIngo Weinhold uint32 nonBufferEntryCount = 0; 501ce50cdc3SIngo Weinhold uint32 previousEntrySize = 0; 502ce50cdc3SIngo Weinhold trace_entry* entry = fFirstEntry; 503ce50cdc3SIngo Weinhold while (errorCount <= kMaxRecoveringErrorCount) { 504ce50cdc3SIngo Weinhold // check previous entry size 505ce50cdc3SIngo Weinhold if (entry->previous_size != previousEntrySize) { 506ce50cdc3SIngo Weinhold if (entry != fFirstEntry) { 507ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: fixing previous_size " 508ce50cdc3SIngo Weinhold "size: %lu (should be %lu)\n", entry, entry->previous_size, 509ce50cdc3SIngo Weinhold previousEntrySize); 5101aed2639SIngo Weinhold errorCount++; 511d829579dSIngo Weinhold } 512ce50cdc3SIngo Weinhold entry->previous_size = previousEntrySize; 513ce50cdc3SIngo Weinhold } 514aa5d2a2dSAxel Dörfler 5153fccf067SIngo Weinhold if (entry == fAfterLastEntry) 516ce50cdc3SIngo Weinhold break; 517aa5d2a2dSAxel Dörfler 518ce50cdc3SIngo Weinhold // check size field 519ce50cdc3SIngo Weinhold if ((entry->flags & WRAP_ENTRY) == 0 && entry->size == 0) { 520ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: non-wrap entry size is 0\n", 521ce50cdc3SIngo Weinhold entry); 5221aed2639SIngo Weinhold errorCount++; 523ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 524ce50cdc3SIngo Weinhold break; 525aa5d2a2dSAxel Dörfler } 526aa5d2a2dSAxel Dörfler 527ce50cdc3SIngo Weinhold if (entry->size > uint32(fBuffer + kBufferSize - entry)) { 528ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: size too big: %lu\n", entry, 529ce50cdc3SIngo Weinhold entry->size); 5301aed2639SIngo Weinhold errorCount++; 531ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 532ce50cdc3SIngo Weinhold break; 5336d369966SIngo Weinhold } 5346d369966SIngo Weinhold 535ce50cdc3SIngo Weinhold if (entry < fAfterLastEntry && entry + entry->size > fAfterLastEntry) { 536ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: entry crosses " 537ce50cdc3SIngo Weinhold "fAfterLastEntry (%p)\n", entry, fAfterLastEntry); 5381aed2639SIngo Weinhold errorCount++; 539ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 540ce50cdc3SIngo Weinhold break; 5416d369966SIngo Weinhold } 5426d369966SIngo Weinhold 543ce50cdc3SIngo Weinhold // check for wrap entry 544ce50cdc3SIngo Weinhold if ((entry->flags & WRAP_ENTRY) != 0) { 545ce50cdc3SIngo Weinhold if ((uint32)(fBuffer + kBufferSize - entry) 546ce50cdc3SIngo Weinhold > kMaxTracingEntryByteSize / sizeof(trace_entry)) { 547ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: wrap entry at invalid " 548ce50cdc3SIngo Weinhold "buffer location\n", entry); 5491aed2639SIngo Weinhold errorCount++; 550ce50cdc3SIngo Weinhold } 5516d369966SIngo Weinhold 552ce50cdc3SIngo Weinhold if (entry->size != 0) { 553ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: invalid wrap entry " 554ce50cdc3SIngo Weinhold "size: %lu\n", entry, entry->size); 5551aed2639SIngo Weinhold errorCount++; 556ce50cdc3SIngo Weinhold entry->size = 0; 557ce50cdc3SIngo Weinhold } 5586d986c16SIngo Weinhold 559ce50cdc3SIngo Weinhold previousEntrySize = fBuffer + kBufferSize - entry; 560ce50cdc3SIngo Weinhold entry = fBuffer; 561ce50cdc3SIngo Weinhold continue; 562ce50cdc3SIngo Weinhold } 563ce50cdc3SIngo Weinhold 564ce50cdc3SIngo Weinhold if ((entry->flags & BUFFER_ENTRY) == 0) { 565ce50cdc3SIngo Weinhold entry->flags |= CHECK_ENTRY; 566ce50cdc3SIngo Weinhold nonBufferEntryCount++; 567ce50cdc3SIngo Weinhold } 568ce50cdc3SIngo Weinhold 569ce50cdc3SIngo Weinhold entryCount++; 570ce50cdc3SIngo Weinhold previousEntrySize = entry->size; 571ce50cdc3SIngo Weinhold 572ce50cdc3SIngo Weinhold entry += entry->size; 573ce50cdc3SIngo Weinhold } 574ce50cdc3SIngo Weinhold 575ce50cdc3SIngo Weinhold if (errorCount > kMaxRecoveringErrorCount) { 576ce50cdc3SIngo Weinhold dprintf("ktrace recovering: Too many errors.\n"); 577ce50cdc3SIngo Weinhold fAfterLastEntry = entry; 578ce50cdc3SIngo Weinhold fAfterLastEntry->previous_size = previousEntrySize; 579ce50cdc3SIngo Weinhold } 580ce50cdc3SIngo Weinhold 581ce50cdc3SIngo Weinhold dprintf("ktrace recovering: Recovered %lu entries + %lu buffer entries " 582ce50cdc3SIngo Weinhold "from previous session. Expected %lu entries.\n", nonBufferEntryCount, 583ce50cdc3SIngo Weinhold entryCount - nonBufferEntryCount, fEntries); 584ce50cdc3SIngo Weinhold fEntries = nonBufferEntryCount; 585ce50cdc3SIngo Weinhold 586ce50cdc3SIngo Weinhold B_INITIALIZE_SPINLOCK(&fLock); 587ce50cdc3SIngo Weinhold 588ce50cdc3SIngo Weinhold // TODO: Actually check the entries! Do that when first accessing the 589ce50cdc3SIngo Weinhold // tracing buffer from the kernel debugger (when sTracingDataRecovered is 590ce50cdc3SIngo Weinhold // true). 5913fccf067SIngo Weinhold sTracingDataRecovered = true; 5926d986c16SIngo Weinhold return true; 5936d986c16SIngo Weinhold } 5946d986c16SIngo Weinhold 5956d986c16SIngo Weinhold 5968e43ece8SAxel Dörfler #endif // ENABLE_TRACING 5978e43ece8SAxel Dörfler 5988e43ece8SAxel Dörfler 5998e43ece8SAxel Dörfler // #pragma mark - 6008e43ece8SAxel Dörfler 6018e43ece8SAxel Dörfler 602350b6dbcSIngo Weinhold TraceOutput::TraceOutput(char* buffer, size_t bufferSize, uint32 flags) 603f1047a1cSIngo Weinhold : fBuffer(buffer), 604350b6dbcSIngo Weinhold fCapacity(bufferSize), 605350b6dbcSIngo Weinhold fFlags(flags) 606f1047a1cSIngo Weinhold { 607f7a5d9c5SIngo Weinhold Clear(); 608f7a5d9c5SIngo Weinhold } 609f7a5d9c5SIngo Weinhold 610f7a5d9c5SIngo Weinhold 611f7a5d9c5SIngo Weinhold void 612f7a5d9c5SIngo Weinhold TraceOutput::Clear() 613f7a5d9c5SIngo Weinhold { 614f7a5d9c5SIngo Weinhold if (fCapacity > 0) 615f7a5d9c5SIngo Weinhold fBuffer[0] = '\0'; 616f7a5d9c5SIngo Weinhold fSize = 0; 617f1047a1cSIngo Weinhold } 618f1047a1cSIngo Weinhold 619f1047a1cSIngo Weinhold 620f1047a1cSIngo Weinhold void 621f1047a1cSIngo Weinhold TraceOutput::Print(const char* format,...) 622f1047a1cSIngo Weinhold { 623b2d95c3cSIngo Weinhold #if ENABLE_TRACING 624f1047a1cSIngo Weinhold if (IsFull()) 625f1047a1cSIngo Weinhold return; 626f1047a1cSIngo Weinhold 6273ce26345SIngo Weinhold if (fSize < fCapacity) { 628f1047a1cSIngo Weinhold va_list args; 629f1047a1cSIngo Weinhold va_start(args, format); 6303ce26345SIngo Weinhold size_t length = vsnprintf(fBuffer + fSize, fCapacity - fSize, format, 6313ce26345SIngo Weinhold args); 6323ce26345SIngo Weinhold fSize += std::min(length, fCapacity - fSize - 1); 633f1047a1cSIngo Weinhold va_end(args); 6343ce26345SIngo Weinhold } 635b2d95c3cSIngo Weinhold #endif 636f1047a1cSIngo Weinhold } 637f1047a1cSIngo Weinhold 638f1047a1cSIngo Weinhold 639350b6dbcSIngo Weinhold void 64065f40152SIngo Weinhold TraceOutput::PrintStackTrace(tracing_stack_trace* stackTrace) 64165f40152SIngo Weinhold { 642b2d95c3cSIngo Weinhold #if ENABLE_TRACING 64365f40152SIngo Weinhold if (stackTrace == NULL || stackTrace->depth <= 0) 64465f40152SIngo Weinhold return; 64565f40152SIngo Weinhold 64665f40152SIngo Weinhold for (int32 i = 0; i < stackTrace->depth; i++) { 64765f40152SIngo Weinhold addr_t address = stackTrace->return_addresses[i]; 64865f40152SIngo Weinhold 64965f40152SIngo Weinhold const char* symbol; 65065f40152SIngo Weinhold const char* imageName; 65165f40152SIngo Weinhold bool exactMatch; 65265f40152SIngo Weinhold addr_t baseAddress; 65365f40152SIngo Weinhold 65465f40152SIngo Weinhold if (elf_debug_lookup_symbol_address(address, &baseAddress, &symbol, 65565f40152SIngo Weinhold &imageName, &exactMatch) == B_OK) { 65665f40152SIngo Weinhold Print(" %p %s + 0x%lx (%s)%s\n", (void*)address, symbol, 65765f40152SIngo Weinhold address - baseAddress, imageName, 65865f40152SIngo Weinhold exactMatch ? "" : " (nearest)"); 65965f40152SIngo Weinhold } else 66065f40152SIngo Weinhold Print(" %p\n", (void*)address); 66165f40152SIngo Weinhold } 662b2d95c3cSIngo Weinhold #endif 66365f40152SIngo Weinhold } 66465f40152SIngo Weinhold 66565f40152SIngo Weinhold 66665f40152SIngo Weinhold void 667350b6dbcSIngo Weinhold TraceOutput::SetLastEntryTime(bigtime_t time) 668350b6dbcSIngo Weinhold { 669350b6dbcSIngo Weinhold fLastEntryTime = time; 670350b6dbcSIngo Weinhold } 671350b6dbcSIngo Weinhold 672350b6dbcSIngo Weinhold 673350b6dbcSIngo Weinhold bigtime_t 674350b6dbcSIngo Weinhold TraceOutput::LastEntryTime() const 675350b6dbcSIngo Weinhold { 676350b6dbcSIngo Weinhold return fLastEntryTime; 677350b6dbcSIngo Weinhold } 678350b6dbcSIngo Weinhold 679350b6dbcSIngo Weinhold 680f1047a1cSIngo Weinhold // #pragma mark - 681f1047a1cSIngo Weinhold 682f1047a1cSIngo Weinhold 6838e43ece8SAxel Dörfler TraceEntry::TraceEntry() 6848e43ece8SAxel Dörfler { 6858e43ece8SAxel Dörfler } 6868e43ece8SAxel Dörfler 6878e43ece8SAxel Dörfler 6888e43ece8SAxel Dörfler TraceEntry::~TraceEntry() 6898e43ece8SAxel Dörfler { 6908e43ece8SAxel Dörfler } 6918e43ece8SAxel Dörfler 6928e43ece8SAxel Dörfler 6938e43ece8SAxel Dörfler void 694f7a5d9c5SIngo Weinhold TraceEntry::Dump(TraceOutput& out) 6958e43ece8SAxel Dörfler { 6968e43ece8SAxel Dörfler #if ENABLE_TRACING 697f1047a1cSIngo Weinhold // to be overridden by subclasses 698f7a5d9c5SIngo Weinhold out.Print("ENTRY %p", this); 6998e43ece8SAxel Dörfler #endif 7008e43ece8SAxel Dörfler } 7018e43ece8SAxel Dörfler 7028e43ece8SAxel Dörfler 7038e43ece8SAxel Dörfler void 70465f40152SIngo Weinhold TraceEntry::DumpStackTrace(TraceOutput& out) 70565f40152SIngo Weinhold { 70665f40152SIngo Weinhold } 70765f40152SIngo Weinhold 70865f40152SIngo Weinhold 70965f40152SIngo Weinhold void 7108e43ece8SAxel Dörfler TraceEntry::Initialized() 7118e43ece8SAxel Dörfler { 7128e43ece8SAxel Dörfler #if ENABLE_TRACING 713b3d6c12dSIngo Weinhold ToTraceEntry()->flags |= ENTRY_INITIALIZED; 7143fccf067SIngo Weinhold sTracingMetaData->IncrementEntriesEver(); 7158e43ece8SAxel Dörfler #endif 7168e43ece8SAxel Dörfler } 7178e43ece8SAxel Dörfler 7188e43ece8SAxel Dörfler 7198e43ece8SAxel Dörfler void* 7208e43ece8SAxel Dörfler TraceEntry::operator new(size_t size, const std::nothrow_t&) throw() 7218e43ece8SAxel Dörfler { 7228e43ece8SAxel Dörfler #if ENABLE_TRACING 7233fccf067SIngo Weinhold trace_entry* entry = sTracingMetaData->AllocateEntry( 7243fccf067SIngo Weinhold size + sizeof(trace_entry), 0); 725b3d6c12dSIngo Weinhold return entry != NULL ? entry + 1 : NULL; 726aa5d2a2dSAxel Dörfler #endif 727989a6e05SIngo Weinhold return NULL; 728aa5d2a2dSAxel Dörfler } 729aa5d2a2dSAxel Dörfler 730aa5d2a2dSAxel Dörfler 731aa5d2a2dSAxel Dörfler // #pragma mark - 732aa5d2a2dSAxel Dörfler 733aa5d2a2dSAxel Dörfler 734f1047a1cSIngo Weinhold AbstractTraceEntry::~AbstractTraceEntry() 735f1047a1cSIngo Weinhold { 736f1047a1cSIngo Weinhold } 737f1047a1cSIngo Weinhold 738f1047a1cSIngo Weinhold 739f1047a1cSIngo Weinhold void 740f7a5d9c5SIngo Weinhold AbstractTraceEntry::Dump(TraceOutput& out) 741f1047a1cSIngo Weinhold { 742350b6dbcSIngo Weinhold bigtime_t time = (out.Flags() & TRACE_OUTPUT_DIFF_TIME) 743350b6dbcSIngo Weinhold ? fTime - out.LastEntryTime() 744350b6dbcSIngo Weinhold : fTime; 745350b6dbcSIngo Weinhold 746350b6dbcSIngo Weinhold if (out.Flags() & TRACE_OUTPUT_TEAM_ID) 747350b6dbcSIngo Weinhold out.Print("[%6ld:%6ld] %10Ld: ", fThread, fTeam, time); 74864fe37eeSIngo Weinhold else 749350b6dbcSIngo Weinhold out.Print("[%6ld] %10Ld: ", fThread, time); 750350b6dbcSIngo Weinhold 751f1047a1cSIngo Weinhold AddDump(out); 752350b6dbcSIngo Weinhold 753350b6dbcSIngo Weinhold out.SetLastEntryTime(fTime); 754f1047a1cSIngo Weinhold } 755f1047a1cSIngo Weinhold 756f1047a1cSIngo Weinhold 757f1047a1cSIngo Weinhold void 758f1047a1cSIngo Weinhold AbstractTraceEntry::AddDump(TraceOutput& out) 759f1047a1cSIngo Weinhold { 760f1047a1cSIngo Weinhold } 761f1047a1cSIngo Weinhold 762f1047a1cSIngo Weinhold 763fe8f0f46SMichael Lotz void 764fe8f0f46SMichael Lotz AbstractTraceEntry::_Init() 765fe8f0f46SMichael Lotz { 766fe8f0f46SMichael Lotz Thread* thread = thread_get_current_thread(); 767fe8f0f46SMichael Lotz if (thread != NULL) { 768fe8f0f46SMichael Lotz fThread = thread->id; 769fe8f0f46SMichael Lotz if (thread->team) 770fe8f0f46SMichael Lotz fTeam = thread->team->id; 771fe8f0f46SMichael Lotz } 772fe8f0f46SMichael Lotz fTime = system_time(); 773fe8f0f46SMichael Lotz } 774fe8f0f46SMichael Lotz 775fe8f0f46SMichael Lotz 776fe8f0f46SMichael Lotz // #pragma mark - AbstractTraceEntryWithStackTrace 777fe8f0f46SMichael Lotz 778fe8f0f46SMichael Lotz 779fe8f0f46SMichael Lotz 780fe8f0f46SMichael Lotz AbstractTraceEntryWithStackTrace::AbstractTraceEntryWithStackTrace( 781fe8f0f46SMichael Lotz size_t stackTraceDepth, size_t skipFrames, bool kernelOnly) 782fe8f0f46SMichael Lotz { 783fe8f0f46SMichael Lotz fStackTrace = capture_tracing_stack_trace(stackTraceDepth, skipFrames + 1, 784fe8f0f46SMichael Lotz kernelOnly); 785fe8f0f46SMichael Lotz } 786fe8f0f46SMichael Lotz 787fe8f0f46SMichael Lotz 788fe8f0f46SMichael Lotz void 789fe8f0f46SMichael Lotz AbstractTraceEntryWithStackTrace::DumpStackTrace(TraceOutput& out) 790fe8f0f46SMichael Lotz { 791fe8f0f46SMichael Lotz out.PrintStackTrace(fStackTrace); 792fe8f0f46SMichael Lotz } 793fe8f0f46SMichael Lotz 794fe8f0f46SMichael Lotz 795a54c125eSIngo Weinhold // #pragma mark - 796a54c125eSIngo Weinhold 797a54c125eSIngo Weinhold 798a54c125eSIngo Weinhold #if ENABLE_TRACING 799a54c125eSIngo Weinhold 8007d2d758dSIngo Weinhold class KernelTraceEntry : public AbstractTraceEntry { 8017d2d758dSIngo Weinhold public: 8027d2d758dSIngo Weinhold KernelTraceEntry(const char* message) 8037d2d758dSIngo Weinhold { 8047d2d758dSIngo Weinhold fMessage = alloc_tracing_buffer_strcpy(message, 256, false); 8057d2d758dSIngo Weinhold 806b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE 807b3d6c12dSIngo Weinhold fStackTrace = capture_tracing_stack_trace( 808b3d6c12dSIngo Weinhold KTRACE_PRINTF_STACK_TRACE, 1, false); 809b3d6c12dSIngo Weinhold #endif 8107d2d758dSIngo Weinhold Initialized(); 8117d2d758dSIngo Weinhold } 8127d2d758dSIngo Weinhold 8137d2d758dSIngo Weinhold virtual void AddDump(TraceOutput& out) 8147d2d758dSIngo Weinhold { 8157d2d758dSIngo Weinhold out.Print("kern: %s", fMessage); 8167d2d758dSIngo Weinhold } 8177d2d758dSIngo Weinhold 818b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE 819b3d6c12dSIngo Weinhold virtual void DumpStackTrace(TraceOutput& out) 820b3d6c12dSIngo Weinhold { 821b3d6c12dSIngo Weinhold out.PrintStackTrace(fStackTrace); 822b3d6c12dSIngo Weinhold } 823b3d6c12dSIngo Weinhold #endif 824b3d6c12dSIngo Weinhold 8257d2d758dSIngo Weinhold private: 8267d2d758dSIngo Weinhold char* fMessage; 827b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE 828b3d6c12dSIngo Weinhold tracing_stack_trace* fStackTrace; 829b3d6c12dSIngo Weinhold #endif 8307d2d758dSIngo Weinhold }; 8317d2d758dSIngo Weinhold 8327d2d758dSIngo Weinhold 833a54c125eSIngo Weinhold class UserTraceEntry : public AbstractTraceEntry { 834a54c125eSIngo Weinhold public: 835a54c125eSIngo Weinhold UserTraceEntry(const char* message) 836a54c125eSIngo Weinhold { 837a54c125eSIngo Weinhold fMessage = alloc_tracing_buffer_strcpy(message, 256, true); 838a54c125eSIngo Weinhold 839bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE 840bc6a5f86SOliver Tappe fStackTrace = capture_tracing_stack_trace( 841bc6a5f86SOliver Tappe KTRACE_PRINTF_STACK_TRACE, 1, false); 842bc6a5f86SOliver Tappe #endif 843a54c125eSIngo Weinhold Initialized(); 844a54c125eSIngo Weinhold } 845a54c125eSIngo Weinhold 846a54c125eSIngo Weinhold virtual void AddDump(TraceOutput& out) 847a54c125eSIngo Weinhold { 848a54c125eSIngo Weinhold out.Print("user: %s", fMessage); 849a54c125eSIngo Weinhold } 850a54c125eSIngo Weinhold 851bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE 852bc6a5f86SOliver Tappe virtual void DumpStackTrace(TraceOutput& out) 853bc6a5f86SOliver Tappe { 854bc6a5f86SOliver Tappe out.PrintStackTrace(fStackTrace); 855bc6a5f86SOliver Tappe } 856bc6a5f86SOliver Tappe #endif 857bc6a5f86SOliver Tappe 858a54c125eSIngo Weinhold private: 859a54c125eSIngo Weinhold char* fMessage; 860bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE 861bc6a5f86SOliver Tappe tracing_stack_trace* fStackTrace; 862bc6a5f86SOliver Tappe #endif 863a54c125eSIngo Weinhold }; 864a54c125eSIngo Weinhold 865d829579dSIngo Weinhold 866d829579dSIngo Weinhold class TracingLogStartEntry : public AbstractTraceEntry { 867d829579dSIngo Weinhold public: 868d829579dSIngo Weinhold TracingLogStartEntry() 869d829579dSIngo Weinhold { 870d829579dSIngo Weinhold Initialized(); 871d829579dSIngo Weinhold } 872d829579dSIngo Weinhold 873d829579dSIngo Weinhold virtual void AddDump(TraceOutput& out) 874d829579dSIngo Weinhold { 875d829579dSIngo Weinhold out.Print("ktrace start"); 876d829579dSIngo Weinhold } 877d829579dSIngo Weinhold }; 878d829579dSIngo Weinhold 879a54c125eSIngo Weinhold #endif // ENABLE_TRACING 880a54c125eSIngo Weinhold 881a54c125eSIngo Weinhold 8824c4b14c3SIngo Weinhold // #pragma mark - trace filters 8834c4b14c3SIngo Weinhold 8844c4b14c3SIngo Weinhold 885f97199edSIngo Weinhold TraceFilter::~TraceFilter() 8864c4b14c3SIngo Weinhold { 8874c4b14c3SIngo Weinhold } 8884c4b14c3SIngo Weinhold 8894c4b14c3SIngo Weinhold 890f97199edSIngo Weinhold bool 891f97199edSIngo Weinhold TraceFilter::Filter(const TraceEntry* entry, LazyTraceOutput& out) 8924c4b14c3SIngo Weinhold { 8934c4b14c3SIngo Weinhold return false; 8944c4b14c3SIngo Weinhold } 8954c4b14c3SIngo Weinhold 8964c4b14c3SIngo Weinhold 8974c4b14c3SIngo Weinhold 8984c4b14c3SIngo Weinhold class ThreadTraceFilter : public TraceFilter { 8994c4b14c3SIngo Weinhold public: 9004c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out) 9014c4b14c3SIngo Weinhold { 9024c4b14c3SIngo Weinhold const AbstractTraceEntry* entry 9034c4b14c3SIngo Weinhold = dynamic_cast<const AbstractTraceEntry*>(_entry); 9044535495dSIngo Weinhold return (entry != NULL && entry->ThreadID() == fThread); 9054c4b14c3SIngo Weinhold } 9064c4b14c3SIngo Weinhold }; 9074c4b14c3SIngo Weinhold 9084c4b14c3SIngo Weinhold 90964fe37eeSIngo Weinhold class TeamTraceFilter : public TraceFilter { 91064fe37eeSIngo Weinhold public: 91164fe37eeSIngo Weinhold virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out) 91264fe37eeSIngo Weinhold { 91364fe37eeSIngo Weinhold const AbstractTraceEntry* entry 91464fe37eeSIngo Weinhold = dynamic_cast<const AbstractTraceEntry*>(_entry); 9154535495dSIngo Weinhold return (entry != NULL && entry->TeamID() == fTeam); 91664fe37eeSIngo Weinhold } 91764fe37eeSIngo Weinhold }; 91864fe37eeSIngo Weinhold 91964fe37eeSIngo Weinhold 9204c4b14c3SIngo Weinhold class PatternTraceFilter : public TraceFilter { 9214c4b14c3SIngo Weinhold public: 9224c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9234c4b14c3SIngo Weinhold { 9244c4b14c3SIngo Weinhold return strstr(out.DumpEntry(entry), fString) != NULL; 9254c4b14c3SIngo Weinhold } 9264c4b14c3SIngo Weinhold }; 9274c4b14c3SIngo Weinhold 9284c4b14c3SIngo Weinhold 929dc1a7867SAxel Dörfler class DecimalPatternTraceFilter : public TraceFilter { 930dc1a7867SAxel Dörfler public: 931dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 932dc1a7867SAxel Dörfler { 933dc1a7867SAxel Dörfler // TODO: this is *very* slow 934dc1a7867SAxel Dörfler char buffer[64]; 935dc1a7867SAxel Dörfler snprintf(buffer, sizeof(buffer), "%Ld", fValue); 936dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL; 937dc1a7867SAxel Dörfler } 938dc1a7867SAxel Dörfler }; 939dc1a7867SAxel Dörfler 940dc1a7867SAxel Dörfler class HexPatternTraceFilter : public TraceFilter { 941dc1a7867SAxel Dörfler public: 942dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 943dc1a7867SAxel Dörfler { 944dc1a7867SAxel Dörfler // TODO: this is *very* slow 945dc1a7867SAxel Dörfler char buffer[64]; 946dc1a7867SAxel Dörfler snprintf(buffer, sizeof(buffer), "%Lx", fValue); 947dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL; 948dc1a7867SAxel Dörfler } 949dc1a7867SAxel Dörfler }; 950dc1a7867SAxel Dörfler 951dc1a7867SAxel Dörfler class StringPatternTraceFilter : public TraceFilter { 952dc1a7867SAxel Dörfler public: 953dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 954dc1a7867SAxel Dörfler { 955dc1a7867SAxel Dörfler if (IS_KERNEL_ADDRESS(fValue)) 956dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), (const char*)fValue) != NULL; 957dc1a7867SAxel Dörfler 958dc1a7867SAxel Dörfler // TODO: this is *very* slow 959dc1a7867SAxel Dörfler char buffer[64]; 960dc1a7867SAxel Dörfler user_strlcpy(buffer, (const char*)fValue, sizeof(buffer)); 961dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL; 962dc1a7867SAxel Dörfler } 963dc1a7867SAxel Dörfler }; 964dc1a7867SAxel Dörfler 9654c4b14c3SIngo Weinhold class NotTraceFilter : public TraceFilter { 9664c4b14c3SIngo Weinhold public: 9674c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9684c4b14c3SIngo Weinhold { 9694c4b14c3SIngo Weinhold return !fSubFilters.first->Filter(entry, out); 9704c4b14c3SIngo Weinhold } 9714c4b14c3SIngo Weinhold }; 9724c4b14c3SIngo Weinhold 9734c4b14c3SIngo Weinhold 9744c4b14c3SIngo Weinhold class AndTraceFilter : public TraceFilter { 9754c4b14c3SIngo Weinhold public: 9764c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9774c4b14c3SIngo Weinhold { 9784c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out) 9794c4b14c3SIngo Weinhold && fSubFilters.second->Filter(entry, out); 9804c4b14c3SIngo Weinhold } 9814c4b14c3SIngo Weinhold }; 9824c4b14c3SIngo Weinhold 9834c4b14c3SIngo Weinhold 9844c4b14c3SIngo Weinhold class OrTraceFilter : public TraceFilter { 9854c4b14c3SIngo Weinhold public: 9864c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out) 9874c4b14c3SIngo Weinhold { 9884c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out) 9894c4b14c3SIngo Weinhold || fSubFilters.second->Filter(entry, out); 9904c4b14c3SIngo Weinhold } 9914c4b14c3SIngo Weinhold }; 9924c4b14c3SIngo Weinhold 9934c4b14c3SIngo Weinhold 9944c4b14c3SIngo Weinhold class TraceFilterParser { 9954c4b14c3SIngo Weinhold public: 9964c4b14c3SIngo Weinhold static TraceFilterParser* Default() 9974c4b14c3SIngo Weinhold { 9984c4b14c3SIngo Weinhold return &sParser; 9994c4b14c3SIngo Weinhold } 10004c4b14c3SIngo Weinhold 10014c4b14c3SIngo Weinhold bool Parse(int argc, const char* const* argv) 10024c4b14c3SIngo Weinhold { 10034c4b14c3SIngo Weinhold fTokens = argv; 10044c4b14c3SIngo Weinhold fTokenCount = argc; 10054c4b14c3SIngo Weinhold fTokenIndex = 0; 10064c4b14c3SIngo Weinhold fFilterCount = 0; 10074c4b14c3SIngo Weinhold 10084c4b14c3SIngo Weinhold TraceFilter* filter = _ParseExpression(); 10094c4b14c3SIngo Weinhold return fTokenIndex == fTokenCount && filter != NULL; 10104c4b14c3SIngo Weinhold } 10114c4b14c3SIngo Weinhold 1012f97199edSIngo Weinhold TraceFilter* Filter() 10134c4b14c3SIngo Weinhold { 1014f97199edSIngo Weinhold return &fFilters[0]; 10154c4b14c3SIngo Weinhold } 10164c4b14c3SIngo Weinhold 10174c4b14c3SIngo Weinhold private: 10184c4b14c3SIngo Weinhold TraceFilter* _ParseExpression() 10194c4b14c3SIngo Weinhold { 10204c4b14c3SIngo Weinhold const char* token = _NextToken(); 10214c4b14c3SIngo Weinhold if (!token) { 10224c4b14c3SIngo Weinhold // unexpected end of expression 10234c4b14c3SIngo Weinhold return NULL; 10244c4b14c3SIngo Weinhold } 10254c4b14c3SIngo Weinhold 10264c4b14c3SIngo Weinhold if (fFilterCount == MAX_FILTERS) { 10274c4b14c3SIngo Weinhold // too many filters 10284c4b14c3SIngo Weinhold return NULL; 10294c4b14c3SIngo Weinhold } 10304c4b14c3SIngo Weinhold 10314c4b14c3SIngo Weinhold if (token[0] == '#') { 10324c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 10334c4b14c3SIngo Weinhold PatternTraceFilter; 10344c4b14c3SIngo Weinhold filter->fString = token + 1; 10354c4b14c3SIngo Weinhold return filter; 1036dc1a7867SAxel Dörfler } else if (token[0] == 'd' && token[1] == '#') { 1037dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++]) 1038dc1a7867SAxel Dörfler DecimalPatternTraceFilter; 1039dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2); 1040dc1a7867SAxel Dörfler return filter; 1041dc1a7867SAxel Dörfler } else if (token[0] == 'x' && token[1] == '#') { 1042dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++]) 1043dc1a7867SAxel Dörfler HexPatternTraceFilter; 1044dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2); 1045dc1a7867SAxel Dörfler return filter; 1046dc1a7867SAxel Dörfler } else if (token[0] == 's' && token[1] == '#') { 1047dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++]) 1048dc1a7867SAxel Dörfler StringPatternTraceFilter; 1049dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2); 1050dc1a7867SAxel Dörfler return filter; 10514c4b14c3SIngo Weinhold } else if (strcmp(token, "not") == 0) { 10524c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) NotTraceFilter; 10534c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL) 10544c4b14c3SIngo Weinhold return filter; 10554c4b14c3SIngo Weinhold return NULL; 10564c4b14c3SIngo Weinhold } else if (strcmp(token, "and") == 0) { 10574c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) AndTraceFilter; 10584c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL 10594c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) { 10604c4b14c3SIngo Weinhold return filter; 10614c4b14c3SIngo Weinhold } 10624c4b14c3SIngo Weinhold return NULL; 10634c4b14c3SIngo Weinhold } else if (strcmp(token, "or") == 0) { 10644c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) OrTraceFilter; 10654c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL 10664c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) { 10674c4b14c3SIngo Weinhold return filter; 10684c4b14c3SIngo Weinhold } 10694c4b14c3SIngo Weinhold return NULL; 10704c4b14c3SIngo Weinhold } else if (strcmp(token, "thread") == 0) { 10714c4b14c3SIngo Weinhold const char* arg = _NextToken(); 10724c4b14c3SIngo Weinhold if (arg == NULL) { 10734c4b14c3SIngo Weinhold // unexpected end of expression 10744c4b14c3SIngo Weinhold return NULL; 10754c4b14c3SIngo Weinhold } 10764c4b14c3SIngo Weinhold 10774c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 10784c4b14c3SIngo Weinhold ThreadTraceFilter; 10794c4b14c3SIngo Weinhold filter->fThread = strtol(arg, NULL, 0); 10804c4b14c3SIngo Weinhold return filter; 108164fe37eeSIngo Weinhold } else if (strcmp(token, "team") == 0) { 108264fe37eeSIngo Weinhold const char* arg = _NextToken(); 108364fe37eeSIngo Weinhold if (arg == NULL) { 108464fe37eeSIngo Weinhold // unexpected end of expression 108564fe37eeSIngo Weinhold return NULL; 108664fe37eeSIngo Weinhold } 108764fe37eeSIngo Weinhold 108864fe37eeSIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) 108964fe37eeSIngo Weinhold TeamTraceFilter; 109064fe37eeSIngo Weinhold filter->fTeam = strtol(arg, NULL, 0); 109164fe37eeSIngo Weinhold return filter; 10924c4b14c3SIngo Weinhold } else { 10934c4b14c3SIngo Weinhold // invalid token 10944c4b14c3SIngo Weinhold return NULL; 10954c4b14c3SIngo Weinhold } 10964c4b14c3SIngo Weinhold } 10974c4b14c3SIngo Weinhold 10984c4b14c3SIngo Weinhold const char* _CurrentToken() const 10994c4b14c3SIngo Weinhold { 11004c4b14c3SIngo Weinhold if (fTokenIndex >= 1 && fTokenIndex <= fTokenCount) 11014c4b14c3SIngo Weinhold return fTokens[fTokenIndex - 1]; 11024c4b14c3SIngo Weinhold return NULL; 11034c4b14c3SIngo Weinhold } 11044c4b14c3SIngo Weinhold 11054c4b14c3SIngo Weinhold const char* _NextToken() 11064c4b14c3SIngo Weinhold { 11074c4b14c3SIngo Weinhold if (fTokenIndex >= fTokenCount) 11084c4b14c3SIngo Weinhold return NULL; 11094c4b14c3SIngo Weinhold return fTokens[fTokenIndex++]; 11104c4b14c3SIngo Weinhold } 11114c4b14c3SIngo Weinhold 11124c4b14c3SIngo Weinhold private: 11134c4b14c3SIngo Weinhold enum { MAX_FILTERS = 32 }; 11144c4b14c3SIngo Weinhold 11154c4b14c3SIngo Weinhold const char* const* fTokens; 11164c4b14c3SIngo Weinhold int fTokenCount; 11174c4b14c3SIngo Weinhold int fTokenIndex; 11184c4b14c3SIngo Weinhold TraceFilter fFilters[MAX_FILTERS]; 11194c4b14c3SIngo Weinhold int fFilterCount; 11204c4b14c3SIngo Weinhold 11214c4b14c3SIngo Weinhold static TraceFilterParser sParser; 11224c4b14c3SIngo Weinhold }; 11234c4b14c3SIngo Weinhold 11244c4b14c3SIngo Weinhold 11254c4b14c3SIngo Weinhold TraceFilterParser TraceFilterParser::sParser; 11264c4b14c3SIngo Weinhold 11274c4b14c3SIngo Weinhold 1128f1047a1cSIngo Weinhold // #pragma mark - 1129f1047a1cSIngo Weinhold 1130f1047a1cSIngo Weinhold 1131aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 1132aa5d2a2dSAxel Dörfler 1133aa5d2a2dSAxel Dörfler 1134ef7102faSIngo Weinhold TraceEntry* 1135ef7102faSIngo Weinhold TraceEntryIterator::Next() 11366d369966SIngo Weinhold { 11376d369966SIngo Weinhold if (fIndex == 0) { 11383fccf067SIngo Weinhold fEntry = _NextNonBufferEntry(sTracingMetaData->FirstEntry()); 11396d369966SIngo Weinhold fIndex = 1; 11406d369966SIngo Weinhold } else if (fEntry != NULL) { 11413fccf067SIngo Weinhold fEntry = _NextNonBufferEntry(sTracingMetaData->NextEntry(fEntry)); 11426d369966SIngo Weinhold fIndex++; 11436d369966SIngo Weinhold } 11446d369966SIngo Weinhold 11456d369966SIngo Weinhold return Current(); 11466d369966SIngo Weinhold } 11476d369966SIngo Weinhold 1148ef7102faSIngo Weinhold 1149ef7102faSIngo Weinhold TraceEntry* 1150ef7102faSIngo Weinhold TraceEntryIterator::Previous() 11516d369966SIngo Weinhold { 11523fccf067SIngo Weinhold if (fIndex == (int32)sTracingMetaData->Entries() + 1) 11533fccf067SIngo Weinhold fEntry = sTracingMetaData->AfterLastEntry(); 11546d369966SIngo Weinhold 11556d369966SIngo Weinhold if (fEntry != NULL) { 11563fccf067SIngo Weinhold fEntry = _PreviousNonBufferEntry( 11573fccf067SIngo Weinhold sTracingMetaData->PreviousEntry(fEntry)); 11586d369966SIngo Weinhold fIndex--; 11596d369966SIngo Weinhold } 11606d369966SIngo Weinhold 11616d369966SIngo Weinhold return Current(); 11626d369966SIngo Weinhold } 11636d369966SIngo Weinhold 1164ef7102faSIngo Weinhold 1165ef7102faSIngo Weinhold TraceEntry* 1166ef7102faSIngo Weinhold TraceEntryIterator::MoveTo(int32 index) 11676d369966SIngo Weinhold { 11686d369966SIngo Weinhold if (index == fIndex) 11696d369966SIngo Weinhold return Current(); 11706d369966SIngo Weinhold 11713fccf067SIngo Weinhold if (index <= 0 || index > (int32)sTracingMetaData->Entries()) { 11723fccf067SIngo Weinhold fIndex = (index <= 0 ? 0 : sTracingMetaData->Entries() + 1); 11736d369966SIngo Weinhold fEntry = NULL; 11746d369966SIngo Weinhold return NULL; 11756d369966SIngo Weinhold } 11766d369966SIngo Weinhold 11776d369966SIngo Weinhold // get the shortest iteration path 11786d369966SIngo Weinhold int32 distance = index - fIndex; 11796d369966SIngo Weinhold int32 direction = distance < 0 ? -1 : 1; 11806d369966SIngo Weinhold distance *= direction; 11816d369966SIngo Weinhold 11826d369966SIngo Weinhold if (index < distance) { 11836d369966SIngo Weinhold distance = index; 11846d369966SIngo Weinhold direction = 1; 11856d369966SIngo Weinhold fEntry = NULL; 11866d369966SIngo Weinhold fIndex = 0; 11876d369966SIngo Weinhold } 11883fccf067SIngo Weinhold if ((int32)sTracingMetaData->Entries() + 1 - fIndex < distance) { 11893fccf067SIngo Weinhold distance = sTracingMetaData->Entries() + 1 - fIndex; 11906d369966SIngo Weinhold direction = -1; 11916d369966SIngo Weinhold fEntry = NULL; 11923fccf067SIngo Weinhold fIndex = sTracingMetaData->Entries() + 1; 11936d369966SIngo Weinhold } 11946d369966SIngo Weinhold 11956d369966SIngo Weinhold // iterate to the index 11966d369966SIngo Weinhold if (direction < 0) { 11976d369966SIngo Weinhold while (fIndex != index) 11986d369966SIngo Weinhold Previous(); 11996d369966SIngo Weinhold } else { 12006d369966SIngo Weinhold while (fIndex != index) 12016d369966SIngo Weinhold Next(); 12026d369966SIngo Weinhold } 12036d369966SIngo Weinhold 12046d369966SIngo Weinhold return Current(); 12056d369966SIngo Weinhold } 12066d369966SIngo Weinhold 1207ef7102faSIngo Weinhold 1208ef7102faSIngo Weinhold trace_entry* 1209ef7102faSIngo Weinhold TraceEntryIterator::_NextNonBufferEntry(trace_entry* entry) 12106d369966SIngo Weinhold { 12116d369966SIngo Weinhold while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0) 12123fccf067SIngo Weinhold entry = sTracingMetaData->NextEntry(entry); 12136d369966SIngo Weinhold 12146d369966SIngo Weinhold return entry; 12156d369966SIngo Weinhold } 12166d369966SIngo Weinhold 1217ef7102faSIngo Weinhold 1218ef7102faSIngo Weinhold trace_entry* 1219ef7102faSIngo Weinhold TraceEntryIterator::_PreviousNonBufferEntry(trace_entry* entry) 12206d369966SIngo Weinhold { 12216d369966SIngo Weinhold while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0) 12223fccf067SIngo Weinhold entry = sTracingMetaData->PreviousEntry(entry); 12236d369966SIngo Weinhold 12246d369966SIngo Weinhold return entry; 12256d369966SIngo Weinhold } 12266d369966SIngo Weinhold 12276d369966SIngo Weinhold 1228aa5d2a2dSAxel Dörfler int 1229f97199edSIngo Weinhold dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter) 1230aa5d2a2dSAxel Dörfler { 12314c4b14c3SIngo Weinhold int argi = 1; 12328e43ece8SAxel Dörfler 12336d369966SIngo Weinhold // variables in which we store our state to be continuable 12346d369966SIngo Weinhold static int32 _previousCount = 0; 12356d369966SIngo Weinhold static bool _previousHasFilter = false; 123665f40152SIngo Weinhold static bool _previousPrintStackTrace = false; 12376d369966SIngo Weinhold static int32 _previousMaxToCheck = 0; 12386d369966SIngo Weinhold static int32 _previousFirstChecked = 1; 12396d369966SIngo Weinhold static int32 _previousLastChecked = -1; 12405fa74667SIngo Weinhold static int32 _previousDirection = 1; 12413fccf067SIngo Weinhold static uint32 _previousEntriesEver = 0; 124256213ff4SIngo Weinhold static uint32 _previousEntries = 0; 1243350b6dbcSIngo Weinhold static uint32 _previousOutputFlags = 0; 124456213ff4SIngo Weinhold static TraceEntryIterator iterator; 124556213ff4SIngo Weinhold 12463fccf067SIngo Weinhold uint32 entriesEver = sTracingMetaData->EntriesEver(); 12473fccf067SIngo Weinhold 1248d829579dSIngo Weinhold // Note: start and index are Pascal-like indices (i.e. in [1, Entries()]). 124974652349SIngo Weinhold int32 start = 0; // special index: print the last count entries 12506d369966SIngo Weinhold int32 count = 0; 12516d369966SIngo Weinhold int32 maxToCheck = 0; 125274652349SIngo Weinhold int32 cont = 0; 1253aa5d2a2dSAxel Dörfler 12544c4b14c3SIngo Weinhold bool hasFilter = false; 125565f40152SIngo Weinhold bool printStackTrace = false; 12564c4b14c3SIngo Weinhold 1257350b6dbcSIngo Weinhold uint32 outputFlags = 0; 1258350b6dbcSIngo Weinhold while (argi < argc) { 125965f40152SIngo Weinhold if (strcmp(argv[argi], "--difftime") == 0) { 126065f40152SIngo Weinhold outputFlags |= TRACE_OUTPUT_DIFF_TIME; 126165f40152SIngo Weinhold argi++; 126265f40152SIngo Weinhold } else if (strcmp(argv[argi], "--printteam") == 0) { 1263350b6dbcSIngo Weinhold outputFlags |= TRACE_OUTPUT_TEAM_ID; 126464fe37eeSIngo Weinhold argi++; 126565f40152SIngo Weinhold } else if (strcmp(argv[argi], "--stacktrace") == 0) { 126665f40152SIngo Weinhold printStackTrace = true; 1267350b6dbcSIngo Weinhold argi++; 1268350b6dbcSIngo Weinhold } else 1269350b6dbcSIngo Weinhold break; 127064fe37eeSIngo Weinhold } 127164fe37eeSIngo Weinhold 12724c4b14c3SIngo Weinhold if (argi < argc) { 12734c4b14c3SIngo Weinhold if (strcmp(argv[argi], "forward") == 0) { 127474652349SIngo Weinhold cont = 1; 12754c4b14c3SIngo Weinhold argi++; 12764c4b14c3SIngo Weinhold } else if (strcmp(argv[argi], "backward") == 0) { 127774652349SIngo Weinhold cont = -1; 12784c4b14c3SIngo Weinhold argi++; 12794c4b14c3SIngo Weinhold } 12805fa74667SIngo Weinhold } else 12815fa74667SIngo Weinhold cont = _previousDirection; 12822d81f045SAxel Dörfler 12836d369966SIngo Weinhold if (cont != 0) { 12846d369966SIngo Weinhold if (argi < argc) { 1285a7e979caSIngo Weinhold print_debugger_command_usage(argv[0]); 1286aa5d2a2dSAxel Dörfler return 0; 1287aa5d2a2dSAxel Dörfler } 12883fccf067SIngo Weinhold if (entriesEver == 0 || entriesEver != _previousEntriesEver 12893fccf067SIngo Weinhold || sTracingMetaData->Entries() != _previousEntries) { 12906d369966SIngo Weinhold kprintf("Can't continue iteration. \"%s\" has not been invoked " 12916d369966SIngo Weinhold "before, or there were new entries written since the last " 12926d369966SIngo Weinhold "invocation.\n", argv[0]); 12936d369966SIngo Weinhold return 0; 12946d369966SIngo Weinhold } 12956d369966SIngo Weinhold } 1296aa5d2a2dSAxel Dörfler 12976d369966SIngo Weinhold // get start, count, maxToCheck 12986d369966SIngo Weinhold int32* params[3] = { &start, &count, &maxToCheck }; 12996d369966SIngo Weinhold for (int i = 0; i < 3 && !hasFilter && argi < argc; i++) { 13004c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) { 13014c4b14c3SIngo Weinhold hasFilter = true; 13024c4b14c3SIngo Weinhold argi++; 13034c4b14c3SIngo Weinhold } else if (argv[argi][0] == '#') { 13044c4b14c3SIngo Weinhold hasFilter = true; 13054c4b14c3SIngo Weinhold } else { 13066d369966SIngo Weinhold *params[i] = parse_expression(argv[argi]); 13074c4b14c3SIngo Weinhold argi++; 13084c4b14c3SIngo Weinhold } 13094c4b14c3SIngo Weinhold } 13104c4b14c3SIngo Weinhold 13114c4b14c3SIngo Weinhold // filter specification 13124c4b14c3SIngo Weinhold if (argi < argc) { 13134c4b14c3SIngo Weinhold hasFilter = true; 13144c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) 13154c4b14c3SIngo Weinhold argi++; 13164c4b14c3SIngo Weinhold 13174c4b14c3SIngo Weinhold if (!TraceFilterParser::Default()->Parse(argc - argi, argv + argi)) { 13184c4b14c3SIngo Weinhold print_debugger_command_usage(argv[0]); 13194c4b14c3SIngo Weinhold return 0; 13204c4b14c3SIngo Weinhold } 13214c4b14c3SIngo Weinhold } 13224c4b14c3SIngo Weinhold 13236d369966SIngo Weinhold int32 direction; 13246d369966SIngo Weinhold int32 firstToCheck; 13256d369966SIngo Weinhold int32 lastToCheck; 13266d369966SIngo Weinhold 132774652349SIngo Weinhold if (cont != 0) { 13286d369966SIngo Weinhold // get values from the previous iteration 13296d369966SIngo Weinhold direction = cont; 13306d369966SIngo Weinhold count = _previousCount; 13316d369966SIngo Weinhold maxToCheck = _previousMaxToCheck; 13326d369966SIngo Weinhold hasFilter = _previousHasFilter; 1333350b6dbcSIngo Weinhold outputFlags = _previousOutputFlags; 133465f40152SIngo Weinhold printStackTrace = _previousPrintStackTrace; 13356d369966SIngo Weinhold 13366d369966SIngo Weinhold if (direction < 0) 13376d369966SIngo Weinhold start = _previousFirstChecked - 1; 13386d369966SIngo Weinhold else 13396d369966SIngo Weinhold start = _previousLastChecked + 1; 13406d369966SIngo Weinhold } else { 13416d369966SIngo Weinhold // defaults for count and maxToCheck 13426d369966SIngo Weinhold if (count == 0) 13436d369966SIngo Weinhold count = 30; 13446d369966SIngo Weinhold if (maxToCheck == 0 || !hasFilter) 13456d369966SIngo Weinhold maxToCheck = count; 13466d369966SIngo Weinhold else if (maxToCheck < 0) 13473fccf067SIngo Weinhold maxToCheck = sTracingMetaData->Entries(); 13486d369966SIngo Weinhold 13496d369966SIngo Weinhold // determine iteration direction 13506d369966SIngo Weinhold direction = (start <= 0 || count < 0 ? -1 : 1); 13516d369966SIngo Weinhold 13526d369966SIngo Weinhold // validate count and maxToCheck 13536d369966SIngo Weinhold if (count < 0) 13546d369966SIngo Weinhold count = -count; 13556d369966SIngo Weinhold if (maxToCheck < 0) 13566d369966SIngo Weinhold maxToCheck = -maxToCheck; 13573fccf067SIngo Weinhold if (maxToCheck > (int32)sTracingMetaData->Entries()) 13583fccf067SIngo Weinhold maxToCheck = sTracingMetaData->Entries(); 13596d369966SIngo Weinhold if (count > maxToCheck) 13606d369966SIngo Weinhold count = maxToCheck; 13616d369966SIngo Weinhold 13626d369966SIngo Weinhold // validate start 13633fccf067SIngo Weinhold if (start <= 0 || start > (int32)sTracingMetaData->Entries()) 13643fccf067SIngo Weinhold start = max_c(1, sTracingMetaData->Entries()); 136574652349SIngo Weinhold } 1366aa5d2a2dSAxel Dörfler 13676d369966SIngo Weinhold if (direction < 0) { 13686d369966SIngo Weinhold firstToCheck = max_c(1, start - maxToCheck + 1); 13696d369966SIngo Weinhold lastToCheck = start; 13706d369966SIngo Weinhold } else { 13716d369966SIngo Weinhold firstToCheck = start; 13723fccf067SIngo Weinhold lastToCheck = min_c((int32)sTracingMetaData->Entries(), 13733fccf067SIngo Weinhold start + maxToCheck - 1); 13748e43ece8SAxel Dörfler } 1375aa5d2a2dSAxel Dörfler 137656213ff4SIngo Weinhold // reset the iterator, if something changed in the meantime 13773fccf067SIngo Weinhold if (entriesEver == 0 || entriesEver != _previousEntriesEver 13783fccf067SIngo Weinhold || sTracingMetaData->Entries() != _previousEntries) { 137956213ff4SIngo Weinhold iterator.Reset(); 138056213ff4SIngo Weinhold } 13816d369966SIngo Weinhold 13823fccf067SIngo Weinhold LazyTraceOutput out(sTracingMetaData->TraceOutputBuffer(), 1383d829579dSIngo Weinhold kTraceOutputBufferSize, outputFlags); 1384f7a5d9c5SIngo Weinhold 138556213ff4SIngo Weinhold bool markedMatching = false; 138656213ff4SIngo Weinhold int32 firstToDump = firstToCheck; 138756213ff4SIngo Weinhold int32 lastToDump = lastToCheck; 138856213ff4SIngo Weinhold 1389f97199edSIngo Weinhold TraceFilter* filter = NULL; 1390f97199edSIngo Weinhold if (hasFilter) 1391f97199edSIngo Weinhold filter = TraceFilterParser::Default()->Filter(); 1392f97199edSIngo Weinhold 1393f97199edSIngo Weinhold if (wrapperFilter != NULL) { 1394f97199edSIngo Weinhold wrapperFilter->Init(filter, direction, cont != 0); 1395f97199edSIngo Weinhold filter = wrapperFilter; 1396f97199edSIngo Weinhold } 1397f97199edSIngo Weinhold 1398f97199edSIngo Weinhold if (direction < 0 && filter && lastToCheck - firstToCheck >= count) { 13996d369966SIngo Weinhold // iteration direction is backwards 140056213ff4SIngo Weinhold markedMatching = true; 14016d369966SIngo Weinhold 14026d369966SIngo Weinhold // From the last entry to check iterate backwards to check filter 14036d369966SIngo Weinhold // matches. 14046d369966SIngo Weinhold int32 matching = 0; 14056d369966SIngo Weinhold 14066d369966SIngo Weinhold // move to the entry after the last entry to check 14076d369966SIngo Weinhold iterator.MoveTo(lastToCheck + 1); 14086d369966SIngo Weinhold 14096d369966SIngo Weinhold // iterate backwards 141056213ff4SIngo Weinhold firstToDump = -1; 141156213ff4SIngo Weinhold lastToDump = -1; 14126d369966SIngo Weinhold while (iterator.Index() > firstToCheck) { 14136d369966SIngo Weinhold TraceEntry* entry = iterator.Previous(); 1414b3d6c12dSIngo Weinhold if ((entry->Flags() & ENTRY_INITIALIZED) != 0) { 14156d369966SIngo Weinhold out.Clear(); 1416f97199edSIngo Weinhold if (filter->Filter(entry, out)) { 1417b3d6c12dSIngo Weinhold entry->ToTraceEntry()->flags |= FILTER_MATCH; 141856213ff4SIngo Weinhold if (lastToDump == -1) 141956213ff4SIngo Weinhold lastToDump = iterator.Index(); 142056213ff4SIngo Weinhold firstToDump = iterator.Index(); 142156213ff4SIngo Weinhold 14226d369966SIngo Weinhold matching++; 14236d369966SIngo Weinhold if (matching >= count) 14246d369966SIngo Weinhold break; 142556213ff4SIngo Weinhold } else 1426b3d6c12dSIngo Weinhold entry->ToTraceEntry()->flags &= ~FILTER_MATCH; 14276d369966SIngo Weinhold } 14286d369966SIngo Weinhold } 14296d369966SIngo Weinhold 14306d369966SIngo Weinhold firstToCheck = iterator.Index(); 14316d369966SIngo Weinhold 14326d369966SIngo Weinhold // iterate to the previous entry, so that the next loop starts at the 14336d369966SIngo Weinhold // right one 14346d369966SIngo Weinhold iterator.Previous(); 14356d369966SIngo Weinhold } 14366d369966SIngo Weinhold 1437350b6dbcSIngo Weinhold out.SetLastEntryTime(0); 1438350b6dbcSIngo Weinhold 143956213ff4SIngo Weinhold // set the iterator to the entry before the first one to dump 144056213ff4SIngo Weinhold iterator.MoveTo(firstToDump - 1); 144156213ff4SIngo Weinhold 144256213ff4SIngo Weinhold // dump the entries matching the filter in the range 144356213ff4SIngo Weinhold // [firstToDump, lastToDump] 14446d369966SIngo Weinhold int32 dumped = 0; 14456d369966SIngo Weinhold 14466d369966SIngo Weinhold while (TraceEntry* entry = iterator.Next()) { 14476d369966SIngo Weinhold int32 index = iterator.Index(); 144856213ff4SIngo Weinhold if (index < firstToDump) 14496d369966SIngo Weinhold continue; 145056213ff4SIngo Weinhold if (index > lastToDump || dumped >= count) { 14516d369966SIngo Weinhold if (direction > 0) 14526d369966SIngo Weinhold lastToCheck = index - 1; 14536d369966SIngo Weinhold break; 14546d369966SIngo Weinhold } 14556d369966SIngo Weinhold 1456b3d6c12dSIngo Weinhold if ((entry->Flags() & ENTRY_INITIALIZED) != 0) { 14576d369966SIngo Weinhold out.Clear(); 1458f97199edSIngo Weinhold if (filter && (markedMatching 1459b3d6c12dSIngo Weinhold ? (entry->Flags() & FILTER_MATCH) == 0 1460f97199edSIngo Weinhold : !filter->Filter(entry, out))) { 14618e43ece8SAxel Dörfler continue; 146256213ff4SIngo Weinhold } 14638e43ece8SAxel Dörfler 14640c45a120SIngo Weinhold // don't print trailing new line 14650c45a120SIngo Weinhold const char* dump = out.DumpEntry(entry); 14660c45a120SIngo Weinhold int len = strlen(dump); 14670c45a120SIngo Weinhold if (len > 0 && dump[len - 1] == '\n') 14680c45a120SIngo Weinhold len--; 14690c45a120SIngo Weinhold 14700c45a120SIngo Weinhold kprintf("%5ld. %.*s\n", index, len, dump); 147165f40152SIngo Weinhold 147265f40152SIngo Weinhold if (printStackTrace) { 147365f40152SIngo Weinhold out.Clear(); 147465f40152SIngo Weinhold entry->DumpStackTrace(out); 147565f40152SIngo Weinhold if (out.Size() > 0) 147665f40152SIngo Weinhold kputs(out.Buffer()); 147765f40152SIngo Weinhold } 1478f97199edSIngo Weinhold } else if (!filter) 14798e43ece8SAxel Dörfler kprintf("%5ld. ** uninitialized entry **\n", index); 148074652349SIngo Weinhold 148174652349SIngo Weinhold dumped++; 1482aa5d2a2dSAxel Dörfler } 1483aa5d2a2dSAxel Dörfler 14846d369966SIngo Weinhold kprintf("printed %ld entries within range %ld to %ld (%ld of %ld total, " 14856d369966SIngo Weinhold "%ld ever)\n", dumped, firstToCheck, lastToCheck, 14863fccf067SIngo Weinhold lastToCheck - firstToCheck + 1, sTracingMetaData->Entries(), 14873fccf067SIngo Weinhold entriesEver); 148874652349SIngo Weinhold 14896d369966SIngo Weinhold // store iteration state 14906d369966SIngo Weinhold _previousCount = count; 14916d369966SIngo Weinhold _previousMaxToCheck = maxToCheck; 14926d369966SIngo Weinhold _previousHasFilter = hasFilter; 149365f40152SIngo Weinhold _previousPrintStackTrace = printStackTrace; 14946d369966SIngo Weinhold _previousFirstChecked = firstToCheck; 14956d369966SIngo Weinhold _previousLastChecked = lastToCheck; 14965fa74667SIngo Weinhold _previousDirection = direction; 14973fccf067SIngo Weinhold _previousEntriesEver = entriesEver; 14983fccf067SIngo Weinhold _previousEntries = sTracingMetaData->Entries(); 1499350b6dbcSIngo Weinhold _previousOutputFlags = outputFlags; 150074652349SIngo Weinhold 150174652349SIngo Weinhold return cont != 0 ? B_KDEBUG_CONT : 0; 1502aa5d2a2dSAxel Dörfler } 1503aa5d2a2dSAxel Dörfler 1504aa5d2a2dSAxel Dörfler 1505f97199edSIngo Weinhold static int 1506f97199edSIngo Weinhold dump_tracing_command(int argc, char** argv) 1507f97199edSIngo Weinhold { 1508f97199edSIngo Weinhold return dump_tracing_internal(argc, argv, NULL); 1509f97199edSIngo Weinhold } 1510f97199edSIngo Weinhold 1511f97199edSIngo Weinhold 1512aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING 1513aa5d2a2dSAxel Dörfler 15142d81f045SAxel Dörfler 15158e43ece8SAxel Dörfler extern "C" uint8* 15168e43ece8SAxel Dörfler alloc_tracing_buffer(size_t size) 15178e43ece8SAxel Dörfler { 15188e43ece8SAxel Dörfler #if ENABLE_TRACING 15193fccf067SIngo Weinhold trace_entry* entry = sTracingMetaData->AllocateEntry( 15203fccf067SIngo Weinhold size + sizeof(trace_entry), BUFFER_ENTRY); 15218e43ece8SAxel Dörfler if (entry == NULL) 15228e43ece8SAxel Dörfler return NULL; 15238e43ece8SAxel Dörfler 15248e43ece8SAxel Dörfler return (uint8*)(entry + 1); 15258e43ece8SAxel Dörfler #else 15268e43ece8SAxel Dörfler return NULL; 15278e43ece8SAxel Dörfler #endif 15288e43ece8SAxel Dörfler } 15298e43ece8SAxel Dörfler 1530aa5d2a2dSAxel Dörfler 15310b60583fSIngo Weinhold uint8* 15320b60583fSIngo Weinhold alloc_tracing_buffer_memcpy(const void* source, size_t size, bool user) 15330b60583fSIngo Weinhold { 15348bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source)) 15358bd6d45dSIngo Weinhold return NULL; 15368bd6d45dSIngo Weinhold 15370b60583fSIngo Weinhold uint8* buffer = alloc_tracing_buffer(size); 15380b60583fSIngo Weinhold if (buffer == NULL) 15390b60583fSIngo Weinhold return NULL; 15400b60583fSIngo Weinhold 15410b60583fSIngo Weinhold if (user) { 15420b60583fSIngo Weinhold if (user_memcpy(buffer, source, size) != B_OK) 15430b60583fSIngo Weinhold return NULL; 15440b60583fSIngo Weinhold } else 15450b60583fSIngo Weinhold memcpy(buffer, source, size); 15460b60583fSIngo Weinhold 15470b60583fSIngo Weinhold return buffer; 15480b60583fSIngo Weinhold } 15490b60583fSIngo Weinhold 15500b60583fSIngo Weinhold 15510b60583fSIngo Weinhold char* 15520b60583fSIngo Weinhold alloc_tracing_buffer_strcpy(const char* source, size_t maxSize, bool user) 15530b60583fSIngo Weinhold { 15548bd6d45dSIngo Weinhold if (source == NULL || maxSize == 0) 15550b60583fSIngo Weinhold return NULL; 15560b60583fSIngo Weinhold 15578bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source)) 15588bd6d45dSIngo Weinhold return NULL; 15598bd6d45dSIngo Weinhold 15608bd6d45dSIngo Weinhold // limit maxSize to the actual source string len 15618bd6d45dSIngo Weinhold if (user) { 15628bd6d45dSIngo Weinhold ssize_t size = user_strlcpy(NULL, source, 0); 15638bd6d45dSIngo Weinhold // there's no user_strnlen() 15648bd6d45dSIngo Weinhold if (size < 0) 15658bd6d45dSIngo Weinhold return 0; 15668bd6d45dSIngo Weinhold maxSize = min_c(maxSize, (size_t)size + 1); 15678bd6d45dSIngo Weinhold } else 15680b60583fSIngo Weinhold maxSize = strnlen(source, maxSize - 1) + 1; 15690b60583fSIngo Weinhold 15700b60583fSIngo Weinhold char* buffer = (char*)alloc_tracing_buffer(maxSize); 15710b60583fSIngo Weinhold if (buffer == NULL) 15720b60583fSIngo Weinhold return NULL; 15730b60583fSIngo Weinhold 15740b60583fSIngo Weinhold if (user) { 15750b60583fSIngo Weinhold if (user_strlcpy(buffer, source, maxSize) < B_OK) 15760b60583fSIngo Weinhold return NULL; 15770b60583fSIngo Weinhold } else 15780b60583fSIngo Weinhold strlcpy(buffer, source, maxSize); 15790b60583fSIngo Weinhold 15800b60583fSIngo Weinhold return buffer; 15810b60583fSIngo Weinhold } 15820b60583fSIngo Weinhold 15830b60583fSIngo Weinhold 158465f40152SIngo Weinhold tracing_stack_trace* 1585a38f8503SIngo Weinhold capture_tracing_stack_trace(int32 maxCount, int32 skipFrames, bool kernelOnly) 158665f40152SIngo Weinhold { 158765f40152SIngo Weinhold #if ENABLE_TRACING 15884502d80dSIngo Weinhold // page_fault_exception() doesn't allow us to gracefully handle a bad 15894502d80dSIngo Weinhold // address in the stack trace, if interrupts are disabled, so we always 15904502d80dSIngo Weinhold // restrict the stack traces to the kernel only in this case. A bad address 15914502d80dSIngo Weinhold // in the kernel stack trace would still cause a panic(), but this is 15924502d80dSIngo Weinhold // probably even desired. 159365f40152SIngo Weinhold if (!are_interrupts_enabled()) 15944502d80dSIngo Weinhold kernelOnly = true; 159565f40152SIngo Weinhold 159665f40152SIngo Weinhold tracing_stack_trace* stackTrace 159765f40152SIngo Weinhold = (tracing_stack_trace*)alloc_tracing_buffer( 159865f40152SIngo Weinhold sizeof(tracing_stack_trace) + maxCount * sizeof(addr_t)); 159965f40152SIngo Weinhold 160065f40152SIngo Weinhold if (stackTrace != NULL) { 160165f40152SIngo Weinhold stackTrace->depth = arch_debug_get_stack_trace( 1602e670fc6fSIngo Weinhold stackTrace->return_addresses, maxCount, 0, skipFrames + 1, 16034502d80dSIngo Weinhold STACK_TRACE_KERNEL | (kernelOnly ? 0 : STACK_TRACE_USER)); 160465f40152SIngo Weinhold } 160565f40152SIngo Weinhold 160665f40152SIngo Weinhold return stackTrace; 160765f40152SIngo Weinhold #else 160865f40152SIngo Weinhold return NULL; 160965f40152SIngo Weinhold #endif 161065f40152SIngo Weinhold } 161165f40152SIngo Weinhold 161265f40152SIngo Weinhold 1613*69d7ad7dSIngo Weinhold addr_t 1614*69d7ad7dSIngo Weinhold tracing_find_caller_in_stack_trace(struct tracing_stack_trace* stackTrace, 1615*69d7ad7dSIngo Weinhold const addr_t excludeRanges[], uint32 excludeRangeCount) 1616*69d7ad7dSIngo Weinhold { 1617*69d7ad7dSIngo Weinhold for (int32 i = 0; i < stackTrace->depth; i++) { 1618*69d7ad7dSIngo Weinhold addr_t returnAddress = stackTrace->return_addresses[i]; 1619*69d7ad7dSIngo Weinhold 1620*69d7ad7dSIngo Weinhold bool inRange = false; 1621*69d7ad7dSIngo Weinhold for (uint32 j = 0; j < excludeRangeCount; j++) { 1622*69d7ad7dSIngo Weinhold if (returnAddress >= excludeRanges[j * 2 + 0] 1623*69d7ad7dSIngo Weinhold && returnAddress < excludeRanges[j * 2 + 1]) { 1624*69d7ad7dSIngo Weinhold inRange = true; 1625*69d7ad7dSIngo Weinhold break; 1626*69d7ad7dSIngo Weinhold } 1627*69d7ad7dSIngo Weinhold } 1628*69d7ad7dSIngo Weinhold 1629*69d7ad7dSIngo Weinhold if (!inRange) 1630*69d7ad7dSIngo Weinhold return returnAddress; 1631*69d7ad7dSIngo Weinhold } 1632*69d7ad7dSIngo Weinhold 1633*69d7ad7dSIngo Weinhold return 0; 1634*69d7ad7dSIngo Weinhold } 1635*69d7ad7dSIngo Weinhold 1636*69d7ad7dSIngo Weinhold 1637f97199edSIngo Weinhold int 1638f97199edSIngo Weinhold dump_tracing(int argc, char** argv, WrapperTraceFilter* wrapperFilter) 1639f97199edSIngo Weinhold { 1640f97199edSIngo Weinhold #if ENABLE_TRACING 1641f97199edSIngo Weinhold return dump_tracing_internal(argc, argv, wrapperFilter); 1642f97199edSIngo Weinhold #else 1643f97199edSIngo Weinhold return 0; 1644f97199edSIngo Weinhold #endif 1645f97199edSIngo Weinhold } 1646f97199edSIngo Weinhold 1647f97199edSIngo Weinhold 1648*69d7ad7dSIngo Weinhold bool 1649*69d7ad7dSIngo Weinhold tracing_is_entry_valid(TraceEntry* candidate, bigtime_t entryTime) 1650*69d7ad7dSIngo Weinhold { 1651*69d7ad7dSIngo Weinhold #if ENABLE_TRACING 1652*69d7ad7dSIngo Weinhold TraceEntryIterator iterator; 1653*69d7ad7dSIngo Weinhold while (TraceEntry* entry = iterator.Next()) { 1654*69d7ad7dSIngo Weinhold AbstractTraceEntry* abstract = dynamic_cast<AbstractTraceEntry*>(entry); 1655*69d7ad7dSIngo Weinhold if (abstract == NULL) 1656*69d7ad7dSIngo Weinhold continue; 1657*69d7ad7dSIngo Weinhold 1658*69d7ad7dSIngo Weinhold // TODO: This could be better by additionally checking if the 1659*69d7ad7dSIngo Weinhold // candidate entry address falls within the valid entry range. 1660*69d7ad7dSIngo Weinhold return abstract == candidate || abstract->Time() < entryTime; 1661*69d7ad7dSIngo Weinhold } 1662*69d7ad7dSIngo Weinhold #endif 1663*69d7ad7dSIngo Weinhold 1664*69d7ad7dSIngo Weinhold return false; 1665*69d7ad7dSIngo Weinhold } 1666*69d7ad7dSIngo Weinhold 1667*69d7ad7dSIngo Weinhold 1668aa1a64f3SIngo Weinhold void 1669aa1a64f3SIngo Weinhold lock_tracing_buffer() 1670aa1a64f3SIngo Weinhold { 1671aa1a64f3SIngo Weinhold #if ENABLE_TRACING 16723fccf067SIngo Weinhold sTracingMetaData->Lock(); 1673aa1a64f3SIngo Weinhold #endif 1674aa1a64f3SIngo Weinhold } 1675aa1a64f3SIngo Weinhold 1676aa1a64f3SIngo Weinhold 1677aa1a64f3SIngo Weinhold void 1678aa1a64f3SIngo Weinhold unlock_tracing_buffer() 1679aa1a64f3SIngo Weinhold { 1680aa1a64f3SIngo Weinhold #if ENABLE_TRACING 16813fccf067SIngo Weinhold sTracingMetaData->Unlock(); 1682aa1a64f3SIngo Weinhold #endif 1683aa1a64f3SIngo Weinhold } 1684aa1a64f3SIngo Weinhold 1685aa1a64f3SIngo Weinhold 1686aa5d2a2dSAxel Dörfler extern "C" status_t 1687aa5d2a2dSAxel Dörfler tracing_init(void) 1688aa5d2a2dSAxel Dörfler { 1689aa5d2a2dSAxel Dörfler #if ENABLE_TRACING 1690d829579dSIngo Weinhold status_t result = TracingMetaData::Create(sTracingMetaData); 1691d829579dSIngo Weinhold if (result != B_OK) { 1692d829579dSIngo Weinhold sTracingMetaData = &sDummyTracingMetaData; 1693d829579dSIngo Weinhold return result; 1694d829579dSIngo Weinhold } 1695aa5d2a2dSAxel Dörfler 1696d829579dSIngo Weinhold new(nothrow) TracingLogStartEntry(); 1697aa5d2a2dSAxel Dörfler 1698f97199edSIngo Weinhold add_debugger_command_etc("traced", &dump_tracing_command, 169974652349SIngo Weinhold "Dump recorded trace entries", 1700093e0057SAxel Dörfler "[ --printteam ] [ --difftime ] [ --stacktrace ] " 1701093e0057SAxel Dörfler "(\"forward\" | \"backward\") " 170264fe37eeSIngo Weinhold "| ([ <start> [ <count> [ <range> ] ] ] " 17034c4b14c3SIngo Weinhold "[ #<pattern> | (\"filter\" <filter>) ])\n" 170474652349SIngo Weinhold "Prints recorded trace entries. If \"backward\" or \"forward\" is\n" 170574652349SIngo Weinhold "specified, the command continues where the previous invocation left\n" 170674652349SIngo Weinhold "off, i.e. printing the previous respectively next entries (as many\n" 170774652349SIngo Weinhold "as printed before). In this case the command is continuable, that is\n" 170874652349SIngo Weinhold "afterwards entering an empty line in the debugger will reinvoke it.\n" 17095fa74667SIngo Weinhold "If no arguments are given, the command continues in the direction\n" 17105fa74667SIngo Weinhold "of the last invocation.\n" 1711093e0057SAxel Dörfler "--printteam - enables printing the entries' team IDs.\n" 1712093e0057SAxel Dörfler "--difftime - print difference times for all but the first entry.\n" 1713093e0057SAxel Dörfler "--stacktrace - print stack traces for entries that captured one.\n" 17146d369966SIngo Weinhold " <start> - The base index of the entries to print. Depending on\n" 17156d369966SIngo Weinhold " whether the iteration direction is forward or\n" 17166d369966SIngo Weinhold " backward this will be the first or last entry printed\n" 17176d369966SIngo Weinhold " (potentially, if a filter is specified). The index of\n" 17186d369966SIngo Weinhold " the first entry in the trace buffer is 1. If 0 is\n" 17196d369966SIngo Weinhold " specified, the last <count> recorded entries are\n" 17206d369966SIngo Weinhold " printed (iteration direction is backward). Defaults \n" 172174652349SIngo Weinhold " to 0.\n" 172274652349SIngo Weinhold " <count> - The number of entries to be printed. Defaults to 30.\n" 17236d369966SIngo Weinhold " If negative, the -<count> entries before and\n" 17246d369966SIngo Weinhold " including <start> will be printed.\n" 17256d369966SIngo Weinhold " <range> - Only relevant if a filter is specified. Specifies the\n" 17266d369966SIngo Weinhold " number of entries to be filtered -- depending on the\n" 17276d369966SIngo Weinhold " iteration direction the entries before or after\n" 17286d369966SIngo Weinhold " <start>. If more than <count> entries match the\n" 17296d369966SIngo Weinhold " filter, only the first (forward) or last (backward)\n" 17306d369966SIngo Weinhold " <count> matching entries will be printed. If 0 is\n" 17316d369966SIngo Weinhold " specified <range> will be set to <count>. If -1,\n" 17326d369966SIngo Weinhold " <range> will be set to the number of recorded\n" 17336d369966SIngo Weinhold " entries.\n" 173474652349SIngo Weinhold " <pattern> - If specified only entries containing this string are\n" 17354c4b14c3SIngo Weinhold " printed.\n" 17364c4b14c3SIngo Weinhold " <filter> - If specified only entries matching this filter\n" 17374c4b14c3SIngo Weinhold " expression are printed. The expression can consist of\n" 173864fe37eeSIngo Weinhold " prefix operators \"not\", \"and\", \"or\", and\n" 173964fe37eeSIngo Weinhold " filters \"'thread' <thread>\" (matching entries\n" 174064fe37eeSIngo Weinhold " with the given thread ID), \"'team' <team>\"\n" 174164fe37eeSIngo Weinhold "(matching entries with the given team ID), and\n" 17424c4b14c3SIngo Weinhold " \"#<pattern>\" (matching entries containing the given\n" 174364fe37eeSIngo Weinhold " string).\n", 0); 1744aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING 1745aa5d2a2dSAxel Dörfler return B_OK; 1746aa5d2a2dSAxel Dörfler } 1747aa5d2a2dSAxel Dörfler 1748a54c125eSIngo Weinhold 1749a54c125eSIngo Weinhold void 17507d2d758dSIngo Weinhold ktrace_printf(const char *format, ...) 17517d2d758dSIngo Weinhold { 17527d2d758dSIngo Weinhold #if ENABLE_TRACING 17537d2d758dSIngo Weinhold va_list list; 17547d2d758dSIngo Weinhold va_start(list, format); 17557d2d758dSIngo Weinhold 17567d2d758dSIngo Weinhold char buffer[256]; 17577d2d758dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list); 17587d2d758dSIngo Weinhold 17597d2d758dSIngo Weinhold va_end(list); 17607d2d758dSIngo Weinhold 17617d2d758dSIngo Weinhold new(nothrow) KernelTraceEntry(buffer); 17627d2d758dSIngo Weinhold #endif // ENABLE_TRACING 17637d2d758dSIngo Weinhold } 17647d2d758dSIngo Weinhold 17657d2d758dSIngo Weinhold 17667d2d758dSIngo Weinhold void 1767a54c125eSIngo Weinhold _user_ktrace_output(const char *message) 1768a54c125eSIngo Weinhold { 1769a54c125eSIngo Weinhold #if ENABLE_TRACING 1770a54c125eSIngo Weinhold new(nothrow) UserTraceEntry(message); 1771a54c125eSIngo Weinhold #endif // ENABLE_TRACING 1772a54c125eSIngo Weinhold } 1773a54c125eSIngo Weinhold 1774