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.
41e068aeaSRene Gollent * Copyright 2012, Rene Gollent, rene@gollent.com.
52d81f045SAxel Dörfler * Distributed under the terms of the MIT License.
62d81f045SAxel Dörfler */
72d81f045SAxel Dörfler
82d81f045SAxel Dörfler
9aa5d2a2dSAxel Dörfler #include <tracing.h>
10aa5d2a2dSAxel Dörfler
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>
171e068aeaSRene Gollent #include <debug_heap.h>
1865f40152SIngo Weinhold #include <elf.h>
1965f40152SIngo Weinhold #include <int.h>
208bd6d45dSIngo Weinhold #include <kernel.h>
2164fe37eeSIngo Weinhold #include <team.h>
2264fe37eeSIngo Weinhold #include <thread.h>
232d81f045SAxel Dörfler #include <util/AutoLock.h>
24e50cf876SIngo Weinhold #include <vm/vm.h>
252d81f045SAxel Dörfler
26aa5d2a2dSAxel Dörfler
27aa5d2a2dSAxel Dörfler #if ENABLE_TRACING
28aa5d2a2dSAxel Dörfler
295276dad0SAxel Dörfler //#define TRACE_TRACING
305276dad0SAxel Dörfler #ifdef TRACE_TRACING
316d986c16SIngo Weinhold # define TRACE(x) dprintf_no_syslog x
325276dad0SAxel Dörfler #else
335276dad0SAxel Dörfler # define TRACE(x) ;
345276dad0SAxel Dörfler #endif
355276dad0SAxel Dörfler
365276dad0SAxel Dörfler
37aa5d2a2dSAxel Dörfler enum {
38aa5d2a2dSAxel Dörfler WRAP_ENTRY = 0x01,
398e43ece8SAxel Dörfler ENTRY_INITIALIZED = 0x02,
4056213ff4SIngo Weinhold BUFFER_ENTRY = 0x04,
413fccf067SIngo Weinhold FILTER_MATCH = 0x08,
423fccf067SIngo Weinhold INVALID_ENTRY = 0x10,
433fccf067SIngo Weinhold CHECK_ENTRY = 0x20,
44aa5d2a2dSAxel Dörfler };
45aa5d2a2dSAxel Dörfler
4665f40152SIngo Weinhold
4765f40152SIngo Weinhold static const size_t kTraceOutputBufferSize = 10240;
483fccf067SIngo Weinhold static const size_t kBufferSize = MAX_TRACE_SIZE / sizeof(trace_entry);
49aa5d2a2dSAxel Dörfler
50ce50cdc3SIngo Weinhold static const uint32 kMaxRecoveringErrorCount = 100;
51d829579dSIngo Weinhold static const addr_t kMetaDataBaseAddress = 32 * 1024 * 1024;
52d829579dSIngo Weinhold static const addr_t kMetaDataBaseEndAddress = 128 * 1024 * 1024;
53d829579dSIngo Weinhold static const addr_t kMetaDataAddressIncrement = 8 * 1024 * 1024;
54d829579dSIngo Weinhold static const uint32 kMetaDataMagic1 = 'Vali';
55d829579dSIngo Weinhold static const uint32 kMetaDataMagic2 = 'dTra';
56d829579dSIngo Weinhold static const uint32 kMetaDataMagic3 = 'cing';
57d829579dSIngo Weinhold
583fccf067SIngo Weinhold // the maximum we can address with the trace_entry::[previous_]size fields
59ce50cdc3SIngo Weinhold static const size_t kMaxTracingEntryByteSize
603fccf067SIngo Weinhold = ((1 << 13) - 1) * sizeof(trace_entry);
613fccf067SIngo Weinhold
62d829579dSIngo Weinhold
63328df922SIngo Weinhold struct TraceOutputPrint {
TraceOutputPrintTraceOutputPrint64328df922SIngo Weinhold TraceOutputPrint(TraceOutput& output)
65328df922SIngo Weinhold :
66328df922SIngo Weinhold fOutput(output)
67328df922SIngo Weinhold {
68328df922SIngo Weinhold }
69328df922SIngo Weinhold
operator ()TraceOutputPrint70328df922SIngo Weinhold void operator()(const char* format,...) const
71328df922SIngo Weinhold {
72328df922SIngo Weinhold va_list args;
73328df922SIngo Weinhold va_start(args, format);
74328df922SIngo Weinhold fOutput.PrintArgs(format, args);
75328df922SIngo Weinhold va_end(args);
76328df922SIngo Weinhold }
77328df922SIngo Weinhold
78328df922SIngo Weinhold private:
79328df922SIngo Weinhold TraceOutput& fOutput;
80328df922SIngo Weinhold };
81328df922SIngo Weinhold
82328df922SIngo Weinhold
83d829579dSIngo Weinhold class TracingMetaData {
84d829579dSIngo Weinhold public:
853fccf067SIngo Weinhold static status_t Create(TracingMetaData*& _metaData);
86d829579dSIngo Weinhold
873fccf067SIngo Weinhold inline bool Lock();
883fccf067SIngo Weinhold inline void Unlock();
893fccf067SIngo Weinhold
903fccf067SIngo Weinhold inline trace_entry* FirstEntry() const;
913fccf067SIngo Weinhold inline trace_entry* AfterLastEntry() const;
923fccf067SIngo Weinhold
933fccf067SIngo Weinhold inline uint32 Entries() const;
943fccf067SIngo Weinhold inline uint32 EntriesEver() const;
953fccf067SIngo Weinhold
963fccf067SIngo Weinhold inline void IncrementEntriesEver();
973fccf067SIngo Weinhold
983fccf067SIngo Weinhold inline char* TraceOutputBuffer() const;
993fccf067SIngo Weinhold
1003fccf067SIngo Weinhold trace_entry* NextEntry(trace_entry* entry);
1013fccf067SIngo Weinhold trace_entry* PreviousEntry(trace_entry* entry);
1023fccf067SIngo Weinhold
1033fccf067SIngo Weinhold trace_entry* AllocateEntry(size_t size, uint16 flags);
1043fccf067SIngo Weinhold
1059a79e531SMichael Lotz bool IsInBuffer(void* address, size_t size);
1069a79e531SMichael Lotz
1073fccf067SIngo Weinhold private:
1083fccf067SIngo Weinhold bool _FreeFirstEntry();
1093fccf067SIngo Weinhold bool _MakeSpace(size_t needed);
1103fccf067SIngo Weinhold
1113fccf067SIngo Weinhold static status_t _CreateMetaDataArea(bool findPrevious,
1123fccf067SIngo Weinhold area_id& _area,
1133fccf067SIngo Weinhold TracingMetaData*& _metaData);
114ce50cdc3SIngo Weinhold bool _InitPreviousTracingData();
1153fccf067SIngo Weinhold
1163fccf067SIngo Weinhold private:
1173fccf067SIngo Weinhold uint32 fMagic1;
1183fccf067SIngo Weinhold trace_entry* fBuffer;
1193fccf067SIngo Weinhold trace_entry* fFirstEntry;
1203fccf067SIngo Weinhold trace_entry* fAfterLastEntry;
1213fccf067SIngo Weinhold uint32 fEntries;
1223fccf067SIngo Weinhold uint32 fMagic2;
1233fccf067SIngo Weinhold uint32 fEntriesEver;
1243fccf067SIngo Weinhold spinlock fLock;
1253fccf067SIngo Weinhold char* fTraceOutputBuffer;
12664d79effSIngo Weinhold phys_addr_t fPhysicalAddress;
1273fccf067SIngo Weinhold uint32 fMagic3;
1283fccf067SIngo Weinhold };
1293fccf067SIngo Weinhold
130c53508b7SIngo Weinhold static TracingMetaData sFallbackTracingMetaData;
131c53508b7SIngo Weinhold static TracingMetaData* sTracingMetaData = &sFallbackTracingMetaData;
1323fccf067SIngo Weinhold static bool sTracingDataRecovered = false;
1333fccf067SIngo Weinhold
1343fccf067SIngo Weinhold
1353fccf067SIngo Weinhold // #pragma mark -
1363fccf067SIngo Weinhold
1373fccf067SIngo Weinhold
138328df922SIngo Weinhold template<typename Print>
139328df922SIngo Weinhold static void
print_stack_trace(struct tracing_stack_trace * stackTrace,const Print & print)140328df922SIngo Weinhold print_stack_trace(struct tracing_stack_trace* stackTrace,
141328df922SIngo Weinhold const Print& print)
142328df922SIngo Weinhold {
143328df922SIngo Weinhold if (stackTrace == NULL || stackTrace->depth <= 0)
144328df922SIngo Weinhold return;
145328df922SIngo Weinhold
1461e068aeaSRene Gollent static const size_t kBufferSize = 256;
1471e068aeaSRene Gollent char* buffer = (char*)debug_malloc(kBufferSize);
1481e068aeaSRene Gollent
149328df922SIngo Weinhold for (int32 i = 0; i < stackTrace->depth; i++) {
150328df922SIngo Weinhold addr_t address = stackTrace->return_addresses[i];
151328df922SIngo Weinhold
152328df922SIngo Weinhold const char* symbol;
1531e068aeaSRene Gollent const char* demangledName = NULL;
154328df922SIngo Weinhold const char* imageName;
155328df922SIngo Weinhold bool exactMatch;
156328df922SIngo Weinhold addr_t baseAddress;
157328df922SIngo Weinhold
158328df922SIngo Weinhold if (elf_debug_lookup_symbol_address(address, &baseAddress, &symbol,
159328df922SIngo Weinhold &imageName, &exactMatch) == B_OK) {
1601e068aeaSRene Gollent
1611e068aeaSRene Gollent if (buffer != NULL) {
1621e068aeaSRene Gollent bool isObjectMethod;
1631e068aeaSRene Gollent demangledName = debug_demangle_symbol(symbol, buffer,
1641e068aeaSRene Gollent kBufferSize, &isObjectMethod);
1651e068aeaSRene Gollent }
1661e068aeaSRene Gollent
1671e068aeaSRene Gollent print(" %p %s + 0x%lx (%s)%s\n", (void*)address,
1681e068aeaSRene Gollent demangledName != NULL ? demangledName : symbol,
169328df922SIngo Weinhold address - baseAddress, imageName,
170328df922SIngo Weinhold exactMatch ? "" : " (nearest)");
171328df922SIngo Weinhold } else
172328df922SIngo Weinhold print(" %p\n", (void*)address);
173328df922SIngo Weinhold }
1741e068aeaSRene Gollent
1751e068aeaSRene Gollent if (buffer != NULL)
1761e068aeaSRene Gollent debug_free(buffer);
177328df922SIngo Weinhold }
178328df922SIngo Weinhold
179328df922SIngo Weinhold
1803fccf067SIngo Weinhold // #pragma mark - TracingMetaData
1813fccf067SIngo Weinhold
1823fccf067SIngo Weinhold
1833fccf067SIngo Weinhold bool
Lock()1843fccf067SIngo Weinhold TracingMetaData::Lock()
1853fccf067SIngo Weinhold {
1863fccf067SIngo Weinhold acquire_spinlock(&fLock);
1873fccf067SIngo Weinhold return true;
1883fccf067SIngo Weinhold }
1893fccf067SIngo Weinhold
1903fccf067SIngo Weinhold
1913fccf067SIngo Weinhold void
Unlock()1923fccf067SIngo Weinhold TracingMetaData::Unlock()
1933fccf067SIngo Weinhold {
1943fccf067SIngo Weinhold release_spinlock(&fLock);
1953fccf067SIngo Weinhold }
1963fccf067SIngo Weinhold
1973fccf067SIngo Weinhold
1983fccf067SIngo Weinhold trace_entry*
FirstEntry() const1993fccf067SIngo Weinhold TracingMetaData::FirstEntry() const
2003fccf067SIngo Weinhold {
2013fccf067SIngo Weinhold return fFirstEntry;
2023fccf067SIngo Weinhold }
2033fccf067SIngo Weinhold
2043fccf067SIngo Weinhold
2053fccf067SIngo Weinhold trace_entry*
AfterLastEntry() const2063fccf067SIngo Weinhold TracingMetaData::AfterLastEntry() const
2073fccf067SIngo Weinhold {
2083fccf067SIngo Weinhold return fAfterLastEntry;
2093fccf067SIngo Weinhold }
2103fccf067SIngo Weinhold
2113fccf067SIngo Weinhold
2123fccf067SIngo Weinhold uint32
Entries() const2133fccf067SIngo Weinhold TracingMetaData::Entries() const
2143fccf067SIngo Weinhold {
2153fccf067SIngo Weinhold return fEntries;
2163fccf067SIngo Weinhold }
2173fccf067SIngo Weinhold
2183fccf067SIngo Weinhold
2193fccf067SIngo Weinhold uint32
EntriesEver() const2203fccf067SIngo Weinhold TracingMetaData::EntriesEver() const
2213fccf067SIngo Weinhold {
2223fccf067SIngo Weinhold return fEntriesEver;
2233fccf067SIngo Weinhold }
2243fccf067SIngo Weinhold
2253fccf067SIngo Weinhold
2263fccf067SIngo Weinhold void
IncrementEntriesEver()2273fccf067SIngo Weinhold TracingMetaData::IncrementEntriesEver()
2283fccf067SIngo Weinhold {
2293fccf067SIngo Weinhold fEntriesEver++;
230ce50cdc3SIngo Weinhold // NOTE: Race condition on SMP machines! We should use atomic_add(),
231ce50cdc3SIngo Weinhold // though that costs some performance and the information is for
232ce50cdc3SIngo Weinhold // informational purpose anyway.
2333fccf067SIngo Weinhold }
2343fccf067SIngo Weinhold
2353fccf067SIngo Weinhold
2363fccf067SIngo Weinhold char*
TraceOutputBuffer() const2373fccf067SIngo Weinhold TracingMetaData::TraceOutputBuffer() const
2383fccf067SIngo Weinhold {
2393fccf067SIngo Weinhold return fTraceOutputBuffer;
2403fccf067SIngo Weinhold }
2413fccf067SIngo Weinhold
2423fccf067SIngo Weinhold
2433fccf067SIngo Weinhold trace_entry*
NextEntry(trace_entry * entry)2443fccf067SIngo Weinhold TracingMetaData::NextEntry(trace_entry* entry)
2453fccf067SIngo Weinhold {
2463fccf067SIngo Weinhold entry += entry->size;
2473fccf067SIngo Weinhold if ((entry->flags & WRAP_ENTRY) != 0)
2483fccf067SIngo Weinhold entry = fBuffer;
2493fccf067SIngo Weinhold
2503fccf067SIngo Weinhold if (entry == fAfterLastEntry)
2513fccf067SIngo Weinhold return NULL;
2523fccf067SIngo Weinhold
2533fccf067SIngo Weinhold return entry;
2543fccf067SIngo Weinhold }
2553fccf067SIngo Weinhold
2563fccf067SIngo Weinhold
2573fccf067SIngo Weinhold trace_entry*
PreviousEntry(trace_entry * entry)2583fccf067SIngo Weinhold TracingMetaData::PreviousEntry(trace_entry* entry)
2593fccf067SIngo Weinhold {
2603fccf067SIngo Weinhold if (entry == fFirstEntry)
2613fccf067SIngo Weinhold return NULL;
2623fccf067SIngo Weinhold
2633fccf067SIngo Weinhold if (entry == fBuffer) {
2643fccf067SIngo Weinhold // beginning of buffer -- previous entry is a wrap entry
2653fccf067SIngo Weinhold entry = fBuffer + kBufferSize - entry->previous_size;
2663fccf067SIngo Weinhold }
2673fccf067SIngo Weinhold
2683fccf067SIngo Weinhold return entry - entry->previous_size;
2693fccf067SIngo Weinhold }
2703fccf067SIngo Weinhold
2713fccf067SIngo Weinhold
2723fccf067SIngo Weinhold trace_entry*
AllocateEntry(size_t size,uint16 flags)2733fccf067SIngo Weinhold TracingMetaData::AllocateEntry(size_t size, uint16 flags)
2743fccf067SIngo Weinhold {
275ce50cdc3SIngo Weinhold if (fAfterLastEntry == NULL || size == 0
276ce50cdc3SIngo Weinhold || size >= kMaxTracingEntryByteSize) {
2773fccf067SIngo Weinhold return NULL;
278ce50cdc3SIngo Weinhold }
2793fccf067SIngo Weinhold
2803fccf067SIngo Weinhold InterruptsSpinLocker _(fLock);
2813fccf067SIngo Weinhold
2823fccf067SIngo Weinhold size = (size + 3) >> 2;
2833fccf067SIngo Weinhold // 4 byte aligned, don't store the lower 2 bits
2843fccf067SIngo Weinhold
2853fccf067SIngo Weinhold TRACE(("AllocateEntry(%lu), start %p, end %p, buffer %p\n", size * 4,
2863fccf067SIngo Weinhold fFirstEntry, fAfterLastEntry, fBuffer));
2873fccf067SIngo Weinhold
2883fccf067SIngo Weinhold if (!_MakeSpace(size))
2893fccf067SIngo Weinhold return NULL;
2903fccf067SIngo Weinhold
2913fccf067SIngo Weinhold trace_entry* entry = fAfterLastEntry;
2923fccf067SIngo Weinhold entry->size = size;
2933fccf067SIngo Weinhold entry->flags = flags;
2943fccf067SIngo Weinhold fAfterLastEntry += size;
2953fccf067SIngo Weinhold fAfterLastEntry->previous_size = size;
2963fccf067SIngo Weinhold
2973fccf067SIngo Weinhold if (!(flags & BUFFER_ENTRY))
2983fccf067SIngo Weinhold fEntries++;
2993fccf067SIngo Weinhold
3003fccf067SIngo Weinhold TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry,
3013fccf067SIngo Weinhold fAfterLastEntry, fFirstEntry, fEntries));
3023fccf067SIngo Weinhold
3033fccf067SIngo Weinhold return entry;
3043fccf067SIngo Weinhold }
3053fccf067SIngo Weinhold
3063fccf067SIngo Weinhold
3073fccf067SIngo Weinhold bool
IsInBuffer(void * address,size_t size)3089a79e531SMichael Lotz TracingMetaData::IsInBuffer(void* address, size_t size)
3099a79e531SMichael Lotz {
3109a79e531SMichael Lotz if (fEntries == 0)
3119a79e531SMichael Lotz return false;
3129a79e531SMichael Lotz
3139a79e531SMichael Lotz addr_t start = (addr_t)address;
3149a79e531SMichael Lotz addr_t end = start + size;
3159a79e531SMichael Lotz
3169a79e531SMichael Lotz if (start < (addr_t)fBuffer || end > (addr_t)(fBuffer + kBufferSize))
3179a79e531SMichael Lotz return false;
3189a79e531SMichael Lotz
3199a79e531SMichael Lotz if (fFirstEntry > fAfterLastEntry)
3209a79e531SMichael Lotz return start >= (addr_t)fFirstEntry || end <= (addr_t)fAfterLastEntry;
3219a79e531SMichael Lotz
3229a79e531SMichael Lotz return start >= (addr_t)fFirstEntry && end <= (addr_t)fAfterLastEntry;
3239a79e531SMichael Lotz }
3249a79e531SMichael Lotz
3259a79e531SMichael Lotz
3269a79e531SMichael Lotz bool
_FreeFirstEntry()3273fccf067SIngo Weinhold TracingMetaData::_FreeFirstEntry()
3283fccf067SIngo Weinhold {
3293fccf067SIngo Weinhold TRACE((" skip start %p, %lu*4 bytes\n", fFirstEntry, fFirstEntry->size));
3303fccf067SIngo Weinhold
3313fccf067SIngo Weinhold trace_entry* newFirst = NextEntry(fFirstEntry);
3323fccf067SIngo Weinhold
3333fccf067SIngo Weinhold if (fFirstEntry->flags & BUFFER_ENTRY) {
3343fccf067SIngo Weinhold // a buffer entry -- just skip it
3353fccf067SIngo Weinhold } else if (fFirstEntry->flags & ENTRY_INITIALIZED) {
33637e6de5dSIngo Weinhold // Fully initialized TraceEntry: We could destroy it, but don't do so
33737e6de5dSIngo Weinhold // for sake of robustness. The destructors of tracing entry classes
33837e6de5dSIngo Weinhold // should be empty anyway.
3393fccf067SIngo Weinhold fEntries--;
3403fccf067SIngo Weinhold } else {
3413fccf067SIngo Weinhold // Not fully initialized TraceEntry. We can't free it, since
3423fccf067SIngo Weinhold // then it's constructor might still write into the memory and
3433fccf067SIngo Weinhold // overwrite data of the entry we're going to allocate.
3443fccf067SIngo Weinhold // We can't do anything until this entry can be discarded.
3453fccf067SIngo Weinhold return false;
3463fccf067SIngo Weinhold }
3473fccf067SIngo Weinhold
3483fccf067SIngo Weinhold if (newFirst == NULL) {
3493fccf067SIngo Weinhold // everything is freed -- practically this can't happen, if
3503fccf067SIngo Weinhold // the buffer is large enough to hold three max-sized entries
3513fccf067SIngo Weinhold fFirstEntry = fAfterLastEntry = fBuffer;
3523fccf067SIngo Weinhold TRACE(("_FreeFirstEntry(): all entries freed!\n"));
3533fccf067SIngo Weinhold } else
3543fccf067SIngo Weinhold fFirstEntry = newFirst;
3553fccf067SIngo Weinhold
3563fccf067SIngo Weinhold return true;
3573fccf067SIngo Weinhold }
3583fccf067SIngo Weinhold
3593fccf067SIngo Weinhold
3603fccf067SIngo Weinhold /*! Makes sure we have needed * 4 bytes of memory at fAfterLastEntry.
3613fccf067SIngo Weinhold Returns \c false, if unable to free that much.
3623fccf067SIngo Weinhold */
3633fccf067SIngo Weinhold bool
_MakeSpace(size_t needed)3643fccf067SIngo Weinhold TracingMetaData::_MakeSpace(size_t needed)
3653fccf067SIngo Weinhold {
3663fccf067SIngo Weinhold // we need space for fAfterLastEntry, too (in case we need to wrap around
3673fccf067SIngo Weinhold // later)
3683fccf067SIngo Weinhold needed++;
3693fccf067SIngo Weinhold
3703fccf067SIngo Weinhold // If there's not enough space (free or occupied) after fAfterLastEntry,
3713fccf067SIngo Weinhold // we free all entries in that region and wrap around.
3723fccf067SIngo Weinhold if (fAfterLastEntry + needed > fBuffer + kBufferSize) {
3733fccf067SIngo Weinhold TRACE(("_MakeSpace(%lu), wrapping around: after last: %p\n", needed,
3743fccf067SIngo Weinhold fAfterLastEntry));
3753fccf067SIngo Weinhold
3763fccf067SIngo Weinhold // Free all entries after fAfterLastEntry and one more at the beginning
3773fccf067SIngo Weinhold // of the buffer.
3783fccf067SIngo Weinhold while (fFirstEntry > fAfterLastEntry) {
3793fccf067SIngo Weinhold if (!_FreeFirstEntry())
3803fccf067SIngo Weinhold return false;
3813fccf067SIngo Weinhold }
3823fccf067SIngo Weinhold if (fAfterLastEntry != fBuffer && !_FreeFirstEntry())
3833fccf067SIngo Weinhold return false;
3843fccf067SIngo Weinhold
3853fccf067SIngo Weinhold // just in case _FreeFirstEntry() freed the very last existing entry
3863fccf067SIngo Weinhold if (fAfterLastEntry == fBuffer)
3873fccf067SIngo Weinhold return true;
3883fccf067SIngo Weinhold
3893fccf067SIngo Weinhold // mark as wrap entry and actually wrap around
3903fccf067SIngo Weinhold trace_entry* wrapEntry = fAfterLastEntry;
3913fccf067SIngo Weinhold wrapEntry->size = 0;
3923fccf067SIngo Weinhold wrapEntry->flags = WRAP_ENTRY;
3933fccf067SIngo Weinhold fAfterLastEntry = fBuffer;
3943fccf067SIngo Weinhold fAfterLastEntry->previous_size = fBuffer + kBufferSize - wrapEntry;
3953fccf067SIngo Weinhold }
3963fccf067SIngo Weinhold
3973fccf067SIngo Weinhold if (fFirstEntry <= fAfterLastEntry) {
3983fccf067SIngo Weinhold // buffer is empty or the space after fAfterLastEntry is unoccupied
3993fccf067SIngo Weinhold return true;
4003fccf067SIngo Weinhold }
4013fccf067SIngo Weinhold
4023fccf067SIngo Weinhold // free the first entries, until there's enough space
4033fccf067SIngo Weinhold size_t space = fFirstEntry - fAfterLastEntry;
4043fccf067SIngo Weinhold
4053fccf067SIngo Weinhold if (space < needed) {
4063fccf067SIngo Weinhold TRACE(("_MakeSpace(%lu), left %ld\n", needed, space));
4073fccf067SIngo Weinhold }
4083fccf067SIngo Weinhold
4093fccf067SIngo Weinhold while (space < needed) {
4103fccf067SIngo Weinhold space += fFirstEntry->size;
4113fccf067SIngo Weinhold
4123fccf067SIngo Weinhold if (!_FreeFirstEntry())
4133fccf067SIngo Weinhold return false;
4143fccf067SIngo Weinhold }
4153fccf067SIngo Weinhold
4163fccf067SIngo Weinhold TRACE((" out: start %p, entries %ld\n", fFirstEntry, fEntries));
4173fccf067SIngo Weinhold
4183fccf067SIngo Weinhold return true;
4193fccf067SIngo Weinhold }
4203fccf067SIngo Weinhold
4213fccf067SIngo Weinhold
4223fccf067SIngo Weinhold /*static*/ status_t
Create(TracingMetaData * & _metaData)4233fccf067SIngo Weinhold TracingMetaData::Create(TracingMetaData*& _metaData)
424d829579dSIngo Weinhold {
425d829579dSIngo Weinhold // search meta data in memory (from previous session)
426d829579dSIngo Weinhold area_id area;
427d829579dSIngo Weinhold TracingMetaData* metaData;
428d829579dSIngo Weinhold status_t error = _CreateMetaDataArea(true, area, metaData);
429d829579dSIngo Weinhold if (error == B_OK) {
430ce50cdc3SIngo Weinhold if (metaData->_InitPreviousTracingData()) {
431d829579dSIngo Weinhold _metaData = metaData;
432d829579dSIngo Weinhold return B_OK;
433d829579dSIngo Weinhold }
434d829579dSIngo Weinhold
435d829579dSIngo Weinhold dprintf("Found previous tracing meta data, but failed to init.\n");
436d829579dSIngo Weinhold
437d829579dSIngo Weinhold // invalidate the meta data
4383fccf067SIngo Weinhold metaData->fMagic1 = 0;
4393fccf067SIngo Weinhold metaData->fMagic2 = 0;
4403fccf067SIngo Weinhold metaData->fMagic3 = 0;
441d829579dSIngo Weinhold delete_area(area);
442d829579dSIngo Weinhold } else
443d829579dSIngo Weinhold dprintf("No previous tracing meta data found.\n");
444d829579dSIngo Weinhold
44555d903d2SAxel Dörfler // no previous tracing data found -- create new one
446d829579dSIngo Weinhold error = _CreateMetaDataArea(false, area, metaData);
447d829579dSIngo Weinhold if (error != B_OK)
448d829579dSIngo Weinhold return error;
449d829579dSIngo Weinhold
450a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {};
451a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
452a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {};
4537198f765SAxel Dörfler area = create_area_etc(B_SYSTEM_TEAM, "tracing log",
454d829579dSIngo Weinhold kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS,
455d1f280c8SHamish Morrison B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT, 0,
456a8ad734fSIngo Weinhold &virtualRestrictions, &physicalRestrictions,
457a8ad734fSIngo Weinhold (void**)&metaData->fTraceOutputBuffer);
458d829579dSIngo Weinhold if (area < 0)
459d829579dSIngo Weinhold return area;
460d829579dSIngo Weinhold
461d829579dSIngo Weinhold // get the physical address
462d829579dSIngo Weinhold physical_entry physicalEntry;
4633fccf067SIngo Weinhold if (get_memory_map(metaData->fTraceOutputBuffer, B_PAGE_SIZE,
464d829579dSIngo Weinhold &physicalEntry, 1) == B_OK) {
46564d79effSIngo Weinhold metaData->fPhysicalAddress = physicalEntry.address;
466d829579dSIngo Weinhold } else {
467d829579dSIngo Weinhold dprintf("TracingMetaData::Create(): failed to get physical address "
468d829579dSIngo Weinhold "of tracing buffer\n");
4693fccf067SIngo Weinhold metaData->fPhysicalAddress = 0;
470d829579dSIngo Weinhold }
471d829579dSIngo Weinhold
4723fccf067SIngo Weinhold metaData->fBuffer = (trace_entry*)(metaData->fTraceOutputBuffer
473d829579dSIngo Weinhold + kTraceOutputBufferSize);
4743fccf067SIngo Weinhold metaData->fFirstEntry = metaData->fBuffer;
4753fccf067SIngo Weinhold metaData->fAfterLastEntry = metaData->fBuffer;
476d829579dSIngo Weinhold
4773fccf067SIngo Weinhold metaData->fEntries = 0;
4783fccf067SIngo Weinhold metaData->fEntriesEver = 0;
4793fccf067SIngo Weinhold B_INITIALIZE_SPINLOCK(&metaData->fLock);
480d829579dSIngo Weinhold
4813fccf067SIngo Weinhold metaData->fMagic1 = kMetaDataMagic1;
4823fccf067SIngo Weinhold metaData->fMagic2 = kMetaDataMagic2;
4833fccf067SIngo Weinhold metaData->fMagic3 = kMetaDataMagic3;
484d829579dSIngo Weinhold
485d829579dSIngo Weinhold _metaData = metaData;
486d829579dSIngo Weinhold return B_OK;
487d829579dSIngo Weinhold }
488d829579dSIngo Weinhold
4893fccf067SIngo Weinhold
4903fccf067SIngo Weinhold /*static*/ status_t
_CreateMetaDataArea(bool findPrevious,area_id & _area,TracingMetaData * & _metaData)4913fccf067SIngo Weinhold TracingMetaData::_CreateMetaDataArea(bool findPrevious, area_id& _area,
4923fccf067SIngo Weinhold TracingMetaData*& _metaData)
493d829579dSIngo Weinhold {
494d829579dSIngo Weinhold // search meta data in memory (from previous session)
495d829579dSIngo Weinhold TracingMetaData* metaData;
496a8ad734fSIngo Weinhold phys_addr_t metaDataAddress = kMetaDataBaseAddress;
497d829579dSIngo Weinhold for (; metaDataAddress <= kMetaDataBaseEndAddress;
498d829579dSIngo Weinhold metaDataAddress += kMetaDataAddressIncrement) {
499a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {};
500a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
501a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {};
502a8ad734fSIngo Weinhold physicalRestrictions.low_address = metaDataAddress;
503a8ad734fSIngo Weinhold physicalRestrictions.high_address = metaDataAddress + B_PAGE_SIZE;
504cdb638a8SAxel Dörfler area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing metadata",
505cdb638a8SAxel Dörfler B_PAGE_SIZE, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
506d1f280c8SHamish Morrison CREATE_AREA_DONT_CLEAR, 0, &virtualRestrictions,
507d1f280c8SHamish Morrison &physicalRestrictions, (void**)&metaData);
508d829579dSIngo Weinhold if (area < 0)
509d829579dSIngo Weinhold continue;
510d829579dSIngo Weinhold
511d829579dSIngo Weinhold if (!findPrevious) {
512d829579dSIngo Weinhold _area = area;
513d829579dSIngo Weinhold _metaData = metaData;
514d829579dSIngo Weinhold return B_OK;
515d829579dSIngo Weinhold }
516d829579dSIngo Weinhold
5173fccf067SIngo Weinhold if (metaData->fMagic1 == kMetaDataMagic1
5183fccf067SIngo Weinhold && metaData->fMagic2 == kMetaDataMagic2
5193fccf067SIngo Weinhold && metaData->fMagic3 == kMetaDataMagic3) {
520d829579dSIngo Weinhold _area = area;
521d829579dSIngo Weinhold _metaData = metaData;
522d829579dSIngo Weinhold return B_OK;
523d829579dSIngo Weinhold }
524d829579dSIngo Weinhold
525d829579dSIngo Weinhold delete_area(area);
526d829579dSIngo Weinhold }
527d829579dSIngo Weinhold
528c53508b7SIngo Weinhold if (findPrevious)
529d829579dSIngo Weinhold return B_ENTRY_NOT_FOUND;
530c53508b7SIngo Weinhold
531c53508b7SIngo Weinhold // We could allocate any of the standard locations. Instead of failing
532c53508b7SIngo Weinhold // entirely, we use the static meta data. The tracing buffer won't be
533c53508b7SIngo Weinhold // reattachable in the next session, but at least we can use it in this
534c53508b7SIngo Weinhold // session.
535c53508b7SIngo Weinhold _metaData = &sFallbackTracingMetaData;
536c53508b7SIngo Weinhold return B_OK;
537d829579dSIngo Weinhold }
538d829579dSIngo Weinhold
5393fccf067SIngo Weinhold
540ce50cdc3SIngo Weinhold bool
_InitPreviousTracingData()541ce50cdc3SIngo Weinhold TracingMetaData::_InitPreviousTracingData()
542d829579dSIngo Weinhold {
543b0eaa06cSIngo Weinhold // TODO: ATM re-attaching the previous tracing buffer doesn't work very
5449a79e531SMichael Lotz // well. The entries should be checked more thoroughly for validity -- e.g.
5459a79e531SMichael Lotz // the pointers to the entries' vtable pointers could be invalid, which can
546b0eaa06cSIngo Weinhold // make the "traced" command quite unusable. The validity of the entries
547b0eaa06cSIngo Weinhold // could be checked in a safe environment (i.e. with a fault handler) with
548b0eaa06cSIngo Weinhold // typeid() and call of a virtual function.
549b0eaa06cSIngo Weinhold return false;
550b0eaa06cSIngo Weinhold
551d829579dSIngo Weinhold addr_t bufferStart
552ce50cdc3SIngo Weinhold = (addr_t)fTraceOutputBuffer + kTraceOutputBufferSize;
553d829579dSIngo Weinhold addr_t bufferEnd = bufferStart + MAX_TRACE_SIZE;
554d829579dSIngo Weinhold
555ce50cdc3SIngo Weinhold if (bufferStart > bufferEnd || (addr_t)fBuffer != bufferStart
556ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry % sizeof(trace_entry) != 0
557ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry < bufferStart
558ce50cdc3SIngo Weinhold || (addr_t)fFirstEntry + sizeof(trace_entry) >= bufferEnd
559ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry % sizeof(trace_entry) != 0
560ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry < bufferStart
561ce50cdc3SIngo Weinhold || (addr_t)fAfterLastEntry > bufferEnd
562ce50cdc3SIngo Weinhold || fPhysicalAddress == 0) {
563d829579dSIngo Weinhold dprintf("Failed to init tracing meta data: Sanity checks "
564d829579dSIngo Weinhold "failed.\n");
565d829579dSIngo Weinhold return false;
566d829579dSIngo Weinhold }
567d829579dSIngo Weinhold
568d829579dSIngo Weinhold // re-map the previous tracing buffer
569a8ad734fSIngo Weinhold virtual_address_restrictions virtualRestrictions = {};
570a8ad734fSIngo Weinhold virtualRestrictions.address = fTraceOutputBuffer;
571a8ad734fSIngo Weinhold virtualRestrictions.address_specification = B_EXACT_ADDRESS;
572a8ad734fSIngo Weinhold physical_address_restrictions physicalRestrictions = {};
573a8ad734fSIngo Weinhold physicalRestrictions.low_address = fPhysicalAddress;
574a8ad734fSIngo Weinhold physicalRestrictions.high_address = fPhysicalAddress
575cdb638a8SAxel Dörfler + ROUNDUP(kTraceOutputBufferSize + MAX_TRACE_SIZE, B_PAGE_SIZE);
576d829579dSIngo Weinhold area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing log",
577a8ad734fSIngo Weinhold kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS,
578d1f280c8SHamish Morrison B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_CLEAR, 0,
579a8ad734fSIngo Weinhold &virtualRestrictions, &physicalRestrictions, NULL);
580d829579dSIngo Weinhold if (area < 0) {
581d829579dSIngo Weinhold dprintf("Failed to init tracing meta data: Mapping tracing log "
582d829579dSIngo Weinhold "buffer failed: %s\n", strerror(area));
583d829579dSIngo Weinhold return false;
584d829579dSIngo Weinhold }
585d829579dSIngo Weinhold
5861aed2639SIngo Weinhold dprintf("ktrace: Remapped tracing buffer at %p, size: %" B_PRIuSIZE "\n",
587a8ad734fSIngo Weinhold fTraceOutputBuffer, kTraceOutputBufferSize + MAX_TRACE_SIZE);
5881aed2639SIngo Weinhold
5893fccf067SIngo Weinhold // verify/repair the tracing entry list
590ce50cdc3SIngo Weinhold uint32 errorCount = 0;
591ce50cdc3SIngo Weinhold uint32 entryCount = 0;
592ce50cdc3SIngo Weinhold uint32 nonBufferEntryCount = 0;
593ce50cdc3SIngo Weinhold uint32 previousEntrySize = 0;
594ce50cdc3SIngo Weinhold trace_entry* entry = fFirstEntry;
595ce50cdc3SIngo Weinhold while (errorCount <= kMaxRecoveringErrorCount) {
596ce50cdc3SIngo Weinhold // check previous entry size
597ce50cdc3SIngo Weinhold if (entry->previous_size != previousEntrySize) {
598ce50cdc3SIngo Weinhold if (entry != fFirstEntry) {
599ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: fixing previous_size "
6008627383bSAlex Smith "size: %" B_PRIu32 " (should be %" B_PRIu32 ")\n", entry,
6018627383bSAlex Smith entry->previous_size, previousEntrySize);
6021aed2639SIngo Weinhold errorCount++;
603d829579dSIngo Weinhold }
604ce50cdc3SIngo Weinhold entry->previous_size = previousEntrySize;
605ce50cdc3SIngo Weinhold }
606aa5d2a2dSAxel Dörfler
6073fccf067SIngo Weinhold if (entry == fAfterLastEntry)
608ce50cdc3SIngo Weinhold break;
609aa5d2a2dSAxel Dörfler
610ce50cdc3SIngo Weinhold // check size field
611ce50cdc3SIngo Weinhold if ((entry->flags & WRAP_ENTRY) == 0 && entry->size == 0) {
612ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: non-wrap entry size is 0\n",
613ce50cdc3SIngo Weinhold entry);
6141aed2639SIngo Weinhold errorCount++;
615ce50cdc3SIngo Weinhold fAfterLastEntry = entry;
616ce50cdc3SIngo Weinhold break;
617aa5d2a2dSAxel Dörfler }
618aa5d2a2dSAxel Dörfler
619ce50cdc3SIngo Weinhold if (entry->size > uint32(fBuffer + kBufferSize - entry)) {
6208627383bSAlex Smith dprintf("ktrace recovering: entry %p: size too big: %" B_PRIu32 "\n",
6218627383bSAlex Smith entry, entry->size);
6221aed2639SIngo Weinhold errorCount++;
623ce50cdc3SIngo Weinhold fAfterLastEntry = entry;
624ce50cdc3SIngo Weinhold break;
6256d369966SIngo Weinhold }
6266d369966SIngo Weinhold
627ce50cdc3SIngo Weinhold if (entry < fAfterLastEntry && entry + entry->size > fAfterLastEntry) {
628ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: entry crosses "
629ce50cdc3SIngo Weinhold "fAfterLastEntry (%p)\n", entry, fAfterLastEntry);
6301aed2639SIngo Weinhold errorCount++;
631ce50cdc3SIngo Weinhold fAfterLastEntry = entry;
632ce50cdc3SIngo Weinhold break;
6336d369966SIngo Weinhold }
6346d369966SIngo Weinhold
635ce50cdc3SIngo Weinhold // check for wrap entry
636ce50cdc3SIngo Weinhold if ((entry->flags & WRAP_ENTRY) != 0) {
637ce50cdc3SIngo Weinhold if ((uint32)(fBuffer + kBufferSize - entry)
638ce50cdc3SIngo Weinhold > kMaxTracingEntryByteSize / sizeof(trace_entry)) {
639ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: wrap entry at invalid "
640ce50cdc3SIngo Weinhold "buffer location\n", entry);
6411aed2639SIngo Weinhold errorCount++;
642ce50cdc3SIngo Weinhold }
6436d369966SIngo Weinhold
644ce50cdc3SIngo Weinhold if (entry->size != 0) {
645ce50cdc3SIngo Weinhold dprintf("ktrace recovering: entry %p: invalid wrap entry "
6468627383bSAlex Smith "size: %" B_PRIu32 "\n", entry, entry->size);
6471aed2639SIngo Weinhold errorCount++;
648ce50cdc3SIngo Weinhold entry->size = 0;
649ce50cdc3SIngo Weinhold }
6506d986c16SIngo Weinhold
651ce50cdc3SIngo Weinhold previousEntrySize = fBuffer + kBufferSize - entry;
652ce50cdc3SIngo Weinhold entry = fBuffer;
653ce50cdc3SIngo Weinhold continue;
654ce50cdc3SIngo Weinhold }
655ce50cdc3SIngo Weinhold
656ce50cdc3SIngo Weinhold if ((entry->flags & BUFFER_ENTRY) == 0) {
657ce50cdc3SIngo Weinhold entry->flags |= CHECK_ENTRY;
658ce50cdc3SIngo Weinhold nonBufferEntryCount++;
659ce50cdc3SIngo Weinhold }
660ce50cdc3SIngo Weinhold
661ce50cdc3SIngo Weinhold entryCount++;
662ce50cdc3SIngo Weinhold previousEntrySize = entry->size;
663ce50cdc3SIngo Weinhold
664ce50cdc3SIngo Weinhold entry += entry->size;
665ce50cdc3SIngo Weinhold }
666ce50cdc3SIngo Weinhold
667ce50cdc3SIngo Weinhold if (errorCount > kMaxRecoveringErrorCount) {
668ce50cdc3SIngo Weinhold dprintf("ktrace recovering: Too many errors.\n");
669ce50cdc3SIngo Weinhold fAfterLastEntry = entry;
670ce50cdc3SIngo Weinhold fAfterLastEntry->previous_size = previousEntrySize;
671ce50cdc3SIngo Weinhold }
672ce50cdc3SIngo Weinhold
6738627383bSAlex Smith dprintf("ktrace recovering: Recovered %" B_PRIu32 " entries + %" B_PRIu32
6748627383bSAlex Smith " buffer entries from previous session. Expected %" B_PRIu32
6758627383bSAlex Smith " entries.\n", nonBufferEntryCount, entryCount - nonBufferEntryCount,
6768627383bSAlex Smith fEntries);
677ce50cdc3SIngo Weinhold fEntries = nonBufferEntryCount;
678ce50cdc3SIngo Weinhold
679ce50cdc3SIngo Weinhold B_INITIALIZE_SPINLOCK(&fLock);
680ce50cdc3SIngo Weinhold
681ce50cdc3SIngo Weinhold // TODO: Actually check the entries! Do that when first accessing the
682ce50cdc3SIngo Weinhold // tracing buffer from the kernel debugger (when sTracingDataRecovered is
683ce50cdc3SIngo Weinhold // true).
6843fccf067SIngo Weinhold sTracingDataRecovered = true;
6856d986c16SIngo Weinhold return true;
6866d986c16SIngo Weinhold }
6876d986c16SIngo Weinhold
6886d986c16SIngo Weinhold
6898e43ece8SAxel Dörfler #endif // ENABLE_TRACING
6908e43ece8SAxel Dörfler
6918e43ece8SAxel Dörfler
6928e43ece8SAxel Dörfler // #pragma mark -
6938e43ece8SAxel Dörfler
6948e43ece8SAxel Dörfler
TraceOutput(char * buffer,size_t bufferSize,uint32 flags)695350b6dbcSIngo Weinhold TraceOutput::TraceOutput(char* buffer, size_t bufferSize, uint32 flags)
696f1047a1cSIngo Weinhold : fBuffer(buffer),
697350b6dbcSIngo Weinhold fCapacity(bufferSize),
698350b6dbcSIngo Weinhold fFlags(flags)
699f1047a1cSIngo Weinhold {
700f7a5d9c5SIngo Weinhold Clear();
701f7a5d9c5SIngo Weinhold }
702f7a5d9c5SIngo Weinhold
703f7a5d9c5SIngo Weinhold
704f7a5d9c5SIngo Weinhold void
Clear()705f7a5d9c5SIngo Weinhold TraceOutput::Clear()
706f7a5d9c5SIngo Weinhold {
707f7a5d9c5SIngo Weinhold if (fCapacity > 0)
708f7a5d9c5SIngo Weinhold fBuffer[0] = '\0';
709f7a5d9c5SIngo Weinhold fSize = 0;
710f1047a1cSIngo Weinhold }
711f1047a1cSIngo Weinhold
712f1047a1cSIngo Weinhold
713f1047a1cSIngo Weinhold void
PrintArgs(const char * format,va_list args)714328df922SIngo Weinhold TraceOutput::PrintArgs(const char* format, va_list args)
715f1047a1cSIngo Weinhold {
716b2d95c3cSIngo Weinhold #if ENABLE_TRACING
717f1047a1cSIngo Weinhold if (IsFull())
718f1047a1cSIngo Weinhold return;
719f1047a1cSIngo Weinhold
720328df922SIngo Weinhold size_t length = vsnprintf(fBuffer + fSize, fCapacity - fSize, format, args);
7213ce26345SIngo Weinhold fSize += std::min(length, fCapacity - fSize - 1);
722b2d95c3cSIngo Weinhold #endif
723f1047a1cSIngo Weinhold }
724f1047a1cSIngo Weinhold
725f1047a1cSIngo Weinhold
726350b6dbcSIngo Weinhold void
PrintStackTrace(tracing_stack_trace * stackTrace)72765f40152SIngo Weinhold TraceOutput::PrintStackTrace(tracing_stack_trace* stackTrace)
72865f40152SIngo Weinhold {
729b2d95c3cSIngo Weinhold #if ENABLE_TRACING
730328df922SIngo Weinhold print_stack_trace(stackTrace, TraceOutputPrint(*this));
731b2d95c3cSIngo Weinhold #endif
73265f40152SIngo Weinhold }
73365f40152SIngo Weinhold
73465f40152SIngo Weinhold
73565f40152SIngo Weinhold void
SetLastEntryTime(bigtime_t time)736350b6dbcSIngo Weinhold TraceOutput::SetLastEntryTime(bigtime_t time)
737350b6dbcSIngo Weinhold {
738350b6dbcSIngo Weinhold fLastEntryTime = time;
739350b6dbcSIngo Weinhold }
740350b6dbcSIngo Weinhold
741350b6dbcSIngo Weinhold
742350b6dbcSIngo Weinhold bigtime_t
LastEntryTime() const743350b6dbcSIngo Weinhold TraceOutput::LastEntryTime() const
744350b6dbcSIngo Weinhold {
745350b6dbcSIngo Weinhold return fLastEntryTime;
746350b6dbcSIngo Weinhold }
747350b6dbcSIngo Weinhold
748350b6dbcSIngo Weinhold
749f1047a1cSIngo Weinhold // #pragma mark -
750f1047a1cSIngo Weinhold
751f1047a1cSIngo Weinhold
TraceEntry()7528e43ece8SAxel Dörfler TraceEntry::TraceEntry()
7538e43ece8SAxel Dörfler {
7548e43ece8SAxel Dörfler }
7558e43ece8SAxel Dörfler
7568e43ece8SAxel Dörfler
~TraceEntry()7578e43ece8SAxel Dörfler TraceEntry::~TraceEntry()
7588e43ece8SAxel Dörfler {
7598e43ece8SAxel Dörfler }
7608e43ece8SAxel Dörfler
7618e43ece8SAxel Dörfler
7628e43ece8SAxel Dörfler void
Dump(TraceOutput & out)763f7a5d9c5SIngo Weinhold TraceEntry::Dump(TraceOutput& out)
7648e43ece8SAxel Dörfler {
7658e43ece8SAxel Dörfler #if ENABLE_TRACING
766f1047a1cSIngo Weinhold // to be overridden by subclasses
767f7a5d9c5SIngo Weinhold out.Print("ENTRY %p", this);
7688e43ece8SAxel Dörfler #endif
7698e43ece8SAxel Dörfler }
7708e43ece8SAxel Dörfler
7718e43ece8SAxel Dörfler
7728e43ece8SAxel Dörfler void
DumpStackTrace(TraceOutput & out)77365f40152SIngo Weinhold TraceEntry::DumpStackTrace(TraceOutput& out)
77465f40152SIngo Weinhold {
77565f40152SIngo Weinhold }
77665f40152SIngo Weinhold
77765f40152SIngo Weinhold
77865f40152SIngo Weinhold void
Initialized()7798e43ece8SAxel Dörfler TraceEntry::Initialized()
7808e43ece8SAxel Dörfler {
7818e43ece8SAxel Dörfler #if ENABLE_TRACING
782b3d6c12dSIngo Weinhold ToTraceEntry()->flags |= ENTRY_INITIALIZED;
7833fccf067SIngo Weinhold sTracingMetaData->IncrementEntriesEver();
7848e43ece8SAxel Dörfler #endif
7858e43ece8SAxel Dörfler }
7868e43ece8SAxel Dörfler
7878e43ece8SAxel Dörfler
7888e43ece8SAxel Dörfler void*
operator new(size_t size,const std::nothrow_t &)7898e43ece8SAxel Dörfler TraceEntry::operator new(size_t size, const std::nothrow_t&) throw()
7908e43ece8SAxel Dörfler {
7918e43ece8SAxel Dörfler #if ENABLE_TRACING
7923fccf067SIngo Weinhold trace_entry* entry = sTracingMetaData->AllocateEntry(
7933fccf067SIngo Weinhold size + sizeof(trace_entry), 0);
794b3d6c12dSIngo Weinhold return entry != NULL ? entry + 1 : NULL;
795aa5d2a2dSAxel Dörfler #endif
796989a6e05SIngo Weinhold return NULL;
797aa5d2a2dSAxel Dörfler }
798aa5d2a2dSAxel Dörfler
799aa5d2a2dSAxel Dörfler
800aa5d2a2dSAxel Dörfler // #pragma mark -
801aa5d2a2dSAxel Dörfler
802aa5d2a2dSAxel Dörfler
~AbstractTraceEntry()803f1047a1cSIngo Weinhold AbstractTraceEntry::~AbstractTraceEntry()
804f1047a1cSIngo Weinhold {
805f1047a1cSIngo Weinhold }
806f1047a1cSIngo Weinhold
807f1047a1cSIngo Weinhold
808f1047a1cSIngo Weinhold void
Dump(TraceOutput & out)809f7a5d9c5SIngo Weinhold AbstractTraceEntry::Dump(TraceOutput& out)
810f1047a1cSIngo Weinhold {
811350b6dbcSIngo Weinhold bigtime_t time = (out.Flags() & TRACE_OUTPUT_DIFF_TIME)
812350b6dbcSIngo Weinhold ? fTime - out.LastEntryTime()
813350b6dbcSIngo Weinhold : fTime;
814350b6dbcSIngo Weinhold
8154f78437cSAlex Smith if (out.Flags() & TRACE_OUTPUT_TEAM_ID) {
816294711f9SAlex Smith out.Print("[%6" B_PRId32 ":%6" B_PRId32 "] %10" B_PRId64 ": ", fThread,
817294711f9SAlex Smith fTeam, time);
8184f78437cSAlex Smith } else
819294711f9SAlex Smith out.Print("[%6" B_PRId32 "] %10" B_PRId64 ": ", fThread, time);
820350b6dbcSIngo Weinhold
821f1047a1cSIngo Weinhold AddDump(out);
822350b6dbcSIngo Weinhold
823350b6dbcSIngo Weinhold out.SetLastEntryTime(fTime);
824f1047a1cSIngo Weinhold }
825f1047a1cSIngo Weinhold
826f1047a1cSIngo Weinhold
827f1047a1cSIngo Weinhold void
AddDump(TraceOutput & out)828f1047a1cSIngo Weinhold AbstractTraceEntry::AddDump(TraceOutput& out)
829f1047a1cSIngo Weinhold {
830f1047a1cSIngo Weinhold }
831f1047a1cSIngo Weinhold
832f1047a1cSIngo Weinhold
833fe8f0f46SMichael Lotz void
_Init()834fe8f0f46SMichael Lotz AbstractTraceEntry::_Init()
835fe8f0f46SMichael Lotz {
836fe8f0f46SMichael Lotz Thread* thread = thread_get_current_thread();
837fe8f0f46SMichael Lotz if (thread != NULL) {
838fe8f0f46SMichael Lotz fThread = thread->id;
839fe8f0f46SMichael Lotz if (thread->team)
840fe8f0f46SMichael Lotz fTeam = thread->team->id;
841fe8f0f46SMichael Lotz }
842fe8f0f46SMichael Lotz fTime = system_time();
843fe8f0f46SMichael Lotz }
844fe8f0f46SMichael Lotz
845fe8f0f46SMichael Lotz
846fe8f0f46SMichael Lotz // #pragma mark - AbstractTraceEntryWithStackTrace
847fe8f0f46SMichael Lotz
848fe8f0f46SMichael Lotz
849fe8f0f46SMichael Lotz
AbstractTraceEntryWithStackTrace(size_t stackTraceDepth,size_t skipFrames,bool kernelOnly)850fe8f0f46SMichael Lotz AbstractTraceEntryWithStackTrace::AbstractTraceEntryWithStackTrace(
851fe8f0f46SMichael Lotz size_t stackTraceDepth, size_t skipFrames, bool kernelOnly)
852fe8f0f46SMichael Lotz {
853fe8f0f46SMichael Lotz fStackTrace = capture_tracing_stack_trace(stackTraceDepth, skipFrames + 1,
854fe8f0f46SMichael Lotz kernelOnly);
855fe8f0f46SMichael Lotz }
856fe8f0f46SMichael Lotz
857fe8f0f46SMichael Lotz
858fe8f0f46SMichael Lotz void
DumpStackTrace(TraceOutput & out)859fe8f0f46SMichael Lotz AbstractTraceEntryWithStackTrace::DumpStackTrace(TraceOutput& out)
860fe8f0f46SMichael Lotz {
861fe8f0f46SMichael Lotz out.PrintStackTrace(fStackTrace);
862fe8f0f46SMichael Lotz }
863fe8f0f46SMichael Lotz
864fe8f0f46SMichael Lotz
865a54c125eSIngo Weinhold // #pragma mark -
866a54c125eSIngo Weinhold
867a54c125eSIngo Weinhold
868a54c125eSIngo Weinhold #if ENABLE_TRACING
869a54c125eSIngo Weinhold
8707d2d758dSIngo Weinhold class KernelTraceEntry : public AbstractTraceEntry {
8717d2d758dSIngo Weinhold public:
KernelTraceEntry(const char * message)8727d2d758dSIngo Weinhold KernelTraceEntry(const char* message)
8737d2d758dSIngo Weinhold {
8747d2d758dSIngo Weinhold fMessage = alloc_tracing_buffer_strcpy(message, 256, false);
8757d2d758dSIngo Weinhold
876b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE
877b3d6c12dSIngo Weinhold fStackTrace = capture_tracing_stack_trace(
878b3d6c12dSIngo Weinhold KTRACE_PRINTF_STACK_TRACE, 1, false);
879b3d6c12dSIngo Weinhold #endif
8807d2d758dSIngo Weinhold Initialized();
8817d2d758dSIngo Weinhold }
8827d2d758dSIngo Weinhold
AddDump(TraceOutput & out)8837d2d758dSIngo Weinhold virtual void AddDump(TraceOutput& out)
8847d2d758dSIngo Weinhold {
8857d2d758dSIngo Weinhold out.Print("kern: %s", fMessage);
8867d2d758dSIngo Weinhold }
8877d2d758dSIngo Weinhold
888b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE
DumpStackTrace(TraceOutput & out)889b3d6c12dSIngo Weinhold virtual void DumpStackTrace(TraceOutput& out)
890b3d6c12dSIngo Weinhold {
891b3d6c12dSIngo Weinhold out.PrintStackTrace(fStackTrace);
892b3d6c12dSIngo Weinhold }
893b3d6c12dSIngo Weinhold #endif
894b3d6c12dSIngo Weinhold
8957d2d758dSIngo Weinhold private:
8967d2d758dSIngo Weinhold char* fMessage;
897b3d6c12dSIngo Weinhold #if KTRACE_PRINTF_STACK_TRACE
898b3d6c12dSIngo Weinhold tracing_stack_trace* fStackTrace;
899b3d6c12dSIngo Weinhold #endif
9007d2d758dSIngo Weinhold };
9017d2d758dSIngo Weinhold
9027d2d758dSIngo Weinhold
903a54c125eSIngo Weinhold class UserTraceEntry : public AbstractTraceEntry {
904a54c125eSIngo Weinhold public:
UserTraceEntry(const char * message)905a54c125eSIngo Weinhold UserTraceEntry(const char* message)
906a54c125eSIngo Weinhold {
907a54c125eSIngo Weinhold fMessage = alloc_tracing_buffer_strcpy(message, 256, true);
908a54c125eSIngo Weinhold
909bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE
910bc6a5f86SOliver Tappe fStackTrace = capture_tracing_stack_trace(
911bc6a5f86SOliver Tappe KTRACE_PRINTF_STACK_TRACE, 1, false);
912bc6a5f86SOliver Tappe #endif
913a54c125eSIngo Weinhold Initialized();
914a54c125eSIngo Weinhold }
915a54c125eSIngo Weinhold
AddDump(TraceOutput & out)916a54c125eSIngo Weinhold virtual void AddDump(TraceOutput& out)
917a54c125eSIngo Weinhold {
918a54c125eSIngo Weinhold out.Print("user: %s", fMessage);
919a54c125eSIngo Weinhold }
920a54c125eSIngo Weinhold
921bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE
DumpStackTrace(TraceOutput & out)922bc6a5f86SOliver Tappe virtual void DumpStackTrace(TraceOutput& out)
923bc6a5f86SOliver Tappe {
924bc6a5f86SOliver Tappe out.PrintStackTrace(fStackTrace);
925bc6a5f86SOliver Tappe }
926bc6a5f86SOliver Tappe #endif
927bc6a5f86SOliver Tappe
928a54c125eSIngo Weinhold private:
929a54c125eSIngo Weinhold char* fMessage;
930bc6a5f86SOliver Tappe #if KTRACE_PRINTF_STACK_TRACE
931bc6a5f86SOliver Tappe tracing_stack_trace* fStackTrace;
932bc6a5f86SOliver Tappe #endif
933a54c125eSIngo Weinhold };
934a54c125eSIngo Weinhold
935d829579dSIngo Weinhold
936d829579dSIngo Weinhold class TracingLogStartEntry : public AbstractTraceEntry {
937d829579dSIngo Weinhold public:
TracingLogStartEntry()938d829579dSIngo Weinhold TracingLogStartEntry()
939d829579dSIngo Weinhold {
940d829579dSIngo Weinhold Initialized();
941d829579dSIngo Weinhold }
942d829579dSIngo Weinhold
AddDump(TraceOutput & out)943d829579dSIngo Weinhold virtual void AddDump(TraceOutput& out)
944d829579dSIngo Weinhold {
945d829579dSIngo Weinhold out.Print("ktrace start");
946d829579dSIngo Weinhold }
947d829579dSIngo Weinhold };
948d829579dSIngo Weinhold
949a54c125eSIngo Weinhold #endif // ENABLE_TRACING
950a54c125eSIngo Weinhold
951a54c125eSIngo Weinhold
9524c4b14c3SIngo Weinhold // #pragma mark - trace filters
9534c4b14c3SIngo Weinhold
9544c4b14c3SIngo Weinhold
~TraceFilter()955f97199edSIngo Weinhold TraceFilter::~TraceFilter()
9564c4b14c3SIngo Weinhold {
9574c4b14c3SIngo Weinhold }
9584c4b14c3SIngo Weinhold
9594c4b14c3SIngo Weinhold
960f97199edSIngo Weinhold bool
Filter(const TraceEntry * entry,LazyTraceOutput & out)961f97199edSIngo Weinhold TraceFilter::Filter(const TraceEntry* entry, LazyTraceOutput& out)
9624c4b14c3SIngo Weinhold {
9634c4b14c3SIngo Weinhold return false;
9644c4b14c3SIngo Weinhold }
9654c4b14c3SIngo Weinhold
9664c4b14c3SIngo Weinhold
9674c4b14c3SIngo Weinhold
9684c4b14c3SIngo Weinhold class ThreadTraceFilter : public TraceFilter {
9694c4b14c3SIngo Weinhold public:
Filter(const TraceEntry * _entry,LazyTraceOutput & out)9704c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out)
9714c4b14c3SIngo Weinhold {
9724c4b14c3SIngo Weinhold const AbstractTraceEntry* entry
9734c4b14c3SIngo Weinhold = dynamic_cast<const AbstractTraceEntry*>(_entry);
9744535495dSIngo Weinhold return (entry != NULL && entry->ThreadID() == fThread);
9754c4b14c3SIngo Weinhold }
9764c4b14c3SIngo Weinhold };
9774c4b14c3SIngo Weinhold
9784c4b14c3SIngo Weinhold
97964fe37eeSIngo Weinhold class TeamTraceFilter : public TraceFilter {
98064fe37eeSIngo Weinhold public:
Filter(const TraceEntry * _entry,LazyTraceOutput & out)98164fe37eeSIngo Weinhold virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out)
98264fe37eeSIngo Weinhold {
98364fe37eeSIngo Weinhold const AbstractTraceEntry* entry
98464fe37eeSIngo Weinhold = dynamic_cast<const AbstractTraceEntry*>(_entry);
9854535495dSIngo Weinhold return (entry != NULL && entry->TeamID() == fTeam);
98664fe37eeSIngo Weinhold }
98764fe37eeSIngo Weinhold };
98864fe37eeSIngo Weinhold
98964fe37eeSIngo Weinhold
9904c4b14c3SIngo Weinhold class PatternTraceFilter : public TraceFilter {
9914c4b14c3SIngo Weinhold public:
Filter(const TraceEntry * entry,LazyTraceOutput & out)9924c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
9934c4b14c3SIngo Weinhold {
9944c4b14c3SIngo Weinhold return strstr(out.DumpEntry(entry), fString) != NULL;
9954c4b14c3SIngo Weinhold }
9964c4b14c3SIngo Weinhold };
9974c4b14c3SIngo Weinhold
9984c4b14c3SIngo Weinhold
999dc1a7867SAxel Dörfler class DecimalPatternTraceFilter : public TraceFilter {
1000dc1a7867SAxel Dörfler public:
Filter(const TraceEntry * entry,LazyTraceOutput & out)1001dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
1002dc1a7867SAxel Dörfler {
1003dc1a7867SAxel Dörfler // TODO: this is *very* slow
1004dc1a7867SAxel Dörfler char buffer[64];
1005294711f9SAlex Smith snprintf(buffer, sizeof(buffer), "%" B_PRId64, fValue);
1006dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL;
1007dc1a7867SAxel Dörfler }
1008dc1a7867SAxel Dörfler };
1009dc1a7867SAxel Dörfler
1010dc1a7867SAxel Dörfler class HexPatternTraceFilter : public TraceFilter {
1011dc1a7867SAxel Dörfler public:
Filter(const TraceEntry * entry,LazyTraceOutput & out)1012dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
1013dc1a7867SAxel Dörfler {
1014dc1a7867SAxel Dörfler // TODO: this is *very* slow
1015dc1a7867SAxel Dörfler char buffer[64];
1016294711f9SAlex Smith snprintf(buffer, sizeof(buffer), "%" B_PRIx64, fValue);
1017dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL;
1018dc1a7867SAxel Dörfler }
1019dc1a7867SAxel Dörfler };
1020dc1a7867SAxel Dörfler
1021dc1a7867SAxel Dörfler class StringPatternTraceFilter : public TraceFilter {
1022dc1a7867SAxel Dörfler public:
Filter(const TraceEntry * entry,LazyTraceOutput & out)1023dc1a7867SAxel Dörfler virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
1024dc1a7867SAxel Dörfler {
1025dc1a7867SAxel Dörfler if (IS_KERNEL_ADDRESS(fValue))
1026dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), (const char*)fValue) != NULL;
1027dc1a7867SAxel Dörfler
1028dc1a7867SAxel Dörfler // TODO: this is *very* slow
1029dc1a7867SAxel Dörfler char buffer[64];
1030dc1a7867SAxel Dörfler user_strlcpy(buffer, (const char*)fValue, sizeof(buffer));
1031dc1a7867SAxel Dörfler return strstr(out.DumpEntry(entry), buffer) != NULL;
1032dc1a7867SAxel Dörfler }
1033dc1a7867SAxel Dörfler };
1034dc1a7867SAxel Dörfler
10354c4b14c3SIngo Weinhold class NotTraceFilter : public TraceFilter {
10364c4b14c3SIngo Weinhold public:
Filter(const TraceEntry * entry,LazyTraceOutput & out)10374c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
10384c4b14c3SIngo Weinhold {
10394c4b14c3SIngo Weinhold return !fSubFilters.first->Filter(entry, out);
10404c4b14c3SIngo Weinhold }
10414c4b14c3SIngo Weinhold };
10424c4b14c3SIngo Weinhold
10434c4b14c3SIngo Weinhold
10444c4b14c3SIngo Weinhold class AndTraceFilter : public TraceFilter {
10454c4b14c3SIngo Weinhold public:
Filter(const TraceEntry * entry,LazyTraceOutput & out)10464c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
10474c4b14c3SIngo Weinhold {
10484c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out)
10494c4b14c3SIngo Weinhold && fSubFilters.second->Filter(entry, out);
10504c4b14c3SIngo Weinhold }
10514c4b14c3SIngo Weinhold };
10524c4b14c3SIngo Weinhold
10534c4b14c3SIngo Weinhold
10544c4b14c3SIngo Weinhold class OrTraceFilter : public TraceFilter {
10554c4b14c3SIngo Weinhold public:
Filter(const TraceEntry * entry,LazyTraceOutput & out)10564c4b14c3SIngo Weinhold virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
10574c4b14c3SIngo Weinhold {
10584c4b14c3SIngo Weinhold return fSubFilters.first->Filter(entry, out)
10594c4b14c3SIngo Weinhold || fSubFilters.second->Filter(entry, out);
10604c4b14c3SIngo Weinhold }
10614c4b14c3SIngo Weinhold };
10624c4b14c3SIngo Weinhold
10634c4b14c3SIngo Weinhold
10644c4b14c3SIngo Weinhold class TraceFilterParser {
10654c4b14c3SIngo Weinhold public:
Default()10664c4b14c3SIngo Weinhold static TraceFilterParser* Default()
10674c4b14c3SIngo Weinhold {
10684c4b14c3SIngo Weinhold return &sParser;
10694c4b14c3SIngo Weinhold }
10704c4b14c3SIngo Weinhold
Parse(int argc,const char * const * argv)10714c4b14c3SIngo Weinhold bool Parse(int argc, const char* const* argv)
10724c4b14c3SIngo Weinhold {
10734c4b14c3SIngo Weinhold fTokens = argv;
10744c4b14c3SIngo Weinhold fTokenCount = argc;
10754c4b14c3SIngo Weinhold fTokenIndex = 0;
10764c4b14c3SIngo Weinhold fFilterCount = 0;
10774c4b14c3SIngo Weinhold
10784c4b14c3SIngo Weinhold TraceFilter* filter = _ParseExpression();
10794c4b14c3SIngo Weinhold return fTokenIndex == fTokenCount && filter != NULL;
10804c4b14c3SIngo Weinhold }
10814c4b14c3SIngo Weinhold
Filter()1082f97199edSIngo Weinhold TraceFilter* Filter()
10834c4b14c3SIngo Weinhold {
1084f97199edSIngo Weinhold return &fFilters[0];
10854c4b14c3SIngo Weinhold }
10864c4b14c3SIngo Weinhold
10874c4b14c3SIngo Weinhold private:
_ParseExpression()10884c4b14c3SIngo Weinhold TraceFilter* _ParseExpression()
10894c4b14c3SIngo Weinhold {
10904c4b14c3SIngo Weinhold const char* token = _NextToken();
10914c4b14c3SIngo Weinhold if (!token) {
10924c4b14c3SIngo Weinhold // unexpected end of expression
10934c4b14c3SIngo Weinhold return NULL;
10944c4b14c3SIngo Weinhold }
10954c4b14c3SIngo Weinhold
10964c4b14c3SIngo Weinhold if (fFilterCount == MAX_FILTERS) {
10974c4b14c3SIngo Weinhold // too many filters
10984c4b14c3SIngo Weinhold return NULL;
10994c4b14c3SIngo Weinhold }
11004c4b14c3SIngo Weinhold
11014c4b14c3SIngo Weinhold if (token[0] == '#') {
11024c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++])
11034c4b14c3SIngo Weinhold PatternTraceFilter;
11044c4b14c3SIngo Weinhold filter->fString = token + 1;
11054c4b14c3SIngo Weinhold return filter;
1106dc1a7867SAxel Dörfler } else if (token[0] == 'd' && token[1] == '#') {
1107dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++])
1108dc1a7867SAxel Dörfler DecimalPatternTraceFilter;
1109dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2);
1110dc1a7867SAxel Dörfler return filter;
1111dc1a7867SAxel Dörfler } else if (token[0] == 'x' && token[1] == '#') {
1112dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++])
1113dc1a7867SAxel Dörfler HexPatternTraceFilter;
1114dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2);
1115dc1a7867SAxel Dörfler return filter;
1116dc1a7867SAxel Dörfler } else if (token[0] == 's' && token[1] == '#') {
1117dc1a7867SAxel Dörfler TraceFilter* filter = new(&fFilters[fFilterCount++])
1118dc1a7867SAxel Dörfler StringPatternTraceFilter;
1119dc1a7867SAxel Dörfler filter->fValue = parse_expression(token + 2);
1120dc1a7867SAxel Dörfler return filter;
11214c4b14c3SIngo Weinhold } else if (strcmp(token, "not") == 0) {
11224c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) NotTraceFilter;
11234c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL)
11244c4b14c3SIngo Weinhold return filter;
1125*40ee778cSRob Gill delete(filter);
11264c4b14c3SIngo Weinhold return NULL;
11274c4b14c3SIngo Weinhold } else if (strcmp(token, "and") == 0) {
11284c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) AndTraceFilter;
11294c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL
11304c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) {
11314c4b14c3SIngo Weinhold return filter;
11324c4b14c3SIngo Weinhold }
1133*40ee778cSRob Gill delete(filter);
11344c4b14c3SIngo Weinhold return NULL;
11354c4b14c3SIngo Weinhold } else if (strcmp(token, "or") == 0) {
11364c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++]) OrTraceFilter;
11374c4b14c3SIngo Weinhold if ((filter->fSubFilters.first = _ParseExpression()) != NULL
11384c4b14c3SIngo Weinhold && (filter->fSubFilters.second = _ParseExpression()) != NULL) {
11394c4b14c3SIngo Weinhold return filter;
11404c4b14c3SIngo Weinhold }
1141*40ee778cSRob Gill delete(filter);
11424c4b14c3SIngo Weinhold return NULL;
11434c4b14c3SIngo Weinhold } else if (strcmp(token, "thread") == 0) {
11444c4b14c3SIngo Weinhold const char* arg = _NextToken();
11454c4b14c3SIngo Weinhold if (arg == NULL) {
11464c4b14c3SIngo Weinhold // unexpected end of expression
11474c4b14c3SIngo Weinhold return NULL;
11484c4b14c3SIngo Weinhold }
11494c4b14c3SIngo Weinhold
11504c4b14c3SIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++])
11514c4b14c3SIngo Weinhold ThreadTraceFilter;
11524c4b14c3SIngo Weinhold filter->fThread = strtol(arg, NULL, 0);
11534c4b14c3SIngo Weinhold return filter;
115464fe37eeSIngo Weinhold } else if (strcmp(token, "team") == 0) {
115564fe37eeSIngo Weinhold const char* arg = _NextToken();
115664fe37eeSIngo Weinhold if (arg == NULL) {
115764fe37eeSIngo Weinhold // unexpected end of expression
115864fe37eeSIngo Weinhold return NULL;
115964fe37eeSIngo Weinhold }
116064fe37eeSIngo Weinhold
116164fe37eeSIngo Weinhold TraceFilter* filter = new(&fFilters[fFilterCount++])
116264fe37eeSIngo Weinhold TeamTraceFilter;
116364fe37eeSIngo Weinhold filter->fTeam = strtol(arg, NULL, 0);
116464fe37eeSIngo Weinhold return filter;
11654c4b14c3SIngo Weinhold } else {
11664c4b14c3SIngo Weinhold // invalid token
11674c4b14c3SIngo Weinhold return NULL;
11684c4b14c3SIngo Weinhold }
11694c4b14c3SIngo Weinhold }
11704c4b14c3SIngo Weinhold
_CurrentToken() const11714c4b14c3SIngo Weinhold const char* _CurrentToken() const
11724c4b14c3SIngo Weinhold {
11734c4b14c3SIngo Weinhold if (fTokenIndex >= 1 && fTokenIndex <= fTokenCount)
11744c4b14c3SIngo Weinhold return fTokens[fTokenIndex - 1];
11754c4b14c3SIngo Weinhold return NULL;
11764c4b14c3SIngo Weinhold }
11774c4b14c3SIngo Weinhold
_NextToken()11784c4b14c3SIngo Weinhold const char* _NextToken()
11794c4b14c3SIngo Weinhold {
11804c4b14c3SIngo Weinhold if (fTokenIndex >= fTokenCount)
11814c4b14c3SIngo Weinhold return NULL;
11824c4b14c3SIngo Weinhold return fTokens[fTokenIndex++];
11834c4b14c3SIngo Weinhold }
11844c4b14c3SIngo Weinhold
11854c4b14c3SIngo Weinhold private:
11864c4b14c3SIngo Weinhold enum { MAX_FILTERS = 32 };
11874c4b14c3SIngo Weinhold
11884c4b14c3SIngo Weinhold const char* const* fTokens;
11894c4b14c3SIngo Weinhold int fTokenCount;
11904c4b14c3SIngo Weinhold int fTokenIndex;
11914c4b14c3SIngo Weinhold TraceFilter fFilters[MAX_FILTERS];
11924c4b14c3SIngo Weinhold int fFilterCount;
11934c4b14c3SIngo Weinhold
11944c4b14c3SIngo Weinhold static TraceFilterParser sParser;
11954c4b14c3SIngo Weinhold };
11964c4b14c3SIngo Weinhold
11974c4b14c3SIngo Weinhold
11984c4b14c3SIngo Weinhold TraceFilterParser TraceFilterParser::sParser;
11994c4b14c3SIngo Weinhold
12004c4b14c3SIngo Weinhold
1201f1047a1cSIngo Weinhold // #pragma mark -
1202f1047a1cSIngo Weinhold
1203f1047a1cSIngo Weinhold
1204aa5d2a2dSAxel Dörfler #if ENABLE_TRACING
1205aa5d2a2dSAxel Dörfler
1206aa5d2a2dSAxel Dörfler
1207ef7102faSIngo Weinhold TraceEntry*
Next()1208ef7102faSIngo Weinhold TraceEntryIterator::Next()
12096d369966SIngo Weinhold {
12106d369966SIngo Weinhold if (fIndex == 0) {
12113fccf067SIngo Weinhold fEntry = _NextNonBufferEntry(sTracingMetaData->FirstEntry());
12126d369966SIngo Weinhold fIndex = 1;
12136d369966SIngo Weinhold } else if (fEntry != NULL) {
12143fccf067SIngo Weinhold fEntry = _NextNonBufferEntry(sTracingMetaData->NextEntry(fEntry));
12156d369966SIngo Weinhold fIndex++;
12166d369966SIngo Weinhold }
12176d369966SIngo Weinhold
12186d369966SIngo Weinhold return Current();
12196d369966SIngo Weinhold }
12206d369966SIngo Weinhold
1221ef7102faSIngo Weinhold
1222ef7102faSIngo Weinhold TraceEntry*
Previous()1223ef7102faSIngo Weinhold TraceEntryIterator::Previous()
12246d369966SIngo Weinhold {
12253fccf067SIngo Weinhold if (fIndex == (int32)sTracingMetaData->Entries() + 1)
12263fccf067SIngo Weinhold fEntry = sTracingMetaData->AfterLastEntry();
12276d369966SIngo Weinhold
12286d369966SIngo Weinhold if (fEntry != NULL) {
12293fccf067SIngo Weinhold fEntry = _PreviousNonBufferEntry(
12303fccf067SIngo Weinhold sTracingMetaData->PreviousEntry(fEntry));
12316d369966SIngo Weinhold fIndex--;
12326d369966SIngo Weinhold }
12336d369966SIngo Weinhold
12346d369966SIngo Weinhold return Current();
12356d369966SIngo Weinhold }
12366d369966SIngo Weinhold
1237ef7102faSIngo Weinhold
1238ef7102faSIngo Weinhold TraceEntry*
MoveTo(int32 index)1239ef7102faSIngo Weinhold TraceEntryIterator::MoveTo(int32 index)
12406d369966SIngo Weinhold {
12416d369966SIngo Weinhold if (index == fIndex)
12426d369966SIngo Weinhold return Current();
12436d369966SIngo Weinhold
12443fccf067SIngo Weinhold if (index <= 0 || index > (int32)sTracingMetaData->Entries()) {
12453fccf067SIngo Weinhold fIndex = (index <= 0 ? 0 : sTracingMetaData->Entries() + 1);
12466d369966SIngo Weinhold fEntry = NULL;
12476d369966SIngo Weinhold return NULL;
12486d369966SIngo Weinhold }
12496d369966SIngo Weinhold
12506d369966SIngo Weinhold // get the shortest iteration path
12516d369966SIngo Weinhold int32 distance = index - fIndex;
12526d369966SIngo Weinhold int32 direction = distance < 0 ? -1 : 1;
12536d369966SIngo Weinhold distance *= direction;
12546d369966SIngo Weinhold
12556d369966SIngo Weinhold if (index < distance) {
12566d369966SIngo Weinhold distance = index;
12576d369966SIngo Weinhold direction = 1;
12586d369966SIngo Weinhold fEntry = NULL;
12596d369966SIngo Weinhold fIndex = 0;
12606d369966SIngo Weinhold }
12613fccf067SIngo Weinhold if ((int32)sTracingMetaData->Entries() + 1 - fIndex < distance) {
12623fccf067SIngo Weinhold distance = sTracingMetaData->Entries() + 1 - fIndex;
12636d369966SIngo Weinhold direction = -1;
12646d369966SIngo Weinhold fEntry = NULL;
12653fccf067SIngo Weinhold fIndex = sTracingMetaData->Entries() + 1;
12666d369966SIngo Weinhold }
12676d369966SIngo Weinhold
12686d369966SIngo Weinhold // iterate to the index
12696d369966SIngo Weinhold if (direction < 0) {
12706d369966SIngo Weinhold while (fIndex != index)
12716d369966SIngo Weinhold Previous();
12726d369966SIngo Weinhold } else {
12736d369966SIngo Weinhold while (fIndex != index)
12746d369966SIngo Weinhold Next();
12756d369966SIngo Weinhold }
12766d369966SIngo Weinhold
12776d369966SIngo Weinhold return Current();
12786d369966SIngo Weinhold }
12796d369966SIngo Weinhold
1280ef7102faSIngo Weinhold
1281ef7102faSIngo Weinhold trace_entry*
_NextNonBufferEntry(trace_entry * entry)1282ef7102faSIngo Weinhold TraceEntryIterator::_NextNonBufferEntry(trace_entry* entry)
12836d369966SIngo Weinhold {
12846d369966SIngo Weinhold while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0)
12853fccf067SIngo Weinhold entry = sTracingMetaData->NextEntry(entry);
12866d369966SIngo Weinhold
12876d369966SIngo Weinhold return entry;
12886d369966SIngo Weinhold }
12896d369966SIngo Weinhold
1290ef7102faSIngo Weinhold
1291ef7102faSIngo Weinhold trace_entry*
_PreviousNonBufferEntry(trace_entry * entry)1292ef7102faSIngo Weinhold TraceEntryIterator::_PreviousNonBufferEntry(trace_entry* entry)
12936d369966SIngo Weinhold {
12946d369966SIngo Weinhold while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0)
12953fccf067SIngo Weinhold entry = sTracingMetaData->PreviousEntry(entry);
12966d369966SIngo Weinhold
12976d369966SIngo Weinhold return entry;
12986d369966SIngo Weinhold }
12996d369966SIngo Weinhold
13006d369966SIngo Weinhold
1301aa5d2a2dSAxel Dörfler int
dump_tracing_internal(int argc,char ** argv,WrapperTraceFilter * wrapperFilter)1302f97199edSIngo Weinhold dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
1303aa5d2a2dSAxel Dörfler {
13044c4b14c3SIngo Weinhold int argi = 1;
13058e43ece8SAxel Dörfler
13066d369966SIngo Weinhold // variables in which we store our state to be continuable
13076d369966SIngo Weinhold static int32 _previousCount = 0;
13086d369966SIngo Weinhold static bool _previousHasFilter = false;
130965f40152SIngo Weinhold static bool _previousPrintStackTrace = false;
13106d369966SIngo Weinhold static int32 _previousMaxToCheck = 0;
13116d369966SIngo Weinhold static int32 _previousFirstChecked = 1;
13126d369966SIngo Weinhold static int32 _previousLastChecked = -1;
13135fa74667SIngo Weinhold static int32 _previousDirection = 1;
13143fccf067SIngo Weinhold static uint32 _previousEntriesEver = 0;
131556213ff4SIngo Weinhold static uint32 _previousEntries = 0;
1316350b6dbcSIngo Weinhold static uint32 _previousOutputFlags = 0;
131756213ff4SIngo Weinhold static TraceEntryIterator iterator;
131856213ff4SIngo Weinhold
13193fccf067SIngo Weinhold uint32 entriesEver = sTracingMetaData->EntriesEver();
13203fccf067SIngo Weinhold
1321d829579dSIngo Weinhold // Note: start and index are Pascal-like indices (i.e. in [1, Entries()]).
132274652349SIngo Weinhold int32 start = 0; // special index: print the last count entries
13236d369966SIngo Weinhold int32 count = 0;
13246d369966SIngo Weinhold int32 maxToCheck = 0;
132574652349SIngo Weinhold int32 cont = 0;
1326aa5d2a2dSAxel Dörfler
13274c4b14c3SIngo Weinhold bool hasFilter = false;
132865f40152SIngo Weinhold bool printStackTrace = false;
13294c4b14c3SIngo Weinhold
1330350b6dbcSIngo Weinhold uint32 outputFlags = 0;
1331350b6dbcSIngo Weinhold while (argi < argc) {
133265f40152SIngo Weinhold if (strcmp(argv[argi], "--difftime") == 0) {
133365f40152SIngo Weinhold outputFlags |= TRACE_OUTPUT_DIFF_TIME;
133465f40152SIngo Weinhold argi++;
133565f40152SIngo Weinhold } else if (strcmp(argv[argi], "--printteam") == 0) {
1336350b6dbcSIngo Weinhold outputFlags |= TRACE_OUTPUT_TEAM_ID;
133764fe37eeSIngo Weinhold argi++;
133865f40152SIngo Weinhold } else if (strcmp(argv[argi], "--stacktrace") == 0) {
133965f40152SIngo Weinhold printStackTrace = true;
1340350b6dbcSIngo Weinhold argi++;
1341350b6dbcSIngo Weinhold } else
1342350b6dbcSIngo Weinhold break;
134364fe37eeSIngo Weinhold }
134464fe37eeSIngo Weinhold
13454c4b14c3SIngo Weinhold if (argi < argc) {
13464c4b14c3SIngo Weinhold if (strcmp(argv[argi], "forward") == 0) {
134774652349SIngo Weinhold cont = 1;
13484c4b14c3SIngo Weinhold argi++;
13494c4b14c3SIngo Weinhold } else if (strcmp(argv[argi], "backward") == 0) {
135074652349SIngo Weinhold cont = -1;
13514c4b14c3SIngo Weinhold argi++;
13524c4b14c3SIngo Weinhold }
13535fa74667SIngo Weinhold } else
13545fa74667SIngo Weinhold cont = _previousDirection;
13552d81f045SAxel Dörfler
13566d369966SIngo Weinhold if (cont != 0) {
13576d369966SIngo Weinhold if (argi < argc) {
1358a7e979caSIngo Weinhold print_debugger_command_usage(argv[0]);
1359aa5d2a2dSAxel Dörfler return 0;
1360aa5d2a2dSAxel Dörfler }
13613fccf067SIngo Weinhold if (entriesEver == 0 || entriesEver != _previousEntriesEver
13623fccf067SIngo Weinhold || sTracingMetaData->Entries() != _previousEntries) {
13636d369966SIngo Weinhold kprintf("Can't continue iteration. \"%s\" has not been invoked "
13646d369966SIngo Weinhold "before, or there were new entries written since the last "
13656d369966SIngo Weinhold "invocation.\n", argv[0]);
13666d369966SIngo Weinhold return 0;
13676d369966SIngo Weinhold }
13686d369966SIngo Weinhold }
1369aa5d2a2dSAxel Dörfler
13706d369966SIngo Weinhold // get start, count, maxToCheck
13716d369966SIngo Weinhold int32* params[3] = { &start, &count, &maxToCheck };
13726d369966SIngo Weinhold for (int i = 0; i < 3 && !hasFilter && argi < argc; i++) {
13734c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0) {
13744c4b14c3SIngo Weinhold hasFilter = true;
13754c4b14c3SIngo Weinhold argi++;
13764c4b14c3SIngo Weinhold } else if (argv[argi][0] == '#') {
13774c4b14c3SIngo Weinhold hasFilter = true;
13784c4b14c3SIngo Weinhold } else {
13796d369966SIngo Weinhold *params[i] = parse_expression(argv[argi]);
13804c4b14c3SIngo Weinhold argi++;
13814c4b14c3SIngo Weinhold }
13824c4b14c3SIngo Weinhold }
13834c4b14c3SIngo Weinhold
13844c4b14c3SIngo Weinhold // filter specification
13854c4b14c3SIngo Weinhold if (argi < argc) {
13864c4b14c3SIngo Weinhold hasFilter = true;
13874c4b14c3SIngo Weinhold if (strcmp(argv[argi], "filter") == 0)
13884c4b14c3SIngo Weinhold argi++;
13894c4b14c3SIngo Weinhold
13904c4b14c3SIngo Weinhold if (!TraceFilterParser::Default()->Parse(argc - argi, argv + argi)) {
13914c4b14c3SIngo Weinhold print_debugger_command_usage(argv[0]);
13924c4b14c3SIngo Weinhold return 0;
13934c4b14c3SIngo Weinhold }
13944c4b14c3SIngo Weinhold }
13954c4b14c3SIngo Weinhold
13966d369966SIngo Weinhold int32 direction;
13976d369966SIngo Weinhold int32 firstToCheck;
13986d369966SIngo Weinhold int32 lastToCheck;
13996d369966SIngo Weinhold
140074652349SIngo Weinhold if (cont != 0) {
14016d369966SIngo Weinhold // get values from the previous iteration
14026d369966SIngo Weinhold direction = cont;
14036d369966SIngo Weinhold count = _previousCount;
14046d369966SIngo Weinhold maxToCheck = _previousMaxToCheck;
14056d369966SIngo Weinhold hasFilter = _previousHasFilter;
1406350b6dbcSIngo Weinhold outputFlags = _previousOutputFlags;
140765f40152SIngo Weinhold printStackTrace = _previousPrintStackTrace;
14086d369966SIngo Weinhold
14096d369966SIngo Weinhold if (direction < 0)
14106d369966SIngo Weinhold start = _previousFirstChecked - 1;
14116d369966SIngo Weinhold else
14126d369966SIngo Weinhold start = _previousLastChecked + 1;
14136d369966SIngo Weinhold } else {
14146d369966SIngo Weinhold // defaults for count and maxToCheck
14156d369966SIngo Weinhold if (count == 0)
14166d369966SIngo Weinhold count = 30;
14176d369966SIngo Weinhold if (maxToCheck == 0 || !hasFilter)
14186d369966SIngo Weinhold maxToCheck = count;
14196d369966SIngo Weinhold else if (maxToCheck < 0)
14203fccf067SIngo Weinhold maxToCheck = sTracingMetaData->Entries();
14216d369966SIngo Weinhold
14226d369966SIngo Weinhold // determine iteration direction
14236d369966SIngo Weinhold direction = (start <= 0 || count < 0 ? -1 : 1);
14246d369966SIngo Weinhold
14256d369966SIngo Weinhold // validate count and maxToCheck
14266d369966SIngo Weinhold if (count < 0)
14276d369966SIngo Weinhold count = -count;
14286d369966SIngo Weinhold if (maxToCheck < 0)
14296d369966SIngo Weinhold maxToCheck = -maxToCheck;
14303fccf067SIngo Weinhold if (maxToCheck > (int32)sTracingMetaData->Entries())
14313fccf067SIngo Weinhold maxToCheck = sTracingMetaData->Entries();
14326d369966SIngo Weinhold if (count > maxToCheck)
14336d369966SIngo Weinhold count = maxToCheck;
14346d369966SIngo Weinhold
14356d369966SIngo Weinhold // validate start
14363fccf067SIngo Weinhold if (start <= 0 || start > (int32)sTracingMetaData->Entries())
14373fccf067SIngo Weinhold start = max_c(1, sTracingMetaData->Entries());
143874652349SIngo Weinhold }
1439aa5d2a2dSAxel Dörfler
14406d369966SIngo Weinhold if (direction < 0) {
14416d369966SIngo Weinhold firstToCheck = max_c(1, start - maxToCheck + 1);
14426d369966SIngo Weinhold lastToCheck = start;
14436d369966SIngo Weinhold } else {
14446d369966SIngo Weinhold firstToCheck = start;
14453fccf067SIngo Weinhold lastToCheck = min_c((int32)sTracingMetaData->Entries(),
14463fccf067SIngo Weinhold start + maxToCheck - 1);
14478e43ece8SAxel Dörfler }
1448aa5d2a2dSAxel Dörfler
144956213ff4SIngo Weinhold // reset the iterator, if something changed in the meantime
14503fccf067SIngo Weinhold if (entriesEver == 0 || entriesEver != _previousEntriesEver
14513fccf067SIngo Weinhold || sTracingMetaData->Entries() != _previousEntries) {
145256213ff4SIngo Weinhold iterator.Reset();
145356213ff4SIngo Weinhold }
14546d369966SIngo Weinhold
14553fccf067SIngo Weinhold LazyTraceOutput out(sTracingMetaData->TraceOutputBuffer(),
1456d829579dSIngo Weinhold kTraceOutputBufferSize, outputFlags);
1457f7a5d9c5SIngo Weinhold
145856213ff4SIngo Weinhold bool markedMatching = false;
145956213ff4SIngo Weinhold int32 firstToDump = firstToCheck;
146056213ff4SIngo Weinhold int32 lastToDump = lastToCheck;
146156213ff4SIngo Weinhold
1462f97199edSIngo Weinhold TraceFilter* filter = NULL;
1463f97199edSIngo Weinhold if (hasFilter)
1464f97199edSIngo Weinhold filter = TraceFilterParser::Default()->Filter();
1465f97199edSIngo Weinhold
1466f97199edSIngo Weinhold if (wrapperFilter != NULL) {
1467f97199edSIngo Weinhold wrapperFilter->Init(filter, direction, cont != 0);
1468f97199edSIngo Weinhold filter = wrapperFilter;
1469f97199edSIngo Weinhold }
1470f97199edSIngo Weinhold
1471f97199edSIngo Weinhold if (direction < 0 && filter && lastToCheck - firstToCheck >= count) {
14726d369966SIngo Weinhold // iteration direction is backwards
147356213ff4SIngo Weinhold markedMatching = true;
14746d369966SIngo Weinhold
14756d369966SIngo Weinhold // From the last entry to check iterate backwards to check filter
14766d369966SIngo Weinhold // matches.
14776d369966SIngo Weinhold int32 matching = 0;
14786d369966SIngo Weinhold
14796d369966SIngo Weinhold // move to the entry after the last entry to check
14806d369966SIngo Weinhold iterator.MoveTo(lastToCheck + 1);
14816d369966SIngo Weinhold
14826d369966SIngo Weinhold // iterate backwards
148356213ff4SIngo Weinhold firstToDump = -1;
148456213ff4SIngo Weinhold lastToDump = -1;
14856d369966SIngo Weinhold while (iterator.Index() > firstToCheck) {
14866d369966SIngo Weinhold TraceEntry* entry = iterator.Previous();
1487b3d6c12dSIngo Weinhold if ((entry->Flags() & ENTRY_INITIALIZED) != 0) {
14886d369966SIngo Weinhold out.Clear();
1489f97199edSIngo Weinhold if (filter->Filter(entry, out)) {
1490b3d6c12dSIngo Weinhold entry->ToTraceEntry()->flags |= FILTER_MATCH;
149156213ff4SIngo Weinhold if (lastToDump == -1)
149256213ff4SIngo Weinhold lastToDump = iterator.Index();
149356213ff4SIngo Weinhold firstToDump = iterator.Index();
149456213ff4SIngo Weinhold
14956d369966SIngo Weinhold matching++;
14966d369966SIngo Weinhold if (matching >= count)
14976d369966SIngo Weinhold break;
149856213ff4SIngo Weinhold } else
1499b3d6c12dSIngo Weinhold entry->ToTraceEntry()->flags &= ~FILTER_MATCH;
15006d369966SIngo Weinhold }
15016d369966SIngo Weinhold }
15026d369966SIngo Weinhold
15036d369966SIngo Weinhold firstToCheck = iterator.Index();
15046d369966SIngo Weinhold
15056d369966SIngo Weinhold // iterate to the previous entry, so that the next loop starts at the
15066d369966SIngo Weinhold // right one
15076d369966SIngo Weinhold iterator.Previous();
15086d369966SIngo Weinhold }
15096d369966SIngo Weinhold
1510350b6dbcSIngo Weinhold out.SetLastEntryTime(0);
1511350b6dbcSIngo Weinhold
151256213ff4SIngo Weinhold // set the iterator to the entry before the first one to dump
151356213ff4SIngo Weinhold iterator.MoveTo(firstToDump - 1);
151456213ff4SIngo Weinhold
151556213ff4SIngo Weinhold // dump the entries matching the filter in the range
151656213ff4SIngo Weinhold // [firstToDump, lastToDump]
15176d369966SIngo Weinhold int32 dumped = 0;
15186d369966SIngo Weinhold
15196d369966SIngo Weinhold while (TraceEntry* entry = iterator.Next()) {
15206d369966SIngo Weinhold int32 index = iterator.Index();
152156213ff4SIngo Weinhold if (index < firstToDump)
15226d369966SIngo Weinhold continue;
152356213ff4SIngo Weinhold if (index > lastToDump || dumped >= count) {
15246d369966SIngo Weinhold if (direction > 0)
15256d369966SIngo Weinhold lastToCheck = index - 1;
15266d369966SIngo Weinhold break;
15276d369966SIngo Weinhold }
15286d369966SIngo Weinhold
1529b3d6c12dSIngo Weinhold if ((entry->Flags() & ENTRY_INITIALIZED) != 0) {
15306d369966SIngo Weinhold out.Clear();
1531f97199edSIngo Weinhold if (filter && (markedMatching
1532b3d6c12dSIngo Weinhold ? (entry->Flags() & FILTER_MATCH) == 0
1533f97199edSIngo Weinhold : !filter->Filter(entry, out))) {
15348e43ece8SAxel Dörfler continue;
153556213ff4SIngo Weinhold }
15368e43ece8SAxel Dörfler
15370c45a120SIngo Weinhold // don't print trailing new line
15380c45a120SIngo Weinhold const char* dump = out.DumpEntry(entry);
15390c45a120SIngo Weinhold int len = strlen(dump);
15400c45a120SIngo Weinhold if (len > 0 && dump[len - 1] == '\n')
15410c45a120SIngo Weinhold len--;
15420c45a120SIngo Weinhold
15438627383bSAlex Smith kprintf("%5" B_PRId32 ". %.*s\n", index, len, dump);
154465f40152SIngo Weinhold
154565f40152SIngo Weinhold if (printStackTrace) {
154665f40152SIngo Weinhold out.Clear();
154765f40152SIngo Weinhold entry->DumpStackTrace(out);
154865f40152SIngo Weinhold if (out.Size() > 0)
154965f40152SIngo Weinhold kputs(out.Buffer());
155065f40152SIngo Weinhold }
1551f97199edSIngo Weinhold } else if (!filter)
15528627383bSAlex Smith kprintf("%5" B_PRId32 ". ** uninitialized entry **\n", index);
155374652349SIngo Weinhold
155474652349SIngo Weinhold dumped++;
1555aa5d2a2dSAxel Dörfler }
1556aa5d2a2dSAxel Dörfler
15578627383bSAlex Smith kprintf("printed %" B_PRId32 " entries within range %" B_PRId32 " to %"
15588627383bSAlex Smith B_PRId32 " (%" B_PRId32 " of %" B_PRId32 " total, %" B_PRId32 " ever)\n",
15598627383bSAlex Smith dumped, firstToCheck, lastToCheck, lastToCheck - firstToCheck + 1,
15608627383bSAlex Smith sTracingMetaData->Entries(), entriesEver);
156174652349SIngo Weinhold
15626d369966SIngo Weinhold // store iteration state
15636d369966SIngo Weinhold _previousCount = count;
15646d369966SIngo Weinhold _previousMaxToCheck = maxToCheck;
15656d369966SIngo Weinhold _previousHasFilter = hasFilter;
156665f40152SIngo Weinhold _previousPrintStackTrace = printStackTrace;
15676d369966SIngo Weinhold _previousFirstChecked = firstToCheck;
15686d369966SIngo Weinhold _previousLastChecked = lastToCheck;
15695fa74667SIngo Weinhold _previousDirection = direction;
15703fccf067SIngo Weinhold _previousEntriesEver = entriesEver;
15713fccf067SIngo Weinhold _previousEntries = sTracingMetaData->Entries();
1572350b6dbcSIngo Weinhold _previousOutputFlags = outputFlags;
157374652349SIngo Weinhold
157474652349SIngo Weinhold return cont != 0 ? B_KDEBUG_CONT : 0;
1575aa5d2a2dSAxel Dörfler }
1576aa5d2a2dSAxel Dörfler
1577aa5d2a2dSAxel Dörfler
1578f97199edSIngo Weinhold static int
dump_tracing_command(int argc,char ** argv)1579f97199edSIngo Weinhold dump_tracing_command(int argc, char** argv)
1580f97199edSIngo Weinhold {
1581f97199edSIngo Weinhold return dump_tracing_internal(argc, argv, NULL);
1582f97199edSIngo Weinhold }
1583f97199edSIngo Weinhold
1584f97199edSIngo Weinhold
1585aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING
1586aa5d2a2dSAxel Dörfler
15872d81f045SAxel Dörfler
15888e43ece8SAxel Dörfler extern "C" uint8*
alloc_tracing_buffer(size_t size)15898e43ece8SAxel Dörfler alloc_tracing_buffer(size_t size)
15908e43ece8SAxel Dörfler {
15918e43ece8SAxel Dörfler #if ENABLE_TRACING
15923fccf067SIngo Weinhold trace_entry* entry = sTracingMetaData->AllocateEntry(
15933fccf067SIngo Weinhold size + sizeof(trace_entry), BUFFER_ENTRY);
15948e43ece8SAxel Dörfler if (entry == NULL)
15958e43ece8SAxel Dörfler return NULL;
15968e43ece8SAxel Dörfler
15978e43ece8SAxel Dörfler return (uint8*)(entry + 1);
15988e43ece8SAxel Dörfler #else
15998e43ece8SAxel Dörfler return NULL;
16008e43ece8SAxel Dörfler #endif
16018e43ece8SAxel Dörfler }
16028e43ece8SAxel Dörfler
1603aa5d2a2dSAxel Dörfler
16040b60583fSIngo Weinhold uint8*
alloc_tracing_buffer_memcpy(const void * source,size_t size,bool user)16050b60583fSIngo Weinhold alloc_tracing_buffer_memcpy(const void* source, size_t size, bool user)
16060b60583fSIngo Weinhold {
16078bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source))
16088bd6d45dSIngo Weinhold return NULL;
16098bd6d45dSIngo Weinhold
16100b60583fSIngo Weinhold uint8* buffer = alloc_tracing_buffer(size);
16110b60583fSIngo Weinhold if (buffer == NULL)
16120b60583fSIngo Weinhold return NULL;
16130b60583fSIngo Weinhold
16140b60583fSIngo Weinhold if (user) {
16150b60583fSIngo Weinhold if (user_memcpy(buffer, source, size) != B_OK)
16160b60583fSIngo Weinhold return NULL;
16170b60583fSIngo Weinhold } else
16180b60583fSIngo Weinhold memcpy(buffer, source, size);
16190b60583fSIngo Weinhold
16200b60583fSIngo Weinhold return buffer;
16210b60583fSIngo Weinhold }
16220b60583fSIngo Weinhold
16230b60583fSIngo Weinhold
16240b60583fSIngo Weinhold char*
alloc_tracing_buffer_strcpy(const char * source,size_t maxSize,bool user)16250b60583fSIngo Weinhold alloc_tracing_buffer_strcpy(const char* source, size_t maxSize, bool user)
16260b60583fSIngo Weinhold {
16278bd6d45dSIngo Weinhold if (source == NULL || maxSize == 0)
16280b60583fSIngo Weinhold return NULL;
16290b60583fSIngo Weinhold
16308bd6d45dSIngo Weinhold if (user && !IS_USER_ADDRESS(source))
16318bd6d45dSIngo Weinhold return NULL;
16328bd6d45dSIngo Weinhold
16338bd6d45dSIngo Weinhold // limit maxSize to the actual source string len
16348bd6d45dSIngo Weinhold if (user) {
16358bd6d45dSIngo Weinhold ssize_t size = user_strlcpy(NULL, source, 0);
16368bd6d45dSIngo Weinhold // there's no user_strnlen()
16378bd6d45dSIngo Weinhold if (size < 0)
16388bd6d45dSIngo Weinhold return 0;
16398bd6d45dSIngo Weinhold maxSize = min_c(maxSize, (size_t)size + 1);
16408bd6d45dSIngo Weinhold } else
16410b60583fSIngo Weinhold maxSize = strnlen(source, maxSize - 1) + 1;
16420b60583fSIngo Weinhold
16430b60583fSIngo Weinhold char* buffer = (char*)alloc_tracing_buffer(maxSize);
16440b60583fSIngo Weinhold if (buffer == NULL)
16450b60583fSIngo Weinhold return NULL;
16460b60583fSIngo Weinhold
16470b60583fSIngo Weinhold if (user) {
16480b60583fSIngo Weinhold if (user_strlcpy(buffer, source, maxSize) < B_OK)
16490b60583fSIngo Weinhold return NULL;
16500b60583fSIngo Weinhold } else
16510b60583fSIngo Weinhold strlcpy(buffer, source, maxSize);
16520b60583fSIngo Weinhold
16530b60583fSIngo Weinhold return buffer;
16540b60583fSIngo Weinhold }
16550b60583fSIngo Weinhold
16560b60583fSIngo Weinhold
165765f40152SIngo Weinhold tracing_stack_trace*
capture_tracing_stack_trace(int32 maxCount,int32 skipFrames,bool kernelOnly)1658a38f8503SIngo Weinhold capture_tracing_stack_trace(int32 maxCount, int32 skipFrames, bool kernelOnly)
165965f40152SIngo Weinhold {
166065f40152SIngo Weinhold #if ENABLE_TRACING
16614502d80dSIngo Weinhold // page_fault_exception() doesn't allow us to gracefully handle a bad
16624502d80dSIngo Weinhold // address in the stack trace, if interrupts are disabled, so we always
16634502d80dSIngo Weinhold // restrict the stack traces to the kernel only in this case. A bad address
16644502d80dSIngo Weinhold // in the kernel stack trace would still cause a panic(), but this is
16654502d80dSIngo Weinhold // probably even desired.
166665f40152SIngo Weinhold if (!are_interrupts_enabled())
16674502d80dSIngo Weinhold kernelOnly = true;
166865f40152SIngo Weinhold
166965f40152SIngo Weinhold tracing_stack_trace* stackTrace
167065f40152SIngo Weinhold = (tracing_stack_trace*)alloc_tracing_buffer(
167165f40152SIngo Weinhold sizeof(tracing_stack_trace) + maxCount * sizeof(addr_t));
167265f40152SIngo Weinhold
167365f40152SIngo Weinhold if (stackTrace != NULL) {
167465f40152SIngo Weinhold stackTrace->depth = arch_debug_get_stack_trace(
1675e670fc6fSIngo Weinhold stackTrace->return_addresses, maxCount, 0, skipFrames + 1,
16764502d80dSIngo Weinhold STACK_TRACE_KERNEL | (kernelOnly ? 0 : STACK_TRACE_USER));
167765f40152SIngo Weinhold }
167865f40152SIngo Weinhold
167965f40152SIngo Weinhold return stackTrace;
168065f40152SIngo Weinhold #else
168165f40152SIngo Weinhold return NULL;
168265f40152SIngo Weinhold #endif
168365f40152SIngo Weinhold }
168465f40152SIngo Weinhold
168565f40152SIngo Weinhold
168669d7ad7dSIngo Weinhold addr_t
tracing_find_caller_in_stack_trace(struct tracing_stack_trace * stackTrace,const addr_t excludeRanges[],uint32 excludeRangeCount)168769d7ad7dSIngo Weinhold tracing_find_caller_in_stack_trace(struct tracing_stack_trace* stackTrace,
168869d7ad7dSIngo Weinhold const addr_t excludeRanges[], uint32 excludeRangeCount)
168969d7ad7dSIngo Weinhold {
169069d7ad7dSIngo Weinhold for (int32 i = 0; i < stackTrace->depth; i++) {
169169d7ad7dSIngo Weinhold addr_t returnAddress = stackTrace->return_addresses[i];
169269d7ad7dSIngo Weinhold
169369d7ad7dSIngo Weinhold bool inRange = false;
169469d7ad7dSIngo Weinhold for (uint32 j = 0; j < excludeRangeCount; j++) {
169569d7ad7dSIngo Weinhold if (returnAddress >= excludeRanges[j * 2 + 0]
169669d7ad7dSIngo Weinhold && returnAddress < excludeRanges[j * 2 + 1]) {
169769d7ad7dSIngo Weinhold inRange = true;
169869d7ad7dSIngo Weinhold break;
169969d7ad7dSIngo Weinhold }
170069d7ad7dSIngo Weinhold }
170169d7ad7dSIngo Weinhold
170269d7ad7dSIngo Weinhold if (!inRange)
170369d7ad7dSIngo Weinhold return returnAddress;
170469d7ad7dSIngo Weinhold }
170569d7ad7dSIngo Weinhold
170669d7ad7dSIngo Weinhold return 0;
170769d7ad7dSIngo Weinhold }
170869d7ad7dSIngo Weinhold
170969d7ad7dSIngo Weinhold
1710328df922SIngo Weinhold void
tracing_print_stack_trace(struct tracing_stack_trace * stackTrace)1711328df922SIngo Weinhold tracing_print_stack_trace(struct tracing_stack_trace* stackTrace)
1712328df922SIngo Weinhold {
171345cbd814SMichael Lotz #if ENABLE_TRACING
1714328df922SIngo Weinhold print_stack_trace(stackTrace, kprintf);
171545cbd814SMichael Lotz #endif
1716328df922SIngo Weinhold }
1717328df922SIngo Weinhold
1718328df922SIngo Weinhold
1719f97199edSIngo Weinhold int
dump_tracing(int argc,char ** argv,WrapperTraceFilter * wrapperFilter)1720f97199edSIngo Weinhold dump_tracing(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
1721f97199edSIngo Weinhold {
1722f97199edSIngo Weinhold #if ENABLE_TRACING
1723f97199edSIngo Weinhold return dump_tracing_internal(argc, argv, wrapperFilter);
1724f97199edSIngo Weinhold #else
1725f97199edSIngo Weinhold return 0;
1726f97199edSIngo Weinhold #endif
1727f97199edSIngo Weinhold }
1728f97199edSIngo Weinhold
1729f97199edSIngo Weinhold
173069d7ad7dSIngo Weinhold bool
tracing_is_entry_valid(AbstractTraceEntry * candidate,bigtime_t entryTime)17319a79e531SMichael Lotz tracing_is_entry_valid(AbstractTraceEntry* candidate, bigtime_t entryTime)
173269d7ad7dSIngo Weinhold {
173369d7ad7dSIngo Weinhold #if ENABLE_TRACING
17349a79e531SMichael Lotz if (!sTracingMetaData->IsInBuffer(candidate, sizeof(*candidate)))
17359a79e531SMichael Lotz return false;
17369a79e531SMichael Lotz
17379a79e531SMichael Lotz if (entryTime < 0)
17389a79e531SMichael Lotz return true;
17399a79e531SMichael Lotz
174069d7ad7dSIngo Weinhold TraceEntryIterator iterator;
174169d7ad7dSIngo Weinhold while (TraceEntry* entry = iterator.Next()) {
174269d7ad7dSIngo Weinhold AbstractTraceEntry* abstract = dynamic_cast<AbstractTraceEntry*>(entry);
174369d7ad7dSIngo Weinhold if (abstract == NULL)
174469d7ad7dSIngo Weinhold continue;
174569d7ad7dSIngo Weinhold
17469a79e531SMichael Lotz if (abstract != candidate && abstract->Time() > entryTime)
17479a79e531SMichael Lotz return false;
17489a79e531SMichael Lotz
17499a79e531SMichael Lotz return candidate->Time() == entryTime;
175069d7ad7dSIngo Weinhold }
175169d7ad7dSIngo Weinhold #endif
175269d7ad7dSIngo Weinhold
175369d7ad7dSIngo Weinhold return false;
175469d7ad7dSIngo Weinhold }
175569d7ad7dSIngo Weinhold
175669d7ad7dSIngo Weinhold
1757aa1a64f3SIngo Weinhold void
lock_tracing_buffer()1758aa1a64f3SIngo Weinhold lock_tracing_buffer()
1759aa1a64f3SIngo Weinhold {
1760aa1a64f3SIngo Weinhold #if ENABLE_TRACING
17613fccf067SIngo Weinhold sTracingMetaData->Lock();
1762aa1a64f3SIngo Weinhold #endif
1763aa1a64f3SIngo Weinhold }
1764aa1a64f3SIngo Weinhold
1765aa1a64f3SIngo Weinhold
1766aa1a64f3SIngo Weinhold void
unlock_tracing_buffer()1767aa1a64f3SIngo Weinhold unlock_tracing_buffer()
1768aa1a64f3SIngo Weinhold {
1769aa1a64f3SIngo Weinhold #if ENABLE_TRACING
17703fccf067SIngo Weinhold sTracingMetaData->Unlock();
1771aa1a64f3SIngo Weinhold #endif
1772aa1a64f3SIngo Weinhold }
1773aa1a64f3SIngo Weinhold
1774aa1a64f3SIngo Weinhold
1775aa5d2a2dSAxel Dörfler extern "C" status_t
tracing_init(void)1776aa5d2a2dSAxel Dörfler tracing_init(void)
1777aa5d2a2dSAxel Dörfler {
1778aa5d2a2dSAxel Dörfler #if ENABLE_TRACING
1779d829579dSIngo Weinhold status_t result = TracingMetaData::Create(sTracingMetaData);
1780d829579dSIngo Weinhold if (result != B_OK) {
1781c53508b7SIngo Weinhold memset(&sFallbackTracingMetaData, 0, sizeof(sFallbackTracingMetaData));
1782c53508b7SIngo Weinhold sTracingMetaData = &sFallbackTracingMetaData;
1783d829579dSIngo Weinhold return result;
1784d829579dSIngo Weinhold }
1785aa5d2a2dSAxel Dörfler
1786d829579dSIngo Weinhold new(nothrow) TracingLogStartEntry();
1787aa5d2a2dSAxel Dörfler
1788f97199edSIngo Weinhold add_debugger_command_etc("traced", &dump_tracing_command,
178974652349SIngo Weinhold "Dump recorded trace entries",
1790093e0057SAxel Dörfler "[ --printteam ] [ --difftime ] [ --stacktrace ] "
1791093e0057SAxel Dörfler "(\"forward\" | \"backward\") "
179264fe37eeSIngo Weinhold "| ([ <start> [ <count> [ <range> ] ] ] "
17934c4b14c3SIngo Weinhold "[ #<pattern> | (\"filter\" <filter>) ])\n"
179474652349SIngo Weinhold "Prints recorded trace entries. If \"backward\" or \"forward\" is\n"
179574652349SIngo Weinhold "specified, the command continues where the previous invocation left\n"
179674652349SIngo Weinhold "off, i.e. printing the previous respectively next entries (as many\n"
179774652349SIngo Weinhold "as printed before). In this case the command is continuable, that is\n"
179874652349SIngo Weinhold "afterwards entering an empty line in the debugger will reinvoke it.\n"
17995fa74667SIngo Weinhold "If no arguments are given, the command continues in the direction\n"
18005fa74667SIngo Weinhold "of the last invocation.\n"
1801093e0057SAxel Dörfler "--printteam - enables printing the entries' team IDs.\n"
1802093e0057SAxel Dörfler "--difftime - print difference times for all but the first entry.\n"
1803093e0057SAxel Dörfler "--stacktrace - print stack traces for entries that captured one.\n"
18046d369966SIngo Weinhold " <start> - The base index of the entries to print. Depending on\n"
18056d369966SIngo Weinhold " whether the iteration direction is forward or\n"
18066d369966SIngo Weinhold " backward this will be the first or last entry printed\n"
18076d369966SIngo Weinhold " (potentially, if a filter is specified). The index of\n"
18086d369966SIngo Weinhold " the first entry in the trace buffer is 1. If 0 is\n"
18096d369966SIngo Weinhold " specified, the last <count> recorded entries are\n"
18106d369966SIngo Weinhold " printed (iteration direction is backward). Defaults \n"
181174652349SIngo Weinhold " to 0.\n"
181274652349SIngo Weinhold " <count> - The number of entries to be printed. Defaults to 30.\n"
18136d369966SIngo Weinhold " If negative, the -<count> entries before and\n"
18146d369966SIngo Weinhold " including <start> will be printed.\n"
18156d369966SIngo Weinhold " <range> - Only relevant if a filter is specified. Specifies the\n"
18166d369966SIngo Weinhold " number of entries to be filtered -- depending on the\n"
18176d369966SIngo Weinhold " iteration direction the entries before or after\n"
18186d369966SIngo Weinhold " <start>. If more than <count> entries match the\n"
18196d369966SIngo Weinhold " filter, only the first (forward) or last (backward)\n"
18206d369966SIngo Weinhold " <count> matching entries will be printed. If 0 is\n"
18216d369966SIngo Weinhold " specified <range> will be set to <count>. If -1,\n"
18226d369966SIngo Weinhold " <range> will be set to the number of recorded\n"
18236d369966SIngo Weinhold " entries.\n"
182474652349SIngo Weinhold " <pattern> - If specified only entries containing this string are\n"
18254c4b14c3SIngo Weinhold " printed.\n"
18264c4b14c3SIngo Weinhold " <filter> - If specified only entries matching this filter\n"
18274c4b14c3SIngo Weinhold " expression are printed. The expression can consist of\n"
182864fe37eeSIngo Weinhold " prefix operators \"not\", \"and\", \"or\", and\n"
182964fe37eeSIngo Weinhold " filters \"'thread' <thread>\" (matching entries\n"
183064fe37eeSIngo Weinhold " with the given thread ID), \"'team' <team>\"\n"
183164fe37eeSIngo Weinhold "(matching entries with the given team ID), and\n"
18324c4b14c3SIngo Weinhold " \"#<pattern>\" (matching entries containing the given\n"
183364fe37eeSIngo Weinhold " string).\n", 0);
1834aa5d2a2dSAxel Dörfler #endif // ENABLE_TRACING
1835aa5d2a2dSAxel Dörfler return B_OK;
1836aa5d2a2dSAxel Dörfler }
1837aa5d2a2dSAxel Dörfler
1838a54c125eSIngo Weinhold
1839a54c125eSIngo Weinhold void
ktrace_printf(const char * format,...)18407d2d758dSIngo Weinhold ktrace_printf(const char *format, ...)
18417d2d758dSIngo Weinhold {
18427d2d758dSIngo Weinhold #if ENABLE_TRACING
18437d2d758dSIngo Weinhold va_list list;
18447d2d758dSIngo Weinhold va_start(list, format);
18457d2d758dSIngo Weinhold
18467d2d758dSIngo Weinhold char buffer[256];
18477d2d758dSIngo Weinhold vsnprintf(buffer, sizeof(buffer), format, list);
18487d2d758dSIngo Weinhold
18497d2d758dSIngo Weinhold va_end(list);
18507d2d758dSIngo Weinhold
18517d2d758dSIngo Weinhold new(nothrow) KernelTraceEntry(buffer);
18527d2d758dSIngo Weinhold #endif // ENABLE_TRACING
18537d2d758dSIngo Weinhold }
18547d2d758dSIngo Weinhold
18557d2d758dSIngo Weinhold
18567d2d758dSIngo Weinhold void
_user_ktrace_output(const char * message)1857a54c125eSIngo Weinhold _user_ktrace_output(const char *message)
1858a54c125eSIngo Weinhold {
1859a54c125eSIngo Weinhold #if ENABLE_TRACING
1860a54c125eSIngo Weinhold new(nothrow) UserTraceEntry(message);
1861a54c125eSIngo Weinhold #endif // ENABLE_TRACING
1862a54c125eSIngo Weinhold }
1863a54c125eSIngo Weinhold
1864