2012-05-18 Sergio Durigan Junior <sergiodj@redhat.com>
[deliverable/binutils-gdb.git] / gdb / dwarf2-frame.c
index a923edffdcca6763c6a03c19753d6926c45b084c..670e26f2de90c0757c4108cef40781cf947147c3 100644 (file)
@@ -1,7 +1,6 @@
 /* Frame unwinder for frames with DWARF Call Frame Information.
 
-   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 2003-2005, 2007-2012 Free Software Foundation, Inc.
 
    Contributed by Mark Kettenis.
 
 
 #include "complaints.h"
 #include "dwarf2-frame.h"
+#include "ax.h"
+#include "dwarf2loc.h"
+#include "exceptions.h"
+#include "dwarf2-frame-tailcall.h"
 
 struct comp_unit;
 
@@ -77,6 +80,9 @@ struct dwarf2_cie
   /* Target address size in bytes.  */
   int addr_size;
 
+  /* Target pointer size in bytes.  */
+  int ptr_size;
+
   /* True if a 'z' augmentation existed.  */
   unsigned char saw_z_augmentation;
 
@@ -85,6 +91,9 @@ struct dwarf2_cie
 
   /* The version recorded in the CIE.  */
   unsigned char version;
+
+  /* The segment size.  */
+  unsigned char segment_size;
 };
 
 struct dwarf2_cie_table
@@ -147,13 +156,14 @@ struct comp_unit
   bfd_vma tbase;
 };
 
-static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc);
+static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc,
+                                                CORE_ADDR *out_offset);
 
 static int dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum,
                                       int eh_frame_p);
 
 static CORE_ADDR read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
-                                    int ptr_len, gdb_byte *buf,
+                                    int ptr_len, const gdb_byte *buf,
                                     unsigned int *bytes_read_ptr,
                                     CORE_ADDR func_base);
 \f
@@ -176,7 +186,7 @@ struct dwarf2_frame_state
       CFA_REG_OFFSET,
       CFA_EXP
     } cfa_how;
-    gdb_byte *cfa_exp;
+    const gdb_byte *cfa_exp;
 
     /* Used to implement DW_CFA_remember_state.  */
     struct dwarf2_frame_state_reg_info *prev;
@@ -302,29 +312,6 @@ read_mem (void *baton, gdb_byte *buf, CORE_ADDR addr, size_t len)
   read_memory (addr, buf, len);
 }
 
-static void
-no_get_frame_base (void *baton, gdb_byte **start, size_t *length)
-{
-  internal_error (__FILE__, __LINE__,
-                 _("Support for DW_OP_fbreg is unimplemented"));
-}
-
-/* Helper function for execute_stack_op.  */
-
-static CORE_ADDR
-no_get_frame_cfa (void *baton)
-{
-  internal_error (__FILE__, __LINE__,
-                 _("Support for DW_OP_call_frame_cfa is unimplemented"));
-}
-
-static CORE_ADDR
-no_get_tls_address (void *baton, CORE_ADDR offset)
-{
-  internal_error (__FILE__, __LINE__,
-                 _("Support for DW_OP_GNU_push_tls_address is unimplemented"));
-}
-
 /* Execute the required actions for both the DW_CFA_restore and
 DW_CFA_restore_extended instructions.  */
 static void
@@ -355,9 +342,26 @@ register %s (#%d) at %s"),
                       paddress (gdbarch, fs->pc));
 }
 
+/* Virtual method table for execute_stack_op below.  */
+
+static const struct dwarf_expr_context_funcs dwarf2_frame_ctx_funcs =
+{
+  read_reg,
+  read_mem,
+  ctx_no_get_frame_base,
+  ctx_no_get_frame_cfa,
+  ctx_no_get_frame_pc,
+  ctx_no_get_tls_address,
+  ctx_no_dwarf_call,
+  ctx_no_get_base_type,
+  ctx_no_push_dwarf_reg_entry_value,
+  ctx_no_get_addr_index
+};
+
 static CORE_ADDR
-execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size,
-                 struct frame_info *this_frame, CORE_ADDR initial)
+execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
+                 CORE_ADDR offset, struct frame_info *this_frame,
+                 CORE_ADDR initial, int initial_in_stack_memory)
 {
   struct dwarf_expr_context *ctx;
   CORE_ADDR result;
@@ -365,28 +369,29 @@ execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size,
 
   ctx = new_dwarf_expr_context ();
   old_chain = make_cleanup_free_dwarf_expr_context (ctx);
+  make_cleanup_value_free_to_mark (value_mark ());
 
   ctx->gdbarch = get_frame_arch (this_frame);
   ctx->addr_size = addr_size;
+  ctx->ref_addr_size = -1;
+  ctx->offset = offset;
   ctx->baton = this_frame;
-  ctx->read_reg = read_reg;
-  ctx->read_mem = read_mem;
-  ctx->get_frame_base = no_get_frame_base;
-  ctx->get_frame_cfa = no_get_frame_cfa;
-  ctx->get_tls_address = no_get_tls_address;
+  ctx->funcs = &dwarf2_frame_ctx_funcs;
 
-  dwarf_expr_push (ctx, initial);
+  dwarf_expr_push_address (ctx, initial, initial_in_stack_memory);
   dwarf_expr_eval (ctx, exp, len);
-  result = dwarf_expr_fetch (ctx, 0);
 
-  if (ctx->location == DWARF_VALUE_REGISTER)
-    result = read_reg (this_frame, result);
-  else if (ctx->location != DWARF_VALUE_MEMORY)
+  if (ctx->location == DWARF_VALUE_MEMORY)
+    result = dwarf_expr_fetch_address (ctx, 0);
+  else if (ctx->location == DWARF_VALUE_REGISTER)
+    result = read_reg (this_frame, value_as_long (dwarf_expr_fetch (ctx, 0)));
+  else
     {
       /* This is actually invalid DWARF, but if we ever do run across
         it somehow, we might as well support it.  So, instead, report
         it as unimplemented.  */
-      error (_("Not implemented: computing unwound register using explicit value operator"));
+      error (_("\
+Not implemented: computing unwound register using explicit value operator"));
     }
 
   do_cleanups (old_chain);
@@ -395,15 +400,17 @@ execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size,
 }
 \f
 
