1be45fb85STyler Dauwalder//----------------------------------------------------------------------
2be45fb85STyler Dauwalder//  This software is part of the OpenBeOS distribution and is covered
3b6f76ebeSAugustin Cavalier//  by the MIT License.
4be45fb85STyler Dauwalder//
521ea9aeaSTyler Dauwalder//  This version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
6be45fb85STyler Dauwalder//  Initial version copyright (c) 2002 Axel D��rfler, axeld@pinc-software.de
7be45fb85STyler Dauwalder//----------------------------------------------------------------------
8be45fb85STyler Dauwalder
921ea9aeaSTyler Dauwalder/*! \file Debug.cpp
10be45fb85STyler Dauwalder
11be45fb85STyler Dauwalder	Support code for handy debugging macros.
12fe89a5baSTyler Dauwalder*/
13fe89a5baSTyler Dauwalder
14be45fb85STyler Dauwalder#include "UdfDebug.h"
15fe89a5baSTyler Dauwalder
1621ea9aeaSTyler Dauwalder#include <stdlib.h>
17c49d6efcSSalvatore Benedetto#include <string.h>
18fe89a5baSTyler Dauwalder#include <KernelExport.h>
19be45fb85STyler Dauwalder#include <TLS.h>
20be45fb85STyler Dauwalder
21778d70caSTyler Dauwalder//----------------------------------------------------------------------
22778d70caSTyler Dauwalder// Long-winded overview of the debug output macros:
23778d70caSTyler Dauwalder//----------------------------------------------------------------------
2421ea9aeaSTyler Dauwalder/*! \def DEBUG_INIT()
25778d70caSTyler Dauwalder	\brief Increases the indentation level, prints out the enclosing function's
266cbf5bf3STyler Dauwalder	name, and creates a \c DebugHelper object on the stack to automatically
27778d70caSTyler Dauwalder	decrease the indentation level upon function exit.
28778d70caSTyler Dauwalder
29778d70caSTyler Dauwalder	This macro should be called at the very beginning of any function in
30778d70caSTyler Dauwalder	which you wish to use any of the other debugging macros.
31778d70caSTyler Dauwalder
32778d70caSTyler Dauwalder	If DEBUG is undefined, does nothing.
33778d70caSTyler Dauwalder*/
34778d70caSTyler Dauwalder//----------------------------------------------------------------------
35778d70caSTyler Dauwalder/*! \def PRINT(x)
36778d70caSTyler Dauwalder	\brief Prints out the enclosing function's name followed by the contents
37778d70caSTyler Dauwalder	of \a x at the current indentation level.
38778d70caSTyler Dauwalder
39778d70caSTyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
40778d70caSTyler Dauwalder	         e.g. PRINT(("%d\n", 0));
41778d70caSTyler Dauwalder
42778d70caSTyler Dauwalder	If DEBUG is undefined, does nothing.
43778d70caSTyler Dauwalder*/
44778d70caSTyler Dauwalder//----------------------------------------------------------------------
45778d70caSTyler Dauwalder/*! \def LPRINT(x)
46778d70caSTyler Dauwalder	\brief Identical to \c PRINT(x), except that the line number in the source
47778d70caSTyler Dauwalder	file at which the macro is invoked is also printed.
48778d70caSTyler Dauwalder
49778d70caSTyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
50778d70caSTyler Dauwalder	         e.g. PRINT(("%d\n", 0));
51778d70caSTyler Dauwalder
52778d70caSTyler Dauwalder	If DEBUG is undefined, does nothing.
53778d70caSTyler Dauwalder*/
54778d70caSTyler Dauwalder//----------------------------------------------------------------------
55778d70caSTyler Dauwalder/*! \def SIMPLE_PRINT(x)
56778d70caSTyler Dauwalder	\brief Directly prints the contents of \a x with no extra formatting or
57778d70caSTyler Dauwalder	information included (just like a straight \c printf() call).
58778d70caSTyler Dauwalder
59778d70caSTyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
60778d70caSTyler Dauwalder	         e.g. PRINT(("%d\n", 0));
61778d70caSTyler Dauwalder
62778d70caSTyler Dauwalder	If DEBUG is undefined, does nothing.
63778d70caSTyler Dauwalder*/
64778d70caSTyler Dauwalder//----------------------------------------------------------------------
65778d70caSTyler Dauwalder/*! \def PRINT_INDENT()
66778d70caSTyler Dauwalder	\brief Prints out enough indentation characters to indent the current line
67778d70caSTyler Dauwalder	to the current indentation level (assuming the cursor was flush left to
68778d70caSTyler Dauwalder	begin with...).
69778d70caSTyler Dauwalder
70778d70caSTyler Dauwalder	This function is called by the other \c *PRINT* macros, and isn't really
71778d70caSTyler Dauwalder	intended for general consumption, but you might find it useful.
72778d70caSTyler Dauwalder
73778d70caSTyler Dauwalder	If DEBUG is undefined, does nothing.
74778d70caSTyler Dauwalder*/
75778d70caSTyler Dauwalder//----------------------------------------------------------------------
7643c2ddb4STyler Dauwalder/*! \def REPORT_ERROR(error)
77778d70caSTyler Dauwalder	\brief Calls \c LPRINT(x) with a format string listing the error
7843c2ddb4STyler Dauwalder	code in \c error (assumed to be a \c status_t value) and the
79778d70caSTyler Dauwalder	corresponding text error code returned by a call to \c strerror().
80778d70caSTyler Dauwalder
81778d70caSTyler Dauwalder	This function is called by the \c RETURN* macros, and isn't really
82778d70caSTyler Dauwalder	intended for general consumption, but you might find it useful.
83778d70caSTyler Dauwalder
8443c2ddb4STyler Dauwalder	\param error A \c status_t error code to report.
85778d70caSTyler Dauwalder
86778d70caSTyler Dauwalder	If DEBUG is undefined, does nothing.
87778d70caSTyler Dauwalder*/
88778d70caSTyler Dauwalder//----------------------------------------------------------------------
8943c2ddb4STyler Dauwalder/*! \def RETURN_ERROR(error)
9043c2ddb4STyler Dauwalder	\brief Calls \c REPORT_ERROR(error) if error is a an error code (i.e.
91778d70caSTyler Dauwalder	negative), otherwise remains silent. In either case, the enclosing
9243c2ddb4STyler Dauwalder	function is then exited with a call to \c "return error;".
93778d70caSTyler Dauwalder
9443c2ddb4STyler Dauwalder	\param error A \c status_t error code to report (if negative) and return.
95778d70caSTyler Dauwalder
9643c2ddb4STyler Dauwalder	If DEBUG is undefined, silently returns the value in \c error.
97778d70caSTyler Dauwalder*/
98778d70caSTyler Dauwalder//----------------------------------------------------------------------
9943c2ddb4STyler Dauwalder/*! \def RETURN(error)
100778d70caSTyler Dauwalder	\brief Prints out a description of the error code being returned
101778d70caSTyler Dauwalder	(which, in this case, may be either "erroneous" or "successful")
10243c2ddb4STyler Dauwalder	and then exits the enclosing function with a call to \c "return error;".
103778d70caSTyler Dauwalder
10443c2ddb4STyler Dauwalder	\param error A \c status_t error code to report and return.
105778d70caSTyler Dauwalder
10643c2ddb4STyler Dauwalder	If DEBUG is undefined, silently returns the value in \c error.
107778d70caSTyler Dauwalder*/
108778d70caSTyler Dauwalder//----------------------------------------------------------------------
109778d70caSTyler Dauwalder/*! \def FATAL(x)
110778d70caSTyler Dauwalder	\brief Prints out a fatal error message.
111778d70caSTyler Dauwalder
112778d70caSTyler Dauwalder	This one's still a work in progress...
113778d70caSTyler Dauwalder
114778d70caSTyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
115778d70caSTyler Dauwalder	         e.g. PRINT(("%d\n", 0));
116778d70caSTyler Dauwalder
117778d70caSTyler Dauwalder	If DEBUG is undefined, does nothing.
118778d70caSTyler Dauwalder*/
119778d70caSTyler Dauwalder//----------------------------------------------------------------------
120778d70caSTyler Dauwalder/*! \def INFORM(x)
121778d70caSTyler Dauwalder	\brief Directly prints the contents of \a x with no extra formatting or
122778d70caSTyler Dauwalder	information included (just like a straight \c printf() call). Does so
123778d70caSTyler Dauwalder	whether \c DEBUG is defined or not.
124778d70caSTyler Dauwalder
125778d70caSTyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
126778d70caSTyler Dauwalder	         e.g. PRINT(("%d\n", 0));
127778d70caSTyler Dauwalder
128778d70caSTyler Dauwalder	I'll say it again: Prints its output regardless to DEBUG being defined or
129778d70caSTyler Dauwalder	undefined.
130778d70caSTyler Dauwalder*/
131778d70caSTyler Dauwalder//----------------------------------------------------------------------
132778d70caSTyler Dauwalder/*! \def DBG(x)
133778d70caSTyler Dauwalder	\brief If debug is defined, \a x is passed along to the code and
134778d70caSTyler Dauwalder	executed unmodified. If \c DEBUG is undefined, the contents of
135778d70caSTyler Dauwalder	\a x disappear into the ether.
136778d70caSTyler Dauwalder
137778d70caSTyler Dauwalder	\param x Damn near anything resembling valid C\C++.
138778d70caSTyler Dauwalder*/
139778d70caSTyler Dauwalder//----------------------------------------------------------------------
140778d70caSTyler Dauwalder/*! \def DIE(x)
141778d70caSTyler Dauwalder	\brief Drops the user into the appropriate debugger (user or kernel)
142778d70caSTyler Dauwalder	after printing out the handy message bundled in the parenthesee
143778d70caSTyler Dauwalder	enclosed printf-style format string found in \a x.
144778d70caSTyler Dauwalder
145778d70caSTyler Dauwalder	\param x A printf-style format string enclosed in an extra set of parenteses,
146778d70caSTyler Dauwalder	         e.g. PRINT(("%d\n", 0));
147778d70caSTyler Dauwalder*/
148778d70caSTyler Dauwalder
149778d70caSTyler Dauwalder
150be45fb85STyler Dauwalder//----------------------------------------------------------------------
151be45fb85STyler Dauwalder// declarations
152be45fb85STyler Dauwalder//----------------------------------------------------------------------
153be45fb85STyler Dauwalder
1546cbf5bf3STyler Dauwalderstatic void indent(uint8 tabCount);
1556cbf5bf3STyler Dauwalderstatic void unindent(uint8 tabCount);
156063b74d2STyler Dauwalder#if !_KERNEL_MODE
157778d70caSTyler Dauwalder	static int32 get_tls_handle();
158778d70caSTyler Dauwalder#endif
159be45fb85STyler Dauwalder
160be45fb85STyler Dauwalder//! Used to keep the tls handle from being allocated more than once.
16149a6a0ebSAdrien Destuguesint32 tls_spinlock = 0;
162be45fb85STyler Dauwalder
163be45fb85STyler Dauwalder/*! \brief Used to flag whether the tls handle has been allocated yet.
164fe89a5baSTyler Dauwalder
165be45fb85STyler Dauwalder	Not sure if this really needs to be \c volatile or not...
166be45fb85STyler Dauwalder*/
167be45fb85STyler Dauwaldervolatile bool tls_handle_initialized = false;
168be45fb85STyler Dauwalder
169be45fb85STyler Dauwalder//! The tls handle of the tls var used to store indentation info.
170be45fb85STyler Dauwalderint32 tls_handle = 0;
171be45fb85STyler Dauwalder
172be45fb85STyler Dauwalder//----------------------------------------------------------------------
173be45fb85STyler Dauwalder// public functions
174be45fb85STyler Dauwalder//----------------------------------------------------------------------
175be45fb85STyler Dauwalder
176be45fb85STyler Dauwalder/*! \brief Returns the current debug indentation level for the
177be45fb85STyler Dauwalder	current thread.
178778d70caSTyler Dauwalder
179778d70caSTyler Dauwalder	NOTE: indentation is currently unsupported for R5::kernelland due
180778d70caSTyler Dauwalder	to lack of thread local storage support.
181be45fb85STyler Dauwalder*/
182be45fb85STyler Dauwalderint32
183be45fb85STyler Dauwalder_get_debug_indent_level()
184be45fb85STyler Dauwalder{
185063b74d2STyler Dauwalder#if !_KERNEL_MODE
1869aec6561SOliver Tappe	return (addr_t)tls_get(get_tls_handle());
187778d70caSTyler Dauwalder#else
188778d70caSTyler Dauwalder	return 1;
189778d70caSTyler Dauwalder#endif
190be45fb85STyler Dauwalder}
191be45fb85STyler Dauwalder
192be45fb85STyler Dauwalder//----------------------------------------------------------------------
193be45fb85STyler Dauwalder// static functions
194be45fb85STyler Dauwalder//----------------------------------------------------------------------
195fe89a5baSTyler Dauwalder
196be45fb85STyler Dauwalder/*! \brief Increases the current debug indentation level for
197be45fb85STyler Dauwalder	the current thread by 1.
198be45fb85STyler Dauwalder*/
199be45fb85STyler Dauwaldervoid
2006cbf5bf3STyler Dauwalderindent(uint8 tabCount)
201be45fb85STyler Dauwalder{
202063b74d2STyler Dauwalder#if !_KERNEL_MODE
2039aec6561SOliver Tappe	tls_set(get_tls_handle(),
2049aec6561SOliver Tappe		(void*)(addr_t(_get_debug_indent_level()+tabCount)));
205778d70caSTyler Dauwalder#endif
206be45fb85STyler Dauwalder}
207be45fb85STyler Dauwalder
208be45fb85STyler Dauwalder/*! \brief Decreases the current debug indentation level for
209be45fb85STyler Dauwalder	the current thread by 1.
210be45fb85STyler Dauwalder*/
211be45fb85STyler Dauwaldervoid
2126cbf5bf3STyler Dauwalderunindent(uint8 tabCount)
213be45fb85STyler Dauwalder{
214063b74d2STyler Dauwalder#if !_KERNEL_MODE
2159aec6561SOliver Tappe	tls_set(get_tls_handle(),
2169aec6561SOliver Tappe		(void*)(addr_t(_get_debug_indent_level()-tabCount)));
217778d70caSTyler Dauwalder#endif
218be45fb85STyler Dauwalder}
219be45fb85STyler Dauwalder
220063b74d2STyler Dauwalder#if !_KERNEL_MODE
221be45fb85STyler Dauwalder/*! \brief Returns the thread local storage handle used to store
222be45fb85STyler Dauwalder	indentation information, allocating the handle first if
223be45fb85STyler Dauwalder	necessary.
224be45fb85STyler Dauwalder*/
225be45fb85STyler Dauwalderint32
226be45fb85STyler Dauwalderget_tls_handle()
227be45fb85STyler Dauwalder{
228be45fb85STyler Dauwalder	// Init the tls handle if this is the first call.
229be45fb85STyler Dauwalder	if (!tls_handle_initialized) {
230be45fb85STyler Dauwalder		if (atomic_or(&tls_spinlock, 1) == 0) {
231be45fb85STyler Dauwalder			// First one in gets to init
232be45fb85STyler Dauwalder			tls_handle = tls_allocate();
233be45fb85STyler Dauwalder			tls_handle_initialized = true;
234be45fb85STyler Dauwalder			atomic_and(&tls_spinlock, 0);
235be45fb85STyler Dauwalder		} else {
236be45fb85STyler Dauwalder			// All others must wait patiently
237be45fb85STyler Dauwalder			while (!tls_handle_initialized) {
238be45fb85STyler Dauwalder				snooze(1);
239be45fb85STyler Dauwalder			}
240be45fb85STyler Dauwalder		}
241be45fb85STyler Dauwalder	}
242be45fb85STyler Dauwalder	return tls_handle;
243be45fb85STyler Dauwalder}
244778d70caSTyler Dauwalder#endif
245be45fb85STyler Dauwalder
24649cab548STyler Dauwalder/*! \brief Helper class for initializing the debugging output
24749cab548STyler Dauwalder	file.
24849cab548STyler Dauwalder
24949cab548STyler Dauwalder	Note that this hummer isn't threadsafe, but it doesn't really
25049cab548STyler Dauwalder	matter for our concerns, since the worst it'll result in is
25149cab548STyler Dauwalder	a dangling file descriptor, and that would be in the case of
25249cab548STyler Dauwalder	two or more volumes being mounted almost simultaneously...
25349cab548STyler Dauwalder	not too big of a worry.
25449cab548STyler Dauwalder*/
25549cab548STyler Dauwalderclass DebugOutputFile {
25649cab548STyler Dauwalderpublic:
25749cab548STyler Dauwalder	DebugOutputFile(const char *filename = NULL)
25849cab548STyler Dauwalder		: fFile(-1)
25949cab548STyler Dauwalder	{
26049cab548STyler Dauwalder		Init(filename);
26149cab548STyler Dauwalder	}
26249cab548STyler Dauwalder
26349cab548STyler Dauwalder	~DebugOutputFile() {
26449cab548STyler Dauwalder		if (fFile >= 0)
26549cab548STyler Dauwalder			close(fFile);
26649cab548STyler Dauwalder	}
26749cab548STyler Dauwalder
26849cab548STyler Dauwalder	void Init(const char *filename) {
26949cab548STyler Dauwalder		if (fFile < 0 && filename)
27049cab548STyler Dauwalder			fFile = open(filename, O_RDWR | O_CREAT | O_TRUNC);
27149cab548STyler Dauwalder	}
27249cab548STyler Dauwalder
27349cab548STyler Dauwalder	int File() const { return fFile; }
27449cab548STyler Dauwalderprivate:
27549cab548STyler Dauwalder	int fFile;
27649cab548STyler Dauwalder};
27749cab548STyler Dauwalder
278eaa70c97STyler DauwalderDebugOutputFile *out = NULL;
27949cab548STyler Dauwalder
28049cab548STyler Dauwalder/*!	\brief It doesn't appear that the constructor for the global
28149cab548STyler Dauwalder	\c out variable is called when built as an R5 filesystem add-on,
28249cab548STyler Dauwalder	so this function needs to be called in udf_mount to let the
28349cab548STyler Dauwalder	magic happen.
28449cab548STyler Dauwalder*/
28549cab548STyler Dauwaldervoid initialize_debugger(const char *filename)
28649cab548STyler Dauwalder{
287eaa70c97STyler Dauwalder#if DEBUG_TO_FILE
288eaa70c97STyler Dauwalder	if (!out) {
289f50008f9STyler Dauwalder		out = new(nothrow) DebugOutputFile(filename);
290eaa70c97STyler Dauwalder		dbg_printf("out was NULL!\n");
291eaa70c97STyler Dauwalder	} else {
292eaa70c97STyler Dauwalder		DebugOutputFile *temp = out;
293f50008f9STyler Dauwalder		out = new(nothrow) DebugOutputFile(filename);
294eaa70c97STyler Dauwalder		dbg_printf("out was %p!\n", temp);
295eaa70c97STyler Dauwalder	}
296eaa70c97STyler Dauwalder#endif
29749cab548STyler Dauwalder}
29849cab548STyler Dauwalder
29949cab548STyler Dauwalder// dbg_printf, stolen from Ingo's ReiserFS::Debug.cpp.
30049cab548STyler Dauwaldervoid
30149cab548STyler Dauwalderdbg_printf(const char *format,...)
30249cab548STyler Dauwalder{
30349cab548STyler Dauwalder#if DEBUG_TO_FILE
304eaa70c97STyler Dauwalder	if (!out)
305eaa70c97STyler Dauwalder		return;
306eaa70c97STyler Dauwalder
30749cab548STyler Dauwalder	char buffer[1024];
30849cab548STyler Dauwalder	va_list args;
30949cab548STyler Dauwalder	va_start(args, format);
31021ea9aeaSTyler Dauwalder	// no vsnprintf() on PPC
3115ffbe7d7SAugustin Cavalier	#if defined(__i386__) && !_KERNEL_MODE
31249cab548STyler Dauwalder		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
31349cab548STyler Dauwalder	#else
31449cab548STyler Dauwalder		vsprintf(buffer, format, args);
31549cab548STyler Dauwalder	#endif
31649cab548STyler Dauwalder	va_end(args);
31749cab548STyler Dauwalder	buffer[sizeof(buffer) - 1] = '\0';
318eaa70c97STyler Dauwalder	write(out->File(), buffer, strlen(buffer));
31949cab548STyler Dauwalder#endif
32049cab548STyler Dauwalder}
32149cab548STyler Dauwalder
322be45fb85STyler Dauwalder//----------------------------------------------------------------------
3236cbf5bf3STyler Dauwalder// DebugHelper
324be45fb85STyler Dauwalder//----------------------------------------------------------------------
325be45fb85STyler Dauwalder
326be45fb85STyler Dauwalder/*! \brief Increases the current indentation level.
327be45fb85STyler Dauwalder*/
32821ea9aeaSTyler DauwalderDebugHelper::DebugHelper(const char *className, uint8 tabCount)
32921ea9aeaSTyler Dauwalder	: fTabCount(tabCount)
3306cbf5bf3STyler Dauwalder	, fClassName(NULL)
331be45fb85STyler Dauwalder{
33221ea9aeaSTyler Dauwalder	indent(fTabCount);
3336cbf5bf3STyler Dauwalder	if (className) {
3346cbf5bf3STyler Dauwalder		fClassName = (char*)malloc(strlen(className)+1);
3356cbf5bf3STyler Dauwalder		if (fClassName)
3366cbf5bf3STyler Dauwalder			strcpy(fClassName, className);
3376cbf5bf3STyler Dauwalder	}
338be45fb85STyler Dauwalder}
339be45fb85STyler Dauwalder
340be45fb85STyler Dauwalder/*! \brief Decreases the current indentation level.
341be45fb85STyler Dauwalder*/
3426cbf5bf3STyler DauwalderDebugHelper::~DebugHelper()
343be45fb85STyler Dauwalder{
34421ea9aeaSTyler Dauwalder	unindent(fTabCount);
3456cbf5bf3STyler Dauwalder	free(fClassName);
346be45fb85STyler Dauwalder}
347fe89a5baSTyler Dauwalder