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]

Re: PATCH: Support gcc v3 unwind frame in gcc pre 3.0


On Mon, Jul 09, 2001 at 01:07:17AM -0700, H . J . Lu wrote:
> This is not a patch against gcc 2.95. It is for gcc 2.96 from RedHat
> 7.1. But the idea for gcc 2.95 is the same. Combining frame-dwarf2.c
> from gcc 2.96 as well as unwind-dw2-fde.c, unwind-dw2-fde.h,
> unwind-pe.h and unwind-dw2.c fro gcc 3.0, we can put a mixed gcc v2
> and v3 frame unwinder in glibc. I will post my updated glibc patch
> later.
> 

Here is a patch for gcc 2.95. It seems to work for me.


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

	* dwarf2.h: Updated from gcc 3.0.

	* frame.c: Include glibc heade files instead if _LIBC is
	defined. Support the frame unwinder only build in glibc.
	(cie_info): Add pc, fde_encoding, lsda_encoding and saw_z.
	(extract_cie_info): Recognize gcc v3 unwind frame.
	(execute_cfa_insn): Remove the last argument. `pc' is passed
	in `info' now.
	(__frame_state_for): Call _Unwind_GetFrameForV2 for gcc v3
	unwind frame if NEED__Unwind_GetFrameForV2 is defined.

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

	* dwarf2.h: Updated from gcc 3.0.

	* frame.c: Include glibc heade files instead if _LIBC is
	defined. Support the frame unwinder only build in glibc.
	(cie_info): Add pc, fde_encoding, lsda_encoding and saw_z.
	(extract_cie_info): Recognize gcc v3 unwind frame.
	(execute_cfa_insn): Remove the last argument. `pc' is passed
	in `info' now.
	(__frame_state_for): Call _Unwind_GetFrameForV2 for gcc v3
	unwind frame if NEED__Unwind_GetFrameForV2 is defined.

--- gcc/dwarf2.h.mixed	Fri Dec 22 06:24:59 2000
+++ gcc/dwarf2.h	Mon Jul  9 09:15:09 2001
@@ -88,7 +88,9 @@ enum dwarf_tag
     /* GNU extensions */
     DW_TAG_format_label = 0x4101,	/* for FORTRAN 77 and Fortran 90 */
     DW_TAG_function_template = 0x4102,	/* for C++ */
-    DW_TAG_class_template = 0x4103	/* for C++ */
+    DW_TAG_class_template = 0x4103,	/* for C++ */
+    DW_TAG_GNU_BINCL = 0x4104,
+    DW_TAG_GNU_EINCL = 0x4105
   };
 
 #define DW_TAG_lo_user	0x4080
@@ -532,6 +534,7 @@ enum dwarf_source_language
     DW_LANG_Fortran90 = 0x0008,
     DW_LANG_Pascal83 = 0x0009,
     DW_LANG_Modula2 = 0x000a,
+    DW_LANG_Java = 0x000b,
     DW_LANG_Mips_Assembler = 0x8001
   };
 
@@ -549,3 +552,27 @@ enum dwarf_macinfo_record_type
     DW_MACINFO_end_file = 4,
     DW_MACINFO_vendor_ext = 255
   };
+
+
+/* @@@ For use with GNU frame unwind information.  */
+
+#define DW_EH_PE_absptr		0x00
+#define DW_EH_PE_omit		0xff
+
+#define DW_EH_PE_uleb128	0x01
+#define DW_EH_PE_udata2		0x02
+#define DW_EH_PE_udata4		0x03
+#define DW_EH_PE_udata8		0x04
+#define DW_EH_PE_sleb128	0x09
+#define DW_EH_PE_sdata2		0x0A
+#define DW_EH_PE_sdata4		0x0B
+#define DW_EH_PE_sdata8		0x0C
+#define DW_EH_PE_signed		0x08
+
+#define DW_EH_PE_pcrel		0x10
+#define DW_EH_PE_textrel	0x20
+#define DW_EH_PE_datarel	0x30
+#define DW_EH_PE_funcrel	0x40
+#define DW_EH_PE_aligned	0x50
+
+#define DW_EH_PE_indirect	0x80
--- gcc/frame.c.mixed	Thu Jan 25 06:03:15 2001
+++ gcc/frame.c	Mon Jul  9 10:13:42 2001
@@ -31,6 +31,25 @@ Boston, MA 02111-1307, USA.  */
    compiled for the target, and hence definitions concerning only the host
    do not apply.  */
 
