clang 3.8.0 can mess up __builtin_dwarf_cfa (), at least for TARGET_ARCH=powerpc: a bug 207325 update

Mark Millard markmi at dsl-only.net
Sat Feb 27 23:32:08 UTC 2016


[Top post for dinging the low level problem that directly breaks c++ exception handling for TARGET_ARCH=powerpc for clang 3.8.0 generated code.]

I've tracked down the c++ exception problem for TARGET_ARCH=powerpc via clang 3.8.0: misbehavior of clang 3.8.0 code generation for __builtin_dwarf_cfa () as used in:

#define uw_init_context(CONTEXT)                                           \
  do                                                                       \
    {                                                                      \
      /* Do any necessary initialization to access arbitrary stack frames. \
         On the SPARC, this means flushing the register windows.  */       \
      __builtin_unwind_init ();                                            \
      uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),                  \
                         __builtin_return_address (0));                    \
    }                                                                      \
  while (0)
. . .
85	_Unwind_Reason_Code
86	_Unwind_RaiseException(struct _Unwind_Exception *exc)
87	{
88	  struct _Unwind_Context this_context, cur_context;
89	  _Unwind_Reason_Code code;
90	
91	  /* Set up this_context to describe the current stack frame.  */
92	  uw_init_context (&this_context);

In the below r4 ends up with the __builtin_dwarf_cfa () value supplied to uw_init_context_1:

Dump of assembler code for function _Unwind_RaiseException:
   0x419a8fd8 <+0>:	mflr    r0
   0x419a8fdc <+4>:	stw     r31,-148(r1)
   0x419a8fe0 <+8>:	stw     r30,-152(r1)
   0x419a8fe4 <+12>:	stw     r0,4(r1)
   0x419a8fe8 <+16>:	stwu    r1,-2992(r1)
   0x419a8fec <+20>:	mr      r31,r1
. . .
   0x419a9094 <+188>:	mr      r4,r31
   0x419a9098 <+192>:	mflr    r30
   0x419a909c <+196>:	lwz     r5,2996(r31)
   0x419a90a0 <+200>:	mr      r3,r28
   0x419a90a4 <+204>:	bl      0x419a929c <uw_init_context_1>

That r4 ends up holding the stack pointer value for after it has been decremented. r4 is not pointing at the boundary with the caller's frame.

The .eh_frame information and unwind code is set up for pointing at the boundary with the caller's frame. So the cfa relative addressing is messed up for what it actually extracts.

Contrast this with gcc/g++ 5.3's TARGET_ARCH=powerpc64 code where r4 is  made to be at the boundary with the caller's frame:

Dump of assembler code for function _Unwind_RaiseException:
   0x00000000501cb810 <+0>:	mflr    r0
   0x00000000501cb814 <+4>:	stdu    r1,-5648(r1)
. . .
   0x00000000501cb8d0 <+192>:	addi    r4,r1,5648
   0x00000000501cb8d4 <+196>:	stw     r12,5656(r1)
   0x00000000501cb8d8 <+200>:	mr      r28,r3
   0x00000000501cb8dc <+204>:	addi    r31,r1,2544
   0x00000000501cb8e0 <+208>:	mr      r3,r27
   0x00000000501cb8e4 <+212>:	addi    r29,r1,112
   0x00000000501cb8e8 <+216>:	bl      0x501cae60 <uw_init_context_1>


NOTE: The powerpc (32-bit) issue may in some way be associated with the clang 3.8.0 powerpc ABI violation in how it handles the stack pointer for FreeBSD: TARGET_ARCH=powerpc is currently using a "red zone", decrementing the stack pointer late, and incrementing the stack pointer early compared to the FreeBSD ABI rules. (This is similar to the official FreeBSD ABI for TARGET_ARCH=powerpc64.)




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

On 2016-Feb-26, at 3:26 PM, Mark Millard <markmi at dsl-only.net> wrote:
> 
> On 2016-Feb-19, at 11:37 AM, Mark Millard <markmi at dsl-only.net> wrote:
> 
>> The following program does not work for my example TARGET_ARCH=powerpc and TARGET_ARCH=powerpc64 environments for buildworld based on projects/clang380-import -r205601:
>> 
>> #include <exception>
>> 
>> int main(void)
>> {
>>   try { throw std::exception(); }
>>   catch (std::exception& e) {} // same result without &
>>   return 0;
>> }
>> 
>> The details vary for what happens and what compiler is in use.
>> 
>> TARGET_ARCH=powerpc with clang 3.8.0: SEGV
>> 
>> TARGET_ARCH=powerpc64 with devel/powerpc64-gcc: unbouded loop in _Unwind_RaiseException
>> 
>> For the powerpc64 context: g++49 can be used to show the problem as well:
>> 
>> Using g++49's a.out gets the same unbounded loop result for:
>> 
>> # g++49 -I /usr/include/c++/v1/ -L /usr/lib/ -g -Wall -pedantic exception_test.cpp                                                                                                                      
>> 
>> But the a.out works fine for a normal g++49 header/library usage:
>> 
>> # g++49 -g -Wall -pedantic exception_test.cpp
>> # ./a.out
>> # 
>> 
>> 
>> 
>> (These were noticed by trying to build and use kyua to run the /usr/tests material in tehse enviroments.)
>> 
>> 
>> ===
>> Mark Millard
>> markmi at dsl-only.net
> 
> [Note: The _Unwind_RaiseException involved below was compiled by clang 3.8.0 during buildworld. So clang generated the .eh_frame information involved.]
> 
> In the TARGET_ARCH=powerpc operation there are a sequence of 2 errors, the 2nd of which gets the SEGV:
> 
> A) The catch clause is rejected/ignored so std::terminate is called
> 
> B) During the std::terminate related execution the SEGV happens.
> 
> (A) is the more fundamental issue.
> 
> I have found the following mismatch between some powerpc code generated and the .eh_frame information generated by clang 3.8.0 for the TARGET_ARCH=powerpc context. (Using objdump and dwarfdump notation below, no relocations.) The specific example need not be directly involved in (A) or (B) but is inaccurate .eh_frame generation either way.
> 
>> 00007fd8 <_Unwind_RaiseException> mflr    r0
>> 00007fdc <_Unwind_RaiseException+0x4> stw     r31,-148(r1)
>> 00007fe0 <_Unwind_RaiseException+0x8> stw     r30,-152(r1)
>> 00007fe4 <_Unwind_RaiseException+0xc> stw     r0,4(r1)
>> 00007fe8 <_Unwind_RaiseException+0x10> stwu    r1,-2992(r1)
>> 00007fec <_Unwind_RaiseException+0x14> mr      r31,r1
>> 00007ff0 <_Unwind_RaiseException+0x18> mfcr    r12
>> . . .
>> 0000827c <_Unwind_RaiseException+0x2a4> lwz     r14,2776(r31)
>> 00008280 <_Unwind_RaiseException+0x2a8> addi    r1,r1,2992
>> 00008284 <_Unwind_RaiseException+0x2ac> lwz     r0,4(r1)
>> 00008288 <_Unwind_RaiseException+0x2b0> lwz     r31,-148(r1)
>> 0000828c <_Unwind_RaiseException+0x2b4> lwz     r30,-152(r1)
>> 00008290 <_Unwind_RaiseException+0x2b8> mtlr    r0
>> 00008294 <_Unwind_RaiseException+0x2bc> blr
>> 00008298 <_Unwind_RaiseException+0x2c0> bl      0001eccc <abort at plt>
> 
> The .eh_frame information shown by dwarfdump (see later below) shows off cfa=2992(r31) over the range starting at 0x00007ff0 but 0x828c to 0x8298 comes after R31 is returned to its old value. (The range goes up to 0x0000829c, which is the start of the next block of addresses.)
> 
> <off cfa=2992(r31) > is just wrong at 0000828c and later above.
> 
> (I'm not going to make claims here about 0x00007ff0 below listing both <off cfa=2992(r31) > and <off r31=-148(cfa) > or how such is handled. But it would seem that cfa=?(r31)'s interpretation would need to ignore any prior or same line r31=?(cfa). Either way it is generally wrong once cfa itself is inaccurate, as it is at 0000828c.)
> 
> The dwarfdump -v -v -F material for this is:
> 
>> <    0><0x00007fd8:0x0000829c><><fde offset 0x000002b4 length: 0x00000064><eh aug data len 0x0>
>>        0x00007fd8: <off cfa=00(r1) > 
>>        0x00007fec: <off cfa=2992(r1) > <off r30=-152(cfa) > <off r31=-148(cfa) > <off r65=04(cfa) > 
>>        0x00007ff0: <off cfa=2992(r31) > <off r14=-216(cfa) > <off r15=-212(cfa) > <off r16=-208(cfa) > <off r17=-204(cfa) > <off r18=-200(cfa) > <off r19=-196(cfa) > <off r20=-192(cfa) > <off r21=-188(cfa) > <off r22=-184(cfa) > <off r23=-180(cfa) > <off r24=-176(cfa) > <off r25=-172(cfa) > <off r26=-168(cfa) > <off r27=-164(cfa) > <off r28=-160(cfa) > <off r29=-156(cfa) > <off r30=-152(cfa) > <off r31=-148(cfa) > <off r46=-144(cfa) > <off r47=-136(cfa) > <off r48=-128(cfa) > <off r49=-120(cfa) > <off r50=-112(cfa) > <off r51=-104(cfa) > <off r52=-96(cfa) > <off r53=-88(cfa) > <off r54=-80(cfa) > <off r55=-72(cfa) > <off r56=-64(cfa) > <off r57=-56(cfa) > <off r58=-48(cfa) > <off r59=-40(cfa) > <off r60=-32(cfa) > <off r61=-24(cfa) > <off r62=-16(cfa) > <off r63=-8(cfa) > <off r65=04(cfa) > 
>> fde section offset 692 0x000002b4 cie offset for fde: 696 0x000002b8
>>         0 DW_CFA_advance_loc 20  (5 * 4)
>>         1 DW_CFA_def_cfa_offset 2992
>>         4 DW_CFA_offset r31 -148  (37 * -4)
>>         6 DW_CFA_offset r30 -152  (38 * -4)
>>         8 DW_CFA_offset_extended_sf r65 4  (-1 * -4)
>>        11 DW_CFA_advance_loc 4  (1 * 4)
>>        12 DW_CFA_def_cfa_register r31
>>        14 DW_CFA_offset r14 -216  (54 * -4)
>>        16 DW_CFA_offset r15 -212  (53 * -4)
>>        18 DW_CFA_offset r16 -208  (52 * -4)
>>        20 DW_CFA_offset r17 -204  (51 * -4)
>>        22 DW_CFA_offset r18 -200  (50 * -4)
>>        24 DW_CFA_offset r19 -196  (49 * -4)
>>        26 DW_CFA_offset r20 -192  (48 * -4)
>>        28 DW_CFA_offset r21 -188  (47 * -4)
>>        30 DW_CFA_offset r22 -184  (46 * -4)
>>        32 DW_CFA_offset r23 -180  (45 * -4)
>>        34 DW_CFA_offset r24 -176  (44 * -4)
>>        36 DW_CFA_offset r25 -172  (43 * -4)
>>        38 DW_CFA_offset r26 -168  (42 * -4)
>>        40 DW_CFA_offset r27 -164  (41 * -4)
>>        42 DW_CFA_offset r28 -160  (40 * -4)
>>        44 DW_CFA_offset r29 -156  (39 * -4)
>>        46 DW_CFA_offset r30 -152  (38 * -4)
>>        48 DW_CFA_offset r31 -148  (37 * -4)
>>        50 DW_CFA_offset r46 -144  (36 * -4)
>>        52 DW_CFA_offset r47 -136  (34 * -4)
>>        54 DW_CFA_offset r48 -128  (32 * -4)
>>        56 DW_CFA_offset r49 -120  (30 * -4)
>>        58 DW_CFA_offset r50 -112  (28 * -4)
>>        60 DW_CFA_offset r51 -104  (26 * -4)
>>        62 DW_CFA_offset r52 -96  (24 * -4)
>>        64 DW_CFA_offset r53 -88  (22 * -4)
>>        66 DW_CFA_offset r54 -80  (20 * -4)
>>        68 DW_CFA_offset r55 -72  (18 * -4)
>>        70 DW_CFA_offset r56 -64  (16 * -4)
>>        72 DW_CFA_offset r57 -56  (14 * -4)
>>        74 DW_CFA_offset r58 -48  (12 * -4)
>>        76 DW_CFA_offset r59 -40  (10 * -4)
>>        78 DW_CFA_offset r60 -32  (8 * -4)
>>        80 DW_CFA_offset r61 -24  (6 * -4)
>>        82 DW_CFA_offset r62 -16  (4 * -4)
>>        84 DW_CFA_offset r63 -8  (2 * -4)
>>        86 DW_CFA_nop
> 
> ===
> Mark Millard
> markmi at dsl-only.net
> 
> 


More information about the freebsd-ppc mailing list