On 2016-Feb-26, at 3:16 AM, Mark Millard <[email protected]> wrote:
> 
> [Top post for a new, level level detail tracking of the error. It may be 
> libgcc_s's .eh_frame handling instead of a comiler output problem after all. 
> Both 207471 and 207359 have this material now.]
> 
> I state the relationship below from the point of view of what the existing 
> fde operations would need to do to be correct as they are. The alternate is 
> that the missing activity is missing operations in the list instead of the 
> activity being "inside" DW_CFA_remember_state and DW_CFA_restore_state.
> 
> The problem is that the DW_CFA_remember_state and later DW_CFA_restore_state 
> do not in fact restore the fs->cfa_offset (in this case 128 as it was at the 
> time of the DW_CFA_remember_state).
> 
> dwarfdump shows in its notation that the DW_CFA_restore_state should restore 
> the "off cfa=128(r1)" status that was in place at the time of the 
> DW_CFA_remember_state. This makes sense for the code in question: otherwise 
> it would be wrong for the purpose. But 
> DW_CFA_remember_state/DW_CFA_restore_state do not save and restore the 
> cfa_offset (128 here).
> 
> DW_CFA_remember_state only saves fs->regs.
> DW_CFA_restore_state only restores fs->regs.
> 
> fs->cfa_offset is not part of regs but is later used by uw_update_context_1 
> for:
> 
>  /* Compute this frame's CFA.  */
>  switch (fs->cfa_how)
>    {
>    case CFA_REG_OFFSET:
>      cfa = _Unwind_GetPtr (&orig_context, fs->cfa_reg);
>      cfa += fs->cfa_offset;
>      break;
> . . .
>  context->cfa = cfa;
> 
> 
> In the example fs->cfa_offset ends up being 0 instead of 128 after the 
> DW_CFA_restore_state, causing the wrong frame's return address to be used.
> 
> For reference: The below is the dwarfdump -v -v -F for throw_exception (where 
> the "stuck" return address vale problem [0x000153a0] is observed):
> 
> 
> <    0><0x00015310:0x000153dc><throw_exception><fde offset 0x000010d8 length: 
> 0x00000034><eh aug data len 0x0>
>        0x00015310: <off cfa=00(r1) > 
>        0x00015318: <off cfa=00(r1) > <off r31=-8(cfa) > <off r65=r0 > 
>        0x00015324: <off cfa=128(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>        0x00015368: <off cfa=00(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>        0x00015378: <off cfa=00(r1) > 
>        0x00015380: <off cfa=128(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>        0x000153a8: <off cfa=00(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>        0x000153b8: <off cfa=00(r1) > 
>        0x000153c0: <off cfa=128(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
> fde section offset 4312 0x000010d8 cie offset for fde: 4316 0x000010dc
>         0 DW_CFA_advance_loc 8  (2 * 4)
>         1 DW_CFA_register r65 = r0
>         4 DW_CFA_offset r31 -8  (1 * -8)
>         6 DW_CFA_advance_loc 12  (3 * 4)
>         7 DW_CFA_def_cfa_offset 128
>        10 DW_CFA_offset_extended_sf r65 16  (-2 * -8)
>        13 DW_CFA_advance_loc 68  (17 * 4)
>        14 DW_CFA_remember_state
>        15 DW_CFA_def_cfa_offset 0
>        17 DW_CFA_advance_loc 16  (4 * 4)
>        18 DW_CFA_restore_extended r65
>        20 DW_CFA_restore r31
>        21 DW_CFA_advance_loc 8  (2 * 4)
>        22 DW_CFA_restore_state
>        23 DW_CFA_advance_loc 40  (10 * 4)
>        24 DW_CFA_remember_state
>        25 DW_CFA_def_cfa_offset 0
>        27 DW_CFA_advance_loc 16  (4 * 4)
>        28 DW_CFA_restore_extended r65
>        30 DW_CFA_restore r31
>        31 DW_CFA_advance_loc 8  (2 * 4)
>        32 DW_CFA_restore_state
>        33 DW_CFA_nop
>        34 DW_CFA_nop
>        35 DW_CFA_nop
>        36 DW_CFA_nop
>        37 DW_CFA_nop
>        38 DW_CFA_nop
> 
> 
> Note that if fs->cfa_reg could be varying then DW_CFA_remember_state and 
> DW_CFA_restore_state would need to do appropriate save/restore activity for 
> that too.
> 
> ===
> Mark Millard
> markmi at dsl-only.net

I have verified that dwarfdump and its libdwarf do save and restore the 
following for the cfa for DW_CFA_remember_state/DW_CFA_restore_state:

A) If the offset is relevant or not (if it has a offset style rule)

B) the rule-value type

C) the register number that the cfa is based on

D) the offset or block length by naming conventions

E) the block pointer

I do not claim that all that applies to the mostly dwarf2 FreeBSD context. But 
I expect that (A)-(D) apply, (D) just for the offset case.


I do not expect this issue to be strictly TARGET_ARCH=powerpc64 (or powerpc): 
This is a very general property of DW_CFA_remember_state/DW_CFA_restore_state 
use for .eh_frame that just depends on code generation accidental-details for 
if it will be touched or not.


I've also found that the working simple examples [g++ 4.9, 5.3, 6.0(?) using 
their own libraries] happen to leave the CFA = OFFSET(r1) with a constant 
OFFSET over the throw routine (from libstdc++) that calls 
_Unwind_RaiseException. So even if their libgcc_s's have the incomplete 
save/restore problem those throw routines do not happen to get code that 
touches the problem.

