Some context: /usr/src/gnu/lib/libgcc/Makefile has:
.if ${TARGET_CPUARCH} == "arm" LIB2ADDEH = unwind-arm.c libunwind-arm.S pr-support.c unwind-c.c .else LIB2ADDEH = unwind-dw2.c unwind-dw2-fde-glibc.c unwind-sjlj.c gthr-gnat.c \ unwind-c.c .endif It appears that only powerpc families and sparc64 use unwind-dw2.c and company unless someone uses WITHOUT_LLVM_LIBUNWIND= deliberately for non-arm. This is about unwind-dw2.c and company and uses a powerpc context for illustration. The problem: gnu/lib/libgcc 's libgcc_s.so when based on unwind-dw2.c and company do not correctly/completely handle: DW_CFA_remember_state DW_CFA_restore_state as they are put to use by fairly modern c++ compilers, use that requires cfa-rule save/restore. Here I use g++8 for illustration, but g++6 is similar, for example. Yet gcc 4.2.1 tends to "work" because it has less complete stack (cfa) tracking in the exception handling output it produces, thus commonly avoiding use of DW_CFA_{remember,restore}_state . The evidence: I'm going to illustrate with 32-powerpc because I happen to have g++ 4.2.1 handy in that context, as well as g++8 . g++ 4.2.1 toolchain (and why it does not illustrate the problem): (The c++ source code is not directly significant here --but that it is the same for both g++*'s is important .) (gdb) disass g Dump of assembler code for function g(): (mixed with related dwarfdump lines and other notes) 0x018008e0: <off cfa=00(r1) > 0x018008e0 <+0>: mflr r0 0x018008e4 <+4>: stwu r1,-16(r1) 0x018008e8: <off cfa=16(r1) > 0x018008e8 <+8>: lis r9,385 0x018008ec <+12>: stw r0,20(r1) 0x018008f0: <off cfa=16(r1) > <off r65=04(cfa) > 0x018008f0 <+16>: lwz r0,3496(r9) 0x018008f4 <+20>: cmpwi cr7,r0,0 0x018008f8 <+24>: bne cr7,0x180090c <g()+44> (Note: the branch target requires cfa=16(r1) ) 0x018008fc <+28>: lwz r0,20(r1) 0x01800900 <+32>: addi r1,r1,16 (Note: the cfa changed but nothing reports it here: still treated as cfa=16(r1) ) (Later: Compare to what a more modern g++ compilers produce after adjusting r1.) 0x01800904 <+36>: mtlr r0 0x01800908 <+40>: b 0x18008b8 <f()> (Compare here to what more modern g++ compilers produce.) 0x0180090c <+44>: li r3,4 0x01800910 <+48>: bl 0x1810e0c <__cxa_allocate_exception@plt> 0x01800914 <+52>: lis r9,385 0x01800918 <+56>: addi r9,r9,3712 0x0180091c <+60>: lis r4,385 0x01800920 <+64>: lis r5,385 0x01800924 <+68>: stw r9,0(r3) 0x01800928 <+72>: addi r4,r4,3724 0x0180092c <+76>: addi r5,r5,3652 0x01800930 <+80>: bl 0x1810e14 <__cxa_throw@plt> End of assembler dump. No use of DW_CFA_remember_state or DW_CFA_restore_state, despite the tail call optimization. This is why gcc 4.2.1 tests do not show the DW_CFA_{remember,restore}_state problem here. g++8 toolchain: (but a.out using /lib/libgcc_s.so.1 in order to test that library) (gdb) disass g Dump of assembler code for function g(): (mixed with related dwarfdump lines) (Note: f()'s code was inlined.) 0x01800978: <off cfa=00(r1) > 0x01800978 <+0>: lis r10,385 0x0180097c <+4>: stwu r1,-32(r1) 0x01800980: <off cfa=32(r1) > 0x01800980 <+8>: lwz r9,3176(r10) 0x01800984 <+12>: cmpwi cr7,r9,0 0x01800988 <+16>: bne cr7,0x18009ac <g()+52> (Note: branch target requires cfa=32(r1) ) 0x0180098c <+20>: li r9,97 0x01800990 <+24>: stb r9,8(r1) 0x01800994 <+28>: lwz r9,3176(r10) 0x01800998 <+32>: addi r9,r9,1 0x0180099c <+36>: stw r9,3176(r10) 0x018009a0 <+40>: lbz r9,8(r1) 0x018009a4 <+44>: addi r1,r1,32 DW_CFA_remember_state is generate before the following change is made. (unwind-dw2.c and company do not record the cfa=32(r1) material but should) 0x018009a8: <off cfa=00(r1) > (gcc 4.2.1 did not generate anything to cause this) 0x018009a8 <+48>: blr DW_CFA_restore_state is generated to cause the following change: 0x018009ac: <off cfa=32(r1) > (unwind-dw2.c and company did not record the cfa=32(r1) material but should have) (unwind-dw2.c and company cause defaults here: cfa=0(r1), which is wrong) 0x018009ac <+52>: mflr r0 0x018009b0: <off cfa=32(r1) > <off r65=r0 > (unwind-dw2.c and company caused defaults here: cfa=0(r1), which is wrong) 0x018009b0 <+56>: li r3,4 0x018009b4 <+60>: stw r0,36(r1) 0x018009b8: <off cfa=32(r1) > <off r65=04(cfa) > (unwind-dw2.c and company caused defaults here: cfa=0(r1), which is wrong) 0x018009b8 <+64>: bl 0x1810cc4 <__cxa_allocate_exception@plt> 0x018009bc <+68>: lis r9,385 0x018009c0 <+72>: lis r5,385 0x018009c4 <+76>: addi r9,r9,2916 0x018009c8 <+80>: lis r4,385 0x018009cc <+84>: stw r9,0(r3) 0x018009d0 <+88>: addi r5,r5,3332 0x018009d4 <+92>: addi r4,r4,3380 0x018009d8 <+96>: bl 0x1810cec <__cxa_throw@plt> End of assembler dump. g++8 and the like track more of the cfa changes in the exception handling information and so use DW_CFA_{remember,restore}_state in more types of contexts. This leads to running into the incomplete implementation in unwind-dw2.c and company more as well. Based on the incorrect cfa=0(r1) _Unwind_RaiseException ends up looping, looking at the same frame each time, making no progress. powerpc64 notes: It turns out that devel/powerpc64-gcc used for buildworld generates code in /lib/libgcc_s.so's exception handling code that hits the problem, blocking all c++ exception handling via that library because of _Unwind_RaiseException never finishing. For testing I touched the library code to avoid ending up with the DW_CFA_{remember,restore}_state usage where it was a problem. This allowed for simple programs to be used for illustration of the problem in that context --and programs that do not show the problem as well (via lack of DW_CFA_{remember,restore}_state use). clang++ does generate DW_CFA_{remember,restore}_state in some contexts and these have the problem too. Any DW_CFA_restore_state where the result should not have cfa=0(r1) is broken for powerpc families. For reference: For the g++8 based a.out: # ldd a.out a.out: libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x41860000) libm.so.5 => /lib/libm.so.5 (0x41972000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x419ab000) libc.so.7 => /lib/libc.so.7 (0x419cb000) (g++8's own libgcc_s.so does not have such problems.) # more exception_test1.cpp #include <exception> // -O2 context used. volatile unsigned int v = 1; extern int f() { volatile unsigned char c = 'a'; v++; // despite volatile the access to v in g // was otherwise optimized out and the // std::exception was not followed by // code for f(). return c; } extern void g() { if (v) throw std::exception(); f(); // Modern g++'s: ends up inlined but the problem is demonstrated. } int main(void) { try {g();} // Used a separate function to avoid any potential // special handling of code in main. catch (std::exception& e) {} return 0; } === Mark Millard marklmi at yahoo.com ( dsl-only.net went away in early 2018-Mar) _______________________________________________ freebsd-toolchain@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/freebsd-toolchain To unsubscribe, send any mail to "freebsd-toolchain-unsubscr...@freebsd.org"