+#ifdef _LIBC
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <libintl.h>
+#include <dwarf2.h>
+#define DWARF2_FRAME_UNWIND_V2
+#define NEED__Unwind_GetFrameForV2
+#define NEED_DWARF2_FRAME_UNWIND_OLD_OBJECT
+#include <unwind-pe.h>
+
+/* Values for the 'saved' field in struct frame_state defined in
+   unwind-pe.h.  */
+#define REG_UNSAVED 0
+#define REG_SAVED_OFFSET 1
+#define REG_SAVED_REG 2
+
+#define DWARF2_UNWIND_INFO 1
+#else /* _LIBC */
 #include "tconfig.h"
 
 /* We disable this when inhibit_libc, so that gcc can still be built without
@@ -61,7 +80,10 @@ static __gthread_mutex_t object_mutex;
 #ifdef abort
 #undef abort
 #endif
+#endif /* DWARF2_UNWIND_INFO */
+#endif /* _LIBC */
 
+#ifdef DWARF2_UNWIND_INFO
 /* Some types used by the DWARF 2 spec.  */
 
 typedef          int  sword __attribute__ ((mode (SI)));
@@ -109,6 +131,7 @@ struct dwarf_fde {
   uaddr pc_range;
 } __attribute__ ((packed, aligned (__alignof__ (void *))));
 
+#ifndef _LIBC
 typedef struct dwarf_fde fde;
 
 /* Objects to be searched for frame unwind info.  */
@@ -120,19 +143,15 @@ static struct object *objects;
 struct cie_info {
   char *augmentation;
   void *eh_ptr;
+  void *pc;
   int code_align;
   int data_align;
   unsigned ra_regno;
+  unsigned char fde_encoding;
+  unsigned char lsda_encoding;
+  unsigned char saw_z;
 };
 
-/* 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;
-};
-
 /* This is undefined below if we need it to be an actual function.  */
 #define init_object_mutex_once()
 
@@ -159,7 +178,16 @@ init_object_mutex_once (void)
 
 #endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
 #endif /* __GTHREADS */
+#endif /* !_LIBC */
   
+/* 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;
+};
+
 /* Decode the unsigned LEB128 constant at BUF into the variable pointed to
    by R, and return the new value of BUF.  */
 
@@ -230,6 +258,15 @@ static inline unsigned long
 read_8byte (void *p)
 { union unaligned *up = p; return up->b8; }
 
+/* Return the address of the FDE after P.  */
+
+static inline fde *
+next_fde (fde *p)
+{
+  return (fde *)(((char *)p) + p->length + sizeof (p->length));
+}
+
+#ifndef _LIBC
 /* Ordering function for FDEs.  Functions can't overlap, so we just compare
    their starting addresses.  */
 
@@ -239,14 +276,6 @@ fde_compare (fde *x, fde *y)
   return (saddr)x->pc_begin - (saddr)y->pc_begin;
 }
 
-/* Return the address of the FDE after P.  */
-
-static inline fde *
-next_fde (fde *p)
-{
-  return (fde *)(((char *)p) + p->length + sizeof (p->length));
-}
-
 /* Sorting an array of FDEs by address.
    (Ideally we would have the linker sort the FDEs so we don't have to do
    it at run time. But the linkers are not yet prepared for this.)  */