-static void
-execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr,
-                    gdb_byte *insn_end, struct frame_info *this_frame,
-                    struct dwarf2_frame_state *fs)
+/* Execute FDE program from INSN_PTR possibly up to INSN_END or up to inferior
+   PC.  Modify FS state accordingly.  Return current INSN_PTR where the
+   execution has stopped, one can resume it on the next call.  */
+
+static const gdb_byte *
+execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
+                    const gdb_byte *insn_end, struct gdbarch *gdbarch,
+                    CORE_ADDR pc, struct dwarf2_frame_state *fs)
 {
   int eh_frame_p = fde->eh_frame_p;
-  CORE_ADDR pc = get_frame_pc (this_frame);
   int bytes_read;
-  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
   while (insn_ptr < insn_end && fs->pc <= pc)
@@ -435,7 +442,7 @@ execute_cfa_program (struct dwarf2_fde *fde, gdb_byte *insn_ptr,
            {
            case DW_CFA_set_loc:
              fs->pc = read_encoded_value (fde->cie->unit, fde->cie->encoding,
-                                          fde->cie->addr_size, insn_ptr,
+                                          fde->cie->ptr_size, insn_ptr,
                                           &bytes_read, fde->initial_location);
              /* Apply the objfile offset for relocatable objects.  */
              fs->pc += ANOFFSET (fde->cie->unit->objfile->section_offsets,
@@ -643,6 +650,7 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"),
                 unwinder.  */
              {
                int size = register_size (gdbarch, 0);
+
                dwarf2_frame_state_alloc_regs (&fs->regs, 32);
                for (reg = 8; reg < 16; reg++)
                  {
@@ -673,14 +681,20 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"),
              break;
 
            default:
-             internal_error (__FILE__, __LINE__, _("Unknown CFI encountered."));
+             internal_error (__FILE__, __LINE__,
+                             _("Unknown CFI encountered."));
            }
        }
     }
 
-  /* Don't allow remember/restore between CIE and FDE programs.  */
-  dwarf2_frame_state_free_regs (fs->regs.prev);
-  fs->regs.prev = NULL;
+  if (fs->initial.reg == NULL)
+    {
+      /* Don't allow remember/restore between CIE and FDE programs.  */
+      dwarf2_frame_state_free_regs (fs->regs.prev);
+      fs->regs.prev = NULL;
+    }
+
+  return insn_ptr;
 }
 \f
 
@@ -825,7 +839,8 @@ dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch,
    register.  */
 
 static int
-dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, int eh_frame_p)
+dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch,
+                           int regnum, int eh_frame_p)
 {
   struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
 
@@ -838,51 +853,124 @@ static void
 dwarf2_frame_find_quirks (struct dwarf2_frame_state *fs,
                          struct dwarf2_fde *fde)
 {
-  static const char *arm_idents[] = {
-    "ARM C Compiler, ADS",
-    "Thumb C Compiler, ADS",
-    "ARM C++ Compiler, ADS",
-    "Thumb C++ Compiler, ADS",
-    "ARM/Thumb C/C++ Compiler, RVCT"
-  };
-  int i;
-
   struct symtab *s;
 
   s = find_pc_symtab (fs->pc);
-  if (s == NULL || s->producer == NULL)
+  if (s == NULL)
     return;
 
-  for (i = 0; i < ARRAY_SIZE (arm_idents); i++)
-    if (strncmp (s->producer, arm_idents[i], strlen (arm_idents[i])) == 0)
+  if (producer_is_realview (s->producer))
+    {
+      if (fde->cie->version == 1)
+       fs->armcc_cfa_offsets_sf = 1;
+
+      if (fde->cie->version == 1)
+       fs->armcc_cfa_offsets_reversed = 1;
+
+      /* The reversed offset problem is present in some compilers
+        using DWARF3, but it was eventually fixed.  Check the ARM
+        defined augmentations, which are in the format "armcc" followed
+        by a list of one-character options.  The "+" option means
+        this problem is fixed (no quirk needed).  If the armcc
+        augmentation is missing, the quirk is needed.  */
+      if (fde->cie->version == 3
+         && (strncmp (fde->cie->augmentation, "armcc", 5) != 0
+             || strchr (fde->cie->augmentation + 5, '+') == NULL))
+       fs->armcc_cfa_offsets_reversed = 1;
+
+      return;
+    }
+}
+\f
+
+void
+dwarf2_compile_cfa_to_ax (struct agent_expr *expr, struct axs_value *loc,
+                         struct gdbarch *gdbarch,
+                         CORE_ADDR pc,
+                         struct dwarf2_per_cu_data *data)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch)
+                      + gdbarch_num_pseudo_regs (gdbarch);
+  struct dwarf2_fde *fde;
+  CORE_ADDR text_offset;
+  struct dwarf2_frame_state fs;
+  int addr_size;
+
+  memset (&fs, 0, sizeof (struct dwarf2_frame_state));
+
+  fs.pc = pc;
+
+  /* Find the correct FDE.  */
+  fde = dwarf2_frame_find_fde (&fs.pc, &text_offset);
+  if (fde == NULL)
+    error (_("Could not compute CFA; needed to translate this expression"));
+
+  /* Extract any interesting information from the CIE.  */
+  fs.data_align = fde->cie->data_alignment_factor;
+  fs.code_align = fde->cie->code_alignment_factor;
+  fs.retaddr_column = fde->cie->return_address_register;
+  addr_size = fde->cie->addr_size;
+
+  /* Check for "quirks" - known bugs in producers.  */
+  dwarf2_frame_find_quirks (&fs, fde);
+
+  /* First decode all the insns in the CIE.  */
+  execute_cfa_program (fde, fde->cie->initial_instructions,
+                      fde->cie->end, gdbarch, pc, &fs);
+
+  /* Save the initialized register set.  */
+  fs.initial = fs.regs;
+  fs.initial.reg = dwarf2_frame_state_copy_regs (&fs.regs);
+
+  /* Then decode the insns in the FDE up to our target PC.  */
+  execute_cfa_program (fde, fde->instructions, fde->end, gdbarch, pc, &fs);
+
+  /* Calculate the CFA.  */
+  switch (fs.regs.cfa_how)
+    {
+    case CFA_REG_OFFSET:
       {
-       if (fde->cie->version == 1)
-         fs->armcc_cfa_offsets_sf = 1;
-
-       if (fde->cie->version == 1)
-         fs->armcc_cfa_offsets_reversed = 1;
-
-       /* The reversed offset problem is present in some compilers
-          using DWARF3, but it was eventually fixed.  Check the ARM
-          defined augmentations, which are in the format "armcc" followed
-          by a list of one-character options.  The "+" option means
-          this problem is fixed (no quirk needed).  If the armcc
-          augmentation is missing, the quirk is needed.  */
-       if (fde->cie->version == 3
-           && (strncmp (fde->cie->augmentation, "armcc", 5) != 0
-               || strchr (fde->cie->augmentation + 5, '+') == NULL))
-         fs->armcc_cfa_offsets_reversed = 1;
-
-       return;
+       int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, fs.regs.cfa_reg);
+
+       if (regnum == -1)
+         error (_("Unable to access DWARF register number %d"),
+                (int) fs.regs.cfa_reg); /* FIXME */
+       ax_reg (expr, regnum);
+
+       if (fs.regs.cfa_offset != 0)
+         {
+           if (fs.armcc_cfa_offsets_reversed)
+             ax_const_l (expr, -fs.regs.cfa_offset);
+           else
+             ax_const_l (expr, fs.regs.cfa_offset);
+           ax_simple (expr, aop_add);
+         }
       }
