summaryrefslogtreecommitdiffstats
path: root/include/haproxy/bug.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/haproxy/bug.h')
-rw-r--r--include/haproxy/bug.h109
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