101e04c3fSmrg/************************************************************************** 201e04c3fSmrg * 301e04c3fSmrg * Copyright 2008 VMware, Inc. 401e04c3fSmrg * All Rights Reserved. 501e04c3fSmrg * 601e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 701e04c3fSmrg * copy of this software and associated documentation files (the 801e04c3fSmrg * "Software"), to deal in the Software without restriction, including 901e04c3fSmrg * without limitation the rights to use, copy, modify, merge, publish, 1001e04c3fSmrg * distribute, sub license, and/or sell copies of the Software, and to 1101e04c3fSmrg * permit persons to whom the Software is furnished to do so, subject to 1201e04c3fSmrg * the following conditions: 1301e04c3fSmrg * 1401e04c3fSmrg * The above copyright notice and this permission notice (including the 1501e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions 1601e04c3fSmrg * of the Software. 1701e04c3fSmrg * 1801e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1901e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2001e04c3fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2101e04c3fSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 2201e04c3fSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 2301e04c3fSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 2401e04c3fSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2501e04c3fSmrg * 2601e04c3fSmrg **************************************************************************/ 2701e04c3fSmrg 2801e04c3fSmrg/** 2901e04c3fSmrg * @file 3001e04c3fSmrg * Cross-platform debugging helpers. 3101e04c3fSmrg * 3201e04c3fSmrg * For now it just has assert and printf replacements, but it might be extended 3301e04c3fSmrg * with stack trace reports and more advanced logging in the near future. 3401e04c3fSmrg * 3501e04c3fSmrg * @author Jose Fonseca <jfonseca@vmware.com> 3601e04c3fSmrg */ 3701e04c3fSmrg 3801e04c3fSmrg#ifndef U_DEBUG_H_ 3901e04c3fSmrg#define U_DEBUG_H_ 4001e04c3fSmrg 417ec681f3Smrg#include <stdarg.h> 427ec681f3Smrg#include <string.h> 437ec681f3Smrg#if !defined(_WIN32) 447ec681f3Smrg#include <sys/types.h> 457ec681f3Smrg#include <unistd.h> 467ec681f3Smrg#endif 4701e04c3fSmrg 4801e04c3fSmrg#include "util/os_misc.h" 497ec681f3Smrg#include "util/detect_os.h" 507ec681f3Smrg#include "util/macros.h" 5101e04c3fSmrg 527ec681f3Smrg#if DETECT_OS_HAIKU 5301e04c3fSmrg/* Haiku provides debug_printf in libroot with OS.h */ 5401e04c3fSmrg#include <OS.h> 5501e04c3fSmrg#endif 5601e04c3fSmrg 5701e04c3fSmrg#ifdef __cplusplus 5801e04c3fSmrgextern "C" { 5901e04c3fSmrg#endif 6001e04c3fSmrg 6101e04c3fSmrg 627ec681f3Smrg#define _util_printf_format(fmt, list) PRINTFLIKE(fmt, list) 6301e04c3fSmrg 6401e04c3fSmrgvoid _debug_vprintf(const char *format, va_list ap); 6501e04c3fSmrg 6601e04c3fSmrg 6701e04c3fSmrgstatic inline void 6801e04c3fSmrg_debug_printf(const char *format, ...) 6901e04c3fSmrg{ 7001e04c3fSmrg va_list ap; 7101e04c3fSmrg va_start(ap, format); 7201e04c3fSmrg _debug_vprintf(format, ap); 7301e04c3fSmrg va_end(ap); 7401e04c3fSmrg} 7501e04c3fSmrg 7601e04c3fSmrg 7701e04c3fSmrg/** 7801e04c3fSmrg * Print debug messages. 7901e04c3fSmrg * 8001e04c3fSmrg * The actual channel used to output debug message is platform specific. To 8101e04c3fSmrg * avoid misformating or truncation, follow these rules of thumb: 8201e04c3fSmrg * - output whole lines 8301e04c3fSmrg * - avoid outputing large strings (512 bytes is the current maximum length 8401e04c3fSmrg * that is guaranteed to be printed in all platforms) 8501e04c3fSmrg */ 867ec681f3Smrg#if !DETECT_OS_HAIKU 8701e04c3fSmrgstatic inline void 8801e04c3fSmrgdebug_printf(const char *format, ...) _util_printf_format(1,2); 8901e04c3fSmrg 9001e04c3fSmrgstatic inline void 9101e04c3fSmrgdebug_printf(const char *format, ...) 9201e04c3fSmrg{ 9301e04c3fSmrg#ifdef DEBUG 9401e04c3fSmrg va_list ap; 9501e04c3fSmrg va_start(ap, format); 9601e04c3fSmrg _debug_vprintf(format, ap); 9701e04c3fSmrg va_end(ap); 9801e04c3fSmrg#else 9901e04c3fSmrg (void) format; /* silence warning */ 10001e04c3fSmrg#endif 10101e04c3fSmrg} 10201e04c3fSmrg#endif 10301e04c3fSmrg 10401e04c3fSmrg 10501e04c3fSmrg/* 10601e04c3fSmrg * ... isn't portable so we need to pass arguments in parentheses. 10701e04c3fSmrg * 10801e04c3fSmrg * usage: 10901e04c3fSmrg * debug_printf_once(("answer: %i\n", 42)); 11001e04c3fSmrg */ 11101e04c3fSmrg#define debug_printf_once(args) \ 11201e04c3fSmrg do { \ 1137ec681f3Smrg static bool once = true; \ 11401e04c3fSmrg if (once) { \ 1157ec681f3Smrg once = false; \ 11601e04c3fSmrg debug_printf args; \ 11701e04c3fSmrg } \ 11801e04c3fSmrg } while (0) 11901e04c3fSmrg 12001e04c3fSmrg 12101e04c3fSmrg#ifdef DEBUG 12201e04c3fSmrg#define debug_vprintf(_format, _ap) _debug_vprintf(_format, _ap) 12301e04c3fSmrg#else 12401e04c3fSmrg#define debug_vprintf(_format, _ap) ((void)0) 12501e04c3fSmrg#endif 12601e04c3fSmrg 12701e04c3fSmrg 12801e04c3fSmrg#ifdef DEBUG 12901e04c3fSmrg/** 13001e04c3fSmrg * Dump a blob in hex to the same place that debug_printf sends its 13101e04c3fSmrg * messages. 13201e04c3fSmrg */ 13301e04c3fSmrgvoid debug_print_blob( const char *name, const void *blob, unsigned size ); 13401e04c3fSmrg#else 13501e04c3fSmrg#define debug_print_blob(_name, _blob, _size) ((void)0) 13601e04c3fSmrg#endif 13701e04c3fSmrg 13801e04c3fSmrg 13901e04c3fSmrg/** 14001e04c3fSmrg * Disable interactive error message boxes. 14101e04c3fSmrg * 14201e04c3fSmrg * Should be called as soon as possible for effectiveness. 14301e04c3fSmrg */ 14401e04c3fSmrgvoid 14501e04c3fSmrgdebug_disable_error_message_boxes(void); 14601e04c3fSmrg 14701e04c3fSmrg 14801e04c3fSmrg/** 14901e04c3fSmrg * Hard-coded breakpoint. 15001e04c3fSmrg */ 15101e04c3fSmrg#ifdef DEBUG 15201e04c3fSmrg#define debug_break() os_break() 15301e04c3fSmrg#else /* !DEBUG */ 15401e04c3fSmrg#define debug_break() ((void)0) 15501e04c3fSmrg#endif /* !DEBUG */ 15601e04c3fSmrg 15701e04c3fSmrg 15801e04c3fSmrglong 15901e04c3fSmrgdebug_get_num_option(const char *name, long dfault); 16001e04c3fSmrg 1617ec681f3Smrgvoid 1627ec681f3Smrgdebug_get_version_option(const char *name, unsigned *major, unsigned *minor); 1637ec681f3Smrg 16401e04c3fSmrg#ifdef _MSC_VER 16501e04c3fSmrg__declspec(noreturn) 16601e04c3fSmrg#endif 16701e04c3fSmrgvoid _debug_assert_fail(const char *expr, 16801e04c3fSmrg const char *file, 16901e04c3fSmrg unsigned line, 17001e04c3fSmrg const char *function) 17101e04c3fSmrg#if defined(__GNUC__) && !defined(DEBUG) 17201e04c3fSmrg __attribute__((noreturn)) 17301e04c3fSmrg#endif 17401e04c3fSmrg; 17501e04c3fSmrg 17601e04c3fSmrg 17701e04c3fSmrg/** 17801e04c3fSmrg * Assert macro 17901e04c3fSmrg * 18001e04c3fSmrg * Do not expect that the assert call terminates -- errors must be handled 18101e04c3fSmrg * regardless of assert behavior. 18201e04c3fSmrg * 18301e04c3fSmrg * For non debug builds the assert macro will expand to a no-op, so do not 18401e04c3fSmrg * call functions with side effects in the assert expression. 18501e04c3fSmrg */ 18601e04c3fSmrg#ifndef NDEBUG 18701e04c3fSmrg#define debug_assert(expr) ((expr) ? (void)0 : _debug_assert_fail(#expr, __FILE__, __LINE__, __FUNCTION__)) 18801e04c3fSmrg#else 18901e04c3fSmrg#define debug_assert(expr) (void)(0 && (expr)) 19001e04c3fSmrg#endif 19101e04c3fSmrg 19201e04c3fSmrg 19301e04c3fSmrg/** Override standard assert macro */ 19401e04c3fSmrg#ifdef assert 19501e04c3fSmrg#undef assert 19601e04c3fSmrg#endif 19701e04c3fSmrg#define assert(expr) debug_assert(expr) 19801e04c3fSmrg 19901e04c3fSmrg 20001e04c3fSmrg/** 20101e04c3fSmrg * Output the current function name. 20201e04c3fSmrg */ 20301e04c3fSmrg#ifdef DEBUG 20401e04c3fSmrg#define debug_checkpoint() \ 20501e04c3fSmrg _debug_printf("%s\n", __FUNCTION__) 20601e04c3fSmrg#else 20701e04c3fSmrg#define debug_checkpoint() \ 20801e04c3fSmrg ((void)0) 20901e04c3fSmrg#endif 21001e04c3fSmrg 21101e04c3fSmrg 21201e04c3fSmrg/** 21301e04c3fSmrg * Output the full source code position. 21401e04c3fSmrg */ 21501e04c3fSmrg#ifdef DEBUG 21601e04c3fSmrg#define debug_checkpoint_full() \ 21701e04c3fSmrg _debug_printf("%s:%u:%s\n", __FILE__, __LINE__, __FUNCTION__) 21801e04c3fSmrg#else 21901e04c3fSmrg#define debug_checkpoint_full() \ 22001e04c3fSmrg ((void)0) 22101e04c3fSmrg#endif 22201e04c3fSmrg 22301e04c3fSmrg 22401e04c3fSmrg/** 22501e04c3fSmrg * Output a warning message. Muted on release version. 22601e04c3fSmrg */ 22701e04c3fSmrg#ifdef DEBUG 22801e04c3fSmrg#define debug_warning(__msg) \ 22901e04c3fSmrg _debug_printf("%s:%u:%s: warning: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg) 23001e04c3fSmrg#else 23101e04c3fSmrg#define debug_warning(__msg) \ 23201e04c3fSmrg ((void)0) 23301e04c3fSmrg#endif 23401e04c3fSmrg 23501e04c3fSmrg 23601e04c3fSmrg/** 23701e04c3fSmrg * Emit a warning message, but only once. 23801e04c3fSmrg */ 23901e04c3fSmrg#ifdef DEBUG 24001e04c3fSmrg#define debug_warn_once(__msg) \ 24101e04c3fSmrg do { \ 2427ec681f3Smrg static bool warned = false; \ 24301e04c3fSmrg if (!warned) { \ 24401e04c3fSmrg _debug_printf("%s:%u:%s: one time warning: %s\n", \ 24501e04c3fSmrg __FILE__, __LINE__, __FUNCTION__, __msg); \ 2467ec681f3Smrg warned = true; \ 24701e04c3fSmrg } \ 24801e04c3fSmrg } while (0) 24901e04c3fSmrg#else 25001e04c3fSmrg#define debug_warn_once(__msg) \ 25101e04c3fSmrg ((void)0) 25201e04c3fSmrg#endif 25301e04c3fSmrg 25401e04c3fSmrg 25501e04c3fSmrg/** 25601e04c3fSmrg * Output an error message. Not muted on release version. 25701e04c3fSmrg */ 25801e04c3fSmrg#ifdef DEBUG 25901e04c3fSmrg#define debug_error(__msg) \ 26001e04c3fSmrg _debug_printf("%s:%u:%s: error: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg) 26101e04c3fSmrg#else 26201e04c3fSmrg#define debug_error(__msg) \ 26301e04c3fSmrg _debug_printf("error: %s\n", __msg) 26401e04c3fSmrg#endif 26501e04c3fSmrg 26601e04c3fSmrg/** 26701e04c3fSmrg * Output a debug log message to the debug info callback. 26801e04c3fSmrg */ 26901e04c3fSmrg#define pipe_debug_message(cb, type, fmt, ...) do { \ 27001e04c3fSmrg static unsigned id = 0; \ 27101e04c3fSmrg if ((cb) && (cb)->debug_message) { \ 27201e04c3fSmrg _pipe_debug_message(cb, &id, \ 27301e04c3fSmrg PIPE_DEBUG_TYPE_ ## type, \ 27401e04c3fSmrg fmt, ##__VA_ARGS__); \ 27501e04c3fSmrg } \ 27601e04c3fSmrg} while (0) 27701e04c3fSmrg 27801e04c3fSmrgstruct pipe_debug_callback; 27901e04c3fSmrg 28001e04c3fSmrgvoid 28101e04c3fSmrg_pipe_debug_message( 28201e04c3fSmrg struct pipe_debug_callback *cb, 28301e04c3fSmrg unsigned *id, 28401e04c3fSmrg enum pipe_debug_type type, 28501e04c3fSmrg const char *fmt, ...) _util_printf_format(4, 5); 28601e04c3fSmrg 28701e04c3fSmrg 28801e04c3fSmrg/** 28901e04c3fSmrg * Used by debug_dump_enum and debug_dump_flags to describe symbols. 29001e04c3fSmrg */ 29101e04c3fSmrgstruct debug_named_value 29201e04c3fSmrg{ 29301e04c3fSmrg const char *name; 29401e04c3fSmrg uint64_t value; 29501e04c3fSmrg const char *desc; 29601e04c3fSmrg}; 29701e04c3fSmrg 29801e04c3fSmrg 29901e04c3fSmrg/** 30001e04c3fSmrg * Some C pre-processor magic to simplify creating named values. 30101e04c3fSmrg * 30201e04c3fSmrg * Example: 30301e04c3fSmrg * @code 30401e04c3fSmrg * static const debug_named_value my_names[] = { 30501e04c3fSmrg * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_X), 30601e04c3fSmrg * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Y), 30701e04c3fSmrg * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Z), 30801e04c3fSmrg * DEBUG_NAMED_VALUE_END 30901e04c3fSmrg * }; 31001e04c3fSmrg * 31101e04c3fSmrg * ... 31201e04c3fSmrg * debug_printf("%s = %s\n", 31301e04c3fSmrg * name, 31401e04c3fSmrg * debug_dump_enum(my_names, my_value)); 31501e04c3fSmrg * ... 31601e04c3fSmrg * @endcode 31701e04c3fSmrg */ 31801e04c3fSmrg#define DEBUG_NAMED_VALUE(__symbol) {#__symbol, (unsigned long)__symbol, NULL} 31901e04c3fSmrg#define DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, __desc) {#__symbol, (unsigned long)__symbol, __desc} 32001e04c3fSmrg#define DEBUG_NAMED_VALUE_END {NULL, 0, NULL} 32101e04c3fSmrg 32201e04c3fSmrg 32301e04c3fSmrg/** 32401e04c3fSmrg * Convert a enum value to a string. 32501e04c3fSmrg */ 32601e04c3fSmrgconst char * 32701e04c3fSmrgdebug_dump_enum(const struct debug_named_value *names, 32801e04c3fSmrg unsigned long value); 32901e04c3fSmrg 33001e04c3fSmrgconst char * 33101e04c3fSmrgdebug_dump_enum_noprefix(const struct debug_named_value *names, 33201e04c3fSmrg const char *prefix, 33301e04c3fSmrg unsigned long value); 33401e04c3fSmrg 33501e04c3fSmrg 33601e04c3fSmrg/** 33701e04c3fSmrg * Convert binary flags value to a string. 33801e04c3fSmrg */ 33901e04c3fSmrgconst char * 34001e04c3fSmrgdebug_dump_flags(const struct debug_named_value *names, 34101e04c3fSmrg unsigned long value); 34201e04c3fSmrg 34301e04c3fSmrg 34401e04c3fSmrg/** 34501e04c3fSmrg * Function enter exit loggers 34601e04c3fSmrg */ 34701e04c3fSmrg#ifdef DEBUG 34801e04c3fSmrgint debug_funclog_enter(const char* f, const int line, const char* file); 34901e04c3fSmrgvoid debug_funclog_exit(const char* f, const int line, const char* file); 35001e04c3fSmrgvoid debug_funclog_enter_exit(const char* f, const int line, const char* file); 35101e04c3fSmrg 35201e04c3fSmrg#define DEBUG_FUNCLOG_ENTER() \ 35301e04c3fSmrg int __debug_decleration_work_around = \ 35401e04c3fSmrg debug_funclog_enter(__FUNCTION__, __LINE__, __FILE__) 35501e04c3fSmrg#define DEBUG_FUNCLOG_EXIT() \ 35601e04c3fSmrg do { \ 35701e04c3fSmrg (void)__debug_decleration_work_around; \ 35801e04c3fSmrg debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \ 35901e04c3fSmrg return; \ 36001e04c3fSmrg } while(0) 36101e04c3fSmrg#define DEBUG_FUNCLOG_EXIT_RET(ret) \ 36201e04c3fSmrg do { \ 36301e04c3fSmrg (void)__debug_decleration_work_around; \ 36401e04c3fSmrg debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \ 36501e04c3fSmrg return ret; \ 36601e04c3fSmrg } while(0) 36701e04c3fSmrg#define DEBUG_FUNCLOG_ENTER_EXIT() \ 36801e04c3fSmrg debug_funclog_enter_exit(__FUNCTION__, __LINE__, __FILE__) 36901e04c3fSmrg 37001e04c3fSmrg#else 37101e04c3fSmrg#define DEBUG_FUNCLOG_ENTER() \ 37201e04c3fSmrg int __debug_decleration_work_around 37301e04c3fSmrg#define DEBUG_FUNCLOG_EXIT() \ 37401e04c3fSmrg do { (void)__debug_decleration_work_around; return; } while(0) 37501e04c3fSmrg#define DEBUG_FUNCLOG_EXIT_RET(ret) \ 37601e04c3fSmrg do { (void)__debug_decleration_work_around; return ret; } while(0) 37701e04c3fSmrg#define DEBUG_FUNCLOG_ENTER_EXIT() 37801e04c3fSmrg#endif 37901e04c3fSmrg 38001e04c3fSmrg 38101e04c3fSmrg/** 38201e04c3fSmrg * Get option. 38301e04c3fSmrg * 38401e04c3fSmrg * It is an alias for getenv on Linux. 38501e04c3fSmrg * 38601e04c3fSmrg * On Windows it reads C:\gallium.cfg, which is a text file with CR+LF line 38701e04c3fSmrg * endings with one option per line as 38801e04c3fSmrg * 38901e04c3fSmrg * NAME=value 39001e04c3fSmrg * 39101e04c3fSmrg * This file must be terminated with an extra empty line. 39201e04c3fSmrg */ 39301e04c3fSmrgconst char * 39401e04c3fSmrgdebug_get_option(const char *name, const char *dfault); 39501e04c3fSmrg 3967ec681f3Smrgbool 3977ec681f3Smrgdebug_get_bool_option(const char *name, bool dfault); 39801e04c3fSmrg 39901e04c3fSmrglong 40001e04c3fSmrgdebug_get_num_option(const char *name, long dfault); 40101e04c3fSmrg 40201e04c3fSmrguint64_t 40301e04c3fSmrgdebug_get_flags_option(const char *name, 40401e04c3fSmrg const struct debug_named_value *flags, 40501e04c3fSmrg uint64_t dfault); 40601e04c3fSmrg 40701e04c3fSmrg#define DEBUG_GET_ONCE_OPTION(suffix, name, dfault) \ 40801e04c3fSmrgstatic const char * \ 40901e04c3fSmrgdebug_get_option_ ## suffix (void) \ 41001e04c3fSmrg{ \ 4117ec681f3Smrg static bool first = true; \ 41201e04c3fSmrg static const char * value; \ 41301e04c3fSmrg if (first) { \ 4147ec681f3Smrg first = false; \ 41501e04c3fSmrg value = debug_get_option(name, dfault); \ 41601e04c3fSmrg } \ 41701e04c3fSmrg return value; \ 41801e04c3fSmrg} 41901e04c3fSmrg 4207ec681f3Smrgstatic inline bool 4217ec681f3Smrg__check_suid(void) 4227ec681f3Smrg{ 4237ec681f3Smrg#if !defined(_WIN32) 4247ec681f3Smrg if (geteuid() != getuid()) 4257ec681f3Smrg return true; 4267ec681f3Smrg#endif 4277ec681f3Smrg return false; 4287ec681f3Smrg} 4297ec681f3Smrg 4307ec681f3Smrg/** 4317ec681f3Smrg * Define a getter for a debug option which specifies a 'FILE *' 4327ec681f3Smrg * to open, with additional checks for suid executables. Note 4337ec681f3Smrg * that if the return is not NULL, the caller owns the 'FILE *' 4347ec681f3Smrg * reference. 4357ec681f3Smrg */ 4367ec681f3Smrg#define DEBUG_GET_ONCE_FILE_OPTION(suffix, name, dfault, mode) \ 4377ec681f3Smrgstatic FILE * \ 4387ec681f3Smrgdebug_get_option_ ## suffix (void) \ 4397ec681f3Smrg{ \ 4407ec681f3Smrg static bool first = true; \ 4417ec681f3Smrg static const char * value; \ 4427ec681f3Smrg if (__check_suid()) \ 4437ec681f3Smrg return NULL; \ 4447ec681f3Smrg if (first) { \ 4457ec681f3Smrg first = false; \ 4467ec681f3Smrg value = debug_get_option(name, dfault); \ 4477ec681f3Smrg } \ 4487ec681f3Smrg if (!value) \ 4497ec681f3Smrg return NULL; \ 4507ec681f3Smrg return fopen(value, mode); \ 4517ec681f3Smrg} 4527ec681f3Smrg 45301e04c3fSmrg#define DEBUG_GET_ONCE_BOOL_OPTION(sufix, name, dfault) \ 4547ec681f3Smrgstatic bool \ 45501e04c3fSmrgdebug_get_option_ ## sufix (void) \ 45601e04c3fSmrg{ \ 4577ec681f3Smrg static bool first = true; \ 4587ec681f3Smrg static bool value; \ 45901e04c3fSmrg if (first) { \ 4607ec681f3Smrg first = false; \ 46101e04c3fSmrg value = debug_get_bool_option(name, dfault); \ 46201e04c3fSmrg } \ 46301e04c3fSmrg return value; \ 46401e04c3fSmrg} 46501e04c3fSmrg 46601e04c3fSmrg#define DEBUG_GET_ONCE_NUM_OPTION(sufix, name, dfault) \ 46701e04c3fSmrgstatic long \ 46801e04c3fSmrgdebug_get_option_ ## sufix (void) \ 46901e04c3fSmrg{ \ 4707ec681f3Smrg static bool first = true; \ 47101e04c3fSmrg static long value; \ 47201e04c3fSmrg if (first) { \ 4737ec681f3Smrg first = false; \ 47401e04c3fSmrg value = debug_get_num_option(name, dfault); \ 47501e04c3fSmrg } \ 47601e04c3fSmrg return value; \ 47701e04c3fSmrg} 47801e04c3fSmrg 47901e04c3fSmrg#define DEBUG_GET_ONCE_FLAGS_OPTION(sufix, name, flags, dfault) \ 48001e04c3fSmrgstatic unsigned long \ 48101e04c3fSmrgdebug_get_option_ ## sufix (void) \ 48201e04c3fSmrg{ \ 4837ec681f3Smrg static bool first = true; \ 48401e04c3fSmrg static unsigned long value; \ 48501e04c3fSmrg if (first) { \ 4867ec681f3Smrg first = false; \ 48701e04c3fSmrg value = debug_get_flags_option(name, flags, dfault); \ 48801e04c3fSmrg } \ 48901e04c3fSmrg return value; \ 49001e04c3fSmrg} 49101e04c3fSmrg 49201e04c3fSmrg 49301e04c3fSmrg#ifdef __cplusplus 49401e04c3fSmrg} 49501e04c3fSmrg#endif 49601e04c3fSmrg 49701e04c3fSmrg#endif /* U_DEBUG_H_ */ 498