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