Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 26 Feb 2016 03:16:38 -0800
From:      Mark Millard <markmi@dsl-only.net>
To:        FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, FreeBSD Toolchain <freebsd-toolchain@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:  <6B1B4F5B-659B-4142-8B16-283E572C25B1@dsl-only.net>
In-Reply-To: <38D884F8-0EB4-4F3E-9475-7465FE173D79@dsl-only.net>
References:  <38D884F8-0EB4-4F3E-9475-7465FE173D79@dsl-only.net>

next in thread | previous in thread | raw e-mail | index | archive | help
[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=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).

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 =3D _Unwind_GetPtr (&orig_context, fs->cfa_reg);
      cfa +=3D fs->cfa_offset;
      break;
. . .
  context->cfa =3D 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=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


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.

=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;
> }

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 .]


The cause has been tracked down to incomplete (and so inaccurate) =
.eh_frame information as shown below.

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=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

Of note here is that the return "address" from the bl context is =
correctly identified as 0000000000015360 by the .eh_frame information =
and its interpretation.

But also of note there is that 0000000000015360 and 0000000000015364 =
also are identified as having 0000000000015360 as their return address =
(part of the same block of code as the bl as things are classified =
above). (That is what the live code actually generates, up to relocation =
issues changing addresses.)

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=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

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.
. . .

0000000000015360 and 00000000000153a0 should each be starts of new =
code-block ranges for identifying a different return address.

So C++ exception handling is broken for FreeBSD when buildworld is based =
on devel/powerpc65-gcc: libcxxrt has examples of the error in it.

I'd expect that gcc5 (5.3) has other contexts where it does not get the =
correct return address via its .eh_frame generated materials, at least =
for powerpc64.



[207359 might be considered replaced by 207471.]

=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?6B1B4F5B-659B-4142-8B16-283E572C25B1>