expression.h: New ops OP_NSSTRING, OP_SELECTOR, OP_MSGCALL, and OP_SELF.
[deliverable/binutils-gdb.git] / gdb / dwarf2cfi.c
index 783d1c014e0eea20efa3cbe314e8d4097edddfad..18782b16dc87b0b83195064de0c891bc3507ea06 100644 (file)
@@ -21,6 +21,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
+#include "gdbcore.h"
 #include "symtab.h"
 #include "symfile.h"
 #include "objfiles.h"
 #include "inferior.h"
 #include "regcache.h"
 #include "dwarf2cfi.h"
+#include "gdb_assert.h"
 
 /* Common Information Entry - holds information that is shared among many
    Frame Descriptors.  */
 struct cie_unit
 {
-  /* Offset of this unit in dwarf_frame_buffer.  */
+  /* Offset of this unit in .debug_frame or .eh_frame.  */
   ULONGEST offset;
 
   /* A null-terminated string that identifies the augmentation to this CIE or
@@ -176,6 +178,15 @@ struct frame_state
   struct objfile *objfile;
 };
 
+enum ptr_encoding
+{
+  PE_absptr = DW_EH_PE_absptr,
+  PE_pcrel = DW_EH_PE_pcrel,
+  PE_textrel = DW_EH_PE_textrel,
+  PE_datarel = DW_EH_PE_datarel,
+  PE_funcrel = DW_EH_PE_funcrel
+};
+
 #define UNWIND_CONTEXT(fi) ((struct context *) (fi->context))
 \f
 
@@ -188,8 +199,6 @@ extern file_ptr dwarf_frame_offset;
 extern unsigned int dwarf_frame_size;
 extern file_ptr dwarf_eh_frame_offset;
 extern unsigned int dwarf_eh_frame_size;
-
-static char *dwarf_frame_buffer;
 \f
 
 extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset,
@@ -201,26 +210,28 @@ static void fde_chunks_need_space ();
 
 static struct context *context_alloc ();
 static struct frame_state *frame_state_alloc ();
+static void unwind_tmp_obstack_init ();
 static void unwind_tmp_obstack_free ();
 static void context_cpy (struct context *dst, struct context *src);
 
-static unsigned int read_1u (bfd *abfd, char **p);
-static int read_1s (bfd *abfd, char **p);
-static unsigned int read_2u (bfd *abfd, char **p);
-static int read_2s (bfd *abfd, char **p);
-static unsigned int read_4u (bfd *abfd, char **p);
-static int read_4s (bfd *abfd, char **p);
-static ULONGEST read_8u (bfd *abfd, char **p);
-static LONGEST read_8s (bfd *abfd, char **p);
-
-static ULONGEST read_uleb128 (bfd *abfd, char **p);
-static LONGEST read_sleb128 (bfd *abfd, char **p);
-static CORE_ADDR read_pointer (bfd *abfd, char **p);
-static CORE_ADDR read_encoded_pointer (bfd *abfd, char **p,
+static unsigned int read_1u (bfd * abfd, char **p);
+static int read_1s (bfd * abfd, char **p);
+static unsigned int read_2u (bfd * abfd, char **p);
+static int read_2s (bfd * abfd, char **p);
+static unsigned int read_4u (bfd * abfd, char **p);
+static int read_4s (bfd * abfd, char **p);
+static ULONGEST read_8u (bfd * abfd, char **p);
+static LONGEST read_8s (bfd * abfd, char **p);
+
+static ULONGEST read_uleb128 (bfd * abfd, char **p);
+static LONGEST read_sleb128 (bfd * abfd, char **p);
+static CORE_ADDR read_pointer (bfd * abfd, char **p);
+static CORE_ADDR read_encoded_pointer (bfd * abfd, char **p,
                                       unsigned char encoding);
+static enum ptr_encoding pointer_encoding (unsigned char encoding);
 
-static LONGEST read_initial_length (bfd *abfd, char *buf, int *bytes_read);
-static ULONGEST read_length (bfd *abfd, char *buf, int *bytes_read,
+static LONGEST read_initial_length (bfd * abfd, char *buf, int *bytes_read);
+static ULONGEST read_length (bfd * abfd, char *buf, int *bytes_read,
                             int dwarf64);
 
 static int is_cie (ULONGEST cie_id, int dwarf64);
@@ -235,11 +246,12 @@ static void frame_state_for (struct context *context, struct frame_state *fs);
 static void get_reg (char *reg, struct context *context, int regnum);
 static CORE_ADDR execute_stack_op (struct objfile *objfile,
                                   char *op_ptr, char *op_end,
-                                  struct context *context, CORE_ADDR initial);
+                                  struct context *context,
+                                  CORE_ADDR initial);
 static void update_context (struct context *context, struct frame_state *fs,
                            int chain);
-
 \f
+
 /* Memory allocation functions.  */
 static struct fde_unit *
 fde_unit_alloc (void)
@@ -262,7 +274,7 @@ cie_unit_alloc (void)
 }
 
 static void
