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