xref: /haiku/src/add-ons/kernel/file_systems/udf/UdfDebug.cpp (revision 5e7964b0a929555415798dea3373db9ac4611caa)
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 "UdfDebug.h"
15 
16 #include <stdlib.h>
17 #include <string.h>
18 #include <KernelExport.h>
19 #include <TLS.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 
154 static void indent(uint8 tabCount);
155 static void unindent(uint8 tabCount);
156 #if !_KERNEL_MODE
157 	static int32 get_tls_handle();
158 #endif
159 
160 //! Used to keep the tls handle from being allocated more than once.
161 int32 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 */
167 volatile bool tls_handle_initialized = false;
168 
169 //! The tls handle of the tls var used to store indentation info.
170 int32 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 */
182 int32
183 _get_debug_indent_level()
184 {
185 #if !_KERNEL_MODE
186 	return (addr_t)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 */
199 void
200 indent(uint8 tabCount)
201 {
202 #if !_KERNEL_MODE
203 	tls_set(get_tls_handle(),
204 		(void*)(addr_t(_get_debug_indent_level()+tabCount)));
205 #endif
206 }
207 
208 /*! \brief Decreases the current debug indentation level for
209 	the current thread by 1.
210 */
211 void
212 unindent(uint8 tabCount)
213 {
214 #if !_KERNEL_MODE
215 	tls_set(get_tls_handle(),
216 		(void*)(addr_t(_get_debug_indent_level()-tabCount)));
217 #endif
218 }
219 
220 #if !_KERNEL_MODE
221 /*! \brief Returns the thread local storage handle used to store
222 	indentation information, allocating the handle first if
223 	necessary.
224 */
225 int32
226 get_tls_handle()
227 {
228 	// Init the tls handle if this is the first call.
229 	if (!tls_handle_initialized) {
230 		if (atomic_or(&tls_spinlock, 1) == 0) {
231 			// First one in gets to init
232 			tls_handle = tls_allocate();
233 			tls_handle_initialized = true;
234 			atomic_and(&tls_spinlock, 0);
235 		} else {
236 			// All others must wait patiently
237 			while (!tls_handle_initialized) {
238 				snooze(1);
239 			}
240 		}
241 	}
242 	return tls_handle;
243 }
244 #endif
245 
246 /*! \brief Helper class for initializing the debugging output
247 	file.
248 
249 	Note that this hummer isn't threadsafe, but it doesn't really
250 	matter for our concerns, since the worst it'll result in is
251 	a dangling file descriptor, and that would be in the case of
252 	two or more volumes being mounted almost simultaneously...
253 	not too big of a worry.
254 */
255 class DebugOutputFile {
256 public:
257 	DebugOutputFile(const char *filename = NULL)
258 		: fFile(-1)
259 	{
260 		Init(filename);
261 	}
262 
263 	~DebugOutputFile() {
264 		if (fFile >= 0)
265 			close(fFile);
266 	}
267 
268 	void Init(const char *filename) {
269 		if (fFile < 0 && filename)
270 			fFile = open(filename, O_RDWR | O_CREAT | O_TRUNC);
271 	}
272 
273 	int File() const { return fFile; }
274 private:
275 	int fFile;
276 };
277 
278 DebugOutputFile *out = NULL;
279 
280 /*!	\brief It doesn't appear that the constructor for the global
281 	\c out variable is called when built as an R5 filesystem add-on,
282 	so this function needs to be called in udf_mount to let the
283 	magic happen.
284 */
285 void initialize_debugger(const char *filename)
286 {
287 #if DEBUG_TO_FILE
288 	if (!out) {
289 		out = new(nothrow) DebugOutputFile(filename);
290 		dbg_printf("out was NULL!\n");
291 	} else {
292 		DebugOutputFile *temp = out;
293 		out = new(nothrow) DebugOutputFile(filename);
294 		dbg_printf("out was %p!\n", temp);
295 	}
296 #endif
297 }
298 
299 // dbg_printf, stolen from Ingo's ReiserFS::Debug.cpp.
300 void
301 dbg_printf(const char *format,...)
302 {
303 #if DEBUG_TO_FILE
304 	if (!out)
305 		return;
306 
307 	char buffer[1024];
308 	va_list args;
309 	va_start(args, format);
310 	// no vsnprintf() on PPC
311 	#if defined(__INTEL__) && !_KERNEL_MODE
312 		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
313 	#else
314 		vsprintf(buffer, format, args);
315 	#endif
316 	va_end(args);
317 	buffer[sizeof(buffer) - 1] = '\0';
318 	write(out->File(), buffer, strlen(buffer));
319 #endif
320 }
321 
322 //----------------------------------------------------------------------
323 // DebugHelper
324 //----------------------------------------------------------------------
325 
326 /*! \brief Increases the current indentation level.
327 */
328 DebugHelper::DebugHelper(const char *className, uint8 tabCount)
329 	: fTabCount(tabCount)
330 	, fClassName(NULL)
331 {
332 	indent(fTabCount);
333 	if (className) {
334 		fClassName = (char*)malloc(strlen(className)+1);
335 		if (fClassName)
336 			strcpy(fClassName, className);
337 	}
338 }
339 
340 /*! \brief Decreases the current indentation level.
341 */
342 DebugHelper::~DebugHelper()
343 {
344 	unindent(fTabCount);
345 	free(fClassName);
346 }
347 
348