+      break;
+
+    case CFA_EXP:
+      ax_const_l (expr, text_offset);
+      dwarf2_compile_expr_to_ax (expr, loc, gdbarch, addr_size,
+                                fs.regs.cfa_exp,
+                                fs.regs.cfa_exp + fs.regs.cfa_exp_len,
+                                data);
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+    }
 }
-\f
 
+\f
 struct dwarf2_frame_cache
 {
   /* DWARF Call Frame Address.  */
   CORE_ADDR cfa;
 
+  /* Set if the return address column was marked as unavailable
+     (required non-collected memory or registers to compute).  */
+  int unavailable_retaddr;
+
   /* Set if the return address column was marked as undefined.  */
   int undefined_retaddr;
 
@@ -895,6 +983,16 @@ struct dwarf2_frame_cache
 
   /* Target address size in bytes.  */
   int addr_size;
+
+  /* The .text offset.  */
+  CORE_ADDR text_offset;
+
+  /* If not NULL then this frame is the bottom frame of a TAILCALL_FRAME
+     sequence.  If NULL then it is a normal case with no TAILCALL_FRAME
+     involved.  Non-bottom frames of a virtual tail call frames chain use
+     dwarf2_tailcall_frame_unwind unwinder so this field does not apply for
+     them.  */
+  void *tailcall_cache;
 };
 
 static struct dwarf2_frame_cache *
@@ -907,6 +1005,11 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
   struct dwarf2_frame_cache *cache;
   struct dwarf2_frame_state *fs;
   struct dwarf2_fde *fde;
+  volatile struct gdb_exception ex;
+  CORE_ADDR entry_pc;
+  LONGEST entry_cfa_sp_offset;
+  int entry_cfa_sp_offset_p = 0;
+  const gdb_byte *instr;
 
   if (*this_cache)
     return *this_cache;
@@ -914,10 +1017,10 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
   /* Allocate a new cache.  */
   cache = FRAME_OBSTACK_ZALLOC (struct dwarf2_frame_cache);
   cache->reg = FRAME_OBSTACK_CALLOC (num_regs, struct dwarf2_frame_state_reg);
+  *this_cache = cache;
 
   /* Allocate and initialize the frame state.  */
-  fs = XMALLOC (struct dwarf2_frame_state);
-  memset (fs, 0, sizeof (struct dwarf2_frame_state));
+  fs = XZALLOC (struct dwarf2_frame_state);
   old_chain = make_cleanup (dwarf2_frame_state_free, fs);
 
   /* Unwind the PC.
@@ -938,7 +1041,7 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
   fs->pc = get_frame_address_in_block (this_frame);
 
   /* Find the correct FDE.  */
-  fde = dwarf2_frame_find_fde (&fs->pc);
+  fde = dwarf2_frame_find_fde (&fs->pc, &cache->text_offset);
   gdb_assert (fde != NULL);
 
   /* Extract any interesting information from the CIE.  */
@@ -952,34 +1055,66 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
 
   /* First decode all the insns in the CIE.  */
   execute_cfa_program (fde, fde->cie->initial_instructions,
-                      fde->cie->end, this_frame, fs);
+                      fde->cie->end, gdbarch, get_frame_pc (this_frame), fs);
 
   /* Save the initialized register set.  */
   fs->initial = fs->regs;
   fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs);
 
+  if (get_frame_func_if_available (this_frame, &entry_pc))
+    {
+      /* Decode the insns in the FDE up to the entry PC.  */
+      instr = execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,
+                                  entry_pc, fs);
+
+      if (fs->regs.cfa_how == CFA_REG_OFFSET
+         && (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg)
+             == gdbarch_sp_regnum (gdbarch)))
+       {
+         entry_cfa_sp_offset = fs->regs.cfa_offset;
+         entry_cfa_sp_offset_p = 1;
+       }
+    }
+  else
+    instr = fde->instructions;
+
   /* Then decode the insns in the FDE up to our target PC.  */
-  execute_cfa_program (fde, fde->instructions, fde->end, this_frame, fs);
+  execute_cfa_program (fde, instr, fde->end, gdbarch,
+                      get_frame_pc (this_frame), fs);
 
