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