-fde_chunks_need_space ()
+fde_chunks_need_space (void)
 {
   if (fde_chunks.elems < fde_chunks.array_size)
     return;
@@ -275,7 +287,7 @@ fde_chunks_need_space ()
 
 /* Alocate a new `struct context' on temporary obstack.  */
 static struct context *
-context_alloc ()
+context_alloc (void)
 {
   struct context *context;
 
@@ -292,7 +304,7 @@ context_alloc ()
 
 /* Alocate a new `struct frame_state' on temporary obstack.  */
 static struct frame_state *
-frame_state_alloc ()
+frame_state_alloc (void)
 {
   struct frame_state *fs;
 
@@ -301,19 +313,25 @@ frame_state_alloc ()
   fs = (struct frame_state *) obstack_alloc (&unwind_tmp_obstack,
                                             sizeof (struct frame_state));
   memset (fs, 0, sizeof (struct frame_state));
-  fs->regs.reg = (struct frame_state_reg *)  obstack_alloc (&unwind_tmp_obstack,
-                                                           regs_size);
+  fs->regs.reg =
+    (struct frame_state_reg *) obstack_alloc (&unwind_tmp_obstack, regs_size);
   memset (fs->regs.reg, 0, regs_size);
   return fs;
 }
 
 static void
-unwind_tmp_obstack_free ()
+unwind_tmp_obstack_init (void)
 {
-  obstack_free (&unwind_tmp_obstack, NULL);
   obstack_init (&unwind_tmp_obstack);
 }
 
+static void
+unwind_tmp_obstack_free (void)
+{
+  obstack_free (&unwind_tmp_obstack, NULL);
+  unwind_tmp_obstack_init ();
+}
+
 static void
 context_cpy (struct context *dst, struct context *src)
 {
@@ -334,92 +352,92 @@ context_cpy (struct context *dst, struct context *src)
   dreg = dst->reg;
   *dst = *src;
   dst->reg = dreg;
-  
+
   memcpy (dst->reg, src->reg, regs_size);
 }
 
 static unsigned int
-read_1u (bfd *abfd, char **p)
+read_1u (bfd * abfd, char **p)
 {
   unsigned ret;
 
-  ret= bfd_get_8 (abfd, (bfd_byte *) *p);
-  (*p) ++;
+  ret = bfd_get_8 (abfd, (bfd_byte *) * p);
+  (*p)++;
   return ret;
 }
 
 static int
-read_1s (bfd *abfd, char **p)
+read_1s (bfd * abfd, char **p)
 {
   int ret;
 
-  ret= bfd_get_signed_8 (abfd, (bfd_byte *) *p);
-  (*p) ++;
+  ret = bfd_get_signed_8 (abfd, (bfd_byte *) * p);
+  (*p)++;
   return ret;
 }
 
 static unsigned int
-read_2u (bfd *abfd, char **p)
+read_2u (bfd * abfd, char **p)
 {
   unsigned ret;
 
-  ret= bfd_get_16 (abfd, (bfd_byte *) *p);
-  (*p) ++;
+  ret = bfd_get_16 (abfd, (bfd_byte *) * p);
+  (*p)++;
   return ret;
 }
 
 static int
-read_2s (bfd *abfd, char **p)
+read_2s (bfd * abfd, char **p)
 {
   int ret;
 
-  ret= bfd_get_signed_16 (abfd, (bfd_byte *) *p);
+  ret = bfd_get_signed_16 (abfd, (bfd_byte *) * p);
   (*p) += 2;
   return ret;
 }
 
 static unsigned int
-read_4u (bfd *abfd, char **p)
+read_4u (bfd * abfd, char **p)
 {
   unsigned int ret;
 
-  ret= bfd_get_32 (abfd, (bfd_byte *) *p);
+  ret = bfd_get_32 (abfd, (bfd_byte *) * p);
   (*p) += 4;
   return ret;
 }
 
 static int
-read_4s (bfd *abfd, char **p)
+read_4s (bfd * abfd, char **p)
 {
   int ret;
 
-  ret= bfd_get_signed_32 (abfd, (bfd_byte *) *p);
+  ret = bfd_get_signed_32 (abfd, (bfd_byte *) * p);
   (*p) += 4;
   return ret;
 }
 
 static ULONGEST
-read_8u (bfd *abfd, char **p)
+read_8u (bfd * abfd, char **p)
 {
   ULONGEST ret;
 
-  ret = bfd_get_64 (abfd, (bfd_byte *) *p);
+  ret = bfd_get_64 (abfd, (bfd_byte *) * p);
   (*p) += 8;
   return ret;
 }
 
 static LONGEST
-read_8s (bfd *abfd, char **p)
+read_8s (bfd * abfd, char **p)
 {
   LONGEST ret;
 
-  ret = bfd_get_signed_64 (abfd, (bfd_byte *) *p);
+  ret = bfd_get_signed_64 (abfd, (bfd_byte *) * p);
   (*p) += 8;
   return ret;
 }
 
 static ULONGEST
-read_uleb128 (bfd *abfd, char **p)
+read_uleb128 (bfd * abfd, char **p)
 {
   ULONGEST ret;
   int i, shift;
@@ -430,8 +448,8 @@ read_uleb128 (bfd *abfd, char **p)
   i = 0;
   while (1)
     {
-      byte = bfd_get_8 (abfd, (bfd_byte *) *p);
-      (*p) ++;
+      byte = bfd_get_8 (abfd, (bfd_byte *) * p);
+      (*p)++;
       ret |= ((unsigned long) (byte & 127) << shift);
       if ((byte & 128) == 0)
        {
@@ -443,7 +461,7 @@ read_uleb128 (bfd *abfd, char **p)
 }
 
 static LONGEST
-read_sleb128 (bfd *abfd, char **p)
+read_sleb128 (bfd * abfd, char **p)
 {
   LONGEST ret;
   int i, shift, size, num_read;
@@ -456,8 +474,8 @@ read_sleb128 (bfd *abfd, char **p)
   i = 0;
   while (1)
     {
-      byte = bfd_get_8 (abfd, (bfd_byte *) *p);
-      (*p) ++;
+      byte = bfd_get_8 (abfd, (bfd_byte *) * p);
+      (*p)++;
       ret |= ((long) (byte & 127) << shift);
       shift += 7;
       if ((byte & 128) == 0)
@@ -473,7 +491,7 @@ read_sleb128 (bfd *abfd, char **p)
 }
 
 static CORE_ADDR
-read_pointer (bfd *abfd, char **p)
+read_pointer (bfd * abfd, char **p)
 {
   switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
     {
@@ -486,8 +504,11 @@ read_pointer (bfd *abfd, char **p)
     }
 }
 
+/* This functions only reads appropriate amount of data from *p 
+ * and returns the resulting value. Calling function must handle
+ * different encoding possibilities itself!  */
 static CORE_ADDR
-read_encoded_pointer (bfd *abfd, char **p, unsigned char encoding)
+read_encoded_pointer (bfd * abfd, char **p, unsigned char encoding)
 {
   CORE_ADDR ret;
 
@@ -529,22 +550,33 @@ read_encoded_pointer (bfd *abfd, char **p, unsigned char encoding)
                      "read_encoded_pointer: unknown pointer encoding");
     }
 
-  if (ret != 0)
-    switch (encoding & 0xf0)
-      {
-      case DW_EH_PE_absptr:
-       break;
-      case DW_EH_PE_pcrel:
-       ret += (CORE_ADDR) *p;
-       break;
-      case DW_EH_PE_textrel:
-      case DW_EH_PE_datarel:
-      case DW_EH_PE_funcrel:
-      default:
-       internal_error (__FILE__, __LINE__,
-                       "read_encoded_pointer: unknown pointer encoding");
-      }
+  return ret;
+}
 
+/* Variable 'encoding' carries 3 different flags:
+ * - encoding & 0x0f : size of the address (handled in read_encoded_pointer())
+ * - encoding & 0x70 : type (absolute, relative, ...)
+ * - encoding & 0x80 : indirect flag (DW_EH_PE_indirect == 0x80).  */
+enum ptr_encoding
+pointer_encoding (unsigned char encoding)
+{
+  int ret;
+
+  if (encoding & DW_EH_PE_indirect)
+    warning ("CFI: Unsupported pointer encoding: DW_EH_PE_indirect");
+
+  switch (encoding & 0x70)
+    {
+    case DW_EH_PE_absptr:
+    case DW_EH_PE_pcrel:
+    case DW_EH_PE_textrel:
+    case DW_EH_PE_datarel:
+    case DW_EH_PE_funcrel:
+      ret = encoding & 0x70;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "CFI: unknown pointer encoding");
+    }
   return ret;
 }
 
@@ -584,8 +616,8 @@ read_length (bfd * abfd, char *buf, int *bytes_read, int dwarf64)
 }
 
 static void
-execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end,
-                     struct context *context, struct frame_state *fs)
+execute_cfa_program (struct objfile *objfile, char *insn_ptr, char *insn_end,
+                    struct context *context, struct frame_state *fs)
 {
   struct frame_state_regs *unused_rs = NULL;
 
@@ -604,7 +636,7 @@ execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end,
        {
          reg = insn & 0x3f;
          uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
-         offset = (long) uoffset * fs->data_align;
+         offset = (long) uoffset *fs->data_align;
          fs->regs.reg[reg].how = REG_SAVED_OFFSET;
          fs->regs.reg[reg].loc.offset = offset;
        }
@@ -619,6 +651,10 @@ execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end,
          case DW_CFA_set_loc:
            fs->pc = read_encoded_pointer (objfile->obfd, &insn_ptr,
                                           fs->addr_encoding);
+
+           if (pointer_encoding (fs->addr_encoding) != PE_absptr)
+             warning ("CFI: DW_CFA_set_loc uses relative addressing");
+
            break;
 
          case DW_CFA_advance_loc1:
@@ -806,28 +842,23 @@ frame_state_for (struct context *context, struct frame_state *fs)
 
   if (fde == NULL)
     return;
-  
+
   fs->pc = fde->initial_location;
 
-  if (fde->cie_ptr)
-  {
-      cie = fde->cie_ptr;
-      
-      fs->code_align = cie->code_align;
-      fs->data_align = cie->data_align;
-      fs->retaddr_column = cie->ra;
-      fs->addr_encoding = cie->addr_encoding;
-      fs->objfile = cie->objfile;
-
-      execute_cfa_program (cie->objfile, cie->data,
-                          cie->data + cie->data_length, context, fs);
-      execute_cfa_program (cie->objfile, fde->data,
-                          fde->data + fde->data_length, context, fs);
-  }
-  else
-       internal_error (__FILE__, __LINE__,
-               "%s(): Internal error: fde->cie_ptr==NULL !", 
-               __func__);
+  gdb_assert (fde->cie_ptr != NULL);
+
+  cie = fde->cie_ptr;
+  
+  fs->code_align = cie->code_align;
+  fs->data_align = cie->data_align;
+  fs->retaddr_column = cie->ra;
+  fs->addr_encoding = cie->addr_encoding;
+  fs->objfile = cie->objfile;
+  
+  execute_cfa_program (cie->objfile, cie->data,
+                      cie->data + cie->data_length, context, fs);
+  execute_cfa_program (cie->objfile, fde->data,
+                      fde->data + fde->data_length, context, fs);
 }
 
 static void
