Re: What is incomplete for /lib/libgcc_s.so-based C++ exception handling (where WITH_LLVM_LIBUNWIND= and /usr/local/lib/gcc*/libgcc_s.so are not used)

Mark Millard via freebsd-ppc <[email protected]>
Newsgroups gmane.os.freebsd.devel.ppc,gmane.os.freebsd.devel.toolchain,gmane.os.freebsd.devel.hackers,gmane.os.freebsd.architechture
Message-ID <[email protected]>
[I add a note indicating that clang++ does
generate examples of DW_CFA_remember_state
and DW_CFA_restore_state use for pwoerpc64
that lead to /lib/libgcc_s.so messing up
the exception handling.]

On 2018-Oct-17, at 1:25 PM, Mark Millard <[email protected]> wrote:

> [This summarizes other results without the code
> and debugger evidence and such from my recent
> explorations. It should be much easier to
> follow than my exploration reports.]
> 
> Documents like DWARF5.pdf document the "row" vs. Location
> information for Call Frame Information as (also used
> for .eh_frame like materials for C++ exception handling):
> (CFA: Cannonical Frame Address)
> 
> QUOTE ("Structure of Call Frame Information")
> 	LOC CFA R0 R1...RN
> 
> 	L0
> 
> 	L1
> 
> 	...
> 
> 	LN
> END QUOTE
> 
> Note that the CFA is conceptually one of the
> registers in each row, even though it is not a
> machine register but a way to calculate the
> conceptual register's value from machine
> registers.
> 
> The information for the machine registers are
> typically based on the earlier CFA value (from
> the same row!). Absent a correct CFA cell in
> a row, most potential use of that row is likely
> messed up.
> 
> One way CFA is found is by adding an offset to
> the value of a machine register for the range
> in question, Ln up to L(n+1) [or based on the
> end of the overall range for the last Ln]. I
> will use that for illustration because there
> are examples of this in my testing.
> 
> /lib/libgcc_s.so.1 does not implement this
> fully for some DW_CFA_* operations:
> 
> QUOTE (note the "every register" reference, so including CFA)
> DW_CFA_remember_state
> 
> The DW_CFA_remember_state instruction takes no operands. The required action is to push the set of rules for every register onto an implicit stack.
> 
> DW_CFA_restore_state
> 
> The DW_CFA_restore_state instruction takes no operands. The required action is to pop the set of rules off the implicit stack and place them in the current row.
> END QUOTE
> 
> In other words: push and pop a complete row,
> not just machine registers information from
> the row.
> 
> For example, the the "cfa_offset" for computing the CFA
> value from from a register is not saved and restored.
> Nor is which register the offset is based on. (This
> can vary, though not in my examples.) In general the
> CFA cell is not saved and restored, what ever its
> contents.
> 
> So any compiler that produces code depending on
> DW_CFA_remember_state and DW_CFA_restore_state
> for .eh_frame like material ends up with C++
> exception handling messed up when the
> DW_CFA_restore_state should change the CFA to a 
> non-default one (from the prior
> DW_CFA_remember_state).
> 
> This prevents reliable use of throwing C++ exceptions
> when building via the likes of devel/powerpc64-gcc
> or lang/gcc8 ( when not using
> -Wl,-rpath=-Wl,-rpath=/usr/local/lib/gcc8 so that
> /lib/libgcc_s.so.1 ends up being used). One result
> can be _Unwind_RaiseException looping looking at
> the same frame over and over instead of progressing
> to the next frame. For example, this happens via
> cfa_offset 0 being used. devel/powerpc64-gcc -O2
> code tends to get that.
> 
> 
> Notes:
> 
> For powerpc64, clang++ tends to use another register
> (%r31) with the old value (of %r1, the stack pointer)
> instead of involving the
> DW_CFA_remember_state/DW_CFA_restore_state pair
> based on just %r1. (clang has other problems
> relative to sue for buildworld buildkernel.)

/usr/tests/lib/atf/libatf-c++/detail/exceptions_test
has examples were clang++ generated use of
DW_CFA_remember_state and DW_CFA_restore_state and
/lib/libgcc_s.so 's _Unwind_RaiseException ends
up stuck looping. There are other examples as well.

The problem is not limited to devel/powerpc64-gcc
or other g++ use that uses /lib/libgcc_s.so .

> Code generation styles matter for if the incomplete
> coverage by /lib/libgcc_s.so will be visible or not.
> 
> At this stage, WITH_LLVM_LIBUNWIND= builds
> targeting powerpc64 do not even compile/assemble
> the relevant code, apparently both because of
> darwin specific assembler code and FreeBSD's build
> not using the C-preprocessor on the .S file as
> required. (There could be more to getting it
> working.)
> 
> I do not know about other architecture/compiler
> (or toolchain) combinations that may not yet be
> able to use WITH_LLVM_LIBUNWIND= . But I'd
> expect a potentially similar status from some.
> 
> A range of modern /usr/local/lib/gcc*/libgcc_s.so
> do implement DW_CFA_remember_state/DW_CFA_restore_state
> operations and they are put to use. So using the likes
> of -Wl,-rpath=/usr/local/lib/gcc8 works for g++8 C++
> exception handling (but is problematical for buildworld
> buildkernel).
> 
> I made a similar exploration of the issue in around
> early 2016 and got basically the same results, not that
> I remembered much. But I now have a small source code
> example that shows the cfa_offset issue for the likes
> of devel/powerpc64-gcc output.
> 
> The standard source for throw_exception in
> /lib/libgcc_s.so produces the cfa_offset problem
> when devel/powerpc64-gcc is used to buildworld.
> This turns all thrown C++ exceptions in to
> unbounded looping in _Unwind_RaiseException for
> that kind of context.


===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)

_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-ppc
To unsubscribe, send any mail to "[email protected]"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.