Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 26 Feb 2016 05:25:37 -0800
From:      Mark Millard <markmi@dsl-only.net>
To:        FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, FreeBSD Toolchain <freebsd-toolchain@freebsd.org>, Roman Divacky <rdivacky@freebsd.org>
Cc:        Andreas Tobler <andreast-list@fgznet.ch>, Konstantin Belousov <kostikbel@gmail.com>, Baptiste Daroussin <bapt@FreeBSD.org>
Subject:   Re: r207471 submitted against devel/powerpc64-gcc for _Unwind_RaiseException's internal unbounded looping; matching up with 207359 against base system
Message-ID:  <F0BD8275-C1EC-4B61-BFF3-513B5FD05A11@dsl-only.net>
In-Reply-To: <6B1B4F5B-659B-4142-8B16-283E572C25B1@dsl-only.net>
References:  <38D884F8-0EB4-4F3E-9475-7465FE173D79@dsl-only.net> <6B1B4F5B-659B-4142-8B16-283E572C25B1@dsl-only.net>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2016-Feb-26, at 3:16 AM, Mark Millard <markmi@dsl-only.net> wrote:
>=20
> [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.]
>=20
> 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.
>=20
> 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).
>=20
> dwarfdump shows in its notation that the DW_CFA_restore_state should =
restore the "off cfa=3D128(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).
>=20
> DW_CFA_remember_state only saves fs->regs.
> DW_CFA_restore_state only restores fs->regs.
>=20
> fs->cfa_offset is not part of regs but is later used by =
uw_update_context_1 for:
>=20
>  /* Compute this frame's CFA.  */
>  switch (fs->cfa_how)
>    {
>    case CFA_REG_OFFSET:
>      cfa =3D _Unwind_GetPtr (&orig_context, fs->cfa_reg);
>      cfa +=3D fs->cfa_offset;
>      break;
> . . .
>  context->cfa =3D cfa;
>=20
>=20
> 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.
>=20
> For reference: The below is the dwarfdump -v -v -F for throw_exception =
(where the "stuck" return address vale problem [0x000153a0] is =
observed):
>=20
>=20
> <    0><0x00015310:0x000153dc><throw_exception><fde offset 0x000010d8 =
length: 0x00000034><eh aug data len 0x0>
>        0x00015310: <off cfa=3D00(r1) >=20
>        0x00015318: <off cfa=3D00(r1) > <off r31=3D-8(cfa) > <off =
r65=3Dr0 >=20
>        0x00015324: <off cfa=3D128(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>        0x00015368: <off cfa=3D00(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>        0x00015378: <off cfa=3D00(r1) >=20
>        0x00015380: <off cfa=3D128(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>        0x000153a8: <off cfa=3D00(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>        0x000153b8: <off cfa=3D00(r1) >=20
>        0x000153c0: <off cfa=3D128(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
> fde section offset 4312 0x000010d8 cie offset for fde: 4316 0x000010dc
>         0 DW_CFA_advance_loc 8  (2 * 4)
>         1 DW_CFA_register r65 =3D 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
>=20
>=20
> 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.
>=20
> =3D=3D=3D
> 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=3Dpowerpc64 (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 =3D 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.

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

On 2016-Feb-24, at 8:46 PM, Mark Millard <markmi@dsl-only.net> wrote:

> #include <exception>
>=20
> int main(void)
> {
>   try { throw std::exception(); }
>   catch (std::exception& e) {} // same result without &
>   return 0;
> }
>=20
> 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:
>=20
> _Unwind_RaiseException never returns because it is stuck in a =
unbounded loop.
>=20
> [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 =
.]
>=20
>=20
> [. . .]
>=20
> I use a mix of . . .
>=20
> # /usr/local/bin/objdump -d --prefix-addresses libcxxrt.so.1.full
>=20
> output and the matching . . .
>=20
> # dwarfdump -v -v -F libcxxrt.so.1.full | more
>=20
> output to show this.
>=20
> 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=3D00(r1) >=20
>       0x0001506c: <off cfa=3D176(r1) > <off r28=3D-32(cfa) > <off =
r29=3D-24(cfa) > <off r30=3D-16(cfa) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>       0x000150b8: <off cfa=3D00(r1) > <off r28=3D-32(cfa) > <off =
r29=3D-24(cfa) > <off r30=3D-16(cfa) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>       0x000150d0: <off cfa=3D00(r1) >=20
>       0x000150e0: <off cfa=3D176(r1) > <off r28=3D-32(cfa) > <off =
r29=3D-24(cfa) > <off r30=3D-16(cfa) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>=20
> [. . .]
>=20
> So when _Unwind_RaiseException attempts to walk up the stack from =
itself for the first pass up the stack it gets to 0000000000015360.
>=20
> 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.
> . . .
>=20
> 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). =
. .
>=20
> 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=3D00(r1) >=20
>       0x00015318: <off cfa=3D00(r1) > <off r31=3D-8(cfa) > <off r65=3Dr0=
 >=20
>       0x00015324: <off cfa=3D128(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>       0x00015368: <off cfa=3D00(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>       0x00015378: <off cfa=3D00(r1) >=20
>       0x00015380: <off cfa=3D128(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>       0x000153a8: <off cfa=3D00(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>       0x000153b8: <off cfa=3D00(r1) >=20
>       0x000153c0: <off cfa=3D128(r1) > <off r31=3D-8(cfa) > <off =
r65=3D16(cfa) >=20
>=20
> This leads to (during _Unwind_RaiseException's loop):
>=20
> . . .
> 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.
> . . .
>=20
>=20
> [. . .]

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






Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?F0BD8275-C1EC-4B61-BFF3-513B5FD05A11>