From d480b7be9663643025174eae5e047e42f7bdfc37 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 2 Feb 2024 17:09:09 +0100 Subject: [PATCH] MINOR: debug: make ABORT_NOW() store the caller's line number when using abort Placing DO_NOT_FOLD() before abort() only works in -O2 but not in -Os which continues to place only 5 calls to abort() in h3.o for call places. The approach taken here is to replace abort() with a new function that wraps it and stores the line number in the stack. This slightly increases the code size (+0.1%) but when unwinding a crash, the line number remains present now. This is a very low cost, especially if we consider that DEBUG_USE_ABORT is almost only used by code coverage tools and occasional debugging sessions. --- include/haproxy/bug.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/haproxy/bug.h b/include/haproxy/bug.h index 24a38ff172..bee4dab125 100644 --- a/include/haproxy/bug.h +++ b/include/haproxy/bug.h @@ -87,7 +87,24 @@ static inline __attribute((always_inline)) void ha_crash_now(void) #ifdef DEBUG_USE_ABORT /* abort() is better recognized by code analysis tools */ -#define ABORT_NOW() do { DUMP_TRACE(); abort(); } while (0) + +/* abort() is generally tagged noreturn, so there's no 100% safe way to prevent + * the compiler from doing a tail-merge here. Tests show that stopping folding + * just before calling abort() does work in practice at -O2, increasing the + * number of abort() calls in h3.o from 18 to 26, probably because there's no + * more savings to be made by replacing a call with a jump. However, as -Os it + * drops to 5 regardless of the build option. In order to help here, instead we + * wrap abort() into another function, with the line number stored into a local + * variable on the stack and we pretend to use it, so that unwinding the stack + * from abort() will reveal its value even if the call was folded. + */ +static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line) +{ + DISGUISE(&line); + abort(); +} + +#define ABORT_NOW() do { 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. -- 2.39.5