diff options
Diffstat (limited to 'include/haproxy/bug.h')
-rw-r--r-- | include/haproxy/bug.h | 109 |
1 files changed, 75 insertions, 34 deletions
diff --git a/include/haproxy/bug.h b/include/haproxy/bug.h index 1356acf..b89ed22 100644 --- a/include/haproxy/bug.h +++ b/include/haproxy/bug.h @@ -28,6 +28,7 @@ #ifndef _HAPROXY_BUG_H #define _HAPROXY_BUG_H +#include <stddef.h> #include <haproxy/atomic.h> #include <haproxy/compiler.h> @@ -85,6 +86,23 @@ static inline __attribute((always_inline)) void ha_crash_now(void) #endif // end of arch-specific ha_crash_now() definitions + +/* ABORT_NOW() usually takes no argument and will cause the program to abort + * exactly where it is. We prefer to emit an invalid instruction to preserve + * all registers, but it may fall back to a regular abort depending on the + * platform. An optional argument can be a message string that will cause + * the emission of a message saying "ABORT at" followed by the file and line + * number then that message followed by a final line feed. This can be helpful + * in situations where the core cannot be retrieved for example. However it + * will definitely cause the loss of some registers, so should be avoided when + * not strictly necessary. + */ +#define ABORT_NOW(...) \ + _ABORT_NOW(__FILE__, __LINE__, __VA_ARGS__) + +#define _ABORT_NOW(file, line, ...) \ + __ABORT_NOW(file, line, __VA_ARGS__) + #ifdef DEBUG_USE_ABORT /* abort() is better recognized by code analysis tools */ @@ -104,12 +122,22 @@ static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line) abort(); } -#define ABORT_NOW() do { DUMP_TRACE(); abort_with_line(__LINE__); } while (0) +#define __ABORT_NOW(file, line, ...) do { \ + if (sizeof("" __VA_ARGS__) > 1) \ + complain(NULL, "\nABORT at " file ":" #line ": " __VA_ARGS__ "\n", 1); \ + DUMP_TRACE(); \ + abort_with_line(__LINE__); \ + } while (0) #else /* More efficient than abort() because it does not mangle the * stack and stops at the exact location we need. */ -#define ABORT_NOW() do { DUMP_TRACE(); ha_crash_now(); } while (0) +#define __ABORT_NOW(file, line, ...) do { \ + if (sizeof("" __VA_ARGS__) > 1) \ + complain(NULL, "\nABORT at " file ":" #line ": " __VA_ARGS__ "\n", 1); \ + DUMP_TRACE(); \ + ha_crash_now(); \ + } while (0) #endif /* This is the generic low-level macro dealing with conditional warnings and @@ -118,13 +146,21 @@ static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line) * the case where it wouldn't die. The <crash> flag is made of: * - crash & 1: crash yes/no; * - crash & 2: taint as bug instead of warn + * The optional argument must be a single constant string that will be appended + * on a second line after the condition message, to give a bit more context + * about the problem. */ -#define _BUG_ON(cond, file, line, crash, pfx, sfx) \ - __BUG_ON(cond, file, line, crash, pfx, sfx) +#define _BUG_ON(cond, file, line, crash, pfx, sfx, ...) \ + __BUG_ON(cond, file, line, crash, pfx, sfx, __VA_ARGS__) -#define __BUG_ON(cond, file, line, crash, pfx, sfx) \ +#define __BUG_ON(cond, file, line, crash, pfx, sfx, ...) \ (void)(unlikely(cond) ? ({ \ - complain(NULL, "\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n", crash); \ + const char *msg; \ + if (sizeof("" __VA_ARGS__) > 1) \ + msg ="\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n" __VA_ARGS__ "\n"; \ + else \ + msg = "\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n"; \ + complain(NULL, msg, crash); \ if (crash & 1) \ ABORT_NOW(); \ else \ @@ -137,13 +173,18 @@ static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line) * certain unexpected conditions in field. Later on, in cores it will be * possible to verify these counters. */ -#define _BUG_ON_ONCE(cond, file, line, crash, pfx, sfx) \ - __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx) +#define _BUG_ON_ONCE(cond, file, line, crash, pfx, sfx, ...) \ + __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx, __VA_ARGS__) -#define __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx) \ +#define __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx, ...) \ (void)(unlikely(cond) ? ({ \ static int __match_count_##line; \ - complain(&__match_count_##line, "\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n", crash); \ + const char *msg; \ + if (sizeof("" __VA_ARGS__) > 1) \ + msg ="\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n" __VA_ARGS__ "\n"; \ + else \ + msg = "\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n"; \ + complain(&__match_count_##line, msg, crash); \ if (crash & 1) \ ABORT_NOW(); \ else \ @@ -163,32 +204,32 @@ static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line) */ /* The macros below are for general use */ -#if defined(DEBUG_STRICT) +#if defined(DEBUG_STRICT) && (DEBUG_STRICT > 0) # if defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION < 1) /* Lowest level: BUG_ON() warns, WARN_ON() warns, CHECK_IF() warns */ -# define BUG_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 2, "WARNING: bug ", " (not crashing but process is untrusted now, please report to developers)") -# define WARN_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: warn ", " (please report to developers)") -# define CHECK_IF(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)") +# define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 2, "WARNING: bug ", " (not crashing but process is untrusted now, please report to developers)", __VA_ARGS__) +# define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: warn ", " (please report to developers)", __VA_ARGS__) +# define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) # elif !defined(DEBUG_STRICT_ACTION) || (DEBUG_STRICT_ACTION == 1) /* default level: BUG_ON() crashes, WARN_ON() warns, CHECK_IF() warns */ -# define BUG_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "") -# define WARN_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: warn ", " (please report to developers)") -# define CHECK_IF(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)") +# define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) +# define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: warn ", " (please report to developers)", __VA_ARGS__) +# define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) # elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION == 2) /* Stricter level: BUG_ON() crashes, WARN_ON() crashes, CHECK_IF() warns */ -# define BUG_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "") -# define WARN_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 1, "FATAL: warn ", "") -# define CHECK_IF(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)") +# define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) +# define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 1, "FATAL: warn ", "", __VA_ARGS__) +# define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) # elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION >= 3) /* Developer/CI level: BUG_ON() crashes, WARN_ON() crashes, CHECK_IF() crashes */ -# define BUG_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "") -# define WARN_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 1, "FATAL: warn ", "") -# define CHECK_IF(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ", "") +# define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) +# define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 1, "FATAL: warn ", "", __VA_ARGS__) +# define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ", "", __VA_ARGS__) # endif #else -# define BUG_ON(cond) do { (void)sizeof(cond); } while (0) -# define WARN_ON(cond) do { (void)sizeof(cond); } while (0) -# define CHECK_IF(cond) do { (void)sizeof(cond); } while (0) +# define BUG_ON(cond, ...) do { (void)sizeof(cond); } while (0) +# define WARN_ON(cond, ...) do { (void)sizeof(cond); } while (0) +# define CHECK_IF(cond, ...) do { (void)sizeof(cond); } while (0) #endif /* These macros are only for hot paths and remain disabled unless DEBUG_STRICT is 2 or above. @@ -198,20 +239,20 @@ static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line) #if defined(DEBUG_STRICT) && (DEBUG_STRICT > 1) # if defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION < 1) /* Lowest level: BUG_ON() warns, CHECK_IF() warns */ -# define BUG_ON_HOT(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 2, "WARNING: bug ", " (not crashing but process is untrusted now, please report to developers)") -# define CHECK_IF_HOT(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)") +# define BUG_ON_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 2, "WARNING: bug ", " (not crashing but process is untrusted now, please report to developers)", __VA_ARGS__) +# define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) # elif !defined(DEBUG_STRICT_ACTION) || (DEBUG_STRICT_ACTION < 3) /* default level: BUG_ON() crashes, CHECK_IF() warns */ -# define BUG_ON_HOT(cond) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "") -# define CHECK_IF_HOT(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)") +# define BUG_ON_HOT(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) +# define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) # elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION >= 3) /* Developer/CI level: BUG_ON() crashes, CHECK_IF() crashes */ -# define BUG_ON_HOT(cond) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "") -# define CHECK_IF_HOT(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ", "") +# define BUG_ON_HOT(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) +# define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ", "", __VA_ARGS__) # endif #else -# define BUG_ON_HOT(cond) do { (void)sizeof(cond); } while (0) -# define CHECK_IF_HOT(cond) do { (void)sizeof(cond); } while (0) +# define BUG_ON_HOT(cond, ...) do { (void)sizeof(cond) ; } while (0) +# define CHECK_IF_HOT(cond, ...) do { (void)sizeof(cond) ; } while (0) #endif |