mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-05 03:29:35 +00:00
DEBUG: crash using an invalid opcode on x86/x86_64 instead of an invalid access
BUG_ON() calls currently trigger a segfault. This is more convenient than abort() as it doesn't rely on any function call nor signal handler and never causes non-unwindable stacks when opening cores. But it adds quite some confusion in bug reports which are rightfully tagged "segv" and do not instantly allow to distinguish real segv (e.g. null derefs) from code asserts. Some CPU architectures offer various crashing methods. On x86 we have INT3 (0xCC), which stops into the debugger, and UD0/UD1/UD2. INT3 looks appealing but for whatever reason (maybe signal handling somewhere) it loses the last call point in the stack, making backtraces unusable. UD2 has the merit of being only 2 bytes and causing an invalid instruction, which almost never happens normally, so it's easily distinguishable. Here it was defined as a macro so that the line number in the core matches the one where the BUG_ON() macro is called, and the debugger shows the last frame exactly at its calligg point. E.g. when calling "debug dev bug": Program terminated with signal SIGILL, Illegal instruction. #0 debug_parse_cli_bug (args=<optimized out>, payload=<optimized out>, appctx=<optimized out>, private=<optimized out>) at src/debug.c:408 408 BUG_ON(one > zero); [Current thread is 1 (Thread 0x7f7a660cc1c0 (LWP 14238))] (gdb) bt #0 debug_parse_cli_bug (args=<optimized out>, payload=<optimized out>, appctx=<optimized out>, private=<optimized out>) at src/debug.c:408 #1 debug_parse_cli_bug (args=<optimized out>, payload=<optimized out>, appctx=<optimized out>, private=<optimized out>) at src/debug.c:402 #2 0x000000000061a69f in cli_parse_request (appctx=appctx@entry=0x181c0160) at src/cli.c:832 #3 0x000000000061af86 in cli_io_handler (appctx=0x181c0160) at src/cli.c:1035 #4 0x00000000006ca2f2 in task_run_applet (t=0x181c0290, context=0x181c0160, state=<optimized out>) at src/applet.c:449
This commit is contained in:
parent
7d23e8d1a6
commit
77787ec9bc
@ -40,6 +40,23 @@
|
||||
|
||||
#define DUMP_TRACE() do { extern void ha_backtrace_to_stderr(void); ha_backtrace_to_stderr(); } while (0)
|
||||
|
||||
/* First, let's try to handle some arch-specific crashing methods. We prefer
|
||||
* the macro to the function because when opening the core, the debugger will
|
||||
* directly show the calling point (e.g. the BUG_ON() condition) based on the
|
||||
* line number, while the function will create new line numbers. But the
|
||||
* function is needed e.g. if some pragmas are needed.
|
||||
*/
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define ha_crash_now() do { \
|
||||
/* ud2 opcode: 2 bytes, raises illegal instruction */ \
|
||||
__asm__ volatile(".byte 0x0f,0x0b\n"); \
|
||||
my_unreachable(); \
|
||||
} while (0)
|
||||
|
||||
#else // not x86
|
||||
|
||||
/* generic implementation, causes a segfault */
|
||||
static inline __attribute((always_inline)) void ha_crash_now(void)
|
||||
{
|
||||
#if __GNUC_PREREQ__(5, 0)
|
||||
@ -56,6 +73,8 @@ static inline __attribute((always_inline)) void ha_crash_now(void)
|
||||
my_unreachable();
|
||||
}
|
||||
|
||||
#endif // end of arch-specific ha_crash_now() definitions
|
||||
|
||||
#ifdef DEBUG_USE_ABORT
|
||||
/* abort() is better recognized by code analysis tools */
|
||||
#define ABORT_NOW() do { DUMP_TRACE(); abort(); } while (0)
|
||||
|
Loading…
Reference in New Issue
Block a user