Bug 207359 - head -r339076 TARGET_ARCH=powerpc64 via powerpc64-gcc : some or all c++ exceptions unbounded loop in _Unwind_RaiseException
Summary: head -r339076 TARGET_ARCH=powerpc64 via powerpc64-gcc : some or all c++ excep...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: powerpc Any
: --- Affects Only Me
Assignee: freebsd-bugs mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-02-19 19:19 UTC by Mark Millard
Modified: 2019-07-09 01:28 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Millard 2016-02-19 19:19:20 UTC
From a buildworld/buildkernel install for TARGET_ARCH=powerpc64 based on powerpc64-xtoolchain-gcc/powerpc64-gcc form projects/clang380-import -r205601. . .

#include <exception>

int main(void)
{
    try { throw std::exception(); }
    catch (std::exception& e) {} // same result without &
    return 0;
}

(This simplifies what I found in trying to use "kyua test -k /usr/tests/Kyuafile", which does not progress but uses 100% of a cpu/oore.)

# g++ --version
g++ (FreeBSD Ports Collection for powerpc64) 5.3.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# g++ -I /usr/include/c++/v1/ -L /usr/lib/ -g -Wall -pedantic exception_test.cpp

./a.out never finishes.

from gdb:

Program received signal SIGINT, Interrupt.
0x000000005002a088 in .__sys_sigprocmask () from /libexec/ld-elf.so.1
(gdb) bt
#0  0x000000005002a088 in .__sys_sigprocmask () from /libexec/ld-elf.so.1
#1  0x0000000050029c1c in sigprocmask (how=0, set=0x500493a4 <oldsigmask>, oset=0x0) at /usr/src/lib/libc/sys/sigprocmask.c:48
#2  0x0000000050022d98 in def_lock_release (lock=<optimized out>) at /usr/src/libexec/rtld-elf/rtld_lock.c:141
#3  0x0000000050023028 in lock_release (lock=0x500496a8 <rtld_locks+32>, lockstate=<optimized out>) at /usr/src/libexec/rtld-elf/rtld_lock.c:234
#4  0x000000005001ddac in dl_iterate_phdr (callback=@0x501e1b50: 0x501ce350 <_Unwind_IteratePhdrCallback>, param=0xffffffffffffc210) at /usr/src/libexec/rtld-elf/rtld.c:3544
#5  0x00000000501cf33c in _Unwind_Find_FDE (pc=0x5016e39f <throw_exception(__cxxabiv1::__cxa_exception*)+143>, bases=0xffffffffffffd1d8)
    at /usr/src/gnu/lib/libgcc/../../../contrib/gcc/unwind-dw2-fde-glibc.c:420
#6  0x00000000501ca9e0 in uw_frame_state_for (context=context@entry=0xffffffffffffcd30, fs=fs@entry=0xffffffffffffc3b0) at /usr/src/gnu/lib/libgcc/../../../contrib/gcc/unwind-dw2.c:1106
#7  0x00000000501cb968 in _Unwind_RaiseException (exc=0x50815058) at /usr/src/gnu/lib/libgcc/../../../contrib/gcc/unwind.inc:103
#8  0x000000005016e3a0 in throw_exception (ex=0x50815000) at /usr/src/lib/libcxxrt/../../contrib/libcxxrt/exception.cc:751
#9  0x0000000010000d50 in main () at exception_test.cpp:5
. . . repeated finish commands until . . .
(gdb) finish
Run till exit from #0  _Unwind_RaiseException (exc=0x50815058) at /usr/src/gnu/lib/libgcc/../../../contrib/gcc/unwind.inc:117
^C
Program received signal SIGINT, Interrupt.
0x000000005002a088 in .__sys_sigprocmask () from /libexec/ld-elf.so.1

_Unwind_RaiseException never returns.

kyua did the same thing but is a more complicated context.

Using g++49's a.out gets the same 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:

# g++49 -g -Wall -pedantic exception_test.cpp
# ./a.out
# 

The difference is the headers/libraries involved.

(powerpc64-gcc cannot be used that way: it has a freestanding status and the include path and libraries path need to be supplied.)