@@ -854,8 +885,7 @@ get_reg (char *reg, struct context *context, int regnum)
              REGISTER_RAW_SIZE (regnum));
       break;
     default:
-      internal_error (__FILE__, __LINE__,
-                     "get_reg: unknown register rule");
+      internal_error (__FILE__, __LINE__, "get_reg: unknown register rule");
     }
 }
 
@@ -1087,32 +1117,21 @@ execute_stack_op (struct objfile *objfile,
            {
            case DW_OP_deref:
              {
-               char *ptr = (char *) result;
-               result = read_pointer (objfile->obfd, &ptr);
+               int len = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
+               if (len != 4 && len != 8)
+                 internal_error (__FILE__, __LINE__,
+                                 "execute_stack_op error");
+               result = read_memory_unsigned_integer (result, len);
              }
              break;
 
            case DW_OP_deref_size:
              {
-               char *ptr = (char *) result;
-               switch (*op_ptr++)
-                 {
-                 case 1:
-                   result = read_1u (objfile->obfd, &ptr);
-                   break;
-                 case 2:
-                   result = read_2u (objfile->obfd, &ptr);
-                   break;
-                 case 4:
-                   result = read_4u (objfile->obfd, &ptr);
-                   break;
-                 case 8:
-                   result = read_8u (objfile->obfd, &ptr);
-                   break;
-                 default:
-                   internal_error (__FILE__, __LINE__,
-                                   "execute_stack_op error");
-                 }
+               int len = *op_ptr++;
+               if (len != 1 && len != 2 && len != 4 && len !=8)
+                 internal_error (__FILE__, __LINE__,
+                                 "execute_stack_op error");
+               result = read_memory_unsigned_integer (result, len);
              }
              break;
 
@@ -1208,8 +1227,9 @@ execute_stack_op (struct objfile *objfile,
              case DW_OP_ne:
                result = (LONGEST) first != (LONGEST) second;
                break;
-             default:  /* This label is here just to avoid warning.  */
-               break; 
+             default:
+               error ("execute_stack_op: Unknown DW_OP_ value");
+               break;
              }
          }
          break;
@@ -1252,11 +1272,14 @@ static void
 update_context (struct context *context, struct frame_state *fs, int chain)
 {
   struct context *orig_context;
-  CORE_ADDR cfa;
+  CORE_ADDR cfa = 0;
   long i;
 
+  unwind_tmp_obstack_init ();
+
   orig_context = context_alloc ();
   context_cpy (orig_context, context);
+
   /* Compute this frame's CFA.  */
   switch (fs->cfa_how)
     {
@@ -1267,9 +1290,9 @@ update_context (struct context *context, struct frame_state *fs, int chain)
 
     case CFA_EXP:
       /* ??? No way of knowing what register number is the stack pointer
-        to do the same sort of handling as above.  Assume that if the
-        CFA calculation is so complicated as to require a stack program
-        that this will not be a problem.  */
+         to do the same sort of handling as above.  Assume that if the
+         CFA calculation is so complicated as to require a stack program
+         that this will not be a problem.  */
       {
        char *exp = fs->cfa_exp;
        ULONGEST len;
@@ -1324,9 +1347,9 @@ update_context (struct context *context, struct frame_state *fs, int chain)
            context->reg[i].how = REG_CTX_SAVED_ADDR;
            context->reg[i].loc.addr =
              orig_context->reg[fs->regs.reg[i].loc.reg].loc.addr;
+           break;
          default:
-           internal_error (__FILE__, __LINE__,
-                           "%s: unknown register rule", __func__);
+           internal_error (__FILE__, __LINE__, "bad switch");
          }
        break;
       case REG_SAVED_EXP:
@@ -1343,8 +1366,7 @@ update_context (struct context *context, struct frame_state *fs, int chain)
        }
        break;
       default:
-       internal_error (__FILE__, __LINE__,
-                       "%s: unknown register rule", __func__);
+       internal_error (__FILE__, __LINE__, "bad switch");
       }
   get_reg ((char *) &context->ra, context, fs->retaddr_column);
   unwind_tmp_obstack_free ();
@@ -1371,39 +1393,46 @@ compare_fde_unit (const void *a, const void *b)
 }
 
 /*  Build the cie_chunks and fde_chunks tables from informations
-    in .debug_frame section.  */
-void
-dwarf2_build_frame_info (struct objfile *objfile)
+    found in .debug_frame and .eh_frame sections.  */
+/* We can handle both of these sections almost in the same way, however there
+   are some exceptions:
+   - CIE ID is -1 in debug_frame, but 0 in eh_frame
+   - eh_frame may contain some more information that are used only by gcc 
+     (eg. personality pointer, LSDA pointer, ...). Most of them we can ignore.
+   - In debug_frame FDE's item cie_id contains offset of it's parent CIE.
+     In eh_frame FDE's item cie_id is a relative pointer to the parent CIE.
+     Anyway we don't need to bother with this, because we are smart enough 
+     to keep the pointer to the parent CIE of oncomming FDEs in 'last_cie'.
+   - Although debug_frame items can contain Augmentation as well as 
+     eh_frame ones, I have never seen them non-empty. Thus only in eh_frame 
+     we can encounter for example non-absolute pointers (Aug. 'R').  
+                                                              -- mludvig  */
+static void
+parse_frame_info (struct objfile *objfile, file_ptr frame_offset,
+                 unsigned int frame_size, int eh_frame)
 {
   bfd *abfd = objfile->obfd;
+  asection *curr_section_ptr;
   char *start = NULL;
   char *end = NULL;
-  int from_eh = 0;
-
-  obstack_init (&unwind_tmp_obstack);
+  char *frame_buffer = NULL;
+  char *curr_section_name, *aug_data;
+  struct cie_unit *last_cie = NULL;
+  int last_dup_fde = 0;
+  int aug_len, i;
+  CORE_ADDR curr_section_vma = 0;
 
-  dwarf_frame_buffer = 0;
+  unwind_tmp_obstack_init ();
 
-  if (dwarf_frame_offset)
-    {
-      dwarf_frame_buffer = dwarf2_read_section (objfile,
-                                               dwarf_frame_offset,
-                                               dwarf_frame_size);
+  frame_buffer = dwarf2_read_section (objfile, frame_offset, frame_size);
 
-      start = dwarf_frame_buffer;
-      end = dwarf_frame_buffer + dwarf_frame_size;
-    }
-  else if (dwarf_eh_frame_offset)
-    {
-      dwarf_frame_buffer = dwarf2_read_section (objfile,
-                                               dwarf_eh_frame_offset,
-                                               dwarf_eh_frame_size);
+  start = frame_buffer;
+  end = frame_buffer + frame_size;
 
-      start = dwarf_frame_buffer;
-      end = dwarf_frame_buffer + dwarf_eh_frame_size;
-
-      from_eh = 1;
-    }
+  curr_section_name = eh_frame ? ".eh_frame" : ".debug_frame";
+  curr_section_ptr = bfd_get_section_by_name (abfd, curr_section_name);
+  if (curr_section_ptr)
+    curr_section_vma = curr_section_ptr->vma;
 
   if (start)
     {
@@ -1411,9 +1440,8 @@ dwarf2_build_frame_info (struct objfile *objfile)
        {
          unsigned long length;
          ULONGEST cie_id;
-         ULONGEST unit_offset = start - dwarf_frame_buffer;
-         int bytes_read;
-         int dwarf64;
+         ULONGEST unit_offset = start - frame_buffer;
+         int bytes_read, dwarf64;
          char *block_end;
 
          length = read_initial_length (abfd, start, &bytes_read);
@@ -1421,10 +1449,16 @@ dwarf2_build_frame_info (struct objfile *objfile)
          dwarf64 = (bytes_read == 12);
          block_end = start + length;
 
+         if (length == 0)
+           {
+             start = block_end;
+             continue;
+           }
+
          cie_id = read_length (abfd, start, &bytes_read, dwarf64);
          start += bytes_read;
 
-         if ((from_eh && cie_id == 0) || is_cie (cie_id, dwarf64))
+         if ((eh_frame && cie_id == 0) || is_cie (cie_id, dwarf64))
            {
              struct cie_unit *cie = cie_unit_alloc ();
              char *aug;
@@ -1440,84 +1474,186 @@ dwarf2_build_frame_info (struct objfile *objfile)
              start++;          /* version */
 
              cie->augmentation = aug = start;
-             while (*start)
-               start++;
-             start++;          /* skip past NUL */
+             while (*start++); /* Skips last NULL as well */
 
              cie->code_align = read_uleb128 (abfd, &start);
              cie->data_align = read_sleb128 (abfd, &start);
              cie->ra = read_1u (abfd, &start);
 
+             /* Augmentation:
+                z      Indicates that a uleb128 is present to size the
+                augmentation section.
+                L      Indicates the encoding (and thus presence) of
+                an LSDA pointer in the FDE augmentation.
+                R      Indicates a non-default pointer encoding for
+                FDE code pointers.
+                P      Indicates the presence of an encoding + language
+                personality routine in the CIE augmentation.
+
+                [This info comes from GCC's dwarf2out.c]
+              */
              if (*aug == 'z')
                {
-                 int xtra = read_uleb128 (abfd, &start);
-                 start += xtra;
+                 aug_len = read_uleb128 (abfd, &start);
+                 aug_data = start;
+                 start += aug_len;
                  ++aug;
                }
 
+             cie->data = start;
+             cie->data_length = block_end - cie->data;
+
              while (*aug != '\0')
                {
                  if (aug[0] == 'e' && aug[1] == 'h')
                    {
-                     start += sizeof (void *);
-                     aug += 2;
+                     aug_data += sizeof (void *);
+                     aug++;
                    }
                  else if (aug[0] == 'R')
+                   cie->addr_encoding = *aug_data++;
+                 else if (aug[0] == 'P')
                    {
-                     cie->addr_encoding = *start++;
-                     aug += 1;
+                     CORE_ADDR pers_addr;
+                     int pers_addr_enc;
+
+                     pers_addr_enc = *aug_data++;
+                     /* We don't need pers_addr value and so we 
+                        don't care about it's encoding.  */
+                     pers_addr = read_encoded_pointer (abfd, &aug_data,
+                                                       pers_addr_enc);
                    }
-                 else if (aug[0] == 'P')
+                 else if (aug[0] == 'L' && eh_frame)
                    {
-                     CORE_ADDR ptr;
-                     ptr = read_encoded_pointer (abfd, &start,
-                                                 cie->addr_encoding);
-                     aug += 1;
+                     int lsda_addr_enc;
+
+                     /* Perhaps we should save this to CIE for later use?
+                        Do we need it for something in GDB?  */
+                     lsda_addr_enc = *aug_data++;
                    }
                  else
-                   warning ("%s(): unknown augmentation", __func__);
+                   warning ("CFI warning: unknown augmentation \"%c\""
+                            " in \"%s\" of\n"
+                            "\t%s", aug[0], curr_section_name,
+                            objfile->name);
+                 aug++;
                }
 
-             cie->data = start;
-             cie->data_length = block_end - start;
+             last_cie = cie;
            }
          else
            {
              struct fde_unit *fde;
              struct cie_unit *cie;
+             int dup = 0;
+             CORE_ADDR init_loc;
+
+             /* We assume that debug_frame is in order 
+                CIE,FDE,CIE,FDE,FDE,...  and thus the CIE for this FDE
+                should be stored in last_cie pointer. If not, we'll 
+                try to find it by the older way.  */
+             if (last_cie)
+               cie = last_cie;
+             else
+               {
+                 warning ("CFI: last_cie == NULL. "
+                          "Perhaps a malformed %s section in '%s'...?\n",
+                          curr_section_name, objfile->name);
 
-             fde_chunks_need_space ();
-             fde = fde_unit_alloc ();
+                 cie = cie_chunks;
+                 while (cie)
+                   {
+                     if (cie->objfile == objfile)
+                       {
+                         if (eh_frame &&
+                             (cie->offset ==
+                              (unit_offset + bytes_read - cie_id)))
+                           break;
+                         if (!eh_frame && (cie->offset == cie_id))
+                           break;
+                       }
+
+                     cie = cie->next;
+                   }
+                 if (!cie)
+                   error ("CFI: can't find CIE pointer");
+               }
 
-             fde_chunks.array[fde_chunks.elems++] = fde;
-             
-             fde->initial_location = read_pointer (abfd, &start)
-               + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
-             fde->address_range = read_pointer (abfd, &start);
+             init_loc = read_encoded_pointer (abfd, &start,
+                                              cie->addr_encoding);
 
-             cie = cie_chunks;
-             while(cie)
-             {
-               if (cie->objfile == objfile)
+             switch (pointer_encoding (cie->addr_encoding))
                {
-                 if (from_eh && (cie->offset == (unit_offset + bytes_read - cie_id)))
-                     break;
-                 if (!from_eh && (cie->offset == cie_id))
-                   break;
+               case PE_absptr:
+                 break;
+               case PE_pcrel:
+                 /* start-frame_buffer gives offset from 
+                    the beginning of actual section.  */
+                 init_loc += curr_section_vma + start - frame_buffer;
+                 break;
+               default:
+                 warning ("CFI: Unsupported pointer encoding\n");
                }
 
-               cie = cie->next;
-             }
-           
-             if (!cie)
-               error ("%s(): can't find CIE pointer", __func__);
-             fde->cie_ptr = cie;
+             /* For relocatable objects we must add an offset telling
+                where the section is actually mapped in the memory.  */
+             init_loc += ANOFFSET (objfile->section_offsets,
+                                   SECT_OFF_TEXT (objfile));
+
+             /* If we have both .debug_frame and .eh_frame present in 
+                a file, we must eliminate duplicate FDEs. For now we'll 
+                run through all entries in fde_chunks and check it one 
+                by one. Perhaps in the future we can implement a faster 
+                searching algorithm.  */
+             /* eh_frame==2 indicates, that this file has an already 
+                parsed .debug_frame too. When eh_frame==1 it means, that no
+                .debug_frame is present and thus we don't need to check for
+                duplicities. eh_frame==0 means, that we parse .debug_frame
+                and don't need to care about duplicate FDEs, because
+                .debug_frame is parsed first.  */
+             if (eh_frame == 2)
+               for (i = 0; eh_frame == 2 && i < fde_chunks.elems; i++)
+                 {
+                   /* We assume that FDEs in .debug_frame and .eh_frame 
+                      have the same order (if they are present, of course).
+                      If we find a duplicate entry for one FDE and save
+                      it's index to last_dup_fde it's very likely, that 
+                      we'll find an entry for the following FDE right after 
+                      the previous one. Thus in many cases we'll run this 
+                      loop only once.  */
+                   last_dup_fde = (last_dup_fde + i) % fde_chunks.elems;
+                   if (fde_chunks.array[last_dup_fde]->initial_location
+                       == init_loc)
+                     {
+                       dup = 1;
+                       break;
+                     }
+                 }
+
+             /* Allocate a new entry only if this FDE isn't a duplicate of
+                something we have already seen.   */
+             if (!dup)
+               {
+                 fde_chunks_need_space ();
+                 fde = fde_unit_alloc ();
+
+                 fde_chunks.array[fde_chunks.elems++] = fde;
 
-             if (cie->augmentation[0] == 'z')
-                 read_uleb128 (abfd, &start);
+                 fde->initial_location = init_loc;
+                 fde->address_range = read_encoded_pointer (abfd, &start,
+                                                            cie->
+                                                            addr_encoding);
 
-             fde->data = start;
-             fde->data_length = block_end - start;
+                 fde->cie_ptr = cie;
+
+                 /* Here we intentionally ignore augmentation data
+                    from FDE, because we don't need them.  */
+                 if (cie->augmentation[0] == 'z')
+                   start += read_uleb128 (abfd, &start);
+
+                 fde->data = start;
+                 fde->data_length = block_end - start;
+               }
            }
          start = block_end;
        }
@@ -1525,16 +1661,41 @@ dwarf2_build_frame_info (struct objfile *objfile)
             sizeof (struct fde_unit *), compare_fde_unit);
     }
 }