@@ -545,6 +574,7 @@ find_fde (void *pc)
 
   return 0;
 }
+#endif /* !_LIBC */
 
 static inline struct dwarf_cie *
 get_cie (fde *f)
@@ -558,39 +588,82 @@ get_cie (fde *f)
 static void *
 extract_cie_info (fde *f, struct cie_info *c)
 {
+  unsigned char *aug;
   void *p;
-  int i;
+  void *ret = NULL;
 
   c->augmentation = get_cie (f)->augmentation;
+  aug = c->augmentation;
+  p = aug + strlen (aug) + 1;
 
-  if (strcmp (c->augmentation, "") != 0
-      && strcmp (c->augmentation, "eh") != 0
-      && c->augmentation[0] != 'z')
-    return 0;
-
-  p = c->augmentation + strlen (c->augmentation) + 1;
-
-  if (strcmp (c->augmentation, "eh") == 0)
+  /* "eh" was used by g++ v2; recognize and store.  */
+  if (aug[0] == 'e' && aug[1] == 'h')
     {
       c->eh_ptr = read_pointer (p);
       p += sizeof (void *);
     }
-  else
-    c->eh_ptr = 0;
 
+  /* Immediately following the augmentation are the code and
+     data alignment and return address column.  */
   p = decode_uleb128 (p, &c->code_align);
   p = decode_sleb128 (p, &c->data_align);
   c->ra_regno = *(unsigned char *)p++;
+  c->lsda_encoding = DW_EH_PE_omit;
 
-  /* If the augmentation starts with 'z', we now see the length of the
-     augmentation fields.  */
-  if (c->augmentation[0] == 'z')
+  if (c->eh_ptr != NULL)
+    return p;
+
+  /* If the augmentation starts with 'z', then a uleb128 immediately
+     follows containing the length of the augmentation field following
+     the size.  */
+  if (*aug == 'z')
     {
+      int i;
+
       p = decode_uleb128 (p, &i);
-      p += i;
+      ret = p + i;
+
+      c->saw_z = 1;
+      ++aug;
     }
 
-  return p;
+  /* Iterate over recognized augmentation subsequences.  */
+  while (*aug != '\0')
+    {
+      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
+      if (aug[0] == 'L')
+	{
+	  c->lsda_encoding = *(unsigned char *)p++;
+	  aug += 1;
+	}
+
+      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
+      else if (aug[0] == 'R')
+	{
+	  c->fde_encoding = *(unsigned char *)p++;
+	  aug += 1;
+	}
+
+      /* "P" indicates a personality routine in the CIE augmentation.  */
+      else if (aug[0] == 'P')
+	{
+#ifdef NEED__Unwind_GetFrameForV2
+	  error (EXIT_FAILURE, 0,
+		 _("%c: Unsupported gcc v3 exception augmentation."),
+		 aug[0]);
+#else
+	  /* We don't support the V3 frame in gcc 2.9x.  */
+	  abort ();
+#endif
+	}
+
+      /* Otherwise we have an unknown augmentation string.
+	 Bail unless we saw a 'z' prefix.  */
+      else
+	return ret;
+    }
+
+  return ret ? ret : p;
 }
 
 /* Decode one instruction's worth of DWARF 2 call frame information.
@@ -601,14 +674,14 @@ extract_cie_info (fde *f, struct cie_inf
 
 static void *
 execute_cfa_insn (void *p, struct frame_state_internal *state,
-		  struct cie_info *info, void **pc)
+		  struct cie_info *info)
 {
   unsigned insn = *(unsigned char *)p++;
   unsigned reg;
   int offset;
 
   if (insn & DW_CFA_advance_loc)
-    *pc += ((insn & 0x3f) * info->code_align);
+    info->pc += ((insn & 0x3f) * info->code_align);
   else if (insn & DW_CFA_offset)
     {
       reg = (insn & 0x3f);
@@ -625,19 +698,19 @@ execute_cfa_insn (void *p, struct frame_
   else switch (insn)
     {
     case DW_CFA_set_loc:
-      *pc = read_pointer (p);
+      info->pc = read_pointer (p);
       p += sizeof (void *);
       break;
     case DW_CFA_advance_loc1:
-      *pc += read_1byte (p);
+      info->pc += read_1byte (p);
       p += 1;
       break;
     case DW_CFA_advance_loc2:
-      *pc += read_2byte (p);
+      info->pc += read_2byte (p);
       p += 2;
       break;
     case DW_CFA_advance_loc4:
-      *pc += read_4byte (p);
+      info->pc += read_4byte (p);
       p += 4;
       break;
 
@@ -728,6 +801,7 @@ execute_cfa_insn (void *p, struct frame_
   return p;
 }
 
+#ifndef _LIBC
 /* Called from crtbegin.o to register the unwind info for an object.  */
 
 void