(clang 3.8.0 is not up to doing a buildworld. For example: it does not support soft float yet, at least last checked. This is part of why I test the provided (ports) cross compile environment for powerpc64 [but in a self-hosted form].)
Comment 1 Mark Millard 2016-02-23 09:03:04 UTC
(Now using projects/clang380-import -r295902 as a context.)

TARGET_ARCH=powerpc64 here.

It looks like FreeBSD's /lib/libgcc_s.so.1 is incompatible with using the pair: /usr/lib/libc++.so.1 and /lib/libcxxrt.so.1 .

Details follow.

Later below I list the ldd output for compiling the exception_test.cpp example under different compilers with different options that change what ldd shows and how .so's are found/bound. Some are using. . .

ELF ldconfig path: /lib /usr/lib /usr/lib/compat /usr/local/lib /usr/local/lib/compat/pkg /usr/local/lib/compat/pkg /usr/local/lib/gcc49 /usr/local/lib/gcc6

and others are explicitly bound, such as by -Wl,-rpath=<?> .

The only combinations that do not work are the ones that mix 3 things together:

/usr/lib/libc++.so.1
/lib/libcxxrt.so.1
/lib/libgcc_s.so.1

That is: exception_test.clang++380.powerpc64 and exception_test.powerpc64-gcc.powerpc64 get the unbounded looping and the others work fine.

By contrast /lib/libgcc_s.so.1 works with:

/usr/local/lib/gcc49/libstdc++.so.6
and
/usr/local/lib/gcc6/libstdc++.so.6

Of course a matched libstdc++/libgcc_s for a specific compiler also works.




# ldd *powerpc64
exception_test.clang++380.powerpc64:
	libc++.so.1 => /usr/lib/libc++.so.1 (0x50054000)
	libcxxrt.so.1 => /lib/libcxxrt.so.1 (0x5015a000)
	libm.so.5 => /lib/libm.so.5 (0x50181000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x501be000)
	libc.so.7 => /lib/libc.so.7 (0x501e4000)
exception_test.g++49-implicitgcc49.powerpc64:
	libstdc++.so.6 => /usr/local/lib/gcc49/libstdc++.so.6 (0x50054000)
	libm.so.5 => /lib/libm.so.5 (0x501ed000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x5022a000)
	libc.so.7 => /lib/libc.so.7 (0x50250000)
exception_test.g++49.powerpc64:
	libstdc++.so.6 => /usr/local/lib/gcc49/libstdc++.so.6 (0x50054000)
	libm.so.5 => /lib/libm.so.5 (0x501ed000)
	libgcc_s.so.1 => /usr/local/lib/gcc49/libgcc_s.so.1 (0x5022a000)
	libc.so.7 => /lib/libc.so.7 (0x50253000)
exception_test.g++6-implicitgcc49.powerpc64:
	libstdc++.so.6 => /usr/local/lib/gcc49/libstdc++.so.6 (0x50054000)
	libm.so.5 => /lib/libm.so.5 (0x501ed000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x5022a000)
	libc.so.7 => /lib/libc.so.7 (0x50250000)
exception_test.g++6.powerpc64:
	libstdc++.so.6 => /usr/local/lib/gcc6/libstdc++.so.6 (0x50054000)
	libm.so.5 => /lib/libm.so.5 (0x502a6000)
	libgcc_s.so.1 => /usr/local/lib/gcc6/libgcc_s.so.1 (0x502e3000)
	libc.so.7 => /lib/libc.so.7 (0x5030a000)
exception_test.powerpc64-gcc.powerpc64:
	libc++.so.1 => /usr/lib/libc++.so.1 (0x50053000)
	libcxxrt.so.1 => /lib/libcxxrt.so.1 (0x50159000)
	libm.so.5 => /lib/libm.so.5 (0x50180000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x501bd000)
	libc.so.7 => /lib/libc.so.7 (0x501e3000)
Comment 2 Mark Millard 2016-02-25 00:56:23 UTC
I've finally traced the low level details of the _Unwind_RaiseException stuck looping failure. . .

Starting from the observed low-level evidence based on observation via gdb and such:

A backtrace while stopped during the unbounded looping is:

