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