@@ -821,6 +895,7 @@ __deregister_frame (void *begin)
 {
   free (__deregister_frame_info (begin));
 }
+#endif /* !_LIBC */
 
 /* Called from __throw to find the registers to restore for a given
    PC_TARGET.  The caller should allocate a local variable of `struct
@@ -833,11 +908,17 @@ __frame_state_for (void *pc_target, stru
   void *insn, *end, *pc;
   struct cie_info info;
   struct frame_state_internal state;
+#ifdef NEED__Unwind_GetFrameForV2
+  struct dwarf_eh_bases bases;
 
+  f = _Unwind_Find_FDE (pc_target, &bases);
+#else
   f = find_fde (pc_target);
+#endif
   if (f == 0)
     return 0;
 
+  memset (&info, 0, sizeof (info));
   insn = extract_cie_info (f, &info);
   if (insn == 0)
     return 0;
@@ -845,26 +926,39 @@ __frame_state_for (void *pc_target, stru
   memset (&state, 0, sizeof (state));
   state.s.retaddr_column = info.ra_regno;
   state.s.eh_ptr = info.eh_ptr;
+  
+  if (info.lsda_encoding == DW_EH_PE_omit
+      && info.fde_encoding == 0)
+    {
+      void *end;
 
-  /* First decode all the insns in the CIE.  */
-  end = next_fde ((fde*) get_cie (f));
-  while (insn < end)
-    insn = execute_cfa_insn (insn, &state, &info, 0);
+      /* First decode all the insns in the CIE.  */
+      end = next_fde ((fde*) get_cie (f));
+      while (insn < end)
+ 	insn = execute_cfa_insn (insn, &state, &info);
 
-  insn = ((fde *)f) + 1;
+      insn = ((fde *)f) + 1;
 
-  if (info.augmentation[0] == 'z')
-    {
-      int i;
-      insn = decode_uleb128 (insn, &i);
-      insn += i;
-    }
+      if (info.augmentation[0] == 'z')
+	{
+	  int i;
+	  insn = decode_uleb128 (insn, &i);
+	  insn += i;
+	}
 
-  /* Then the insns in the FDE up to our target PC.  */
-  end = next_fde (f);
-  pc = f->pc_begin;
-  while (insn < end && pc <= pc_target)
-    insn = execute_cfa_insn (insn, &state, &info, &pc);
+      /* Then the insns in the FDE up to our target PC.  */
+      end = next_fde (f);
+      info.pc = f->pc_begin;
+      while (insn < end && info.pc <= pc_target)
+	insn = execute_cfa_insn (insn, &state, &info);
+    }
+  else
+#ifdef NEED__Unwind_GetFrameForV2
+    _Unwind_GetFrameForV2 (pc_target, insn, f, &bases, &state.s, &info);
+#else
+    /* We don't support the V3 frame in gcc 2.9x.  */
+    abort ();
+#endif
 
   memcpy (state_in, &state.s, sizeof (state.s));
   return state_in;

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