-  /* Calculate the CFA.  */
-  switch (fs->regs.cfa_how)
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
     {
-    case CFA_REG_OFFSET:
-      cache->cfa = read_reg (this_frame, fs->regs.cfa_reg);
-      if (fs->armcc_cfa_offsets_reversed)
-       cache->cfa -= fs->regs.cfa_offset;
-      else
-       cache->cfa += fs->regs.cfa_offset;
-      break;
-
-    case CFA_EXP:
-      cache->cfa =
-       execute_stack_op (fs->regs.cfa_exp, fs->regs.cfa_exp_len,
-                         cache->addr_size, this_frame, 0);
-      break;
+      /* Calculate the CFA.  */
+      switch (fs->regs.cfa_how)
+       {
+       case CFA_REG_OFFSET:
+         cache->cfa = read_reg (this_frame, fs->regs.cfa_reg);
+         if (fs->armcc_cfa_offsets_reversed)
+           cache->cfa -= fs->regs.cfa_offset;
+         else
+           cache->cfa += fs->regs.cfa_offset;
+         break;
+
+       case CFA_EXP:
+         cache->cfa =
+           execute_stack_op (fs->regs.cfa_exp, fs->regs.cfa_exp_len,
+                             cache->addr_size, cache->text_offset,
+                             this_frame, 0, 0);
+         break;
+
+       default:
+         internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+       }
+    }
+  if (ex.reason < 0)
+    {
+      if (ex.error == NOT_AVAILABLE_ERROR)
+       {
+         cache->unavailable_retaddr = 1;
+         return cache;
+       }
 
-    default:
-      internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+      throw_exception (ex);
     }
 
   /* Initialize the register state.  */
@@ -1085,10 +1220,31 @@ incomplete CFI data; unspecified registers (e.g., %s) at %s"),
 
   do_cleanups (old_chain);
 
-  *this_cache = cache;
+  /* Try to find a virtual tail call frames chain with bottom (callee) frame
+     starting at THIS_FRAME.  */
+  dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache,
+                                (entry_cfa_sp_offset_p
+                                 ? &entry_cfa_sp_offset : NULL));
+
   return cache;
 }
 
+static enum unwind_stop_reason
+dwarf2_frame_unwind_stop_reason (struct frame_info *this_frame,
+                                void **this_cache)
+{
+  struct dwarf2_frame_cache *cache
+    = dwarf2_frame_cache (this_frame, this_cache);
+
+  if (cache->unavailable_retaddr)
+    return UNWIND_UNAVAILABLE;
+
+  if (cache->undefined_retaddr)
+    return UNWIND_OUTERMOST;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache,
                      struct frame_id *this_id)
@@ -1096,6 +1252,9 @@ dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache,
   struct dwarf2_frame_cache *cache =
     dwarf2_frame_cache (this_frame, this_cache);
 
+  if (cache->unavailable_retaddr)
+    return;
+
   if (cache->undefined_retaddr)
     return;
 
@@ -1112,6 +1271,22 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
   CORE_ADDR addr;
   int realnum;
 
+  /* Non-bottom frames of a virtual tail call frames chain use
+     dwarf2_tailcall_frame_unwind unwinder so this code does not apply for
+     them.  If dwarf2_tailcall_prev_register_first does not have specific value
+     unwind the register, tail call frames are assumed to have the register set
+     of the top caller.  */
+  if (cache->tailcall_cache)
+    {
+      struct value *val;
+      
+      val = dwarf2_tailcall_prev_register_first (this_frame,
+                                                &cache->tailcall_cache,
+                                                regnum);
+      if (val)
+       return val;
+    }
+
   switch (cache->reg[regnum].how)
     {
     case DWARF2_FRAME_REG_UNDEFINED:
@@ -1131,7 +1306,8 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
     case DWARF2_FRAME_REG_SAVED_EXP:
       addr = execute_stack_op (cache->reg[regnum].loc.exp,
                               cache->reg[regnum].exp_len,
-                              cache->addr_size, this_frame, cache->cfa);
+                              cache->addr_size, cache->text_offset,
+                              this_frame, cache->cfa, 1);
       return frame_unwind_got_memory (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_SAVED_VAL_OFFSET:
@@ -1141,7 +1317,8 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
     case DWARF2_FRAME_REG_SAVED_VAL_EXP:
       addr = execute_stack_op (cache->reg[regnum].loc.exp,
                               cache->reg[regnum].exp_len,
-                              cache->addr_size, this_frame, cache->cfa);
+                              cache->addr_size, cache->text_offset,
+                              this_frame, cache->cfa, 1);
       return frame_unwind_got_constant (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_UNSPECIFIED:
@@ -1179,6 +1356,18 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
     }
 }
 
+/* Proxy for tailcall_frame_dealloc_cache for bottom frame of a virtual tail
+   call frames chain.  */
+
+static void
+dwarf2_frame_dealloc_cache (struct frame_info *self, void *this_cache)
+{
+  struct dwarf2_frame_cache *cache = dwarf2_frame_cache (self, &this_cache);
+
+  if (cache->tailcall_cache)
+    dwarf2_tailcall_frame_unwind.dealloc_cache (self, cache->tailcall_cache);
+}
+
 static int
 dwarf2_frame_sniffer (const struct frame_unwind *self,
                      struct frame_info *this_frame, void **this_cache)
@@ -1191,7 +1380,8 @@ dwarf2_frame_sniffer (const struct frame_unwind *self,
      extend one byte before its start address or we could potentially
      select the FDE of the previous function.  */
   CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
-  struct dwarf2_fde *fde = dwarf2_frame_find_fde (&block_addr);
+  struct dwarf2_fde *fde = dwarf2_frame_find_fde (&block_addr, NULL);
+
   if (!fde)
     return 0;
 
@@ -1204,25 +1394,38 @@ dwarf2_frame_sniffer (const struct frame_unwind *self,
                                      this_frame))
     return self->type == SIGTRAMP_FRAME;
 
-  return self->type != SIGTRAMP_FRAME;
+  if (self->type != NORMAL_FRAME)
+    return 0;
+
+  /* Preinitializa the cache so that TAILCALL_FRAME can find the record by
+     dwarf2_tailcall_sniffer_first.  */
+  dwarf2_frame_cache (this_frame, this_cache);
+
+  return 1;
 }
 
 static const struct frame_unwind dwarf2_frame_unwind =
 {
   NORMAL_FRAME,
+  dwarf2_frame_unwind_stop_reason,
   dwarf2_frame_this_id,
   dwarf2_frame_prev_register,
   NULL,
-  dwarf2_frame_sniffer
+  dwarf2_frame_sniffer,
+  dwarf2_frame_dealloc_cache
 };
 
 static const struct frame_unwind dwarf2_signal_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  dwarf2_frame_unwind_stop_reason,
   dwarf2_frame_this_id,
   dwarf2_frame_prev_register,
   NULL,
