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

Mark Millard via freebsd-ppc <[email protected]>
Newsgroups gmane.os.freebsd.devel.ppc,gmane.os.freebsd.devel.hackers
Message-ID <[email protected]>
[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
===================================================================
--- /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 = unused_rs;
		unused_rs = unused_rs->prev;
	      }
	    else
	      new_rs = alloca (sizeof (struct frame_state_reg_info));

	    *new_rs = fs->regs;
+	    new_rs->cfa_offset = fs->cfa_offset;
+	    new_rs->cfa_reg = fs->cfa_reg;
+	    new_rs->cfa_exp = fs->cfa_exp;
+	    new_rs->cfa_how = fs->cfa_how;
	    fs->regs.prev = new_rs;
	  }
	  break;

	case DW_CFA_restore_state:
	  {
	    struct frame_state_reg_info *old_rs = fs->regs.prev;
	    fs->regs = *old_rs;
+	    fs->cfa_offset = fs->regs.cfa_offset;
+	    fs->cfa_reg = fs->regs.cfa_reg;
+	    fs->cfa_exp = fs->regs.cfa_exp;
+	    fs->cfa_how = fs->regs.cfa_how;
	    old_rs->prev = unused_rs;
	    unused_rs = old_rs;
	  }
	  break;

	case DW_CFA_def_cfa:
	  insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg);
	  insn_ptr = read_uleb128 (insn_ptr, &utmp);
	  fs->cfa_offset = utmp;
	  fs->cfa_how = CFA_REG_OFFSET;
	  break;

Index: /usr/src/contrib/gcc/unwind-dw2.h
===================================================================
--- /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 = 1;

extern int f()
{
    volatile unsigned char c = '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
===> 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.


===
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.