Date: Sun, 2 Dec 2018 20:07:50 -0800 From: Mark Millard <marklmi@yahoo.com> To: FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, freebsd-hackers Hackers <freebsd-hackers@freebsd.org> Subject: How to get /lib/libgcc_s.so.1 's thrown exception handling to work for the likes of powerpc64 with buildworld via devel/powerpc64-xtoolchain-gcc Message-ID: <502FA1DF-65C2-41B6-BF10-7E712CD44BA9@yahoo.com>
next in thread | raw e-mail | index | archive | help
[This is without the longer term technique of getting llvm's libunwind working.] The code changes in my example are deliberately set up to approximately minimize the number of lines with textual changes. The patching fixes the handling of DW_CFA_remember_state and DW_CFA_restore_state . Without the changes _Unwind_RaiseException can end up looping looking at the same frame over and over when DW_CFA_remember_state and DW_CFA_restore_state are in use. While gcc 4.2.1 generally avoids these, more modern toolchains use them. # svnlite diff --diff-cmd diff -x "-U12" = /usr/src/contrib/gcc/unwind-dw2.* Index: /usr/src/contrib/gcc/unwind-dw2.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- /usr/src/contrib/gcc/unwind-dw2.c (revision 340287) +++ /usr/src/contrib/gcc/unwind-dw2.c (working copy) @@ -949,32 +949,40 @@ case DW_CFA_remember_state: { struct frame_state_reg_info *new_rs; if (unused_rs) { new_rs =3D unused_rs; unused_rs =3D unused_rs->prev; } else new_rs =3D alloca (sizeof (struct frame_state_reg_info)); *new_rs =3D fs->regs; + new_rs->cfa_offset =3D fs->cfa_offset; + new_rs->cfa_reg =3D fs->cfa_reg; + new_rs->cfa_exp =3D fs->cfa_exp; + new_rs->cfa_how =3D fs->cfa_how; fs->regs.prev =3D new_rs; } break; case DW_CFA_restore_state: { struct frame_state_reg_info *old_rs =3D fs->regs.prev; fs->regs =3D *old_rs; + fs->cfa_offset =3D fs->regs.cfa_offset; + fs->cfa_reg =3D fs->regs.cfa_reg; + fs->cfa_exp =3D fs->regs.cfa_exp; + fs->cfa_how =3D fs->regs.cfa_how; old_rs->prev =3D unused_rs; unused_rs =3D old_rs; } break; case DW_CFA_def_cfa: insn_ptr =3D read_uleb128 (insn_ptr, &fs->cfa_reg); insn_ptr =3D read_uleb128 (insn_ptr, &utmp); fs->cfa_offset =3D utmp; fs->cfa_how =3D CFA_REG_OFFSET; break; Index: /usr/src/contrib/gcc/unwind-dw2.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- /usr/src/contrib/gcc/unwind-dw2.h (revision 340287) +++ /usr/src/contrib/gcc/unwind-dw2.h (working copy) @@ -28,60 +28,70 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* A target can override (perhaps for backward compatibility) how many dwarf2 columns are unwound. */ #ifndef DWARF_FRAME_REGISTERS #define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER #endif /* The result of interpreting the frame unwind info for a frame. This is all symbolic at this point, as none of the values can be resolved until the target pc is located. */ +enum frame_state_cfa_how_values { + CFA_UNSET, + CFA_REG_OFFSET, + CFA_EXP +}; typedef struct { /* Each register save state can be described in terms of a CFA slot, another register, or a location expression. */ struct frame_state_reg_info { struct { union { _Unwind_Word reg; _Unwind_Sword offset; const unsigned char *exp; } loc; enum { REG_UNSAVED, REG_SAVED_OFFSET, REG_SAVED_REG, REG_SAVED_EXP, REG_SAVED_VAL_OFFSET, REG_SAVED_VAL_EXP } how; } reg[DWARF_FRAME_REGISTERS+1]; /* Used to implement DW_CFA_remember_state. */ struct frame_state_reg_info *prev; + + /* The following are just for DW_CFA_{remember,restore}_state + handling. */ + /* The CFA can be described in terms of a reg+offset or a + location expression. */ + _Unwind_Sword cfa_offset; + _Unwind_Word cfa_reg; + const unsigned char *cfa_exp; + enum frame_state_cfa_how_values cfa_how; } regs; /* The CFA can be described in terms of a reg+offset or a location expression. */ _Unwind_Sword cfa_offset; _Unwind_Word cfa_reg; const unsigned char *cfa_exp; - enum { - CFA_UNSET, - CFA_REG_OFFSET, - CFA_EXP - } cfa_how; + enum frame_state_cfa_how_values cfa_how; /* The PC described by the current frame state. */ void *pc; /* The information we care about from the CIE/FDE. */ _Unwind_Personality_Fn personality; _Unwind_Sword data_align; _Unwind_Word code_align; _Unwind_Word retaddr_column; unsigned char fde_encoding; unsigned char lsda_encoding; unsigned char saw_z; Without such changes building devel/gdb and devel/kyua via, say, g++8 but still binding to /lib/libgcc_s.so.1 leads to failure of both programs: both make use of thrown c++ exceptions in normal operation and DW_CFA_remember_state and DW_CFA_restore_state end up involved. Even the following program fails, looping in __Unwind_RaiseException: #include <exception> // -O2 context used (but not required for the problem // to occur). volatile unsigned int v =3D 1; extern int f() { volatile unsigned char c =3D 'a'; v++; // despite volatile the access to v in g // was otherwise optimized out and the // std::exception was not followed by // code for f(). return c; } extern void g() { if (v) throw std::exception(); f(); // ends up inlined but the problem is demonstrated. } int main(void) { try {g();} // Used a separate function to avoid any potential // special handling of code in main. Call not // optimized out. catch (std::exception& e) {f();} return 0; } Previous to the changes the following were classified as broken by timing out without completing: # kyua report lib/atf/libatf-c++/detail/exceptions_test =3D=3D=3D> Summary Results read from = /root/.kyua/store/results.usr_tests.20181203-001618-953311.db Test cases: 3 total, 0 skipped, 0 expected failures, 0 broken, 0 failed Total time: 0.064s Using a gcc 4.2.1 based kernel and a devel/powerpc64-xtoolchain-gcc based world, I've done a complete kyua test -k /usr/tests/Kyuafile that completed. (The above report is based on that run.) The reason for the gcc 4.2.1 kernel is the crash in vnet_epair_init during the kyua test -k /usr/tests/Kyuafile run when the kernel was built by devel/powerpc64-xtoolchain-gcc . The linkage/relocation and vnet's code do not seem to be matched when devel/powerpc64-xtoolchain-gcc is used to build the kernel. =3D=3D=3D Mark Millard marklmi at yahoo.com ( dsl-only.net went away in early 2018-Mar)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?502FA1DF-65C2-41B6-BF10-7E712CD44BA9>