1 /*********************************************************************************************************************************** 2 Debug Routines 3 ***********************************************************************************************************************************/ 4 #ifndef COMMON_DEBUG_H 5 #define COMMON_DEBUG_H 6 7 #include "common/assert.h" 8 #include "common/stackTrace.h" 9 #include "common/type/convert.h" 10 #include "common/type/stringZ.h" 11 12 /*********************************************************************************************************************************** 13 Base function debugging macros 14 15 In debug mode parameters will always be recorded in the stack trace while in production mode they will only be recorded when the log 16 level is set to debug or trace. 17 ***********************************************************************************************************************************/ 18 #define FUNCTION_LOG_LEVEL() \ 19 FUNCTION_LOG_logLevel 20 21 #ifdef DEBUG_TEST_TRACE 22 #define FUNCTION_LOG_BEGIN_BASE(logLevel) \ 23 LogLevel FUNCTION_LOG_LEVEL() = STACK_TRACE_PUSH(logLevel); \ 24 \ 25 { \ 26 stackTraceParamLog(); \ 27 stackTraceTestStop(); 28 29 #define FUNCTION_LOG_END_BASE() \ 30 stackTraceTestStart(); \ 31 LOG_FMT(FUNCTION_LOG_LEVEL(), 0, "(%s)", stackTraceParam()); \ 32 } 33 #else 34 #define FUNCTION_LOG_BEGIN_BASE(logLevel) \ 35 LogLevel FUNCTION_LOG_LEVEL() = STACK_TRACE_PUSH(logLevel); \ 36 \ 37 if (logAny(FUNCTION_LOG_LEVEL())) \ 38 { \ 39 stackTraceParamLog(); 40 41 #define FUNCTION_LOG_END_BASE() \ 42 LOG_FMT(FUNCTION_LOG_LEVEL(), 0, "(%s)", stackTraceParam()); \ 43 } 44 #endif 45 46 /*********************************************************************************************************************************** 47 General purpose function debugging macros 48 49 FUNCTION_LOG_VOID() is provided as a shortcut for functions that have no parameters. 50 ***********************************************************************************************************************************/ 51 #define FUNCTION_LOG_BEGIN(logLevel) \ 52 FUNCTION_LOG_BEGIN_BASE(logLevel) 53 54 #define FUNCTION_LOG_END() \ 55 FUNCTION_LOG_END_BASE() 56 57 #define FUNCTION_LOG_VOID(logLevel) \ 58 FUNCTION_LOG_BEGIN_BASE(logLevel); \ 59 FUNCTION_LOG_END_BASE() 60 61 #define FUNCTION_LOG_PARAM(typeMacroPrefix, param) \ 62 stackTraceParamAdd(FUNCTION_LOG_##typeMacroPrefix##_FORMAT(param, stackTraceParamBuffer(#param), STACK_TRACE_PARAM_MAX)) 63 64 #define FUNCTION_LOG_PARAM_P(typeMacroPrefix, param) \ 65 do \ 66 { \ 67 char *buffer = stackTraceParamBuffer(#param); \ 68 \ 69 if (param == NULL) \ 70 stackTraceParamAdd(typeToLog(NULL_Z, buffer, STACK_TRACE_PARAM_MAX)); \ 71 else \ 72 { \ 73 buffer[0] = '*'; \ 74 stackTraceParamAdd(FUNCTION_LOG_##typeMacroPrefix##_FORMAT(*param, buffer + 1, STACK_TRACE_PARAM_MAX - 1) + 1); \ 75 } \ 76 } \ 77 while (0) 78 79 #define FUNCTION_LOG_PARAM_PP(typeMacroPrefix, param) \ 80 do \ 81 { \ 82 char *buffer = stackTraceParamBuffer(#param); \ 83 \ 84 if (param == NULL) \ 85 stackTraceParamAdd(typeToLog(NULL_Z, buffer, STACK_TRACE_PARAM_MAX)); \ 86 else if (*param == NULL) \ 87 stackTraceParamAdd(typeToLog("*null", buffer, STACK_TRACE_PARAM_MAX)); \ 88 else \ 89 { \ 90 buffer[0] = '*'; \ 91 buffer[1] = '*'; \ 92 stackTraceParamAdd(FUNCTION_LOG_##typeMacroPrefix##_FORMAT(**param, buffer + 2, STACK_TRACE_PARAM_MAX - 2) + 2); \ 93 } \ 94 } \ 95 while (0) 96 97 /*********************************************************************************************************************************** 98 Functions and macros to render various data types 99 ***********************************************************************************************************************************/ 100 // Convert object to a zero-terminated string for logging 101 size_t objToLog(const void *object, const char *objectName, char *buffer, size_t bufferSize); 102 103 // Convert pointer to a zero-terminated string for logging 104 size_t ptrToLog(const void *pointer, const char *pointerName, char *buffer, size_t bufferSize); 105 106 // Convert zero-terminated string for logging 107 size_t strzToLog(const char *string, char *buffer, size_t bufferSize); 108 109 // Convert a type name to a zero-terminated string for logging 110 size_t typeToLog(const char *typeName, char *buffer, size_t bufferSize); 111 112 #define FUNCTION_LOG_BOOL_TYPE \ 113 bool 114 #define FUNCTION_LOG_BOOL_FORMAT(value, buffer, bufferSize) \ 115 cvtBoolToZ(value, buffer, bufferSize) 116 117 #define FUNCTION_LOG_CHAR_TYPE \ 118 char 119 #define FUNCTION_LOG_CHAR_FORMAT(value, buffer, bufferSize) \ 120 cvtCharToZ(value, buffer, bufferSize) 121 122 #define FUNCTION_LOG_CHARDATA_TYPE \ 123 char 124 #define FUNCTION_LOG_CHARDATA_FORMAT(value, buffer, bufferSize) \ 125 typeToLog("(char)", buffer, bufferSize) 126 127 #define FUNCTION_LOG_CHARPY_TYPE \ 128 char *[] 129 #define FUNCTION_LOG_CHARPY_FORMAT(value, buffer, bufferSize) \ 130 ptrToLog(value, "char *[]", buffer, bufferSize) 131 132 #define FUNCTION_LOG_DOUBLE_TYPE \ 133 double 134 #define FUNCTION_LOG_DOUBLE_FORMAT(value, buffer, bufferSize) \ 135 cvtDoubleToZ(value, buffer, bufferSize) 136 137 #define FUNCTION_LOG_INT_TYPE \ 138 int 139 #define FUNCTION_LOG_INT_FORMAT(value, buffer, bufferSize) \ 140 cvtIntToZ(value, buffer, bufferSize) 141 142 #define FUNCTION_LOG_INT64_TYPE \ 143 int64_t 144 #define FUNCTION_LOG_INT64_FORMAT(value, buffer, bufferSize) \ 145 cvtInt64ToZ(value, buffer, bufferSize) 146 147 #define FUNCTION_LOG_ENUM_TYPE \ 148 unsigned int 149 #define FUNCTION_LOG_ENUM_FORMAT(value, buffer, bufferSize) \ 150 FUNCTION_LOG_UINT_FORMAT(value, buffer, bufferSize) 151 152 #define FUNCTION_LOG_FUNCTIONP_FORMAT(value, buffer, bufferSize) \ 153 ptrToLog(value == NULL ? NULL : (void *)1, "function *", buffer, bufferSize) 154 155 #define FUNCTION_LOG_MODE_TYPE \ 156 mode_t 157 #define FUNCTION_LOG_MODE_FORMAT(value, buffer, bufferSize) \ 158 cvtModeToZ(value, buffer, bufferSize) 159 160 #define FUNCTION_LOG_TIMEMSEC_TYPE \ 161 TimeMSec 162 #define FUNCTION_LOG_TIMEMSEC_FORMAT(value, buffer, bufferSize) \ 163 cvtUInt64ToZ(value, buffer, bufferSize) 164 165 #define FUNCTION_LOG_UCHARDATA_TYPE \ 166 unsigned char 167 #define FUNCTION_LOG_UCHARDATA_FORMAT(value, buffer, bufferSize) \ 168 typeToLog("(unsigned char)", buffer, bufferSize) 169 170 #define FUNCTION_LOG_SIZE_TYPE \ 171 size_t 172 #define FUNCTION_LOG_SIZE_FORMAT(value, buffer, bufferSize) \ 173 cvtSizeToZ(value, buffer, bufferSize) 174 175 #define FUNCTION_LOG_SSIZE_TYPE \ 176 ssize_t 177 #define FUNCTION_LOG_SSIZE_FORMAT(value, buffer, bufferSize) \ 178 cvtSSizeToZ(value, buffer, bufferSize) 179 180 #define FUNCTION_LOG_TIME_TYPE \ 181 time_t 182 #define FUNCTION_LOG_TIME_FORMAT(value, buffer, bufferSize) \ 183 cvtTimeToZ(value, buffer, bufferSize) 184 185 #define FUNCTION_LOG_UINT_TYPE \ 186 unsigned int 187 #define FUNCTION_LOG_UINT_FORMAT(value, buffer, bufferSize) \ 188 cvtUIntToZ(value, buffer, bufferSize) 189 190 #define FUNCTION_LOG_UINT16_TYPE \ 191 uint16_t 192 #define FUNCTION_LOG_UINT16_FORMAT(value, buffer, bufferSize) \ 193 FUNCTION_LOG_UINT_FORMAT(value, buffer, bufferSize) 194 195 #define FUNCTION_LOG_UINT32_TYPE \ 196 uint32_t 197 #define FUNCTION_LOG_UINT32_FORMAT(value, buffer, bufferSize) \ 198 FUNCTION_LOG_UINT_FORMAT(value, buffer, bufferSize) 199 200 #define FUNCTION_LOG_UINT64_TYPE \ 201 uint64_t 202 #define FUNCTION_LOG_UINT64_FORMAT(value, buffer, bufferSize) \ 203 cvtUInt64ToZ(value, buffer, bufferSize) 204 205 #define FUNCTION_LOG_VOID_TYPE \ 206 void 207 #define FUNCTION_LOG_VOID_FORMAT(value, buffer, bufferSize) \ 208 typeToLog("void", buffer, bufferSize) 209 210 #define FUNCTION_LOG_STRINGZ_TYPE \ 211 char * 212 #define FUNCTION_LOG_STRINGZ_FORMAT(value, buffer, bufferSize) \ 213 strzToLog(value, buffer, bufferSize) 214 215 /*********************************************************************************************************************************** 216 Macros to return function results (or void) 217 ***********************************************************************************************************************************/ 218 #define FUNCTION_LOG_RETURN_BASE(typePre, typeMacroPrefix, typePost, result) \ 219 do \ 220 { \ 221 typePre FUNCTION_LOG_##typeMacroPrefix##_TYPE typePost FUNCTION_LOG_RETURN_result = result; \ 222 \ 223 STACK_TRACE_POP(false); \ 224 \ 225 IF_LOG_ANY(FUNCTION_LOG_LEVEL()) \ 226 { \ 227 char buffer[STACK_TRACE_PARAM_MAX]; \ 228 \ 229 FUNCTION_LOG_##typeMacroPrefix##_FORMAT(FUNCTION_LOG_RETURN_result, buffer, sizeof(buffer)); \ 230 LOG_FMT(FUNCTION_LOG_LEVEL(), 0, "=> %s", buffer); \ 231 } \ 232 \ 233 return FUNCTION_LOG_RETURN_result; \ 234 } \ 235 while (0) 236 237 #define FUNCTION_LOG_RETURN(typeMacroPrefix, result) \ 238 FUNCTION_LOG_RETURN_BASE(, typeMacroPrefix, , result) 239 240 #define FUNCTION_LOG_RETURN_P(typeMacroPrefix, result) \ 241 FUNCTION_LOG_RETURN_BASE(, typeMacroPrefix, *, result) 242 243 #define FUNCTION_LOG_RETURN_PP(typeMacroPrefix, result) \ 244 FUNCTION_LOG_RETURN_BASE(, typeMacroPrefix, **, result) 245 246 #define FUNCTION_LOG_RETURN_CONST(typeMacroPrefix, result) \ 247 FUNCTION_LOG_RETURN_BASE(const, typeMacroPrefix, , result) 248 249 #define FUNCTION_LOG_RETURN_CONST_P(typeMacroPrefix, result) \ 250 FUNCTION_LOG_RETURN_BASE(const, typeMacroPrefix, *, result) 251 252 #define FUNCTION_LOG_RETURN_CONST_PP(typeMacroPrefix, result) \ 253 FUNCTION_LOG_RETURN_BASE(const, typeMacroPrefix, **, result) 254 255 #define FUNCTION_LOG_RETURN_STRUCT(result) \ 256 do \ 257 { \ 258 STACK_TRACE_POP(false); \ 259 \ 260 IF_LOG_ANY(FUNCTION_LOG_LEVEL()) \ 261 LOG_FMT(FUNCTION_LOG_LEVEL(), 0, "=> struct"); \ 262 \ 263 return result; \ 264 } \ 265 while (0) 266 267 #define FUNCTION_LOG_RETURN_VOID() \ 268 do \ 269 { \ 270 STACK_TRACE_POP(false); \ 271 \ 272 LOG(FUNCTION_LOG_LEVEL(), 0, "=> void"); \ 273 } \ 274 while (0) 275 276 /*********************************************************************************************************************************** 277 Function Test Macros 278 279 In debug builds these macros will update the stack trace with function names and parameters but will not log. In production builds 280 all test macros are compiled out (except for return statements). 281 282 Ignore DEBUG_TEST_TRACE_MACRO if DEBUG is not defined because the underlying functions that support the macros will not be present. 283 ***********************************************************************************************************************************/ 284 #ifdef DEBUG 285 #ifdef DEBUG_TEST_TRACE 286 #define DEBUG_TEST_TRACE_MACRO 287 #endif // DEBUG_TEST_TRACE 288 #endif // DEBUG 289 290 #ifdef DEBUG_TEST_TRACE_MACRO 291 #define FUNCTION_TEST_BEGIN() \ 292 /* Ensure that FUNCTION_LOG_BEGIN() and FUNCTION_TEST_BEGIN() are not both used in a single function by declaring the */ \ 293 /* same variable that FUNCTION_LOG_BEGIN() uses to track logging */ \ 294 LogLevel FUNCTION_LOG_LEVEL(); \ 295 (void)FUNCTION_LOG_LEVEL(); \ 296 \ 297 /* Ensure that FUNCTION_TEST_RETURN*() is not used with FUNCTION_LOG_BEGIN*() by declaring a variable that will be */ \ 298 /* referenced in FUNCTION_TEST_RETURN*() */ \ 299 bool FUNCTION_TEST_BEGIN_exists; \ 300 \ 301 if (stackTraceTest()) \ 302 { \ 303 STACK_TRACE_PUSH(logLevelDebug); \ 304 stackTraceParamLog(); \ 305 stackTraceTestStop() 306 307 #define FUNCTION_TEST_PARAM(typeMacroPrefix, param) \ 308 FUNCTION_LOG_PARAM(typeMacroPrefix, param) 309 310 #define FUNCTION_TEST_PARAM_P(typeName, param) \ 311 FUNCTION_LOG_PARAM_P(typeName, param) 312 313 #define FUNCTION_TEST_PARAM_PP(typeName, param) \ 314 FUNCTION_LOG_PARAM_PP(typeName, param) 315 316 #define FUNCTION_TEST_END() \ 317 /* CHECK for presense of FUNCTION_TEST_BEGIN*() */ \ 318 (void)FUNCTION_TEST_BEGIN_exists; \ 319 \ 320 stackTraceTestStart(); \ 321 } 322 323 #define FUNCTION_TEST_VOID() \ 324 FUNCTION_TEST_BEGIN(); \ 325 FUNCTION_TEST_END(); 326 327 #define FUNCTION_TEST_RETURN(result) \ 328 do \ 329 { \ 330 /* CHECK for presense of FUNCTION_TEST_BEGIN*() */ \ 331 (void)FUNCTION_TEST_BEGIN_exists; \ 332 \ 333 STACK_TRACE_POP(true); \ 334 return result; \ 335 } \ 336 while (0) 337 338 #define FUNCTION_TEST_RETURN_VOID() \ 339 do \ 340 { \ 341 /* CHECK for presense of FUNCTION_TEST_BEGIN*() */ \ 342 (void)FUNCTION_TEST_BEGIN_exists; \ 343 \ 344 STACK_TRACE_POP(true); \ 345 } \ 346 while (0) 347 #else 348 #define FUNCTION_TEST_BEGIN() 349 #define FUNCTION_TEST_PARAM(typeMacroPrefix, param) 350 #define FUNCTION_TEST_PARAM_P(typeMacroPrefix, param) 351 #define FUNCTION_TEST_PARAM_PP(typeMacroPrefix, param) 352 #define FUNCTION_TEST_END() 353 #define FUNCTION_TEST_VOID() 354 #define FUNCTION_TEST_RETURN(result) \ 355 return result 356 #define FUNCTION_TEST_RETURN_VOID() 357 #endif // DEBUG_TEST_TRACE_MACRO 358 359 #endif 360