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