xref: /haiku/src/system/kernel/debug/tracing.cpp (revision 40ee778c63369ec444a91dac863c8eca40099979)
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