-\f
+
+/* We must parse both .debug_frame section and .eh_frame because 
+ * not all frames must be present in both of these sections. */
+void
+dwarf2_build_frame_info (struct objfile *objfile)
+{
+  int after_debug_frame = 0;
+
+  /* If we have .debug_frame then the parser is called with 
+     eh_frame==0 for .debug_frame and eh_frame==2 for .eh_frame, 
+     otherwise it's only called once for .eh_frame with argument 
+     eh_frame==1.  */
+
+  if (dwarf_frame_offset)
+    {
+      parse_frame_info (objfile, dwarf_frame_offset,
+                       dwarf_frame_size, 0 /* = debug_frame */ );
+      after_debug_frame = 1;
+    }
+
+  if (dwarf_eh_frame_offset)
+    parse_frame_info (objfile, dwarf_eh_frame_offset, dwarf_eh_frame_size,
+                     1 /* = eh_frame */  + after_debug_frame);
+}
 
 /* Return the frame address.  */
 CORE_ADDR
-cfi_read_fp ()
+cfi_read_fp (void)
 {
   struct context *context;
   struct frame_state *fs;
   CORE_ADDR cfa;
 
+  unwind_tmp_obstack_init ();
+
   context = context_alloc ();
   fs = frame_state_alloc ();
 
@@ -1544,7 +1705,9 @@ cfi_read_fp ()
   update_context (context, fs, 0);
 
   cfa = context->cfa;
+
   unwind_tmp_obstack_free ();
+
   return cfa;
 }
 
