MEDIUM: debug: now always print a backtrace on CRASH_NOW() and friends

The purpose is to enable the dumping of a backtrace on BUG_ON(). While
it's very useful to know that a condition was met, very often some
caller context is missing to figure how the condition could happen.
From now on, on systems featuring backtrace, a backtrace of the calling
thread will also be dumped to stderr in addition to the unexpected
condition. This will help users of DEBUG_STRICT as they'll most often
find this backtrace in their logs even if they can't find their core
file.

A new "debug dev bug" expert-mode CLI command was added to test the
feature.
This commit is contained in:
Willy Tarreau 2021-01-22 14:15:46 +01:00
parent a8459b28c3
commit 5baf4fe31a
2 changed files with 17 additions and 3 deletions

View File

@ -39,12 +39,12 @@
#ifdef DEBUG_USE_ABORT
/* abort() is better recognized by code analysis tools */
#define ABORT_NOW() abort()
#define ABORT_NOW() do { extern void ha_backtrace_to_stderr(); ha_backtrace_to_stderr(); abort(); } 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() (*(volatile int*)1=0)
#define ABORT_NOW() do { extern void ha_backtrace_to_stderr(); ha_backtrace_to_stderr(); (*(volatile int*)1=0); } while (0)
#endif
/* BUG_ON: complains if <cond> is true when DEBUG_STRICT or DEBUG_STRICT_NOCRASH
@ -55,7 +55,7 @@
#if defined(DEBUG_STRICT)
#define CRASH_NOW() ABORT_NOW()
#else
#define CRASH_NOW()
#define CRASH_NOW() do { ha_backtrace_to_stderr(); } while (0)
#endif
#define BUG_ON(cond) _BUG_ON(cond, __FILE__, __LINE__)

View File

@ -322,6 +322,19 @@ static int debug_parse_cli_exit(char **args, char *payload, struct appctx *appct
return 1;
}
/* parse a "debug dev bug" command. It always returns 1, though it should never return.
* Note: we make sure not to make the function static so that it appears in the trace.
*/
int debug_parse_cli_bug(char **args, char *payload, struct appctx *appctx, void *private)
{
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
_HA_ATOMIC_ADD(&debug_commands_issued, 1);
BUG_ON(one > zero);
return 1;
}
/* parse a "debug dev close" command. It always returns 1. */
static int debug_parse_cli_close(char **args, char *payload, struct appctx *appctx, void *private)
{
@ -1144,6 +1157,7 @@ REGISTER_PER_THREAD_INIT(init_debug_per_thread);
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{{ "debug", "dev", "bug", NULL }, "debug dev bug : call BUG_ON()", debug_parse_cli_bug, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "close", NULL }, "debug dev close <fd> : close this file descriptor", debug_parse_cli_close, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "delay", NULL }, "debug dev delay [ms] : sleep this long", debug_parse_cli_delay, NULL, NULL, NULL, ACCESS_EXPERT },
#if defined(DEBUG_DEV)