But I did find other examples in libstdc++ that did not have the CFA's involved 
OFFSET constant over whole routines. Detailed "accidents" of inlining and other 
code generation issues lead to such being involved in places. These code 
generators can also generate examples of the issue.

And, of course, devel/powerpc64-gcc has a g++ 5.3 vintage but is used with the 
system's libgcc_s and that combination has the problem in the throw code's use 
of _Unwind_RaiseException and attempting to unwind back out of 
_Unwind_RaiseException.


I conclude that FreeBSD's libgcc_s libraries' .eh_frame handling is 
insufficient for general C++ exception handling, be it via g++ vintages or, 
probably, clang++ as well. It takes some luck to avoid the problems. Turing off 
in-lining, using -O0, and the like would probably make the problems less likely.

FreeBSD's libgcc_s may not be the only example of the problem.


I have included the older note below for reference, but with the mistaken 
analysis details omitted.

===
Mark Millard
markmi at dsl-only.net

On 2016-Feb-24, at 8:46 PM, Mark Millard <[email protected]> wrote:

> #include <exception>
> 
> int main(void)
> {
>   try { throw std::exception(); }
>   catch (std::exception& e) {} // same result without &
>   return 0;
> }
> 
> compiled under devel/powerpc64-gcc (gcc 5.3 based) on a FreeBSD 
> projects/clang380-import (-r295902, for example) that was also built 
> (buildworld/buildkernel) with the same devel/powerpc64-gcc demonstrates:
> 
> _Unwind_RaiseException never returns because it is stuck in a unbounded loop.
> 
> [clang380-import vs. 11.0-CURRENT is not likely to be a big distinction here. 
> PowerPC64 might be or might not be relative to g++ 5.3 .]
> 
> 
> [. . .]
> 
> I use a mix of . . .
> 
> # /usr/local/bin/objdump -d --prefix-addresses libcxxrt.so.1.full
> 
> output and the matching . . .
> 
> # dwarfdump -v -v -F libcxxrt.so.1.full | more
> 
> output to show this.
> 
> 0000000000015350 <.__cxa_end_catch+0x490> addi    r3,r31,88
> 0000000000015354 <.__cxa_end_catch+0x494> addi    r10,r10,1
> 0000000000015358 <.__cxa_end_catch+0x498> stw     r10,48(r9)
> 000000000001535c <.__cxa_end_catch+0x49c> bl      0000000000009ae0 
> <00000017.plt_call._Unwind_RaiseException@@GCC_3.0>
> 0000000000015360 <.__cxa_end_catch+0x4a0> ld      r2,40(r1)
> 0000000000015364 <.__cxa_end_catch+0x4a4> addi    r1,r1,128
> 0000000000015368 <.__cxa_end_catch+0x4a8> mr      r4,r31
> vs.
> <    0><0x00015050:0x00015310><report_failure><fde offset 0x000010a8 length: 
> 0x0000002c><eh aug data len 0x0>
>       0x00015050: <off cfa=00(r1) > 
>       0x0001506c: <off cfa=176(r1) > <off r28=-32(cfa) > <off r29=-24(cfa) > 
> <off r30=-16(cfa) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>       0x000150b8: <off cfa=00(r1) > <off r28=-32(cfa) > <off r29=-24(cfa) > 
> <off r30=-16(cfa) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>       0x000150d0: <off cfa=00(r1) > 
>       0x000150e0: <off cfa=176(r1) > <off r28=-32(cfa) > <off r29=-24(cfa) > 
> <off r30=-16(cfa) > <off r31=-8(cfa) > <off r65=16(cfa) > 
> 
> [. . .]
> 
> So when _Unwind_RaiseException attempts to walk up the stack from itself for 
> the first pass up the stack it gets to 0000000000015360.
> 
> And from there it gets to 0000000000015360 and loops.
> And from there it gets to 0000000000015360 and loops.
> And from there it gets to 0000000000015360 and loops.
> And from there it gets to 0000000000015360 and loops.
> . . .
> 
> This code/.eh_frame pattern occurs again a little later (and this is where 
> the original problem was observed for this low-level-detail view). . .
> 
> 0000000000015380 <.__cxa_end_catch+0x4c0> addis   r8,r2,-1
> 0000000000015384 <.__cxa_end_catch+0x4c4> addi    r3,r31,88
> 0000000000015388 <.__cxa_end_catch+0x4c8> ld      r10,28144(r8)
> 000000000001538c <.__cxa_end_catch+0x4cc> std     r10,32(r31)
> 0000000000015390 <.__cxa_end_catch+0x4d0> lwz     r10,48(r9)
> 0000000000015394 <.__cxa_end_catch+0x4d4> addi    r10,r10,1
> 0000000000015398 <.__cxa_end_catch+0x4d8> stw     r10,48(r9)
> 000000000001539c <.__cxa_end_catch+0x4dc> bl      0000000000009ae0 
> <00000017.plt_call._Unwind_RaiseException@@GCC_3.0>
> 00000000000153a0 <.__cxa_end_catch+0x4e0> ld      r2,40(r1)
> 00000000000153a4 <.__cxa_end_catch+0x4e4> addi    r1,r1,128
> 00000000000153a8 <.__cxa_end_catch+0x4e8> mr      r4,r31
> 00000000000153ac <.__cxa_end_catch+0x4ec> ld      r0,16(r1)
> vs.
> <    0><0x00015310:0x000153dc><throw_exception><fde offset 0x000010d8 length: 
> 0x00000034><eh aug data len 0x0>
>       0x00015310: <off cfa=00(r1) > 
>       0x00015318: <off cfa=00(r1) > <off r31=-8(cfa) > <off r65=r0 > 
>       0x00015324: <off cfa=128(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>       0x00015368: <off cfa=00(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>       0x00015378: <off cfa=00(r1) > 
>       0x00015380: <off cfa=128(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>       0x000153a8: <off cfa=00(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
>       0x000153b8: <off cfa=00(r1) > 
>       0x000153c0: <off cfa=128(r1) > <off r31=-8(cfa) > <off r65=16(cfa) > 
> 
> This leads to (during _Unwind_RaiseException's loop):
> 
> . . .
> And from there it gets to 00000000000153a0 and loops.
> And from there it gets to 00000000000153a0 and loops.
> And from there it gets to 00000000000153a0 and loops.
> And from there it gets to 00000000000153a0 and loops.
> . . .
> 
> 
> [. . .]

===
Mark Millard
markmi at dsl-only.net



_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-toolchain
To unsubscribe, send any mail to "[email protected]"

Reply via email to