On Tue, Feb 27, 2024 at 10:13:14AM +0100, Jakub Jelinek wrote: > On Tue, Feb 27, 2024 at 10:04:06AM +0100, Jakub Jelinek wrote: > > > I hope we at least avoid that at -O0, possibly also with -Og? > > > > r14-8495 fixed at least that. > > > > Of course, it can break debugging experience even when the noreturn function > > is compiled with -O2 but some or all callers of that are -O0 or -Og. > > So, if unlucky and e.g. abort function in glibc gets the > > no_callee_saved_registers treatment and actually uses some call saved > > registers, backtraces when something aborts will be worse or useless. > > And we don't even have any attribute which would tell gcc not to do that. > > > > So sure, another option is just revert the PR38534 changes. > > For __libc_start_main, glibc surely just could use no_callee_saved_registers > attribute, because that is typically the outermost frame in backtrace, > there is no need to save those there. > And for kernel if it really wants it and nothing will use the backtraces, > perhaps the patch wouldn't need to be reverted completely but just guarded > the implicit no_callee_saved_registers treatment of noreturn > functions on -mcmodel=kernel or -fno-asynchronous-unwind-tables.
So, let's look at admittedly artificial testcase which could very well happen in real world code though, just using some meaningful code creating the register preassure instead of it being created artificially, noipa attribute just a replacement for functions in different TUs or too large to be inlinable, and the noreturn function in a different library where everything is built with -O2, not -O0 or -Og for debugging. Note, it doesn't have to be even abort, can be exit too. I've compiled this with -Og -g with gcc 12, trunk and trunk patched with the patch I've posted, in each case I run it under debugger, type run and bt when it aborts. The gcc 12 case is the expected one: #0 0x00007ffff7dbd765 in abort () from /lib64/libc.so.6 #1 0x00000000004011ca in bar () at /tmp/1.c:30 #2 0x00000000004011f1 in baz (a=a@entry=42, b=b@entry=43, c=c@entry=44, d=d@entry=45, e=e@entry=46, f=f@entry=47, g=48, h=49) at /tmp/1.c:38 #3 0x00000000004012d8 in qux () at /tmp/1.c:55 #4 0x0000000000401319 in main () at /tmp/1.c:62 The gcc trunk hits the backtrace not possible problem because rbp is clobbered and needed in upper frame CFA computation: #0 0x00007ffff7dbd765 in abort () from /lib64/libc.so.6 #1 0x00000000004011b0 in bar () at /tmp/1.c:30 #2 0x00000000004011d1 in baz (a=<error reading variable: Cannot access memory at address 0xdeadbebb>, b=<error reading variable: Cannot access memory at address 0xdeadbeb7>, c=<error reading variable: Cannot access memory at address 0xdeadbeb3>, d=d@entry=-559038737, e=e@entry=-559038737, f=f@entry=-559038737, g=48, h=49) at /tmp/1.c:38 #3 0x00000000004012a9 in qux () at /tmp/1.c:55 Backtrace stopped: previous frame inner to this frame (corrupt stack?) And in the patched gcc backtrace works but many of the values are bogus: #0 0x00007ffff7dbd765 in abort () from /lib64/libc.so.6 #1 0x00000000004011b1 in bar () at /tmp/1.c:30 #2 0x00000000004011d2 in baz (a=a@entry=42, b=b@entry=43, c=c@entry=44, d=d@entry=-559038737, e=e@entry=-559038737, f=f@entry=-559038737, g=48, h=49) at /tmp/1.c:38 #3 0x00000000004012aa in qux () at /tmp/1.c:55 #4 0x00000000004012e4 in main () at /tmp/1.c:62 extern void abort (void); volatile unsigned v = 0xdeadbeefU; int w; __attribute__((noipa)) void corge (char *p) { (void) p; } __attribute__((noipa)) int foo (int x) { return x; } __attribute__((noipa, noreturn, optimize (2))) void bar (void) { unsigned a = v; unsigned b = v; unsigned c = v; unsigned d = v; unsigned e = v; unsigned f = v; unsigned g = v; unsigned h = v; int i = foo (50); v = a + b + c + d + e + f + g + h; abort (); } __attribute__((noipa)) void baz (int a, int b, int c, int d, int e, int f, int g, int h) { int i = foo (51); if (w) bar (); } __attribute__((noipa)) void qux (void) { int a = foo (42); int b = foo (43); int c = foo (44); int d = foo (45); int e = foo (46); int f = foo (47); int g = foo (48); int h = foo (49); corge (__builtin_alloca (foo (52))); baz (a, b, c, d, e, f, g, h); w++; baz (a, b, c, d, e, f, g, h); baz (a, b, c, d, e, f, g, h); } int main () { qux (); } Jakub