Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 06 Mar 2016 00:59:49 +0000
From:      bugzilla-noreply@freebsd.org
To:        freebsd-bugs@FreeBSD.org
Subject:   [Bug 207732] libgcc_s .eh_frame handling messes up interpreting powerpc/powerpc64 frame pointer register use produced by clang 3.8.0
Message-ID:  <bug-207732-8@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D207732

            Bug ID: 207732
           Summary: libgcc_s .eh_frame handling messes up interpreting
                    powerpc/powerpc64 frame pointer register use produced
                    by clang 3.8.0
           Product: Base System
           Version: 11.0-CURRENT
          Hardware: ppc
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: freebsd-bugs@FreeBSD.org
          Reporter: markmi@dsl-only.net

Because I'm pointing at long standing FreeBSD libgcc_s code that is not lim=
ited
to the example TARGET_ARCH's taht I'm using I first review some dwarf CFA
material.

Based on dwarf-2.0.0.pdf (with  my notes added):

        =E2=80=A2       The algorithm to compute the CFA changes as you pro=
gress
through the prologue and epilogue code. (By definition, the CFA value does =
not
change.)=20

So as I understand for the "Call Frame Instruction Usage" . . .

        1.      Initialize a register set by reading the initial_instructio=
ns
field of the associated CIE.=20

The initial CFA value in/for _Unwind_RaiseException is to be established as
initialization before interpreting the first instruction of the
initial_instructions field of the CIE, which is the initial CIE for the
internal exception handling activity.

For that initial CIE (for _Unwind_RaiseException for exception handling): W=
hile
not part of the Itanium C++ exception ABI (as I understand) this initializa=
tion
of the initial CFA value is based on starting from the value returned by
__builtin_dwarf_cfa(), used in the likes of _Unwind_RaiseException. (For
TARGET_ARCH=3Dpowerpc or powerpc64 or possibly others clang 3.8.0 vs.
gcc4.2.1/4.9/5.3/6.0 do not agree about which frame boundary
_builtin_drawf_cfa() returns. So as stands the value may sometimes need
conversion to a standardized-frame-boundary. This is a somewhat separate is=
sue
separately reported.)

Relative to the CFA value: The CIE/FDE instructions for the locations of a
specific routine only change the CFA rule that would reproduce the CFA valu=
e.
(Which would allow back calculating the the value in REG from the CFA value=
 for
CFA=3DOFFSET(REG) contexts: REG=3DCFA-OFFSET.) Any computation that results=
 in a
changed value while interpreting that routines .ef_frame instructions must =
be
wrong.

So finding a CFA for, say, the caller of _Unwind_RaiseException is not via
execution of one of the CIE/FDE "instructions" stored in the .eh_frame
information for _Unwind_RaiseException or for its caller: it is a separate,
additional step based on the information available that may extract some of=
 the
.eh_frame information from the two routines.

        2.      Read and process the FDE=E2=80=99s instruction sequence unt=
il a
DW_CFA_advance_loc, DW_CFA_set_loc, or the end of the instruction stream is
encountered.=20

        3.      If a DW_CFA_advance_loc or DW_CFA_set_loc instruction was
encountered, then compute a new location value (L2). If L1 >=3D L2 then pro=
cess
the instruction and go back to step 2.=20

        4.      The end of the instruction stream can be thought of as a =
=E2=80=A8=20=20=20
DW_CFA_set_loc( initial_location + address_range )=E2=80=A8instruction. Unl=
ess the FDE
is ill-formed, L1 should be less than L2 at this point.=20

The rules in the register set now apply to location L1.=20


So given that dwarf CFA material. . .

As compiled  by clang 3.8.0 for powerpc (for example): libcxxrt ends up with
(dwarfdump -v -v -F output for __cxa_throw):