-  dwarf2_frame_sniffer
+  dwarf2_frame_sniffer,
+
+  /* TAILCALL_CACHE can never be in such frame to need dealloc_cache.  */
+  NULL
 };
 
 /* Append the DWARF-2 frame unwinders to GDBARCH's list.  */
@@ -1230,6 +1433,10 @@ static const struct frame_unwind dwarf2_signal_frame_unwind =
 void
 dwarf2_append_unwinders (struct gdbarch *gdbarch)
 {
+  /* TAILCALL_FRAME must be first to find the record by
+     dwarf2_tailcall_sniffer_first.  */
+  frame_unwind_append_unwinder (gdbarch, &dwarf2_tailcall_frame_unwind);
+
   frame_unwind_append_unwinder (gdbarch, &dwarf2_frame_unwind);
   frame_unwind_append_unwinder (gdbarch, &dwarf2_signal_frame_unwind);
 }
@@ -1262,7 +1469,8 @@ const struct frame_base *
 dwarf2_frame_base_sniffer (struct frame_info *this_frame)
 {
   CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
-  if (dwarf2_frame_find_fde (&block_addr))
+
+  if (dwarf2_frame_find_fde (&block_addr, NULL))
     return &dwarf2_frame_base;
 
   return NULL;
@@ -1280,8 +1488,13 @@ dwarf2_frame_cfa (struct frame_info *this_frame)
   /* This restriction could be lifted if other unwinders are known to
      compute the frame base in a way compatible with the DWARF
      unwinder.  */
-  if (! frame_unwinder_is (this_frame, &dwarf2_frame_unwind))
+  if (!frame_unwinder_is (this_frame, &dwarf2_frame_unwind)
+      && !frame_unwinder_is (this_frame, &dwarf2_tailcall_frame_unwind))
     error (_("can't compute CFA for this frame"));
+  if (get_frame_unwind_stop_reason (this_frame) == UNWIND_UNAVAILABLE)
+    throw_error (NOT_AVAILABLE_ERROR,
+                _("can't compute CFA for this frame: "
+                  "required registers or memory are unavailable"));
   return get_frame_base (this_frame);
 }
 \f
@@ -1414,7 +1627,8 @@ encoding_for_size (unsigned int size)
 
 static CORE_ADDR
 read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
-                   int ptr_len, gdb_byte *buf, unsigned int *bytes_read_ptr,
+                   int ptr_len, const gdb_byte *buf,
+                   unsigned int *bytes_read_ptr,
                    CORE_ADDR func_base)
 {
   ptrdiff_t offset;
@@ -1456,7 +1670,8 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
        }
       break;
     default:
-      internal_error (__FILE__, __LINE__, _("Invalid or unsupported encoding"));
+      internal_error (__FILE__, __LINE__,
+                     _("Invalid or unsupported encoding"));
     }
 
   if ((encoding & 0x07) == 0x00)
@@ -1471,7 +1686,8 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
     case DW_EH_PE_uleb128:
       {
        ULONGEST value;
-       gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7;
+       const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7;
+
        *bytes_read_ptr += read_uleb128 (buf, end_buf, &value) - buf;
        return base + value;
       }
@@ -1487,7 +1703,8 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
     case DW_EH_PE_sleb128:
       {
        LONGEST value;
-       gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7;
+       const gdb_byte *end_buf = buf + (sizeof (value) + 1) * 8 / 7;
+
        *bytes_read_ptr += read_sleb128 (buf, end_buf, &value) - buf;
        return base + value;
       }
@@ -1501,7 +1718,8 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
       *bytes_read_ptr += 8;
       return (base + bfd_get_signed_64 (unit->abfd, (bfd_byte *) buf));
     default:
-      internal_error (__FILE__, __LINE__, _("Invalid or unsupported encoding"));
+      internal_error (__FILE__, __LINE__,
+                     _("Invalid or unsupported encoding"));
     }
 }
 \f
