1 //----------------------------------------------------------------------
2 // This software is part of the OpenBeOS distribution and is covered
3 // by the OpenBeOS license.
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 //----------------------------------------------------------------------
11 Support code for handy debugging macros.
16 #include <KernelExport.h>
21 //----------------------------------------------------------------------
22 // Long-winded overview of the debug output macros:
23 //----------------------------------------------------------------------
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.
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.
32 If DEBUG is undefined, does nothing.
34 //----------------------------------------------------------------------
36 \brief Prints out the enclosing function's name followed by the contents
37 of \a x at the current indentation level.
39 \param x A printf-style format string enclosed in an extra set of parenteses,
40 e.g. PRINT(("%d\n", 0));
42 If DEBUG is undefined, does nothing.
44 //----------------------------------------------------------------------
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.
49 \param x A printf-style format string enclosed in an extra set of parenteses,
50 e.g. PRINT(("%d\n", 0));
52 If DEBUG is undefined, does nothing.
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).
59 \param x A printf-style format string enclosed in an extra set of parenteses,
60 e.g. PRINT(("%d\n", 0));
62 If DEBUG is undefined, does nothing.
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
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.
73 If DEBUG is undefined, does nothing.
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().
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.
84 \param error A \c status_t error code to report.
86 If DEBUG is undefined, does nothing.
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;".
94 \param error A \c status_t error code to report (if negative) and return.
96 If DEBUG is undefined, silently returns the value in \c error.
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;".
104 \param error A \c status_t error code to report and return.
106 If DEBUG is undefined, silently returns the value in \c error.
108 //----------------------------------------------------------------------
110 \brief Prints out a fatal error message.
112 This one's still a work in progress...
114 \param x A printf-style format string enclosed in an extra set of parenteses,
115 e.g. PRINT(("%d\n", 0));
117 If DEBUG is undefined, does nothing.
119 //----------------------------------------------------------------------
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.
125 \param x A printf-style format string enclosed in an extra set of parenteses,
126 e.g. PRINT(("%d\n", 0));
128 I'll say it again: Prints its output regardless to DEBUG being defined or
131 //----------------------------------------------------------------------
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.
137 \param x Damn near anything resembling valid C\C++.
139 //----------------------------------------------------------------------
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.
145 \param x A printf-style format string enclosed in an extra set of parenteses,
146 e.g. PRINT(("%d\n", 0));
150 //----------------------------------------------------------------------
152 //----------------------------------------------------------------------
154 static void indent(uint8 tabCount
);
155 static void unindent(uint8 tabCount
);
157 static int32
get_tls_handle();
160 //! Used to keep the tls handle from being allocated more than once.
161 vint32 tls_spinlock
= 0;
163 /*! \brief Used to flag whether the tls handle has been allocated yet.
165 Not sure if this really needs to be \c volatile or not...
167 volatile bool tls_handle_initialized
= false;
169 //! The tls handle of the tls var used to store indentation info.
170 int32 tls_handle
= 0;
172 //----------------------------------------------------------------------
174 //----------------------------------------------------------------------
176 /*! \brief Returns the current debug indentation level for the
179 NOTE: indentation is currently unsupported for R5::kernelland due
180 to lack of thread local storage support.
183 _get_debug_indent_level()
186 return (int32
)tls_get(get_tls_handle());
192 //----------------------------------------------------------------------
194 //----------------------------------------------------------------------
196 /*! \brief Increases the current debug indentation level for
197 the current thread by 1.
200 indent(uint8 tabCount
)
203 tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()+tabCount
));
207 /*! \brief Decreases the current debug indentation level for
208 the current thread by 1.
211 unindent(uint8 tabCount
)
214 tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()-tabCount
));
219 /*! \brief Returns the thread local storage handle used to store
220 indentation information, allocating the handle first if
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);
234 // All others must wait patiently
235 while (!tls_handle_initialized
) {
244 /*! \brief Helper class for initializing the debugging output
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.
253 class DebugOutputFile
{
255 DebugOutputFile(const char *filename
= NULL
)
266 void Init(const char *filename
) {
267 if (fFile
< 0 && filename
)
268 fFile
= open(filename
, O_RDWR
| O_CREAT
| O_TRUNC
);
271 int File() const { return fFile
; }
276 DebugOutputFile
*out
= NULL
;
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
283 void initialize_debugger(const char *filename
)
287 out
= new DebugOutputFile(filename
);
288 dbg_printf("out was NULL!\n");
290 DebugOutputFile
*temp
= out
;
291 out
= new DebugOutputFile(filename
);
292 dbg_printf("out was %p!\n", temp
);
297 // dbg_printf, stolen from Ingo's ReiserFS::Debug.cpp.
299 dbg_printf(const char *format
,...)
307 va_start(args
, format
);
308 // no vsnprintf() on PPC and in kernel
309 #if defined(__INTEL__) && USER
310 vsnprintf(buffer
, sizeof(buffer
) - 1, format
, args
);
312 vsprintf(buffer
, format
, args
);
315 buffer
[sizeof(buffer
) - 1] = '\0';
316 write(out
->File(), buffer
, strlen(buffer
));
320 //----------------------------------------------------------------------
322 //----------------------------------------------------------------------
324 /*! \brief Increases the current indentation level.
326 DebugHelper::DebugHelper(const char *className
, uint8 tabCount
)
327 : fTabCount(tabCount
)
332 fClassName
= (char*)malloc(strlen(className
)+1);
334 strcpy(fClassName
, className
);
338 /*! \brief Decreases the current indentation level.
340 DebugHelper::~DebugHelper()