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