xref: /haiku/src/system/kernel/debug/tracing.cpp (revision 6d986c16fe6c1915d2084ac2c6d25ff33041a771)
12d81f045SAxel Dörfler /*
22d81f045SAxel Dörfler  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
32d81f045SAxel Dörfler  * Copyright 2008, 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 
1374652349SIngo Weinhold #include <debug.h>
148bd6d45dSIngo Weinhold #include <kernel.h>
152d81f045SAxel Dörfler #include <util/AutoLock.h>
162d81f045SAxel Dörfler 
17aa5d2a2dSAxel Dörfler 
18aa5d2a2dSAxel Dörfler #if ENABLE_TRACING
19aa5d2a2dSAxel Dörfler 
205276dad0SAxel Dörfler //#define TRACE_TRACING
215276dad0SAxel Dörfler #ifdef TRACE_TRACING
22*6d986c16SIngo Weinhold #	define TRACE(x) dprintf_no_syslog x
235276dad0SAxel Dörfler #else
245276dad0SAxel Dörfler #	define TRACE(x) ;
255276dad0SAxel Dörfler #endif
265276dad0SAxel Dörfler 
275276dad0SAxel Dörfler 
28aa5d2a2dSAxel Dörfler enum {
29aa5d2a2dSAxel Dörfler 	WRAP_ENTRY			= 0x01,
308e43ece8SAxel Dörfler 	ENTRY_INITIALIZED	= 0x02,
318e43ece8SAxel Dörfler 	BUFFER_ENTRY		= 0x04
32aa5d2a2dSAxel Dörfler };
33aa5d2a2dSAxel Dörfler 
34aa5d2a2dSAxel Dörfler static const size_t kBufferSize = MAX_TRACE_SIZE / 4 - 1;
35aa5d2a2dSAxel Dörfler 
36aa5d2a2dSAxel Dörfler static trace_entry* sBuffer;
37960f8f24SAxel Dörfler static trace_entry* sFirstEntry;
38960f8f24SAxel Dörfler static trace_entry* sAfterLastEntry;
39aa5d2a2dSAxel Dörfler static uint32 sEntries;
40f70280a7SAxel Dörfler static uint32 sWritten;
41aa5d2a2dSAxel Dörfler static spinlock sLock;
42aa5d2a2dSAxel Dörfler 
43aa5d2a2dSAxel Dörfler 
44aa5d2a2dSAxel Dörfler static trace_entry*
45aa5d2a2dSAxel Dörfler next_entry(trace_entry* entry)
46aa5d2a2dSAxel Dörfler {
47aa5d2a2dSAxel Dörfler 	entry += entry->size >> 2;
48aa5d2a2dSAxel Dörfler 	if ((entry->flags & WRAP_ENTRY) != 0)
49aa5d2a2dSAxel Dörfler 		entry = sBuffer;
50aa5d2a2dSAxel Dörfler 
51960f8f24SAxel Dörfler 	if (entry == sAfterLastEntry)
52aa5d2a2dSAxel Dörfler 		return NULL;
53aa5d2a2dSAxel Dörfler 
54aa5d2a2dSAxel Dörfler 	return entry;
55aa5d2a2dSAxel Dörfler }
56aa5d2a2dSAxel Dörfler 
57aa5d2a2dSAxel Dörfler 
58*6d986c16SIngo Weinhold static bool
59*6d986c16SIngo Weinhold free_first_entry()
60*6d986c16SIngo Weinhold {
61*6d986c16SIngo Weinhold 	TRACE(("  skip start %p, %u bytes\n", sFirstEntry, sFirstEntry->size));
62*6d986c16SIngo Weinhold 
63*6d986c16SIngo Weinhold 	trace_entry* newFirst = next_entry(sFirstEntry);
64*6d986c16SIngo Weinhold 
65*6d986c16SIngo Weinhold 	if (sFirstEntry->flags & BUFFER_ENTRY) {
66*6d986c16SIngo Weinhold 		// a buffer entry -- just skip it
67*6d986c16SIngo Weinhold 	} else if (sFirstEntry->flags & ENTRY_INITIALIZED) {
68*6d986c16SIngo Weinhold 		// fully initialized TraceEntry -- destroy it
69*6d986c16SIngo Weinhold 		((TraceEntry*)sFirstEntry)->~TraceEntry();
70*6d986c16SIngo Weinhold 		sEntries--;
71*6d986c16SIngo Weinhold 	} else {
72*6d986c16SIngo Weinhold 		// Not fully initialized TraceEntry. We can't free it, since
73*6d986c16SIngo Weinhold 		// then it's constructor might still write into the memory and
74*6d986c16SIngo Weinhold 		// overwrite data of the entry we're going to allocate.
75*6d986c16SIngo Weinhold 		// We can't do anything until this entry can be discarded.
76*6d986c16SIngo Weinhold 		return false;
77*6d986c16SIngo Weinhold 	}
78*6d986c16SIngo Weinhold 
79*6d986c16SIngo Weinhold 	if (newFirst == NULL) {
80*6d986c16SIngo Weinhold 		// everything is freed -- that practically this can't happen, if
81*6d986c16SIngo Weinhold 		// the buffer is large enough to hold three max-sized entries
82*6d986c16SIngo Weinhold 		sFirstEntry = sAfterLastEntry = sBuffer;
83*6d986c16SIngo Weinhold 		TRACE(("free_first_entry(): all entries freed!\n"));
84*6d986c16SIngo Weinhold 	} else
85*6d986c16SIngo Weinhold 		sFirstEntry = newFirst;
86*6d986c16SIngo Weinhold 
87*6d986c16SIngo Weinhold 	return true;
88*6d986c16SIngo Weinhold }
89*6d986c16SIngo Weinhold 
90*6d986c16SIngo Weinhold 
91*6d986c16SIngo Weinhold static bool
928e43ece8SAxel Dörfler make_space(size_t needed)
93aa5d2a2dSAxel Dörfler {
94*6d986c16SIngo Weinhold 	// we need space for sAfterLastEntry, too (in case we need to wrap around
95*6d986c16SIngo Weinhold 	// later)
96*6d986c16SIngo Weinhold 	needed += 4;
97*6d986c16SIngo Weinhold 
98*6d986c16SIngo Weinhold 	// If there's not enough space (free or occupied) after sAfterLastEntry,
99*6d986c16SIngo Weinhold 	// we free all entries in that region and wrap around.
100*6d986c16SIngo Weinhold 	if (sAfterLastEntry + needed / 4 > sBuffer + kBufferSize) {
101*6d986c16SIngo Weinhold 		TRACE(("make_space(%lu), wrapping around: after last: %p\n", needed,
102*6d986c16SIngo Weinhold 			sAfterLastEntry));
103*6d986c16SIngo Weinhold 
104*6d986c16SIngo Weinhold 		// Free all entries after sAfterLastEntry and one more at the beginning
105*6d986c16SIngo Weinhold 		// of the buffer.
106*6d986c16SIngo Weinhold 		do {
107*6d986c16SIngo Weinhold 			if (!free_first_entry())
108*6d986c16SIngo Weinhold 				return false;
109*6d986c16SIngo Weinhold 		} while (sFirstEntry > sAfterLastEntry);
110*6d986c16SIngo Weinhold 
111*6d986c16SIngo Weinhold 		// just in case free_first_entry() freed the very last existing entry
112*6d986c16SIngo Weinhold 		if (sAfterLastEntry == sBuffer)
113*6d986c16SIngo Weinhold 			return true;
114*6d986c16SIngo Weinhold 
115*6d986c16SIngo Weinhold 		// mark as wrap entry and actually wrap around
116960f8f24SAxel Dörfler 		sAfterLastEntry->size = 0;
117960f8f24SAxel Dörfler 		sAfterLastEntry->flags = WRAP_ENTRY;
118960f8f24SAxel Dörfler 		sAfterLastEntry = sBuffer;
119aa5d2a2dSAxel Dörfler 	}
120aa5d2a2dSAxel Dörfler 
121*6d986c16SIngo Weinhold 	if (sFirstEntry <= sAfterLastEntry) {
122*6d986c16SIngo Weinhold 		// buffer is empty or the space after sAfterLastEntry is unoccupied
123*6d986c16SIngo Weinhold 		return true;
12474652349SIngo Weinhold 	}
125aa5d2a2dSAxel Dörfler 
126*6d986c16SIngo Weinhold 	// free the first entries, until there's enough space
127*6d986c16SIngo Weinhold 	size_t space = (sFirstEntry - sAfterLastEntry) * 4;
128aa5d2a2dSAxel Dörfler 
129*6d986c16SIngo Weinhold 	if (space < needed) {
130*6d986c16SIngo Weinhold 		TRACE(("make_space(%lu), left %ld\n", needed, space));
131*6d986c16SIngo Weinhold 	}
132*6d986c16SIngo Weinhold 
133*6d986c16SIngo Weinhold 	while (space < needed) {
134*6d986c16SIngo Weinhold 		space += sFirstEntry->size;
135*6d986c16SIngo Weinhold 
136*6d986c16SIngo Weinhold 		if (!free_first_entry())
137*6d986c16SIngo Weinhold 			return false;
138aa5d2a2dSAxel Dörfler 	}
1395276dad0SAxel Dörfler 
140960f8f24SAxel Dörfler 	TRACE(("  out: start %p, entries %ld\n", sFirstEntry, sEntries));
141*6d986c16SIngo Weinhold 
142*6d986c16SIngo Weinhold 	return true;
143aa5d2a2dSAxel Dörfler }
144aa5d2a2dSAxel Dörfler 
145aa5d2a2dSAxel Dörfler 
14674652349SIngo Weinhold static trace_entry*
14774652349SIngo Weinhold allocate_entry(size_t size, uint16 flags)
148aa5d2a2dSAxel Dörfler {
149*6d986c16SIngo Weinhold 	if (sBuffer == NULL || size == 0 || size >= 65532)
150aa5d2a2dSAxel Dörfler 		return NULL;
151aa5d2a2dSAxel Dörfler 
152aa5d2a2dSAxel Dörfler 	InterruptsSpinLocker _(sLock);
153aa5d2a2dSAxel Dörfler 
154aa5d2a2dSAxel Dörfler 	size = (size + 3) & ~3;
155aa5d2a2dSAxel Dörfler 
1565276dad0SAxel Dörfler 	TRACE(("allocate_entry(%lu), start %p, end %p, buffer %p\n", size,
157960f8f24SAxel Dörfler 		sFirstEntry, sAfterLastEntry, sBuffer));
1585276dad0SAxel Dörfler 
159*6d986c16SIngo Weinhold 	if (!make_space(size))
160*6d986c16SIngo Weinhold 		return NULL;
161aa5d2a2dSAxel Dörfler 
162960f8f24SAxel Dörfler 	trace_entry* entry = sAfterLastEntry;
163aa5d2a2dSAxel Dörfler 	entry->size = size;
16474652349SIngo Weinhold 	entry->flags = flags;
165960f8f24SAxel Dörfler 	sAfterLastEntry += size >> 2;
16674652349SIngo Weinhold 
16774652349SIngo Weinhold 	if (!(flags & BUFFER_ENTRY))
168aa5d2a2dSAxel Dörfler 		sEntries++;
16974652349SIngo Weinhold 
170*6d986c16SIngo Weinhold 	TRACE(("  entry: %p, end %p, start %p, entries %ld\n", entry,
171*6d986c16SIngo Weinhold 		sAfterLastEntry, sFirstEntry, sEntries));
17274652349SIngo Weinhold 
173aa5d2a2dSAxel Dörfler 	return entry;
1748e43ece8SAxel Dörfler }
1758e43ece8SAxel Dörfler 
1768e43ece8SAxel Dörfler 
1778e43ece8SAxel Dörfler #endif	// ENABLE_TRACING
1788e43ece8SAxel Dörfler 
1798e43ece8SAxel Dörfler 
1808e43ece8SAxel Dörfler // #pragma mark -
1818e43ece8SAxel Dörfler 
1828e43ece8SAxel Dörfler 
183f1047a1cSIngo Weinhold TraceOutput::TraceOutput(char* buffer, size_t bufferSize)
184f1047a1cSIngo Weinhold 	: fBuffer(buffer),
185f7a5d9c5SIngo Weinhold 	  fCapacity(bufferSize)
186f1047a1cSIngo Weinhold {
187f7a5d9c5SIngo Weinhold 	Clear();
188f7a5d9c5SIngo Weinhold }
189f7a5d9c5SIngo Weinhold 
190f7a5d9c5SIngo Weinhold 
191f7a5d9c5SIngo Weinhold void
192f7a5d9c5SIngo Weinhold TraceOutput::Clear()
193f7a5d9c5SIngo Weinhold {
194f7a5d9c5SIngo Weinhold 	if (fCapacity > 0)
195f7a5d9c5SIngo Weinhold 		fBuffer[0] = '\0';
196f7a5d9c5SIngo Weinhold 	fSize = 0;
197f1047a1cSIngo Weinhold }
198f1047a1cSIngo Weinhold 
199f1047a1cSIngo Weinhold 
200f1047a1cSIngo Weinhold void
201f1047a1cSIngo Weinhold TraceOutput::Print(const char* format,...)
202f1047a1cSIngo Weinhold {
203f1047a1cSIngo Weinhold 	if (IsFull())
204f1047a1cSIngo Weinhold 		return;
205f1047a1cSIngo Weinhold 
206f1047a1cSIngo Weinhold 	va_list args;
207f1047a1cSIngo Weinhold 	va_start(args, format);
208f1047a1cSIngo Weinhold 	fSize += vsnprintf(fBuffer + fSize, fCapacity - fSize, format, args);
209f1047a1cSIngo Weinhold 	va_end(args);
210f1047a1cSIngo Weinhold }
211f1047a1cSIngo Weinhold 
212f1047a1cSIngo Weinhold 
213f1047a1cSIngo Weinhold //	#pragma mark -
214f1047a1cSIngo Weinhold 
215f1047a1cSIngo Weinhold 
2168e43ece8SAxel Dörfler TraceEntry::TraceEntry()
2178e43ece8SAxel Dörfler {
2188e43ece8SAxel Dörfler }
2198e43ece8SAxel Dörfler 
2208e43ece8SAxel Dörfler 
2218e43ece8SAxel Dörfler TraceEntry::~TraceEntry()
2228e43ece8SAxel Dörfler {
2238e43ece8SAxel Dörfler }
2248e43ece8SAxel Dörfler 
2258e43ece8SAxel Dörfler 
2268e43ece8SAxel Dörfler void
227f7a5d9c5SIngo Weinhold TraceEntry::Dump(TraceOutput& out)
2288e43ece8SAxel Dörfler {
2298e43ece8SAxel Dörfler #if ENABLE_TRACING
230f1047a1cSIngo Weinhold 	// to be overridden by subclasses
231f7a5d9c5SIngo Weinhold 	out.Print("ENTRY %p", this);
2328e43ece8SAxel Dörfler #endif
2338e43ece8SAxel Dörfler }
2348e43ece8SAxel Dörfler 
2358e43ece8SAxel Dörfler 
2368e43ece8SAxel Dörfler void
2378e43ece8SAxel Dörfler TraceEntry::Initialized()
2388e43ece8SAxel Dörfler {
2398e43ece8SAxel Dörfler #if ENABLE_TRACING
2408e43ece8SAxel Dörfler 	flags |= ENTRY_INITIALIZED;
241f70280a7SAxel Dörfler 	sWritten++;
2428e43ece8SAxel Dörfler #endif
2438e43ece8SAxel Dörfler }
2448e43ece8SAxel Dörfler 
2458e43ece8SAxel Dörfler 
2468e43ece8SAxel Dörfler void*
2478e43ece8SAxel Dörfler TraceEntry::operator new(size_t size, const std::nothrow_t&) throw()
2488e43ece8SAxel Dörfler {
2498e43ece8SAxel Dörfler #if ENABLE_TRACING
25074652349SIngo Weinhold 	return allocate_entry(size, 0);
2518e43ece8SAxel Dörfler #else
252aa5d2a2dSAxel Dörfler 	return NULL;
253aa5d2a2dSAxel Dörfler #endif
254aa5d2a2dSAxel Dörfler }
255aa5d2a2dSAxel Dörfler 
256aa5d2a2dSAxel Dörfler 
257aa5d2a2dSAxel Dörfler //	#pragma mark -
258aa5d2a2dSAxel Dörfler 
259aa5d2a2dSAxel Dörfler 
260f1047a1cSIngo Weinhold AbstractTraceEntry::~AbstractTraceEntry()
261f1047a1cSIngo Weinhold {
262f1047a1cSIngo Weinhold }
263f1047a1cSIngo Weinhold 
264f1047a1cSIngo Weinhold 
265f1047a1cSIngo Weinhold void
266f7a5d9c5SIngo Weinhold AbstractTraceEntry::Dump(TraceOutput& out)
267f1047a1cSIngo Weinhold {
268f7a5d9c5SIngo Weinhold 	out.Print("[%6ld] %Ld: ", fThread, fTime);
269f1047a1cSIngo Weinhold 	AddDump(out);
270f1047a1cSIngo Weinhold }
271f1047a1cSIngo Weinhold 
272f1047a1cSIngo Weinhold 
273f1047a1cSIngo Weinhold void
274f1047a1cSIngo Weinhold AbstractTraceEntry::AddDump(TraceOutput& out)
275f1047a1cSIngo Weinhold {
276f1047a1cSIngo Weinhold }
277f1047a1cSIngo Weinhold 
278f1047a1cSIngo Weinhold 
2794c4b14c3SIngo Weinhold //	#pragma mark - trace filters
2804c4b14c3SIngo Weinhold 
2814c4b14c3SIngo Weinhold 
2824c4b14c3SIngo Weinhold class LazyTraceOutput : public TraceOutput {
2834c4b14c3SIngo Weinhold public:
2844c4b14c3SIngo Weinhold 	LazyTraceOutput(char* buffer, size_t bufferSize)
2854c4b14c3SIngo Weinhold 		: TraceOutput(buffer, bufferSize)
2864c4b14c3SIngo Weinhold 	{
2874c4b14c3SIngo Weinhold 	}
2884c4b14c3SIngo Weinhold 
2894c4b14c3SIngo Weinhold 	const char* DumpEntry(const TraceEntry* entry)
2904c4b14c3SIngo Weinhold 	{
2914c4b14c3SIngo Weinhold 		if (Size() == 0) {
2924c4b14c3SIngo Weinhold 			const_cast<TraceEntry*>(entry)->Dump(*this);
2934c4b14c3SIngo Weinhold 				// Dump() should probably be const
2944c4b14c3SIngo Weinhold 		}
2954c4b14c3SIngo Weinhold 
2964c4b14c3SIngo Weinhold 		return Buffer();
2974c4b14c3SIngo Weinhold 	}
2984c4b14c3SIngo Weinhold };
2994c4b14c3SIngo Weinhold 
3004c4b14c3SIngo Weinhold 
3014c4b14c3SIngo Weinhold class TraceFilter {
3024c4b14c3SIngo Weinhold public:
3034c4b14c3SIngo Weinhold 	virtual ~TraceFilter()
3044c4b14c3SIngo Weinhold 	{
3054c4b14c3SIngo Weinhold 	}
3064c4b14c3SIngo Weinhold 
3074c4b14c3SIngo Weinhold 	virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
3084c4b14c3SIngo Weinhold 	{
3094c4b14c3SIngo Weinhold 		return false;
3104c4b14c3SIngo Weinhold 	}
3114c4b14c3SIngo Weinhold 
3124c4b14c3SIngo Weinhold public:
3134c4b14c3SIngo Weinhold 	union {
3144c4b14c3SIngo Weinhold 		thread_id	fThread;
3154c4b14c3SIngo Weinhold 		const char*	fString;
3164c4b14c3SIngo Weinhold 		struct {
3174c4b14c3SIngo Weinhold 			TraceFilter*	first;
3184c4b14c3SIngo Weinhold 			TraceFilter*	second;
3194c4b14c3SIngo Weinhold 		} fSubFilters;
3204c4b14c3SIngo Weinhold 	};
3214c4b14c3SIngo Weinhold };
3224c4b14c3SIngo Weinhold 
3234c4b14c3SIngo Weinhold 
3244c4b14c3SIngo Weinhold class ThreadTraceFilter : public TraceFilter {
3254c4b14c3SIngo Weinhold public:
3264c4b14c3SIngo Weinhold 	virtual bool Filter(const TraceEntry* _entry, LazyTraceOutput& out)
3274c4b14c3SIngo Weinhold 	{
3284c4b14c3SIngo Weinhold 		const AbstractTraceEntry* entry
3294c4b14c3SIngo Weinhold 			= dynamic_cast<const AbstractTraceEntry*>(_entry);
3304c4b14c3SIngo Weinhold 		return (entry != NULL && entry->Thread() == fThread);
3314c4b14c3SIngo Weinhold 	}
3324c4b14c3SIngo Weinhold };
3334c4b14c3SIngo Weinhold 
3344c4b14c3SIngo Weinhold 
3354c4b14c3SIngo Weinhold class PatternTraceFilter : public TraceFilter {
3364c4b14c3SIngo Weinhold public:
3374c4b14c3SIngo Weinhold 	virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
3384c4b14c3SIngo Weinhold 	{
3394c4b14c3SIngo Weinhold 		return strstr(out.DumpEntry(entry), fString) != NULL;
3404c4b14c3SIngo Weinhold 	}
3414c4b14c3SIngo Weinhold };
3424c4b14c3SIngo Weinhold 
3434c4b14c3SIngo Weinhold 
3444c4b14c3SIngo Weinhold class NotTraceFilter : public TraceFilter {
3454c4b14c3SIngo Weinhold public:
3464c4b14c3SIngo Weinhold 	virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
3474c4b14c3SIngo Weinhold 	{
3484c4b14c3SIngo Weinhold 		return !fSubFilters.first->Filter(entry, out);
3494c4b14c3SIngo Weinhold 	}
3504c4b14c3SIngo Weinhold };
3514c4b14c3SIngo Weinhold 
3524c4b14c3SIngo Weinhold 
3534c4b14c3SIngo Weinhold class AndTraceFilter : public TraceFilter {
3544c4b14c3SIngo Weinhold public:
3554c4b14c3SIngo Weinhold 	virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
3564c4b14c3SIngo Weinhold 	{
3574c4b14c3SIngo Weinhold 		return fSubFilters.first->Filter(entry, out)
3584c4b14c3SIngo Weinhold 			&& fSubFilters.second->Filter(entry, out);
3594c4b14c3SIngo Weinhold 	}
3604c4b14c3SIngo Weinhold };
3614c4b14c3SIngo Weinhold 
3624c4b14c3SIngo Weinhold 
3634c4b14c3SIngo Weinhold class OrTraceFilter : public TraceFilter {
3644c4b14c3SIngo Weinhold public:
3654c4b14c3SIngo Weinhold 	virtual bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
3664c4b14c3SIngo Weinhold 	{
3674c4b14c3SIngo Weinhold 		return fSubFilters.first->Filter(entry, out)
3684c4b14c3SIngo Weinhold 			|| fSubFilters.second->Filter(entry, out);
3694c4b14c3SIngo Weinhold 	}
3704c4b14c3SIngo Weinhold };
3714c4b14c3SIngo Weinhold 
3724c4b14c3SIngo Weinhold 
3734c4b14c3SIngo Weinhold class TraceFilterParser {
3744c4b14c3SIngo Weinhold public:
3754c4b14c3SIngo Weinhold 	static TraceFilterParser* Default()
3764c4b14c3SIngo Weinhold 	{
3774c4b14c3SIngo Weinhold 		return &sParser;
3784c4b14c3SIngo Weinhold 	}
3794c4b14c3SIngo Weinhold 
3804c4b14c3SIngo Weinhold 	bool Parse(int argc, const char* const* argv)
3814c4b14c3SIngo Weinhold 	{
3824c4b14c3SIngo Weinhold 		fTokens = argv;
3834c4b14c3SIngo Weinhold 		fTokenCount = argc;
3844c4b14c3SIngo Weinhold 		fTokenIndex = 0;
3854c4b14c3SIngo Weinhold 		fFilterCount = 0;
3864c4b14c3SIngo Weinhold 
3874c4b14c3SIngo Weinhold 		TraceFilter* filter = _ParseExpression();
3884c4b14c3SIngo Weinhold 		return fTokenIndex == fTokenCount && filter != NULL;
3894c4b14c3SIngo Weinhold 	}
3904c4b14c3SIngo Weinhold 
3914c4b14c3SIngo Weinhold 	bool Filter(const TraceEntry* entry, LazyTraceOutput& out)
3924c4b14c3SIngo Weinhold 	{
3934c4b14c3SIngo Weinhold 		return fFilters[0].Filter(entry, out);
3944c4b14c3SIngo Weinhold 	}
3954c4b14c3SIngo Weinhold 
3964c4b14c3SIngo Weinhold private:
3974c4b14c3SIngo Weinhold 	TraceFilter* _ParseExpression()
3984c4b14c3SIngo Weinhold 	{
3994c4b14c3SIngo Weinhold 		const char* token = _NextToken();
4004c4b14c3SIngo Weinhold 		if (!token) {
4014c4b14c3SIngo Weinhold 			// unexpected end of expression
4024c4b14c3SIngo Weinhold 			return NULL;
4034c4b14c3SIngo Weinhold 		}
4044c4b14c3SIngo Weinhold 
4054c4b14c3SIngo Weinhold 		if (fFilterCount == MAX_FILTERS) {
4064c4b14c3SIngo Weinhold 			// too many filters
4074c4b14c3SIngo Weinhold 			return NULL;
4084c4b14c3SIngo Weinhold 		}
4094c4b14c3SIngo Weinhold 
4104c4b14c3SIngo Weinhold 		if (token[0] == '#') {
4114c4b14c3SIngo Weinhold 			TraceFilter* filter = new(&fFilters[fFilterCount++])
4124c4b14c3SIngo Weinhold 				PatternTraceFilter;
4134c4b14c3SIngo Weinhold 			filter->fString = token + 1;
4144c4b14c3SIngo Weinhold 			return filter;
4154c4b14c3SIngo Weinhold 		} else if (strcmp(token, "not") == 0) {
4164c4b14c3SIngo Weinhold 			TraceFilter* filter = new(&fFilters[fFilterCount++]) NotTraceFilter;
4174c4b14c3SIngo Weinhold 			if ((filter->fSubFilters.first = _ParseExpression()) != NULL)
4184c4b14c3SIngo Weinhold 				return filter;
4194c4b14c3SIngo Weinhold 			return NULL;
4204c4b14c3SIngo Weinhold 		} else if (strcmp(token, "and") == 0) {
4214c4b14c3SIngo Weinhold 			TraceFilter* filter = new(&fFilters[fFilterCount++]) AndTraceFilter;
4224c4b14c3SIngo Weinhold 			if ((filter->fSubFilters.first = _ParseExpression()) != NULL
4234c4b14c3SIngo Weinhold 				&& (filter->fSubFilters.second = _ParseExpression()) != NULL) {
4244c4b14c3SIngo Weinhold 				return filter;
4254c4b14c3SIngo Weinhold 			}
4264c4b14c3SIngo Weinhold 			return NULL;
4274c4b14c3SIngo Weinhold 		} else if (strcmp(token, "or") == 0) {
4284c4b14c3SIngo Weinhold 			TraceFilter* filter = new(&fFilters[fFilterCount++]) OrTraceFilter;
4294c4b14c3SIngo Weinhold 			if ((filter->fSubFilters.first = _ParseExpression()) != NULL
4304c4b14c3SIngo Weinhold 				&& (filter->fSubFilters.second = _ParseExpression()) != NULL) {
4314c4b14c3SIngo Weinhold 				return filter;
4324c4b14c3SIngo Weinhold 			}
4334c4b14c3SIngo Weinhold 			return NULL;
4344c4b14c3SIngo Weinhold 		} else if (strcmp(token, "thread") == 0) {
4354c4b14c3SIngo Weinhold 			const char* arg = _NextToken();
4364c4b14c3SIngo Weinhold 			if (arg == NULL) {
4374c4b14c3SIngo Weinhold 				// unexpected end of expression
4384c4b14c3SIngo Weinhold 				return NULL;
4394c4b14c3SIngo Weinhold 			}
4404c4b14c3SIngo Weinhold 
4414c4b14c3SIngo Weinhold 			TraceFilter* filter = new(&fFilters[fFilterCount++])
4424c4b14c3SIngo Weinhold 				ThreadTraceFilter;
4434c4b14c3SIngo Weinhold 			filter->fThread = strtol(arg, NULL, 0);
4444c4b14c3SIngo Weinhold 			return filter;
4454c4b14c3SIngo Weinhold 		} else {
4464c4b14c3SIngo Weinhold 			// invalid token
4474c4b14c3SIngo Weinhold 			return NULL;
4484c4b14c3SIngo Weinhold 		}
4494c4b14c3SIngo Weinhold 	}
4504c4b14c3SIngo Weinhold 
4514c4b14c3SIngo Weinhold 	const char* _CurrentToken() const
4524c4b14c3SIngo Weinhold 	{
4534c4b14c3SIngo Weinhold 		if (fTokenIndex >= 1 && fTokenIndex <= fTokenCount)
4544c4b14c3SIngo Weinhold 			return fTokens[fTokenIndex - 1];
4554c4b14c3SIngo Weinhold 		return NULL;
4564c4b14c3SIngo Weinhold 	}
4574c4b14c3SIngo Weinhold 
4584c4b14c3SIngo Weinhold 	const char* _NextToken()
4594c4b14c3SIngo Weinhold 	{
4604c4b14c3SIngo Weinhold 		if (fTokenIndex >= fTokenCount)
4614c4b14c3SIngo Weinhold 			return NULL;
4624c4b14c3SIngo Weinhold 		return fTokens[fTokenIndex++];
4634c4b14c3SIngo Weinhold 	}
4644c4b14c3SIngo Weinhold 
4654c4b14c3SIngo Weinhold private:
4664c4b14c3SIngo Weinhold 	enum { MAX_FILTERS = 32 };
4674c4b14c3SIngo Weinhold 
4684c4b14c3SIngo Weinhold 	const char* const*			fTokens;
4694c4b14c3SIngo Weinhold 	int							fTokenCount;
4704c4b14c3SIngo Weinhold 	int							fTokenIndex;
4714c4b14c3SIngo Weinhold 	TraceFilter					fFilters[MAX_FILTERS];
4724c4b14c3SIngo Weinhold 	int							fFilterCount;
4734c4b14c3SIngo Weinhold 
4744c4b14c3SIngo Weinhold 	static TraceFilterParser	sParser;
4754c4b14c3SIngo Weinhold };
4764c4b14c3SIngo Weinhold 
4774c4b14c3SIngo Weinhold 
4784c4b14c3SIngo Weinhold TraceFilterParser TraceFilterParser::sParser;
4794c4b14c3SIngo Weinhold 
4804c4b14c3SIngo Weinhold 
481f1047a1cSIngo Weinhold //	#pragma mark -
482f1047a1cSIngo Weinhold 
483f1047a1cSIngo Weinhold 
484aa5d2a2dSAxel Dörfler #if ENABLE_TRACING
485aa5d2a2dSAxel Dörfler 
486aa5d2a2dSAxel Dörfler 
487aa5d2a2dSAxel Dörfler int
488aa5d2a2dSAxel Dörfler dump_tracing(int argc, char** argv)
489aa5d2a2dSAxel Dörfler {
4904c4b14c3SIngo Weinhold 	int argi = 1;
4918e43ece8SAxel Dörfler 
49274652349SIngo Weinhold 	// Note: start and index are Pascal-like indices (i.e. in [1, sEntries]).
493aa5d2a2dSAxel Dörfler 	int32 count = 30;
49474652349SIngo Weinhold 	int32 start = 0;	// special index: print the last count entries
49574652349SIngo Weinhold 	int32 cont = 0;
496aa5d2a2dSAxel Dörfler 
4974c4b14c3SIngo Weinhold 	bool hasFilter = false;
4984c4b14c3SIngo Weinhold 
4994c4b14c3SIngo Weinhold 	if (argi < argc) {
5004c4b14c3SIngo Weinhold 		if (strcmp(argv[argi], "forward") == 0) {
50174652349SIngo Weinhold 			cont = 1;
5024c4b14c3SIngo Weinhold 			argi++;
5034c4b14c3SIngo Weinhold 		} else if (strcmp(argv[argi], "backward") == 0) {
50474652349SIngo Weinhold 			cont = -1;
5054c4b14c3SIngo Weinhold 			argi++;
5064c4b14c3SIngo Weinhold 		}
50774652349SIngo Weinhold 	}
5082d81f045SAxel Dörfler 
5094c4b14c3SIngo Weinhold 	if (cont != 0 && argi < argc) {
510a7e979caSIngo Weinhold 		print_debugger_command_usage(argv[0]);
511aa5d2a2dSAxel Dörfler 		return 0;
512aa5d2a2dSAxel Dörfler 	}
513aa5d2a2dSAxel Dörfler 
5144c4b14c3SIngo Weinhold 	// start
5154c4b14c3SIngo Weinhold 	if (argi < argc) {
5164c4b14c3SIngo Weinhold 		if (strcmp(argv[argi], "filter") == 0) {
5174c4b14c3SIngo Weinhold 			hasFilter = true;
5184c4b14c3SIngo Weinhold 			argi++;
5194c4b14c3SIngo Weinhold 		} else if (argv[argi][0] == '#') {
5204c4b14c3SIngo Weinhold 			hasFilter = true;
5214c4b14c3SIngo Weinhold 		} else {
5224c4b14c3SIngo Weinhold 			start = parse_expression(argv[argi]);
5234c4b14c3SIngo Weinhold 			argi++;
5244c4b14c3SIngo Weinhold 		}
5254c4b14c3SIngo Weinhold 	}
5264c4b14c3SIngo Weinhold 
5274c4b14c3SIngo Weinhold 	// count
5284c4b14c3SIngo Weinhold 	if (!hasFilter && argi < argc) {
5294c4b14c3SIngo Weinhold 		if (strcmp(argv[argi], "filter") == 0) {
5304c4b14c3SIngo Weinhold 			hasFilter = true;
5314c4b14c3SIngo Weinhold 			argi++;
5324c4b14c3SIngo Weinhold 		} else if (argv[argi][0] == '#') {
5334c4b14c3SIngo Weinhold 			hasFilter = true;
5344c4b14c3SIngo Weinhold 		} else {
5354c4b14c3SIngo Weinhold 			count = parse_expression(argv[argi]);
5364c4b14c3SIngo Weinhold 			argi++;
5374c4b14c3SIngo Weinhold 		}
5384c4b14c3SIngo Weinhold 	}
5394c4b14c3SIngo Weinhold 
5404c4b14c3SIngo Weinhold 	// filter specification
5414c4b14c3SIngo Weinhold 	if (argi < argc) {
5424c4b14c3SIngo Weinhold 		hasFilter = true;
5434c4b14c3SIngo Weinhold 		if (strcmp(argv[argi], "filter") == 0)
5444c4b14c3SIngo Weinhold 			argi++;
5454c4b14c3SIngo Weinhold 
5464c4b14c3SIngo Weinhold 		if (!TraceFilterParser::Default()->Parse(argc - argi, argv + argi)) {
5474c4b14c3SIngo Weinhold 			print_debugger_command_usage(argv[0]);
5484c4b14c3SIngo Weinhold 			return 0;
5494c4b14c3SIngo Weinhold 		}
5504c4b14c3SIngo Weinhold 	}
5514c4b14c3SIngo Weinhold 
55274652349SIngo Weinhold 	if (cont != 0) {
55374652349SIngo Weinhold 		start = get_debug_variable("_tracingStart", start);
55474652349SIngo Weinhold 		count = get_debug_variable("_tracingCount", count);
55574652349SIngo Weinhold 		start = max_c(1, start + count * cont);
5564c4b14c3SIngo Weinhold 		hasFilter = get_debug_variable("_tracingFilter", count);
55774652349SIngo Weinhold 	}
558aa5d2a2dSAxel Dörfler 
55974652349SIngo Weinhold 	if ((uint32)count > sEntries)
56074652349SIngo Weinhold 		count = sEntries;
56174652349SIngo Weinhold 	if (start <= 0)
56274652349SIngo Weinhold 		start = max_c(1, sEntries - count + 1);
56374652349SIngo Weinhold 	if (uint32(start + count) > sEntries)
56474652349SIngo Weinhold 		count = sEntries - start + 1;
56574652349SIngo Weinhold 
56674652349SIngo Weinhold 	int32 index = 1;
5675276dad0SAxel Dörfler 	int32 dumped = 0;
568aa5d2a2dSAxel Dörfler 
569960f8f24SAxel Dörfler 	for (trace_entry* current = sFirstEntry; current != NULL;
570aa5d2a2dSAxel Dörfler 			current = next_entry(current), index++) {
5715276dad0SAxel Dörfler 		if ((current->flags & BUFFER_ENTRY) != 0) {
5728e43ece8SAxel Dörfler 			// skip buffer entries
5738e43ece8SAxel Dörfler 			index--;
5748e43ece8SAxel Dörfler 			continue;
5758e43ece8SAxel Dörfler 		}
57674652349SIngo Weinhold 		if (index < start)
57774652349SIngo Weinhold 			continue;
57874652349SIngo Weinhold 		if (index >= start + count)
57974652349SIngo Weinhold 			break;
580aa5d2a2dSAxel Dörfler 
5818e43ece8SAxel Dörfler 		if ((current->flags & ENTRY_INITIALIZED) != 0) {
5828e43ece8SAxel Dörfler 			char buffer[256];
5834c4b14c3SIngo Weinhold 			LazyTraceOutput out(buffer, sizeof(buffer));
584f7a5d9c5SIngo Weinhold 
5854c4b14c3SIngo Weinhold 			TraceEntry* entry = (TraceEntry*)current;
5864c4b14c3SIngo Weinhold 			if (hasFilter && !TraceFilterParser::Default()->Filter(entry, out))
5878e43ece8SAxel Dörfler 				continue;
5888e43ece8SAxel Dörfler 
5894c4b14c3SIngo Weinhold 			kprintf("%5ld. %s\n", index, out.DumpEntry(entry));
5908e43ece8SAxel Dörfler 		} else
5918e43ece8SAxel Dörfler 			kprintf("%5ld. ** uninitialized entry **\n", index);
59274652349SIngo Weinhold 
59374652349SIngo Weinhold 		dumped++;
594aa5d2a2dSAxel Dörfler 	}
595aa5d2a2dSAxel Dörfler 
596f70280a7SAxel Dörfler 	kprintf("entries %ld to %ld (%ld of %ld). %ld entries written\n", start,
597f70280a7SAxel Dörfler 		start + count - 1, dumped, sEntries, sWritten);
59874652349SIngo Weinhold 
59974652349SIngo Weinhold 	set_debug_variable("_tracingStart", start);
60074652349SIngo Weinhold 	set_debug_variable("_tracingCount", count);
6014c4b14c3SIngo Weinhold 	set_debug_variable("_tracingFilter", hasFilter);
60274652349SIngo Weinhold 
60374652349SIngo Weinhold 	return cont != 0 ? B_KDEBUG_CONT : 0;
604aa5d2a2dSAxel Dörfler }
605aa5d2a2dSAxel Dörfler 
606aa5d2a2dSAxel Dörfler 
607aa5d2a2dSAxel Dörfler #endif	// ENABLE_TRACING
608aa5d2a2dSAxel Dörfler 
6092d81f045SAxel Dörfler 
6108e43ece8SAxel Dörfler extern "C" uint8*
6118e43ece8SAxel Dörfler alloc_tracing_buffer(size_t size)
6128e43ece8SAxel Dörfler {
6138e43ece8SAxel Dörfler #if	ENABLE_TRACING
61474652349SIngo Weinhold 	trace_entry* entry = allocate_entry(size + sizeof(trace_entry),
61574652349SIngo Weinhold 		BUFFER_ENTRY);
6168e43ece8SAxel Dörfler 	if (entry == NULL)
6178e43ece8SAxel Dörfler 		return NULL;
6188e43ece8SAxel Dörfler 
6198e43ece8SAxel Dörfler 	return (uint8*)(entry + 1);
6208e43ece8SAxel Dörfler #else
6218e43ece8SAxel Dörfler 	return NULL;
6228e43ece8SAxel Dörfler #endif
6238e43ece8SAxel Dörfler }
6248e43ece8SAxel Dörfler 
625aa5d2a2dSAxel Dörfler 
6260b60583fSIngo Weinhold uint8*
6270b60583fSIngo Weinhold alloc_tracing_buffer_memcpy(const void* source, size_t size, bool user)
6280b60583fSIngo Weinhold {
6298bd6d45dSIngo Weinhold 	if (user && !IS_USER_ADDRESS(source))
6308bd6d45dSIngo Weinhold 		return NULL;
6318bd6d45dSIngo Weinhold 
6320b60583fSIngo Weinhold 	uint8* buffer = alloc_tracing_buffer(size);
6330b60583fSIngo Weinhold 	if (buffer == NULL)
6340b60583fSIngo Weinhold 		return NULL;
6350b60583fSIngo Weinhold 
6360b60583fSIngo Weinhold 	if (user) {
6370b60583fSIngo Weinhold 		if (user_memcpy(buffer, source, size) != B_OK)
6380b60583fSIngo Weinhold 			return NULL;
6390b60583fSIngo Weinhold 	} else
6400b60583fSIngo Weinhold 		memcpy(buffer, source, size);
6410b60583fSIngo Weinhold 
6420b60583fSIngo Weinhold 	return buffer;
6430b60583fSIngo Weinhold }
6440b60583fSIngo Weinhold 
6450b60583fSIngo Weinhold 
6460b60583fSIngo Weinhold char*
6470b60583fSIngo Weinhold alloc_tracing_buffer_strcpy(const char* source, size_t maxSize, bool user)
6480b60583fSIngo Weinhold {
6498bd6d45dSIngo Weinhold 	if (source == NULL || maxSize == 0)
6500b60583fSIngo Weinhold 		return NULL;
6510b60583fSIngo Weinhold 
6528bd6d45dSIngo Weinhold 	if (user && !IS_USER_ADDRESS(source))
6538bd6d45dSIngo Weinhold 		return NULL;
6548bd6d45dSIngo Weinhold 
6558bd6d45dSIngo Weinhold 	// limit maxSize to the actual source string len
6568bd6d45dSIngo Weinhold 	if (user) {
6578bd6d45dSIngo Weinhold 		ssize_t size = user_strlcpy(NULL, source, 0);
6588bd6d45dSIngo Weinhold 			// there's no user_strnlen()
6598bd6d45dSIngo Weinhold 		if (size < 0)
6608bd6d45dSIngo Weinhold 			return 0;
6618bd6d45dSIngo Weinhold 		maxSize = min_c(maxSize, (size_t)size + 1);
6628bd6d45dSIngo Weinhold 	} else
6630b60583fSIngo Weinhold 		maxSize = strnlen(source, maxSize - 1) + 1;
6640b60583fSIngo Weinhold 
6650b60583fSIngo Weinhold 	char* buffer = (char*)alloc_tracing_buffer(maxSize);
6660b60583fSIngo Weinhold 	if (buffer == NULL)
6670b60583fSIngo Weinhold 		return NULL;
6680b60583fSIngo Weinhold 
6690b60583fSIngo Weinhold 	if (user) {
6700b60583fSIngo Weinhold 		if (user_strlcpy(buffer, source, maxSize) < B_OK)
6710b60583fSIngo Weinhold 			return NULL;
6720b60583fSIngo Weinhold 	} else
6730b60583fSIngo Weinhold 		strlcpy(buffer, source, maxSize);
6740b60583fSIngo Weinhold 
6750b60583fSIngo Weinhold 	return buffer;
6760b60583fSIngo Weinhold }
6770b60583fSIngo Weinhold 
6780b60583fSIngo Weinhold 
679aa5d2a2dSAxel Dörfler extern "C" status_t
680aa5d2a2dSAxel Dörfler tracing_init(void)
681aa5d2a2dSAxel Dörfler {
682aa5d2a2dSAxel Dörfler #if	ENABLE_TRACING
683aa5d2a2dSAxel Dörfler 	area_id area = create_area("tracing log", (void**)&sBuffer,
684aa5d2a2dSAxel Dörfler 		B_ANY_KERNEL_ADDRESS, MAX_TRACE_SIZE, B_FULL_LOCK,
685aa5d2a2dSAxel Dörfler 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
6865276dad0SAxel Dörfler 	if (area < B_OK)
687aa5d2a2dSAxel Dörfler 		return area;
688aa5d2a2dSAxel Dörfler 
689960f8f24SAxel Dörfler 	sFirstEntry = sBuffer;
690960f8f24SAxel Dörfler 	sAfterLastEntry = sBuffer;
691aa5d2a2dSAxel Dörfler 
69274652349SIngo Weinhold 	add_debugger_command_etc("traced", &dump_tracing,
69374652349SIngo Weinhold 		"Dump recorded trace entries",
69474652349SIngo Weinhold 		"(\"forward\" | \"backward\") | ([ <start> [ <count> ] ] "
6954c4b14c3SIngo Weinhold 			"[ #<pattern> | (\"filter\" <filter>) ])\n"
69674652349SIngo Weinhold 		"Prints recorded trace entries. If \"backward\" or \"forward\" is\n"
69774652349SIngo Weinhold 		"specified, the command continues where the previous invocation left\n"
69874652349SIngo Weinhold 		"off, i.e. printing the previous respectively next entries (as many\n"
69974652349SIngo Weinhold 		"as printed before). In this case the command is continuable, that is\n"
70074652349SIngo Weinhold 		"afterwards entering an empty line in the debugger will reinvoke it.\n"
70174652349SIngo Weinhold 		"  <start>    - The index of the first entry to print. The index of\n"
70274652349SIngo Weinhold 		"               the first recorded entry is 1. If 0 is specified, the\n"
70374652349SIngo Weinhold 		"               last <count> recorded entries are printed. Defaults \n"
70474652349SIngo Weinhold 		"               to 0.\n"
70574652349SIngo Weinhold 		"  <count>    - The number of entries to be printed. Defaults to 30.\n"
70674652349SIngo Weinhold 		"  <pattern>  - If specified only entries containing this string are\n"
7074c4b14c3SIngo Weinhold 		"               printed.\n"
7084c4b14c3SIngo Weinhold 		"  <filter>   - If specified only entries matching this filter\n"
7094c4b14c3SIngo Weinhold 		"               expression are printed. The expression can consist of\n"
7104c4b14c3SIngo Weinhold 		"               prefix operators \"not\", \"and\", \"or\", filters of\n"
7114c4b14c3SIngo Weinhold 		"               the kind \"'thread' <thread>\" (matching entries\n"
7124c4b14c3SIngo Weinhold 		"               with the given thread ID), or filter of the kind\n"
7134c4b14c3SIngo Weinhold 		"               \"#<pattern>\" (matching entries containing the given\n"
7144c4b14c3SIngo Weinhold 		"               string.\n", 0);
715aa5d2a2dSAxel Dörfler #endif	// ENABLE_TRACING
716aa5d2a2dSAxel Dörfler 	return B_OK;
717aa5d2a2dSAxel Dörfler }
718aa5d2a2dSAxel Dörfler 
719