@@ -1524,6 +1742,14 @@ find_cie (struct dwarf2_cie_table *cie_table, ULONGEST cie_pointer)
 {
   struct dwarf2_cie **p_cie;
 
+  /* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to
+     bsearch be non-NULL.  */
+  if (cie_table->entries == NULL)
+    {
+      gdb_assert (cie_table->num_entries == 0);
+      return NULL;
+    }
+
   p_cie = bsearch (&cie_pointer, cie_table->entries, cie_table->num_entries,
                    sizeof (cie_table->entries[0]), bsearch_cie_cmp);
   if (p_cie != NULL)
@@ -1551,6 +1777,7 @@ bsearch_fde_cmp (const void *key, const void *element)
 {
   CORE_ADDR seek_pc = *(CORE_ADDR *) key;
   struct dwarf2_fde *fde = *(struct dwarf2_fde **) element;
+
   if (seek_pc < fde->initial_location)
     return -1;
   if (seek_pc < fde->initial_location + fde->address_range)
@@ -1562,7 +1789,7 @@ bsearch_fde_cmp (const void *key, const void *element)
    inital location associated with it into *PC.  */
 
 static struct dwarf2_fde *
-dwarf2_frame_find_fde (CORE_ADDR *pc)
+dwarf2_frame_find_fde (CORE_ADDR *pc, CORE_ADDR *out_offset)
 {
   struct objfile *objfile;
 
@@ -1575,6 +1802,13 @@ dwarf2_frame_find_fde (CORE_ADDR *pc)
 
       fde_table = objfile_data (objfile, dwarf2_frame_objfile_data);
       if (fde_table == NULL)
+       {
+         dwarf2_build_frame_info (objfile);
+         fde_table = objfile_data (objfile, dwarf2_frame_objfile_data);
+       }
+      gdb_assert (fde_table != NULL);
+
+      if (fde_table->num_entries == 0)
        continue;
 
       gdb_assert (objfile->section_offsets);
@@ -1590,6 +1824,8 @@ dwarf2_frame_find_fde (CORE_ADDR *pc)
       if (p_fde != NULL)
         {
           *pc = (*p_fde)->initial_location + offset;
+         if (out_offset)
+           *out_offset = offset;
           return *p_fde;
         }
     }
@@ -1617,17 +1853,30 @@ add_fde (struct dwarf2_fde_table *fde_table, struct dwarf2_fde *fde)
 #define DW64_CIE_ID ~0
 #endif
 
+/* Defines the type of eh_frames that are expected to be decoded: CIE, FDE
+   or any of them.  */
+
+enum eh_frame_type
+{
+  EH_CIE_TYPE_ID = 1 << 0,
+  EH_FDE_TYPE_ID = 1 << 1,
+  EH_CIE_OR_FDE_TYPE_ID = EH_CIE_TYPE_ID | EH_FDE_TYPE_ID
+};
+
 static gdb_byte *decode_frame_entry (struct comp_unit *unit, gdb_byte *start,
                                     int eh_frame_p,
                                      struct dwarf2_cie_table *cie_table,
-                                     struct dwarf2_fde_table *fde_table);
+                                     struct dwarf2_fde_table *fde_table,
+                                     enum eh_frame_type entry_type);
+
+/* Decode the next CIE or FDE, entry_type specifies the expected type.
+   Return NULL if invalid input, otherwise the next byte to be processed.  */
 
-/* Decode the next CIE or FDE.  Return NULL if invalid input, otherwise
-   the next byte to be processed.  */
 static gdb_byte *
 decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
                       struct dwarf2_cie_table *cie_table,
-                      struct dwarf2_fde_table *fde_table)
+                      struct dwarf2_fde_table *fde_table,
+                      enum eh_frame_type entry_type)
 {
   struct gdbarch *gdbarch = get_objfile_arch (unit->objfile);
   gdb_byte *buf, *end;
@@ -1642,7 +1891,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
   buf += bytes_read;
   end = buf + length;
 
-  /* Are we still within the section? */
+  /* Are we still within the section?  */
   if (end > unit->dwarf_frame_buffer + unit->dwarf_frame_size)
     return NULL;
 
@@ -1678,6 +1927,10 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
       char *augmentation;
       unsigned int cie_version;
 
+      /* Check that a CIE was expected.  */
+      if ((entry_type & EH_CIE_TYPE_ID) == 0)
+       error (_("Found a CIE when not expecting it."));
+
       /* Record the offset into the .debug_frame section of this CIE.  */
       cie_pointer = start - unit->dwarf_frame_buffer;
 
@@ -1695,20 +1948,13 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
          depends on the target address size.  */
       cie->encoding = DW_EH_PE_absptr;
 
-      /* The target address size.  For .eh_frame FDEs this is considered
-        equal to the size of a target pointer.  For .dwarf_frame FDEs, 
-        this is supposed to be the target address size from the associated
-        CU header.  FIXME: We do not have a good way to determine the 
-        latter.  Always use the target pointer size for now.  */
-      cie->addr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
-
       /* We'll determine the final value later, but we need to
         initialize it conservatively.  */
       cie->signal_frame = 0;
 
       /* Check version number.  */
       cie_version = read_1_byte (unit->abfd, buf);
-      if (cie_version != 1 && cie_version != 3)
+      if (cie_version != 1 && cie_version != 3 && cie_version != 4)
        return NULL;
       cie->version = cie_version;
       buf += 1;
@@ -1732,6 +1978,28 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
          augmentation += 2;
        }
 
+      if (cie->version >= 4)
+       {
+         /* FIXME: check that this is the same as from the CU header.  */
+         cie->addr_size = read_1_byte (unit->abfd, buf);
+         ++buf;
+         cie->segment_size = read_1_byte (unit->abfd, buf);
+         ++buf;
+       }
+      else
+       {
+         cie->addr_size = gdbarch_dwarf2_addr_size (gdbarch);
+         cie->segment_size = 0;
+       }
+      /* Address values in .eh_frame sections are defined to have the
+        target's pointer size.  Watchout: This breaks frame info for
+        targets with pointer size < address size, unless a .debug_frame
+        section exists as well.  */
+      if (eh_frame_p)
+       cie->ptr_size = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
+      else
+       cie->ptr_size = cie->addr_size;
+
       cie->code_alignment_factor =
        read_unsigned_leb128 (unit->abfd, buf, &bytes_read);
       buf += bytes_read;
