1//----------------------------------------------------------------------
2//  This software is part of the OpenBeOS distribution and is covered
3//  by the MIT License.
4//
5//  This version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
6//  Initial version copyright (c) 2002 Axel D��rfler, axeld@pinc-software.de
7//----------------------------------------------------------------------
8
9/*! \file Debug.cpp
10
11	Support code for handy debugging macros.
12*/
13
14#include "Debug.h"
15
16#include <KernelExport.h>
17#include <TLS.h>
18
19#include <string.h>
20
21//----------------------------------------------------------------------
22// Long-winded overview of the debug output macros:
23//----------------------------------------------------------------------
24/*! \def DEBUG_INIT()
25	\brief Increases the indentation level, prints out the enclosing function's
26	name, and creates a \c DebugHelper object on the stack to automatically
27	decrease the indentation level upon function exit.
28
29	This macro should be called at the very beginning of any function in
30	which you wish to use any of the other debugging macros.
31
32	If DEBUG is undefined, does nothing.
33*/
34//----------------------------------------------------------------------
35/*! \def PRINT(x)
36	\brief Prints out the enclosing function's name followed by the contents
37	of \a x at the current indentation level.
38
39	\param x A printf-style format string enclosed in an extra set of parenteses,
40	         e.g. PRINT(("%d\n", 0));
41
42	If DEBUG is undefined, does nothing.
43*/
44//----------------------------------------------------------------------
45/*! \def LPRINT(x)
46	\brief Identical to \c PRINT(x), except that the line number in the source
47	file at which the macro is invoked is also printed.
48
49	\param x A printf-style format string enclosed in an extra set of parenteses,
50	         e.g. PRINT(("%d\n", 0));
51
52	If DEBUG is undefined, does nothing.
53*/
54//----------------------------------------------------------------------
55/*! \def SIMPLE_PRINT(x)
56	\brief Directly prints the contents of \a x with no extra formatting or
57	information included (just like a straight \c printf() call).
58
59	\param x A printf-style format string enclosed in an extra set of parenteses,
60	         e.g. PRINT(("%d\n", 0));
61
62	If DEBUG is undefined, does nothing.
63*/
64//----------------------------------------------------------------------
65/*! \def PRINT_INDENT()
66	\brief Prints out enough indentation characters to indent the current line
67	to the current indentation level (assuming the cursor was flush left to
68	begin with...).
69
70	This function is called by the other \c *PRINT* macros, and isn't really
71	intended for general consumption, but you might find it useful.
72
73	If DEBUG is undefined, does nothing.
74*/
75//----------------------------------------------------------------------
76/*! \def REPORT_ERROR(error)
77	\brief Calls \c LPRINT(x) with a format string listing the error
78	code in \c error (assumed to be a \c status_t value) and the
79	corresponding text error code returned by a call to \c strerror().
80
81	This function is called by the \c RETURN* macros, and isn't really
82	intended for general consumption, but you might find it useful.
83
84	\param error A \c status_t error code to report.
85
86	If DEBUG is undefined, does nothing.
87*/
88//----------------------------------------------------------------------
89/*! \def RETURN_ERROR(error)
90	\brief Calls \c REPORT_ERROR(error) if error is a an error code (i.e.
91	negative), otherwise remains silent. In either case, the enclosing
92	function is then exited with a call to \c "return error;".
93
94	\param error A \c status_t error code to report (if negative) and return.
95
96	If DEBUG is undefined, silently returns the value in \c error.
97*/
98//----------------------------------------------------------------------
99/*! \def RETURN(error)
100	\brief Prints out a description of the error code being returned
101	(which, in this case, may be either "erroneous" or "successful")
102	and then exits the enclosing function with a call to \c "return error;".
103
104	\param error A \c status_t error code to report and return.
105
106	If DEBUG is undefined, silently returns the value in \c error.
107*/
108//----------------------------------------------------------------------
109/*! \def FATAL(x)
110	\brief Prints out a fatal error message.
111
112	This one's still a work in progress...
113
114	\param x A printf-style format string enclosed in an extra set of parenteses,
115	         e.g. PRINT(("%d\n", 0));
116
117	If DEBUG is undefined, does nothing.
118*/
119//----------------------------------------------------------------------
120/*! \def INFORM(x)
121	\brief Directly prints the contents of \a x with no extra formatting or
122	information included (just like a straight \c printf() call). Does so
123	whether \c DEBUG is defined or not.
124
125	\param x A printf-style format string enclosed in an extra set of parenteses,
126	         e.g. PRINT(("%d\n", 0));
127
128	I'll say it again: Prints its output regardless to DEBUG being defined or
129	undefined.
130*/
131//----------------------------------------------------------------------
132/*! \def DBG(x)
133	\brief If debug is defined, \a x is passed along to the code and
134	executed unmodified. If \c DEBUG is undefined, the contents of
135	\a x disappear into the ether.
136
137	\param x Damn near anything resembling valid C\C++.
138*/
139//----------------------------------------------------------------------
140/*! \def DIE(x)
141	\brief Drops the user into the appropriate debugger (user or kernel)
142	after printing out the handy message bundled in the parenthesee
143	enclosed printf-style format string found in \a x.
144
145	\param x A printf-style format string enclosed in an extra set of parenteses,
146	         e.g. PRINT(("%d\n", 0));
147*/
148
149
150//----------------------------------------------------------------------
151// declarations
152//----------------------------------------------------------------------
153
154static void indent(uint8 tabCount);
155static void unindent(uint8 tabCount);
156#ifdef USER
157	static int32 get_tls_handle();
158#endif
159
160//! Used to keep the tls handle from being allocated more than once.
161vint32 tls_spinlock = 0;
162
163/*! \brief Used to flag whether the tls handle has been allocated yet.
164
165	Not sure if this really needs to be \c volatile or not...
166*/
167volatile bool tls_handle_initialized = false;
168
169//! The tls handle of the tls var used to store indentation info.
170int32 tls_handle = 0;
171
172//----------------------------------------------------------------------
173// public functions
174//----------------------------------------------------------------------
175
176/*! \brief Returns the current debug indentation level for the
177	current thread.
178
179	NOTE: indentation is currently unsupported for R5::kernelland due
180	to lack of thread local storage support.
181*/
182int32
183_get_debug_indent_level()
184{
185#ifdef USER
186	return (int32)tls_get(get_tls_handle());
187#else
188	return 1;
189#endif
190}
191
192//----------------------------------------------------------------------
193// static functions
194//----------------------------------------------------------------------
195
196/*! \brief Increases the current debug indentation level for
197	the current thread by 1.
198*/
199void
200indent(uint8 tabCount)
201{
202#ifdef USER
203	tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()+tabCount));
204#endif
205}
206
207/*! \brief Decreases the current debug indentation level for
208	the current thread by 1.
209*/
210void
211unindent(uint8 tabCount)
212{
213#ifdef USER
214	tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()-tabCount));
215#endif
216}
217
218#ifdef USER
219/*! \brief Returns the thread local storage handle used to store
220	indentation information, allocating the handle first if
221	necessary.
222*/
223int32
224get_tls_handle()
225{
226	// Init the tls handle if this is the first call.
227	if (!tls_handle_initialized) {
228		if (atomic_or(&tls_spinlock, 1) == 0) {
229			// First one in gets to init
230			tls_handle = tls_allocate();
231			tls_handle_initialized = true;
232			atomic_and(&tls_spinlock, 0);
233		} else {
234			// All others must wait patiently
235			while (!tls_handle_initialized) {
236				snooze(1);
237			}
238		}
239	}
240	return tls_handle;
241}
242#endif
243
244/*! \brief Helper class for initializing the debugging output
245	file.
246
247	Note that this hummer isn't threadsafe, but it doesn't really
248	matter for our concerns, since the worst it'll result in is
249	a dangling file descriptor, and that would be in the case of
250	two or more volumes being mounted almost simultaneously...
251	not too big of a worry.
252*/
253class DebugOutputFile {
254public:
255	DebugOutputFile(const char *filename = NULL)
256		: fFile(-1)
257	{
258		Init(filename);
259	}
260
261	~DebugOutputFile() {
262		if (fFile >= 0)
263			close(fFile);
264	}
265
266	void Init(const char *filename) {
267		if (fFile < 0 && filename)
268			fFile = open(filename, O_RDWR | O_CREAT | O_TRUNC);
269	}
270
271	int File() const { return fFile; }
272private:
273	int fFile;
274};
275
276DebugOutputFile *out = NULL;
277
278/*!	\brief It doesn't appear that the constructor for the global
279	\c out variable is called when built as an R5 filesystem add-on,
280	so this function needs to be called in udf_mount to let the
281	magic happen.
282*/
283void initialize_debugger(const char *filename)
284{
285#if DEBUG_TO_FILE
286	if (!out) {
287		out = new DebugOutputFile(filename);
288		dbg_printf("out was NULL!\n");
289	} else {
290		DebugOutputFile *temp = out;
291		out = new DebugOutputFile(filename);
292		dbg_printf("out was %p!\n", temp);
293	}
294#endif
295}
296
297// dbg_printf, stolen from Ingo's ReiserFS::Debug.cpp.
298void
299dbg_printf(const char *format,...)
300{
301#if DEBUG_TO_FILE
302	if (!out)
303		return;
304
305	char buffer[1024];
306	va_list args;
307	va_start(args, format);
308	// no vsnprintf() on PPC and in kernel
309	#if defined(__i386__) && USER
310		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
311	#else
312		vsprintf(buffer, format, args);
313	#endif
314	va_end(args);
315	buffer[sizeof(buffer) - 1] = '\0';
316	write(out->File(), buffer, strlen(buffer));
317#endif
318}
319
320//----------------------------------------------------------------------
321// DebugHelper
322//----------------------------------------------------------------------
323
324/*! \brief Increases the current indentation level.
325*/
326DebugHelper::DebugHelper(const char *className, uint8 tabCount)
327	: fTabCount(tabCount)
328	, fClassName(NULL)
329{
330	indent(fTabCount);
331	if (className) {
332		fClassName = (char*)malloc(strlen(className)+1);
333		if (fClassName)
334			strcpy(fClassName, className);
335	}
336}
337
338/*! \brief Decreases the current indentation level.
339*/
340DebugHelper::~DebugHelper()
341{
342	unindent(fTabCount);
343	free(fClassName);
344}
345
346