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(error) 93 \brief Calls \c LPRINT(x) with a format string listing the error 94 code in \c error (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 error 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(error) 109 \brief Calls \c REPORT_ERROR(error) if error 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 error;". 112 113 \param error A \c status_t error code to report (if negative) and return. 114 115 If DEBUG is undefined, silently returns the value in \c error. 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(error) 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 error;". 125 126 \param error A \c status_t error code to report and return. 127 128 If DEBUG is undefined, silently returns the value in \c error. 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