This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH: Re: GCC vs GLIBC: why this stance, Drepper ?!?


On Sun, Jul 01, 2001 at 12:02:18PM +0200, Jakub Jelinek wrote:
> 
> You can surely recompile it, but it won't be binary compatible.
> __frame_state_for will be missing, plus glibc won't export the needed new
> __register_frame_info_bases etc. symbols, so if you mixed such glibc and
> some G++ 3.0 compiled library, you'd use two different registration points
> for shared libraries, one in glibc, one in probably libstdc++. So things
> would or would not work properly depending on the particular library order
> (e.g. try dlopening a library written in C++ from a C only main program and
> throw exceptions through sort).
> 
> GLIBC definitely needs a __frame_state_for implementation, plus its
> interaction with libgcc_s.so needs to be decided (see
> http://sources.redhat.com/ml/libc-hacker/2001-06/msg00020.html).
> 

Here is an UNTESTED patch. I don't believe it is even correct. It
only compiles. I think unwind-dw2.c is the best place to add
__frame_state_for. Any comments?

Thanks.


H.J.
-----
2001-07-02  H.J. Lu  (hjl@gnu.org)

	* config/t-linux (TARGET_LIBGCC2_CFLAGS): Add
	-DNEED__frame_state_for.

	* unwind-dw2.c (_Unwind_FrameState): Add eh_ptr for g++ v2.
	(extract_cie_info): Extract eh_ptr for g++ v2.
	(__frame_state_for): New. Define if NEED__frame_state_for is
	defined.

--- gcc/config/t-linux.frame	Wed May 30 07:50:06 2001
+++ gcc/config/t-linux	Mon Jul  2 12:01:33 2001
@@ -4,7 +4,7 @@ STMP_FIXPROTO =
 # Compile crtbeginS.o and crtendS.o with pic.
 CRTSTUFF_T_CFLAGS_S = -fPIC
 # Compile libgcc2.a with pic.
-TARGET_LIBGCC2_CFLAGS = -fPIC
+TARGET_LIBGCC2_CFLAGS = -fPIC -DNEED__frame_state_for
 
 # Override t-slibgcc-elf-ver to export some libgcc symbols with
 # the symbol versions that glibc used.
--- gcc/unwind-dw2.c.frame	Sat May 19 17:31:42 2001
+++ gcc/unwind-dw2.c	Mon Jul  2 12:06:00 2001
@@ -98,6 +98,9 @@ typedef struct
   /* The PC described by the current frame state.  */
   void *pc;
 
+  /* Used by g++ v2. */
+  void *eh_ptr;
+
   /* The information we care about from the CIE/FDE.  */
   _Unwind_Personality_Fn personality;
   signed int data_align;
@@ -242,9 +245,10 @@ extract_cie_info (struct dwarf_cie *cie,
   /* Iterate over recognized augmentation subsequences.  */
   while (*aug != '\0')
     {
-      /* "eh" was used by g++ v2; recognize and skip.  */
+      /* "eh" was used by g++ v2; store it in eh_ptr.  */
       if (aug[0] == 'e' && aug[1] == 'h')
 	{
+	  fs->eh_ptr = read_pointer (p);
 	  p += sizeof (void *);
 	  aug += 2;
 	}
@@ -1118,5 +1122,242 @@ uw_identify_context (struct _Unwind_Cont
 
 
 #include "unwind.inc"
+
+#ifdef NEED__frame_state_for
+/* This provides the backward compatibility for existing binaries
+   compiled against g++ v2 dwarf 2 frame based exception.
+   
+   FIXME: We really need this in libgcc.a only.  */
+
+struct frame_state
+{
+  void *cfa;
+  void *eh_ptr;
+  long cfa_offset;
+  long args_size;
+  long reg_or_offset[DWARF_FRAME_REGISTERS+1];
+  unsigned short cfa_reg;
+  unsigned short retaddr_column;
+  char saved[DWARF_FRAME_REGISTERS+1];
+  long base_offset;
+  char indirect;
+};
+
+/* The current unwind state, plus a saved copy for DW_CFA_remember_state.  */
+
+struct frame_state_internal
+{
+  struct frame_state s;
+  struct frame_state_internal *saved_state;
+};
+
+/* Called from __throw to find the registers to restore for a given
+   PC_TARGET.  The caller should allocate a local variable of `struct
+   frame_state' (declared in frame.h) and pass its address to STATE_IN.  */
+
+#if defined(__linux__) && defined(__sparc__) && !defined(__arch64__)
+/* Grab some info from parent register window so that we don't
+   have to flush register windows and look it up on the stack.  */
+asm ("	.text					\n\
+	.globl __frame_state_for		\n\
+	.type __frame_state_for, #function	\n\
+__frame_state_for:				\n\
+	mov	%fp, %o2			\n\
+	b	___frame_state_for		\n\
+	 mov	%i0, %o3			\n\
+     ");
+
+static struct frame_state *
+___frame_state_for (void *pc_target, struct frame_state *state_in, void *pfp,
+		    int i0)
+#elif defined(__linux__) && defined(__alpha__)
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in, long a2)
+#else
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in)
+#endif
+{
+  struct dwarf_fde *fde;
+  struct dwarf_cie *cie;
+  const unsigned char *aug, *insn, *end;
+  struct _Unwind_Context context;
+  _Unwind_FrameState fs;
+  struct frame_state_internal state;
+  size_t s;
+  
+  memset (&context, 0, sizeof (context));
+
+  fde = _Unwind_Find_FDE (pc_target, &context.bases);
+  if (fde == NULL)
+    return NULL;
+
+  context.ra = pc_target;
+
+  memset (&fs, 0, sizeof (fs));
+  fs.pc = context.bases.func;
+
+  cie = get_cie (fde);
+  insn = extract_cie_info (cie, &context, &fs);
+  if (insn == NULL)
+    return NULL;
+
+  /* First decode all the insns in the CIE.  */
+  end = (unsigned char *) next_fde ((struct dwarf_fde *) cie);
+  execute_cfa_program (insn, end, &context, &fs);
+
+  /* Locate augmentation for the fde.  */
+  aug = (unsigned char *)fde + sizeof (*fde);
+  aug += 2 * size_of_encoded_value (fs.fde_encoding);
+  insn = NULL; 
+  if (fs.saw_z)
+    {
+      _Unwind_Ptr i;
+      aug = read_uleb128 (aug, &i);
+      insn = aug + i;
+    }
+  if (fs.lsda_encoding != DW_EH_PE_omit)
+    aug = read_encoded_value (&context, fs.lsda_encoding, aug,
+                              (_Unwind_Ptr *) &context.lsda);
+
+  /* Then the insns in the FDE up to our target PC.  */ 
+  if (insn == NULL)
+    insn = aug;
+  end = (unsigned char *) next_fde (fde);
+  execute_cfa_program (insn, end, &context, &fs);
+
+  /* Now we convert to the old g++ v2 frame format.  */
+  memset (&state, 0, sizeof (state));
+  state.s.retaddr_column = fs.retaddr_column;
+  state.s.eh_ptr = fs.eh_ptr;
+  state.s.cfa_reg = fs.cfa_reg;
+  state.s.cfa_offset = fs.cfa_offset;
+  state.s.base_offset = context.cfa;
+  state.s.args_size = context.args_size;
+
+  for (s = 0; s <= DWARF_FRAME_REGISTERS; s++)
+    {
+      switch (fs.regs.reg[s].how)
+	{
+	case REG_UNSAVED:
+	  state.s.saved[s] = REG_UNSAVED;
+	  break;
+	case REG_SAVED_OFFSET:
+	  state.s.saved[s] = REG_SAVED_OFFSET;
+	  state.s.reg_or_offset[s] = fs.regs.reg[s].loc.offset;
+	  break;
+	case REG_SAVED_REG:
+	  state.s.saved[s] = REG_SAVED_REG;
+	  state.s.reg_or_offset[s] = fs.regs.reg[s].loc.reg;
+	  break;
+	default:
+	  /* g++ v2 doesn't support REG_SAVED_EXP.  */
+	  abort ();
+	}
+    }
+
+#ifdef __linux__
+  /* Binary compatibility problem: In June 2000, 2 fields
+     were added at the end of struct frame_state. If for some reason
+     __throw (or __rethrow) comes from binary/shared lib compiled
+     with egcs 1.x.y or gcc-2.95.x and __frame_state_for comes from
+     glibc compiled with gcc-2.96-RH up (gcc-3_0-branch in Apr 2001
+     works that way still), then we can overflow __throw's stack.
+     To fix this, we try to find out who calls us.
+     __frame_state_for is called by next_stack_level and __throw/__rethrow.
+     Of these, __throw/__rethrow does not care about indirect/base_offset
+     fields and next_stack_level can be found out because that's the only
+     routine which where state_in does not point into its stackframe.  */
+  s = (size_t) &((struct frame_state *)0)->base_offset;
+# ifdef __i386__
+  {
+    unsigned long pbp, bp;
+    unsigned char *ppc;
+
+    asm ("movl (%%ebp), %0; movl 4(%%ebp), %1; movl %%ebp, %2"
+	 : "=r" (pbp), "=r" (ppc), "=r" (bp));
+    if (pbp < (unsigned long)state_in && pbp - bp == 0x40)
+      /* We've been called from next_stack_level function.
+	 All gcc-2.96-RH rpms shipped by Red Hat satisfy pbp - bp == 64,
+	 none egcs 1.x.y Red Hat shipped do.  */
+      {
+	unsigned char *end;
+	int indirect = 0;
+
+	/* Skim next_stack_level to see if it compares 0x74(base),0
+	   and reads from 0x70(base).  Stop at ret instruction.  */
+	for (end = ppc + 512; ppc < end && *ppc != 0xc3 && indirect < 2;
+	     ppc++)
+	  {
+	    if (*ppc == 0x74 && ppc[1] == 0)
+	      indirect++;
+	    else if (*ppc == 0x70)
+	      indirect++;
+	  }
+	if (indirect == 2)
+	  s = sizeof (state.s);
+      }
+  }
+# elif defined(__sparc__) && !defined(__arch64__)
+  if (pfp < (unsigned long)state_in && i0 == 0)
+    /* We've been called from next_stack_level function.
+       All gcc-2.96-RH rpms shipped by Red Hat clear %i0 in next_stack_level
+       before calling __frame_state_for, all egcs 1.x.y just copy
+       %i0 into %o0, so it is guaranteed to be non-NULL.  */
+    {
+      unsigned int *ppc, *end;
+      int indirect = 0;
+
+      ppc = (unsigned int) __builtin_return_address (0);
+
+      /* Skim next_stack_level to see if it does a ld?b [? + 0x218]
+	 and ld?w [? + 0x214]. Stop at ret instruction.  */
+      for (end = ppc + 128; ppc < end && indirect < 2
+	   && (*ppc | 0x00080000) != 0x81cfe008; ppc++)
+	switch (*ppc & 0xc1b83fff)
+	  {
+	    case 0xc0082218: /* ld?b [? + 0x218], ? */
+	    case 0xc0002214: /* ld?w [? + 0x214], ? */
+	      indirect++;
+	      break;
+	  }
+	if (indirect == 2)
+	  s = sizeof (state.s);
+    }
+# elif defined(__alpha__)
+  if ((long)state_in == a2)
+    /* We've been called most probably from next_stack_level (it has 3 arguments
+       and passes its third argument as second argument to __frame_state_for).  */
+    {
+      unsigned int *ppc, *end;
+      int indirect = 0;
+
+      /* Skim next_stack_level to see if it does a ldq ?,624(?)
+	 and ldl ?,632(?) resp. ldbu ?,632(?). Stop at ret instruction.  */
+      for (end = ppc + 128; ppc < end && indirect < 2
+	   && *ppc != 0x6bfa8001; ppc++)
+	switch (*ppc & 0xfc00ffff)
+	  {
+	    case 0xa4000270: /* ldq ?,624(?) */
+	    case 0xa0000278: /* ldl ?,632(?) */
+	    case 0xa8000278: /* ldbu ?,632(?) */
+	      indirect++;
+	      break;
+	  }
+	if (indirect == 2)
+	  s = sizeof (state.s);
+    }
+# else
+  s = sizeof (state.s);
+# endif
+#else
+  s = sizeof (state.s);
+#endif
+  if (state.s.indirect && s < sizeof (state.s))
+    abort ();
+  memcpy (state_in, &state.s, s);
+  return state_in;
+}
+#endif /* NEED__frame_state_for */
 
 #endif /* !USING_SJLJ_EXCEPTIONS */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]