#0  uw_update_context (context=context@entry=0xffffffffffffccf0, fs=fs@entry=0xffffffffffffc370) at /usr/src/gnu/lib/libgcc/../../../contrib/gcc/unwind-dw2.c:1371
#1  0x00000000501cb95c in _Unwind_RaiseException (exc=0x50815058) at /usr/src/gnu/lib/libgcc/../../../contrib/gcc/unwind.inc:126
#2  0x000000005016e3a0 in throw_exception (ex=0x50815000) at /usr/src/lib/libcxxrt/../../contrib/libcxxrt/exception.cc:751
#3  0x0000000010000d50 in main () at exception_test.cpp:5

_Unwind_RaiseException never returns for source code that looks like:

#include <exception>

int main(void)
{
    try { throw std::exception(); }
    catch (std::exception& e) {}
    return 0;
}

where in /usr/lib/libc++.so.1 there is:

736	static void throw_exception(__cxa_exception *ex)
737	{
. . .
751		_Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
. . .
756	}

The unbounded loop in _Unwind_RaiseException is in the code:

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);
93	  cur_context = this_context;
94	
95	  /* Phase 1: Search.  Unwind the stack, calling the personality routine
96	     with the _UA_SEARCH_PHASE flag set.  Do not modify the stack yet.  */
97	  while (1)
98	    {
99	      _Unwind_FrameState fs;
100	
101	      /* Set up fs to describe the FDE for the caller of cur_context.  The
102		 first time through the loop, that means __cxa_throw.  */
103	      code = uw_frame_state_for (&cur_context, &fs);
. . .
125	      /* Update cur_context to describe the same frame as fs.  */
126	      uw_update_context (&cur_context, &fs);
127	    }
. . .
140	}

The uw_update_context call is doing the following before returning:

1367	  /* Compute the return address now, since the return address column
1368	     can change from frame to frame.  */
1369	  context->ra = __builtin_extract_return_addr
1370	    (_Unwind_GetPtr (context, fs->retaddr_column));

with context->ra before and after the call both being 0x5016e3a0 . In fact it was 0x5016e3a0 for the prior uw_frame_state_for call as well and continues to be so each loop iteration once the problem starts.

As for the code around 0x5016e3a0:

   0x5016e398 <throw_exception(__cxxabiv1::__cxa_exception*)+136>:	stw     r10,48(r9)
   0x5016e39c <throw_exception(__cxxabiv1::__cxa_exception*)+140>:	bl      0x50162ae0 <00000017.plt_call._Unwind_RaiseException@@GCC_3.0>
   0x5016e3a0 <throw_exception(__cxxabiv1::__cxa_exception*)+144>:	ld      r2,40(r1)
   0x5016e3a4 <throw_exception(__cxxabiv1::__cxa_exception*)+148>:	addi    r1,r1,128
   0x5016e3a8 <throw_exception(__cxxabiv1::__cxa_exception*)+152>:	mr      r4,r31
   0x5016e3ac <throw_exception(__cxxabiv1::__cxa_exception*)+156>:	ld      r0,16(r1)

 From /usr/local/bin/objdump for FreeBSD projects/clang380-import -r295902's /usr/lib/libc++.so.1 for the same code (to match up with the .eh_frame dwarf information presented later):

0000000000015398 <.__cxa_end_catch+0x4d8> stw     r10,48(r9)
000000000001539c <.__cxa_end_catch+0x4dc> bl      0000000000009ae0 <CXXABI_1.3+0x9ae0>
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)

The code block above from 153a0 up to 153a8 is being given 153a0 as its "return address" (context->ra) by uw_update_context via interpreting the dwarf .eh_frame information. So once in that range there it never leaves that range.

The relevant dwarfdump output spanning that area is:
(Note that 153a0 up to 153a8 is part of the range that includes the bl to _Unwind_RaiseException .)

<    0><0x00015310:0x000153dc><><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 the stack pointer manipulation (incrementing/popping) *after* the return from the bl. 15339c, 153a0, and 153a4 should be 3 distinct contexts in the .eh_frame information but are not:

000000000001539c <.__cxa_end_catch+0x4dc> bl      0000000000009ae0 <CXXABI_1.3+0x9ae0>
00000000000153a0 <.__cxa_end_catch+0x4e0> ld      r2,40(r1)
00000000000153a4 <.__cxa_end_catch+0x4e4> addi    r1,r1,128

