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: Support gcc v3 unwind frame in gcc pre 3.0


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.


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

	* dwarf2.h: Updated from gcc 3.0.

	* frame-dwarf2.c: Include glibc heade files instead if _LIBC
	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	Sun Jul  2 01:37:02 2000
+++ gcc/dwarf2.h	Sun Jul  8 23:48:33 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
@@ -499,9 +501,14 @@ enum dwarf_call_frame_info
     DW_CFA_def_cfa_offset = 0x0e,
     DW_CFA_def_cfa_expression = 0x0f,
     DW_CFA_expression = 0x10,
+    /* Dwarf 2.1 */
+    DW_CFA_offset_extended_sf = 0x11,
+    DW_CFA_def_cfa_sf = 0x12,
+    DW_CFA_def_cfa_offset_sf = 0x13,
+
     /* SGI/MIPS specific */
     DW_CFA_MIPS_advance_loc8 = 0x1d,
-
+    
     /* GNU extensions */
     DW_CFA_GNU_window_save = 0x2d,
     DW_CFA_GNU_args_size = 0x2e,
@@ -534,6 +541,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
   };
 
@@ -551,3 +559,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-dwarf2.c.mixed	Sun Jul  8 23:32:48 2001
+++ gcc/frame-dwarf2.c	Mon Jul  9 00:54:57 2001
@@ -34,6 +34,24 @@ 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
+#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"
 #include "tsystem.h"
 
@@ -54,7 +72,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)));
@@ -102,6 +123,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.  */
@@ -113,19 +135,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()
 
@@ -152,7 +170,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.  */
 
@@ -223,6 +250,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.  */
 
@@ -232,14 +268,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));
-}
-
 #include "frame.c"
 
 static size_t
@@ -418,6 +446,7 @@ find_fde (void *pc)
     }
   return 0;
 }
+#endif /* !_LIBC */
 
 static inline struct dwarf_cie *
 get_cie (fde *f)
@@ -431,39 +460,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 a DW_OP stack operation.  */
@@ -576,14 +648,14 @@ decode_stack_op (unsigned char *buf, str
 
 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);
@@ -607,19 +679,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;
 
@@ -757,15 +829,21 @@ __frame_state_for (void *pc_target, stru
 #endif
 {
   fde *f;
-  void *insn, *end, *pc;
+  void *insn;
   struct cie_info info;
   size_t s;
   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;
@@ -773,26 +851,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
 
 #ifdef __linux__
   /* Binary compatibility problem: In June 2000, 2 fields


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