@@ -1556,6 +1719,8 @@ cfi_write_fp (CORE_ADDR val)
   struct context *context;
   struct frame_state *fs;
 
+  unwind_tmp_obstack_init ();
+
   context = context_alloc ();
   fs = frame_state_alloc ();
 
@@ -1579,11 +1744,9 @@ cfi_write_fp (CORE_ADDR val)
 void
 cfi_pop_frame (struct frame_info *fi)
 {
-  char regbuf[MAX_REGISTER_RAW_SIZE];
+  char *regbuf = alloca (MAX_REGISTER_RAW_SIZE);
   int regnum;
 
-  fi = get_current_frame ();
-
   for (regnum = 0; regnum < NUM_REGS; regnum++)
     {
       get_reg (regbuf, UNWIND_CONTEXT (fi), regnum);
@@ -1603,6 +1766,8 @@ cfi_frame_chain (struct frame_info *fi)
   struct frame_state *fs;
   CORE_ADDR cfa;
 
+  unwind_tmp_obstack_init ();
+
   context = context_alloc ();
   fs = frame_state_alloc ();
   context_cpy (context, UNWIND_CONTEXT (fi));
@@ -1619,7 +1784,7 @@ cfi_frame_chain (struct frame_info *fi)
 
   cfa = context->cfa;
   unwind_tmp_obstack_free ();
-  
+
   return cfa;
 }
 
@@ -1639,6 +1804,8 @@ cfi_init_extra_frame_info (int fromleaf, struct frame_info *fi)
 {
   struct frame_state *fs;
 
+  unwind_tmp_obstack_init ();
+
   fs = frame_state_alloc ();
   fi->context = frame_obstack_alloc (sizeof (struct context));
   UNWIND_CONTEXT (fi)->reg =
@@ -1658,6 +1825,7 @@ cfi_init_extra_frame_info (int fromleaf, struct frame_info *fi)
       frame_state_for (UNWIND_CONTEXT (fi), fs);
       update_context (UNWIND_CONTEXT (fi), fs, 0);
     }
+
   unwind_tmp_obstack_free ();
 }
 
@@ -1678,7 +1846,7 @@ cfi_get_ra (struct frame_info *fi)
 void
 cfi_get_saved_register (char *raw_buffer,
                        int *optimized,
-                       CORE_ADDR * addrp,
+                       CORE_ADDR *addrp,
                        struct frame_info *frame,
                        int regnum, enum lval_type *lval)
 {
@@ -1765,6 +1933,8 @@ cfi_virtual_frame_pointer (CORE_ADDR pc, int *frame_reg,
   struct context *context;
   struct frame_state *fs;
 
+  unwind_tmp_obstack_init ();
+
   context = context_alloc ();
   fs = frame_state_alloc ();
 
This page took 0.067854 seconds and 4 git commands to generate.