So there is a missing step or more of frame-context tracking in the .eh_frame information.
Comment 3 Mark Millard 2016-02-25 01:45:24 UTC
(In reply to Mark Millard from comment #2)

I should have noted that powerpc64-gcc was used for buildworld of projects/clang380-import -r295902 (and other  versions) --and so for libcxxrt as well.

It is g++ 5.3 that put out the incomplete .eh_frame frame-context tracking.
Comment 4 Mark Millard 2016-02-25 01:49:46 UTC
(In reply to Mark Millard from comment #3)

And now I see that I types "libc++" in places that I should have typed "libcxxrt".

Noted here just to help avoid confusions.
Comment 5 Mark Millard 2016-02-26 11:08:16 UTC
(In reply to Mark Millard from comment #4)

A new, corrected, even lower level detail interpretation. . . which may put the burden on the system's .eh_frame handling in libgcc_s.

I state the relationship from the point of view what the existing fde operations would need to do to be correct. The alternate is that the missing activity is missing operations 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 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. This makes sense for the code in question. But DW_CFA_remember_state/DW_CFA_restore_state do not save and restore the cfa_offset (12 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 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;

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.
Comment 6 Mark Millard 2016-02-26 11:21:57 UTC
(In reply to Mark Millard from comment #5)

The uw_update_context_1 material would have been clearler if I'd listed another line from the source code. So I do below.

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;

That last explains how the fs->cfa_offset is supposed to end up involved in later activity. (fs is local to each loop iteration; context's lifetime spans across iterations.)


Also: I see that in at least one place I typed "12" instead of "128". Be warned.
Comment 7 Mark Millard 2016-02-26 12:43:12 UTC
(In reply to Mark Millard from comment #6)

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) Of 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.
Comment 8 Mark Millard 2016-02-28 00:46:22 UTC
A warning relative to clang 3.8.0 and c++ exception handling and being able to test fixes to c++ exception handling in an overall manor for clang:

clang 3.8.0 for powerpc and powerpc64 messes up what __builtin_dwarf_cfa() returns and the c++ exception handling infrastructure depends on that.

So until both clang 3.8.0's __builtin_dwarf_cfa() and the FreeBSD's libgcc_s's DW_CFA_remember_state/DW_CFA_restore_state handling are fixed c++ exceptions are going to be broken to some degree. (The clang problem is always involved.)

powerpc64's use of a stack "red zone" and late stack pointer decrementing/early incrementing may make it more likely to use DW_CFA_remember_state/DW_CFA_restore_state in the .eh_frame information, especially with inlining and the llike.

Currently clang 3.8.0's ABI violation for powerpc code generation puts it in the same category with powerpc64 for this since it is also using a "red zone".


g++49 and g++5 do not have clang's __builtin_dwarf_cfa() problem for powerpc64 or for powerpc. So for now they are better for having a more overall testing of library code involved in C++ exception handling.
Comment 9 Mark Millard 2016-02-28 04:46:35 UTC
A find over /usr/src/ with egrep use suggests that the later files listed are files that use the cfa fields. They match the pattern:

[.>]cfa_(offset|reg|exp|how)


/usr/src/contrib/gcc/config/mips/linux-unwind.h
/usr/src/contrib/gcc/config/rs6000/linux-unwind.h
/usr/src/contrib/gcc/config/rs6000/darwin-fallback.c
/usr/src/contrib/gcc/config/i386/linux-unwind.h
/usr/src/contrib/gcc/config/sparc/linux-unwind.h
/usr/src/contrib/gcc/config/s390/tpf-unwind.h
/usr/src/contrib/gcc/config/s390/linux-unwind.h
/usr/src/contrib/gcc/unwind-dw2.c
/usr/src/contrib/gcc/dwarf2out.c
/usr/src/contrib/gdb/gdb/dwarf2-frame.c
/usr/src/contrib/binutils/gas/dw2gencfi.c
/usr/src/contrib/binutils/binutils/dwarf.c

And _Unwind_FrameState is mentioned in each of:

/usr/src/contrib/gcc/config/mips/linux-unwind.h
/usr/src/contrib/gcc/config/rs6000/linux-unwind.h
/usr/src/contrib/gcc/config/rs6000/darwin-fallback.c
/usr/src/contrib/gcc/config/rs6000/darwin-unwind.h
/usr/src/contrib/gcc/config/i386/linux-unwind.h
/usr/src/contrib/gcc/config/sparc/linux-unwind.h
/usr/src/contrib/gcc/config/s390/tpf-unwind.h
/usr/src/contrib/gcc/config/s390/linux-unwind.h
/usr/src/contrib/gcc/config/ia64/unwind-ia64.c
/usr/src/contrib/gcc/config/ia64/linux-unwind.h
/usr/src/contrib/gcc/doc/tm.texi
/usr/src/contrib/gcc/unwind-sjlj.c
/usr/src/contrib/gcc/ChangeLog-2006
/usr/src/contrib/gcc/ChangeLog-2001
/usr/src/contrib/gcc/unwind.inc
/usr/src/contrib/gcc/unwind-dw2.h
/usr/src/contrib/gcc/unwind-dw2.c
/usr/src/contrib/gcc/ChangeLog-2004
/usr/src/contrib/gcc/ChangeLog-2003


That in turn suggests that they are most(?) of the files that would be tied to any attempt to have DW_CFA_remember_state/DW_CFA_restore_state save and restore the cfa information.

One possibility is moving the fields into the saved/restored area (regs, along with the contained fields prev and reg). Access notation would then be based on:

->regs.cfa_offset and .regs.cfa_offset
->regs.cfa_reg and .regs.cfa_reg
->regs.cfa_exp and .regs.cfa_exp
->regs.cfa_how and .regs.cfa_how
Comment 10 Mark Millard 2016-03-06 01:36:26 UTC
Here is what dwarf-2.0.0.pdf says about DW_CFA_remember_state and DW_CFA_restore_state:


13. DW_CFA_remember_state
14. DW_CFA_restore_state
These instructions define a stack of information. Encountering the DW_CFA_remember_state instruction means to save the rules for every register on the current row on the stack. Encountering the DW_CFA_restore_state instruction means to pop the set of rules off the stack and place them in the current row. (This operation is useful for compilers that move epilogue code into the body of a function.)



The correct interpretation of "save the rules for every register on the current row on the stack" is to include the cfa "register" as one of those registers that has its rules saved: it is not just processor registers that are to be saved and restored but also the logical one(s).

dwarf-2.0.0.pdf also says:

	•	The algorithm to compute the CFA changes as you progress through the prologue and epilogue code. (By definition, the CFA value does not change.) 



So technically the "rules" material for the cfa "Register" need not include the cfa value on the stack. (But pushing and popping what stays a constant value is still correct.)


Also the cfa register is somewhat special by only having special instructions:

15. DW_CFA_def_cfa takes two unsigned LEB128 arguments representing a register number and an offset. The required action is to define the current CFA rule to use the provided register and offset.

16. DW_CFA_def_cfa_register takes a single unsigned LEB128 argument representing a register number. The required action is to define the current CFA rule to use the provided register (but to keep the old offset).

17. DW_CFA_def_cfa_offset takes a single unsigned LEB128 argument representing an offset. The required action is to define the current CFA rule to use the provided offset (but to keep the old register).



These only allow the resulting cfa definition rules to be of the form: cfa=OFFSET(REG).
Comment 11 Mark Millard 2018-10-31 03:25:28 UTC
(In reply to Mark Millard from comment #10)

Testing with a build based on head -r339076 shows this still
happens. Both clang code generation and
devel/powerpc64-xtoolchain-gcc code generation have examples
of hitting the mishandling in libgcc_s.so and so
__Unwind_RaiseException looping on the same stack frame
over and over.
Comment 12 Andrey Rusev 2019-03-18 07:36:35 UTC
I have similar error on FreeBSD 12 (not on FreeBSD 11 or older) on amd64: any C++ exception to be caught will crash application:

[New LWP 100396 of process 21374]
libunwind: getEncodedP /usr/src/contrib/llvm/projects/libunwind/src/AddressSpace.hpp:280 - unknown pointer encoding
Thread 1 received signal SIGABRT, Aborted.
0x0000000801d2945a in thr_kill () from /lib/libc.so.7
(gdb) where
#0  0x0000000801d2945a in thr_kill () from /lib/libc.so.7
#1  0x0000000801d27844 in raise () from /lib/libc.so.7
#2  0x0000000801c9a079 in abort () from /lib/libc.so.7
#3  0x00000008005dff3e in ?? () from /lib/libgcc_s.so.1
#4  0x00000008005e0e49 in ?? () from /lib/libgcc_s.so.1
#5  0x00000008005e0d31 in ?? () from /lib/libgcc_s.so.1
#6  0x00000008005381ec in dl_iterate_phdr () from /libexec/ld-elf.so.1
#7  0x00000008005de422 in ?? () from /lib/libgcc_s.so.1
#8  0x00000008005dd21a in ?? () from /lib/libgcc_s.so.1
#9  0x00000008005dbd46 in _Unwind_RaiseException () from /lib/libgcc_s.so.1
#10 0x0000000801f7740d in __cxa_throw () from /usr/local/lib/compat/libsupc++.so.1
#11 0x00000008006ae2b9 in MessageDecodeProxyContext::findContentType (this=0x800f67320, hdrLen=@0x7fffffffd97c: 4)
    at /dailybuilds/CSPbuild/CSP/capilite/CMSMessage.cpp:121

As you can see I also get libunwind warning as in Bug #234201

Application is built by GCC 4.2.1 20070719 on FreeBSD 8.1-RELEASE-p12.

If no excetion is thrown everything works fine.
Comment 13 Andrey Rusev 2019-03-23 19:56:27 UTC
The problem has gone after updating build machine to FreeBSD 8.4-RELEASE-p35 and GCC 4.2.1 20070831.
Comment 14 Mark Millard 2019-03-23 20:43:08 UTC
(In reply to Andrey Rusev from comment #12)

My original submittal did not involve "unknown pointer encoding".

What you report for amd64 is not similar at all. (Modern amd64
uses llvm libunwind, not the historical unwind code.)

Please submit your own defect report for your context.

Things have progressed, in that for lbgcc_s.so historical
unwind code I now run with a patch that completes the
implementation of DW_CFA_remember_state and
DW_CFA_restore_state. building via devel/powerpc64-xtoolchain-gcc
materials ( such as devel./powerpc64-gcc ) works for C++
exception handling.

There is a patch under review for llvm materials to fix llvm's
libunwind for pwoerpc64 code so that  it correctly handles the
r2 (TOC) register, at least for the code models normally used.
Comment 15 Mark Millard 2019-03-23 20:52:16 UTC
(In reply to Andrey Rusev from comment #13)

Please submit your own defect report. For powerpc64 reverting
to FreeBSD 8.4-RELEASE-p35 and gcc 4.2.1 is irrelevant to what
I was reporting. powerpc64 does not have the history that amd64
has and a lot has changed since back then.

I was reporting an issue explicit tied to giving information
for using more modern toolchains than gcc 4.2.1 . 

For powerpc64, more is now known for what I was reporting and
patching efforts to fix both the historical unwind code's
DW_CFA_remember_state and DW_CFA_restore_state hnndling and
llvm's libunwind's handling of r2 during unwind (the TOC
register for powerpc64) are in progress. (It may be that
only llvm libunwind will be fixed and used going forward.)
Comment 16 Andrey Rusev 2019-04-12 11:30:23 UTC
I have decided to comment about amd64 here because googling by stack trace brought me here. Maintainers can decide if my problem and resolution is related to the original one. I did not suggest downgrading compiler on powerpc. But there may be the same error in clang that was in gcc lately. For now I do not need any assistance.
Comment 17 Mark Millard 2019-07-09 01:28:24 UTC
Head -r349793 picked up the last of the 8.0.1 rc3 changes
for dealing with  TOC (r2) save/restore for powerpc64.
So use of WITH_LLVM_LIBUNWIND= is able to avoid the known
issues with the old library.

8.0.1 has not been merged to stable/12 yet.

Despite a patch for the old library being available on the
list, various folks indicaeted that they would prefer to
switch-to and require LLMV's libunwind instead.

So, once merged, this submittal likely becomes Overcome
By Events for its status relative to powerpc64. (I'm
not yet as sure of the 32-bit powerpc context for analogous
unwind issues but it is likely going the same direction.)