@@ -1790,7 +2058,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
            {
              /* Skip.  Avoid indirection since we throw away the result.  */
              gdb_byte encoding = (*buf++) & ~DW_EH_PE_indirect;
-             read_encoded_value (unit, encoding, cie->addr_size,
+             read_encoded_value (unit, encoding, cie->ptr_size,
                                  buf, &bytes_read, 0);
              buf += bytes_read;
              augmentation++;
@@ -1828,6 +2096,10 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
       /* This is a FDE.  */
       struct dwarf2_fde *fde;
 
+      /* Check that an FDE was expected.  */
+      if ((entry_type & EH_FDE_TYPE_ID) == 0)
+       error (_("Found an FDE when not expecting it."));
+
       /* In an .eh_frame section, the CIE pointer is the delta between the
         address within the FDE where the CIE pointer is stored and the
         address of the CIE.  Convert it to an offset into the .eh_frame
@@ -1849,20 +2121,21 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
       if (fde->cie == NULL)
        {
          decode_frame_entry (unit, unit->dwarf_frame_buffer + cie_pointer,
-                             eh_frame_p, cie_table, fde_table);
+                             eh_frame_p, cie_table, fde_table,
+                             EH_CIE_TYPE_ID);
          fde->cie = find_cie (cie_table, cie_pointer);
        }
 
       gdb_assert (fde->cie != NULL);
 
       fde->initial_location =
-       read_encoded_value (unit, fde->cie->encoding, fde->cie->addr_size,
+       read_encoded_value (unit, fde->cie->encoding, fde->cie->ptr_size,
                            buf, &bytes_read, 0);
       buf += bytes_read;
 
       fde->address_range =
        read_encoded_value (unit, fde->cie->encoding & 0x0f,
-                           fde->cie->addr_size, buf, &bytes_read, 0);
+                           fde->cie->ptr_size, buf, &bytes_read, 0);
       buf += bytes_read;
 
       /* A 'z' augmentation in the CIE implies the presence of an
@@ -1890,21 +2163,23 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
   return end;
 }
 
-/* Read a CIE or FDE in BUF and decode it.  */
+/* Read a CIE or FDE in BUF and decode it. Entry_type specifies whether we
+   expect an FDE or a CIE.  */
+
 static gdb_byte *
 decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
                     struct dwarf2_cie_table *cie_table,
-                    struct dwarf2_fde_table *fde_table)
+                    struct dwarf2_fde_table *fde_table,
+                    enum eh_frame_type entry_type)
 {
   enum { NONE, ALIGN4, ALIGN8, FAIL } workaround = NONE;
   gdb_byte *ret;
-  const char *msg;
   ptrdiff_t start_offset;
 
   while (1)
     {
       ret = decode_frame_entry_1 (unit, start, eh_frame_p,
-                                  cie_table, fde_table);
+                                 cie_table, fde_table, entry_type);
       if (ret != NULL)
        break;
 
@@ -1961,15 +2236,15 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
       break;
 
     case ALIGN4:
-      complaint (&symfile_complaints,
-                _("Corrupt data in %s:%s; align 4 workaround apparently succeeded"),
+      complaint (&symfile_complaints, _("\
+Corrupt data in %s:%s; align 4 workaround apparently succeeded"),
                 unit->dwarf_frame_section->owner->filename,
                 unit->dwarf_frame_section->name);
       break;
 
     case ALIGN8:
-      complaint (&symfile_complaints,
-                _("Corrupt data in %s:%s; align 8 workaround apparently succeeded"),
+      complaint (&symfile_complaints, _("\
+Corrupt data in %s:%s; align 8 workaround apparently succeeded"),
                 unit->dwarf_frame_section->owner->filename,
                 unit->dwarf_frame_section->name);
       break;
@@ -1985,11 +2260,6 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p,
   return ret;
 }
 \f
-
-/* Imported from dwarf2read.c.  */
-extern void dwarf2_get_section_info (struct objfile *, const char *, asection **,
-                                     gdb_byte **, bfd_size_type *);
-
 static int
 qsort_fde_cmp (const void *a, const void *b)
 {
@@ -2018,6 +2288,8 @@ dwarf2_build_frame_info (struct objfile *objfile)
   gdb_byte *frame_ptr;
   struct dwarf2_cie_table cie_table;
   struct dwarf2_fde_table fde_table;
+  struct dwarf2_fde_table *fde_table2;
+  volatile struct gdb_exception e;
 
   cie_table.num_entries = 0;
   cie_table.entries = NULL;
@@ -2033,52 +2305,104 @@ dwarf2_build_frame_info (struct objfile *objfile)
   unit->dbase = 0;
   unit->tbase = 0;
 
-  dwarf2_get_section_info (objfile, ".eh_frame",
-                           &unit->dwarf_frame_section,
-                           &unit->dwarf_frame_buffer,
-                           &unit->dwarf_frame_size);
-  if (unit->dwarf_frame_size)
+  if (objfile->separate_debug_objfile_backlink == NULL)
     {
-      asection *got, *txt;
-
-      /* FIXME: kettenis/20030602: This is the DW_EH_PE_datarel base
-        that is used for the i386/amd64 target, which currently is
-        the only target in GCC that supports/uses the
-        DW_EH_PE_datarel encoding.  */
-      got = bfd_get_section_by_name (unit->abfd, ".got");
-      if (got)
-       unit->dbase = got->vma;
-
-      /* GCC emits the DW_EH_PE_textrel encoding type on sh and ia64
-         so far.  */
-      txt = bfd_get_section_by_name (unit->abfd, ".text");
-      if (txt)
-       unit->tbase = txt->vma;
-
-      frame_ptr = unit->dwarf_frame_buffer;
-      while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
-       frame_ptr = decode_frame_entry (unit, frame_ptr, 1,
-                                        &cie_table, &fde_table);
-
-      if (cie_table.num_entries != 0)
+      /* Do not read .eh_frame from separate file as they must be also
+         present in the main file.  */
+      dwarf2_get_section_info (objfile, DWARF2_EH_FRAME,
+                               &unit->dwarf_frame_section,
+                               &unit->dwarf_frame_buffer,
+                               &unit->dwarf_frame_size);
+      if (unit->dwarf_frame_size)
         {
-          /* Reinit cie_table: debug_frame has different CIEs.  */
-          xfree (cie_table.entries);
-          cie_table.num_entries = 0;
-          cie_table.entries = NULL;
+          asection *got, *txt;
+
+          /* FIXME: kettenis/20030602: This is the DW_EH_PE_datarel base
+             that is used for the i386/amd64 target, which currently is
+             the only target in GCC that supports/uses the
+             DW_EH_PE_datarel encoding.  */
+          got = bfd_get_section_by_name (unit->abfd, ".got");
+          if (got)
+            unit->dbase = got->vma;
+
+          /* GCC emits the DW_EH_PE_textrel encoding type on sh and ia64
+             so far.  */
+          txt = bfd_get_section_by_name (unit->abfd, ".text");
+          if (txt)
+            unit->tbase = txt->vma;
+
+         TRY_CATCH (e, RETURN_MASK_ERROR)
+           {
+             frame_ptr = unit->dwarf_frame_buffer;
+             while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
+               frame_ptr = decode_frame_entry (unit, frame_ptr, 1,
+                                               &cie_table, &fde_table,
+                                               EH_CIE_OR_FDE_TYPE_ID);
+           }
+
+         if (e.reason < 0)
+           {
+             warning (_("skipping .eh_frame info of %s: %s"),
+                      objfile->name, e.message);
+
+             if (fde_table.num_entries != 0)
+               {
+                  xfree (fde_table.entries);
+                 fde_table.entries = NULL;
+                 fde_table.num_entries = 0;
+               }
+             /* The cie_table is discarded by the next if.  */
+           }
+
+          if (cie_table.num_entries != 0)
+            {
+              /* Reinit cie_table: debug_frame has different CIEs.  */
+              xfree (cie_table.entries);
+              cie_table.num_entries = 0;
+              cie_table.entries = NULL;
+            }
         }
     }
 
-  dwarf2_get_section_info (objfile, ".debug_frame",
+  dwarf2_get_section_info (objfile, DWARF2_DEBUG_FRAME,
                            &unit->dwarf_frame_section,
                            &unit->dwarf_frame_buffer,
                            &unit->dwarf_frame_size);
   if (unit->dwarf_frame_size)
     {
-      frame_ptr = unit->dwarf_frame_buffer;
-      while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
-       frame_ptr = decode_frame_entry (unit, frame_ptr, 0,
-                                        &cie_table, &fde_table);
+      int num_old_fde_entries = fde_table.num_entries;
+
+      TRY_CATCH (e, RETURN_MASK_ERROR)
+       {
+         frame_ptr = unit->dwarf_frame_buffer;
+         while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
+           frame_ptr = decode_frame_entry (unit, frame_ptr, 0,
+                                           &cie_table, &fde_table,
+                                           EH_CIE_OR_FDE_TYPE_ID);
+       }
+      if (e.reason < 0)
+       {
+         warning (_("skipping .debug_frame info of %s: %s"),
+                  objfile->name, e.message);
+
+         if (fde_table.num_entries != 0)
+           {
+             fde_table.num_entries = num_old_fde_entries;
+             if (num_old_fde_entries == 0)
+               {
+                 xfree (fde_table.entries);
+                 fde_table.entries = NULL;
+               }
+             else
+               {
+                 fde_table.entries = xrealloc (fde_table.entries,
+                                               fde_table.num_entries *
+                                               sizeof (fde_table.entries[0]));
+               }
+           }
+         fde_table.num_entries = num_old_fde_entries;
+         /* The cie_table is discarded by the next if.  */
+       }
     }
 
   /* Discard the cie_table, it is no longer needed.  */
@@ -2089,39 +2413,78 @@ dwarf2_build_frame_info (struct objfile *objfile)
       cie_table.num_entries = 0;  /* Paranoia.  */
     }
 
-  if (fde_table.num_entries != 0)
+  /* Copy fde_table to obstack: it is needed at runtime.  */
+  fde_table2 = (struct dwarf2_fde_table *)
+    obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2));
+
+  if (fde_table.num_entries == 0)
+    {
+      fde_table2->entries = NULL;
+      fde_table2->num_entries = 0;
+    }
+  else
     {
-      struct dwarf2_fde_table *fde_table2;
-      int i, j;
+      struct dwarf2_fde *fde_prev = NULL;
+      struct dwarf2_fde *first_non_zero_fde = NULL;
+      int i;
 
       /* Prepare FDE table for lookups.  */
       qsort (fde_table.entries, fde_table.num_entries,
              sizeof (fde_table.entries[0]), qsort_fde_cmp);
 
-      /* Copy fde_table to obstack: it is needed at runtime.  */
-      fde_table2 = (struct dwarf2_fde_table *)
-          obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2));
+      /* Check for leftovers from --gc-sections.  The GNU linker sets
+        the relevant symbols to zero, but doesn't zero the FDE *end*
+        ranges because there's no relocation there.  It's (offset,
+        length), not (start, end).  On targets where address zero is
+        just another valid address this can be a problem, since the
+        FDEs appear to be non-empty in the output --- we could pick
+        out the wrong FDE.  To work around this, when overlaps are
+        detected, we prefer FDEs that do not start at zero.
+
+        Start by finding the first FDE with non-zero start.  Below
+        we'll discard all FDEs that start at zero and overlap this
+        one.  */
+      for (i = 0; i < fde_table.num_entries; i++)
+       {
+         struct dwarf2_fde *fde = fde_table.entries[i];
 
-      /* Since we'll be doing bsearch, squeeze out identical (except for
-         eh_frame_p) fde entries so bsearch result is predictable.  */
-      for (i = 0, j = 0; j < fde_table.num_entries; ++i)
-        {
-          const int k = j;
-
-          obstack_grow (&objfile->objfile_obstack, &fde_table.entries[j],
-                        sizeof (fde_table.entries[0]));
-          while (++j < fde_table.num_entries
-                 && (fde_table.entries[k]->initial_location ==
-                     fde_table.entries[j]->initial_location))
-            /* Skip.  */;
-        }
+         if (fde->initial_location != 0)
+           {
+             first_non_zero_fde = fde;
+             break;
+           }
+       }
+
+      /* Since we'll be doing bsearch, squeeze out identical (except
+        for eh_frame_p) fde entries so bsearch result is predictable.
+        Also discard leftovers from --gc-sections.  */
+      fde_table2->num_entries = 0;
+      for (i = 0; i < fde_table.num_entries; i++)
+       {
+         struct dwarf2_fde *fde = fde_table.entries[i];
+
+         if (fde->initial_location == 0
+             && first_non_zero_fde != NULL
+             && (first_non_zero_fde->initial_location
+                 < fde->initial_location + fde->address_range))
+           continue;
+
+         if (fde_prev != NULL
+             && fde_prev->initial_location == fde->initial_location)
+           continue;
+
+         obstack_grow (&objfile->objfile_obstack, &fde_table.entries[i],
+                       sizeof (fde_table.entries[0]));
+         ++fde_table2->num_entries;
+         fde_prev = fde;
+       }
       fde_table2->entries = obstack_finish (&objfile->objfile_obstack);
-      fde_table2->num_entries = i;
-      set_objfile_data (objfile, dwarf2_frame_objfile_data, fde_table2);
 
       /* Discard the original fde_table.  */
       xfree (fde_table.entries);
     }
+
+  set_objfile_data (objfile, dwarf2_frame_objfile_data, fde_table2);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
This page took 0.037249 seconds and 4 git commands to generate.