< =C2=A0=C2=A0=C2=A00><0x00010620:0x00010794><__cxa_throw><fde offset 0x000=
006c0 length:
0x00000028><eh aug data len 0x0>
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00x00010620: <off cfa=3D00(r1) >=20
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00x00010634: <off cfa=3D48(r1) > <=
off r30=3D-8(cfa) > <off r31=3D-4(cfa) > <off
r65=3D04(cfa) >=20
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00x00010638: <off cfa=3D48(r31) > =
<off r25=3D-28(cfa) > <off r26=3D-24(cfa) >
<off r27=3D-20(cfa) > <off r28=3D-16(cfa) > <off r29=3D-12(cfa) > <off r30=
=3D-8(cfa) >
<off r31=3D-4(cfa) > <off r65=3D04(cfa) >=20
fde section offset 1728 0x000006c0 cie offset for fde: 1732 0x000006c4
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00 DW_CFA_advance_loc 20 =C2=
=A0(5 * 4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A01 DW_CFA_def_cfa_offset 48
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A03 DW_CFA_offset r31 -4 =C2=
=A0(1 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A05 DW_CFA_offset r30 -8 =C2=
=A0(2 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A07 DW_CFA_offset_extended_sf=
 r65 4 =C2=A0(-1 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A010 DW_CFA_advance_loc 4 =C2=A0(1 =
* 4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A011 DW_CFA_def_cfa_register r31
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A013 DW_CFA_offset r25 -28 =C2=A0(7=
 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A015 DW_CFA_offset r26 -24 =C2=A0(6=
 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A017 DW_CFA_offset r27 -20 =C2=A0(5=
 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A019 DW_CFA_offset r28 -16 =C2=A0(4=
 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A021 DW_CFA_offset r29 -12 =C2=A0(3=
 * -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A023 DW_CFA_offset r30 -8 =C2=A0(2 =
* -4)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A025 DW_CFA_nop
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A026 DW_CFA_nop

Note the cfa and r31 references in:

0x00010634: <off cfa=3D48(r1) > =C2=A0. . . <off r31=3D-4(cfa) > . . .
0x00010638: <off cfa=3D48(r31) > . . . <off r31=3D-4(cfa) > . . .

The use of r31 to define cfa is from (in part) the clang++ 3.8.0 code
generation using r31 as a frame pointer in addition to r1 as the stack poin=
ter.
The matching actual sequence of operations listed above is:

=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A01 DW_CFA_def_cfa_offset 48
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A03 DW_CFA_offset r31 -4 =C2=
=A0(1 * -4)
. . .
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A011 DW_CFA_def_cfa_register r31

The "1 DW_CFA_def_cfa_offset 48" just notes that r1 (the stack pointer) was
decremented by 48 by the prior instruction so 48 needs to be added to the n=
ew
r1 value to reference the same _Unwind_Context cfa value as the prior "<off
cfa=3D00(r1) >" status (from the CIE the FDE references) does.

The "3 DW_CFA_offset r31 -4 =C2=A0(1 * -4)" was generated because (soon old=
) r31
value was saved at address cfa-4 ("<off r31=3D-4(cfa) >"). This address to =
access
what will be the old/saved r31 value is recorded in the _Unwind_Context
reg[31].

The "11 DW_CFA_def_cfa_register r31" was generated because the prior
instruction r31 was updated to be a copy of r1 for use as a frame pointer. =
Note
that such does not change the _Unwind_Context cfa value. At this stage r1=
=3Dr31
and 48(r1)=3D48(r31) and such will hold until either r1 or r31 is changed i=
n the
routine (if either is).

The repeat of "<off r31=3D-4(cfa) >" on the "0x00010638: <off cfa=3D48(r31)=
 >" line
indicates that there is no change to where/how to find the pointer to the
old/saved r31 value relative to the CFA value: no new DW_CFA_offset r31
"instruction" for interpretation.


[Note the messy mix of different r31's. gcc 4.2.1 does not (normally?) gene=
rate
such TARGET_ARCH=3Dpowerpc code but clang++ 3.8.0 normally does generate su=
ch a
Frame Pointer and use it in places. Thus clang++ touches an error that g++
4.2.1 and the like normally do not.]


Unfortunately the above is not the interpretation given by the interpreter =
in
libgcc_s:

"11 DW_CFA_def_cfa_register r31" instead accesses the old/saved r31 value v=
ia
the pointer in _Unwind_Context reg[31] and then applies the offset 48 to th=
at
value.

The result is the wrong cfa value (which should not have changed at all) and
all else based on the cfa value is messed up after that. In essence the reg=
[31]
value and the offset value used are of mixed vintages/mixed frames: an
arbitrary combination.

Code for a routine that sticks to cfa=3DOFFSET(r1) for the cfa will not see=
 this
error in the .eh_frame information's interpretation. [r1=3D powerpc/powerpc=
64
stack pointer.]

--=20
You are receiving this mail because:
You are the assignee for the bug.=



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-207732-8>