* dwarf2cfi.c: New file.
authorJiri Smid <smid@suse.cz>
Fri, 7 Dec 2001 12:10:15 +0000 (12:10 +0000)
committerJiri Smid <smid@suse.cz>
Fri, 7 Dec 2001 12:10:15 +0000 (12:10 +0000)
* dwarf2cfi.h: New file.
* dwarf2read.c (dwarf_frame_offset, dwarf_frame_size): New variables.
(dwarf_eh_frame_offset, dwarf_eh_frame_size): New variables.
(dwarf2_read_section): Change to non static.
(dwarf2_locate_sections): Add .debug_frame and .eh_frame section
recognition.
(FRAME_SECTION, EH_FRAME_SECTION): New define.
* elfread.c (elf_symfile_read): Add call of frame informations build.
* frame.h (frame_info): Add pointer to unwind_context.
* symfile.h (dwarf2_build_frame_info): Add declaration.
* gdbarch.sh (DWARF2_BUILD_FRAME_INFO): Add.
* gdbarch.h, gdbarch.c: Regenerate.
* Makefile.in: Add dwarf2cfi_h, dwarf2cfi.o
* x86-64-tdep.c (i386_gdbarch_init): Initialize target vector to
use debug frame info.

12 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/dwarf2cfi.c [new file with mode: 0644]
gdb/dwarf2cfi.h [new file with mode: 0644]
gdb/dwarf2read.c
gdb/elfread.c
gdb/frame.h
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/symfile.h
gdb/x86-64-tdep.c

index e61cebab5480b76d289aba90ae1f2bcf626bc6f6..9b1fc38bff8a33b6b50d800890d41772afd16dea 100644 (file)
@@ -1,3 +1,22 @@
+2001-12-07  Jiri Smid  <smid@suse.cz>
+
+       * dwarf2cfi.c: New file.
+       * dwarf2cfi.h: New file.
+       * dwarf2read.c (dwarf_frame_offset, dwarf_frame_size): New variables.
+       (dwarf_eh_frame_offset, dwarf_eh_frame_size): New variables.
+       (dwarf2_read_section): Change to non static.
+       (dwarf2_locate_sections): Add .debug_frame and .eh_frame section
+       recognition.
+       (FRAME_SECTION, EH_FRAME_SECTION): New define.
+       * elfread.c (elf_symfile_read): Add call of frame informations build.
+       * frame.h (frame_info): Add pointer to unwind_context.
+       * symfile.h (dwarf2_build_frame_info): Add declaration.
+       * gdbarch.sh (DWARF2_BUILD_FRAME_INFO): Add.
+       * gdbarch.h, gdbarch.c: Regenerate.
+       * Makefile.in: Add dwarf2cfi_h, dwarf2cfi.o
+       * x86-64-tdep.c (i386_gdbarch_init): Initialize target vector to
+       use debug frame info.
+
 2001-12-06  Andrew Cagney  <ac131313@redhat.com>
 
        * defs.h: Do not include "mmalloc.h".
index 9d51e425a8a0f288bdd51d565eccfc8e5a1f2438..cf654afb1149fe519f381f0d5fecea47ca22ebef 100644 (file)
@@ -603,6 +603,7 @@ dcache_h =  dcache.h
 defs_h =       defs.h $(xm_h) $(tm_h) $(nm_h) config.status config.h \
                gdbarch.h ui-file.h
 doublest_h =   doublest.h $(floatformat_h)
+dwarf2cfi_h =  dwarf2cfi.h
 event_loop_h =  event-loop.h
 event_top_h =  event-top.h
 expression_h = expression.h $(doublest_h) $(symtab_h)
@@ -1355,6 +1356,9 @@ dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbcore_h) $(gdb_string_h)
 
 dstread.o: dstread.c $(gdb_string_h)
 
+dwarf2cfi.o: dwarf2cfi.c $(defs_h) $(symtab_h) $(symfile_h) $(objfiles_h) \
+       $(target_h) $(inferior_h) $(regcache_h) $(dwarf2cfi_h)
+
 dwarfread.o: dwarfread.c $(bfd_h) $(buildsym_h) $(complaints_h) $(defs_h) \
        $(expression_h) $(gdbtypes_h) $(language_h) $(objfiles_h) \
        $(symfile_h) $(symtab_h) $(gdb_string_h)
diff --git a/gdb/dwarf2cfi.c b/gdb/dwarf2cfi.c
new file mode 100644 (file)
index 0000000..6c574bb
--- /dev/null
@@ -0,0 +1,1740 @@
+/* Stack unwinding code based on dwarf2 frame info for GDB, the GNU debugger.
+   Copyright 2001
+   Free Software Foundation, Inc.
+   Contributed by Jiri Smid, SuSE Labs.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "target.h"
+#include "elf/dwarf2.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "dwarf2cfi.h"
+
+/* Common Information Entry - holds information that is shared among many
+   Frame Descriptors.  */
+struct cie_unit
+{
+  /* Offset of this unit in dwarf_frame_buffer.  */
+  ULONGEST offset;
+
+  /* A null-terminated string that identifies the augmentation to this CIE or
+     to the FDEs that use it.  */
+  char *augmentation;
+
+  /* A constant that is factored out of all advance location instructions.  */
+  unsigned int code_align;
+
+  /* A constant that is factored out of all offset instructions.  */
+  int data_align;
+
+  /* A constant that indicates which regiter represents the return address
+     of a function.  */
+  unsigned char ra;
+
+  /* Indicates how addresses are encoded.  */
+  unsigned char addr_encoding;
+
+  /* Pointer and length of the cie program.  */
+  char *data;
+  unsigned int data_length;
+
+  struct objfile *objfile;
+
+  /* Next in chain.  */
+  struct cie_unit *next;
+};
+
+/* Frame Description Entry.  */
+struct fde_unit
+{
+  /* Address of the first location associated with this entry.  */
+  CORE_ADDR initial_location;
+
+  /* Length of program section described by this entry.  */
+  CORE_ADDR address_range;
+
+  /* Pointer to asociated CIE.  */
+  struct cie_unit *cie_ptr;
+
+  /* Pointer and length of the cie program.  */
+  char *data;
+  unsigned int data_length;
+};
+
+struct fde_array
+{
+  struct fde_unit **array;
+  int elems;
+  int array_size;
+};
+
+struct context_reg
+{
+  union
+  {
+    unsigned int reg;
+    long offset;
+    CORE_ADDR addr;
+  }
+  loc;
+  enum
+  {
+    REG_CTX_UNSAVED,
+    REG_CTX_SAVED_OFFSET,
+    REG_CTX_SAVED_REG,
+    REG_CTX_SAVED_ADDR,
+    REG_CTX_VALUE,
+  }
+  how;
+};
+
+/* This is the register and unwind state for a particular frame.  */
+struct context
+{
+  struct context_reg *reg;
+
+  CORE_ADDR cfa;
+  CORE_ADDR ra;
+  void *lsda;
+  int args_size;
+};
+
+struct frame_state_reg
+{
+  union
+  {
+    unsigned int reg;
+    long offset;
+    unsigned char *exp;
+  }
+  loc;
+  enum
+  {
+    REG_UNSAVED,
+    REG_SAVED_OFFSET,
+    REG_SAVED_REG,
+    REG_SAVED_EXP,
+  }
+  how;
+};
+
+struct frame_state
+{
+  /* Each register save state can be described in terms of a CFA slot,
+     another register, or a location expression.  */
+  struct frame_state_regs
+  {
+    struct frame_state_reg *reg;
+
+    /* Used to implement DW_CFA_remember_state.  */
+    struct frame_state_regs *prev;
+  }
+  regs;
+
+  /* The CFA can be described in terms of a reg+offset or a
+     location expression.  */
+  long cfa_offset;
+  int cfa_reg;
+  unsigned char *cfa_exp;
+  enum
+  {
+    CFA_UNSET,
+    CFA_REG_OFFSET,
+    CFA_EXP,
+  }
+  cfa_how;
+
+  /* The PC described by the current frame state.  */
+  CORE_ADDR pc;
+
+  /* The information we care about from the CIE/FDE.  */
+  int data_align;
+  unsigned int code_align;
+  unsigned char retaddr_column;
+  unsigned char addr_encoding;
+
+  struct objfile *objfile;
+};
+
+#define UNWIND_CONTEXT(fi) ((struct context *) (fi->context))
+\f
+
+static struct cie_unit *cie_chunks;
+static struct fde_array fde_chunks;
+/* Obstack for allocating temporary storage used during unwind operations.  */
+static struct obstack unwind_tmp_obstack;
+
+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,
+                                 unsigned int size);
+
+static struct fde_unit *fde_unit_alloc (void);
+static struct cie_unit *cie_unit_alloc (void);
+static void fde_chunks_need_space ();
+
+static struct context *context_alloc ();
+static struct frame_state *frame_state_alloc ();
+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,
+                                      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,
+                            int dwarf64);
+static ULONGEST read_address (bfd *abfd, char **p);
+
+
+static int is_cie (ULONGEST cie_id, int dwarf64);
+static int compare_fde_unit (const void *a, const void *b);
+void dwarf2_build_frame_info (struct objfile *objfile);
+
+static void execute_cfa_program (struct objfile *objfile, char *insn_ptr,
+                                char *insn_end, struct context *context,
+                                struct frame_state *fs);
+static struct fde_unit *get_fde_for_addr (CORE_ADDR pc);
+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);
+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)
+{
+  struct fde_unit *fde;
+
+  fde = (struct fde_unit *) xmalloc (sizeof (struct fde_unit));
+  memset (fde, 0, sizeof (struct fde_unit));
+  return fde;
+}
+
+static struct cie_unit *
+cie_unit_alloc (void)
+{
+  struct cie_unit *cie;
+
+  cie = (struct cie_unit *) xmalloc (sizeof (struct cie_unit));
+  memset (cie, 0, sizeof (struct cie_unit));
+  return cie;
+}
+
+static void
+fde_chunks_need_space ()
+{
+  if (fde_chunks.elems < fde_chunks.array_size)
+    return;
+  fde_chunks.array_size =
+    fde_chunks.array_size ? 2 * fde_chunks.array_size : 1024;
+  fde_chunks.array =
+    xrealloc (fde_chunks.array,
+             sizeof (struct fde_unit) * fde_chunks.array_size);
+}
+
+/* Alocate a new `struct context' on temporary obstack.  */
+static struct context *
+context_alloc ()
+{
+  struct context *context;
+  struct context_reg *reg;
+  int regs_size = sizeof (struct context_reg) * NUM_REGS;
+
+  context = (struct context *) obstack_alloc (&unwind_tmp_obstack,
+                                             sizeof (struct context));
+  memset (context, 0, sizeof (struct context));
+  context->reg = (struct context_reg *) obstack_alloc (&unwind_tmp_obstack,
+                                                      regs_size);
+  memset (context->reg, 0, regs_size);
+  return context;
+}
+
+/* Alocate a new `struct frame_state' on temporary obstack.  */
+static struct frame_state *
+frame_state_alloc ()
+{
+  struct frame_state *fs;
+  struct frame_state_reg *reg;
+  int regs_size = sizeof (struct frame_state_reg) * NUM_REGS;
+
+  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);
+  memset (fs->regs.reg, 0, regs_size);
+  return fs;
+}
+
+static void
+unwind_tmp_obstack_free ()
+{
+  obstack_free (&unwind_tmp_obstack, NULL);
+  obstack_init (&unwind_tmp_obstack);
+}
+
+static void
+context_cpy (struct context *dst, struct context *src)
+{
+  struct context_reg *reg = dst->reg;
+  int regs_size = sizeof (struct context_reg) * NUM_REGS;
+
+  *dst = *src;
+  memcpy (dst->reg, src->reg, regs_size);
+}
+\f
+
+static unsigned int
+read_1u (bfd *abfd, char **p)
+{
+  unsigned ret;
+
+  ret= bfd_get_8 (abfd, (bfd_byte *) *p);
+  (*p) ++;
+  return ret;
+}
+
+static int
+read_1s (bfd *abfd, char **p)
+{
+  int ret;
+
+  ret= bfd_get_signed_8 (abfd, (bfd_byte *) *p);
+  (*p) ++;
+  return ret;
+}
+
+static unsigned int
+read_2u (bfd *abfd, char **p)
+{
+  unsigned ret;
+
+  ret= bfd_get_16 (abfd, (bfd_byte *) *p);
+  (*p) ++;
+  return ret;
+}
+
+static int
+read_2s (bfd *abfd, char **p)
+{
+  int ret;
+
+  ret= bfd_get_signed_16 (abfd, (bfd_byte *) *p);
+  (*p) += 2;
+  return ret;
+}
+
+static unsigned int
+read_4u (bfd *abfd, char **p)
+{
+  unsigned int ret;
+
+  ret= bfd_get_32 (abfd, (bfd_byte *) *p);
+  (*p) += 4;
+  return ret;
+}
+
+static int
+read_4s (bfd *abfd, char **p)
+{
+  int ret;
+
+  ret= bfd_get_signed_32 (abfd, (bfd_byte *) *p);
+  (*p) += 4;
+  return ret;
+}
+
+static ULONGEST
+read_8u (bfd *abfd, char **p)
+{
+  ULONGEST ret;
+
+  ret = bfd_get_64 (abfd, (bfd_byte *) *p);
+  (*p) += 8;
+  return ret;
+}
+
+static LONGEST
+read_8s (bfd *abfd, char **p)
+{
+  LONGEST ret;
+
+  ret = bfd_get_signed_64 (abfd, (bfd_byte *) *p);
+  (*p) += 8;
+  return ret;
+}
+
+static ULONGEST
+read_uleb128 (bfd *abfd, char **p)
+{
+  ULONGEST ret;
+  int i, shift;
+  unsigned char byte;
+
+  ret = 0;
+  shift = 0;
+  i = 0;
+  while (1)
+    {
+      byte = bfd_get_8 (abfd, (bfd_byte *) *p);
+      (*p) ++;
+      ret |= ((unsigned long) (byte & 127) << shift);
+      if ((byte & 128) == 0)
+       {
+         break;
+       }
+      shift += 7;
+    }
+  return ret;
+}
+
+static LONGEST
+read_sleb128 (bfd *abfd, char **p)
+{
+  LONGEST ret;
+  int i, shift, size, num_read;
+  unsigned char byte;
+
+  ret = 0;
+  shift = 0;
+  size = 32;
+  num_read = 0;
+  i = 0;
+  while (1)
+    {
+      byte = bfd_get_8 (abfd, (bfd_byte *) *p);
+      (*p) ++;
+      ret |= ((long) (byte & 127) << shift);
+      shift += 7;
+      if ((byte & 128) == 0)
+       {
+         break;
+       }
+    }
+  if ((shift < size) && (byte & 0x40))
+    {
+      ret |= -(1 << shift);
+    }
+  return ret;
+}
+
+static CORE_ADDR
+read_pointer (bfd *abfd, char **p)
+{
+  switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+    {
+    case 4:
+      return read_4u (abfd, p);
+    case 8:
+      return read_8u (abfd, p);
+    default:
+      error ("dwarf cfi error: unsupported target address length.");
+    }
+}
+
+static CORE_ADDR
+read_encoded_pointer (bfd *abfd, char **p, unsigned char encoding)
+{
+  CORE_ADDR ret;
+
+  switch (encoding & 0x0f)
+    {
+    case DW_EH_PE_absptr:
+      ret = read_pointer (abfd, p);
+      break;
+
+    case DW_EH_PE_uleb128:
+      ret = read_uleb128 (abfd, p);
+      break;
+    case DW_EH_PE_sleb128:
+      ret = read_sleb128 (abfd, p);
+      break;
+
+    case DW_EH_PE_udata2:
+      ret = read_2u (abfd, p);
+      break;
+    case DW_EH_PE_udata4:
+      ret = read_4u (abfd, p);
+      break;
+    case DW_EH_PE_udata8:
+      ret = read_8u (abfd, p);
+      break;
+
+    case DW_EH_PE_sdata2:
+      ret = read_2s (abfd, p);
+      break;
+    case DW_EH_PE_sdata4:
+      ret = read_4s (abfd, p);
+      break;
+    case DW_EH_PE_sdata8:
+      ret = read_8s (abfd, p);
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "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;
+}
+
+static LONGEST
+read_initial_length (bfd * abfd, char *buf, int *bytes_read)
+{
+  LONGEST ret = 0;
+
+  ret = bfd_get_32 (abfd, (bfd_byte *) buf);
+
+  if (ret == 0xffffffff)
+    {
+      ret = bfd_get_64 (abfd, (bfd_byte *) buf + 4);
+      *bytes_read = 12;
+    }
+  else
+    {
+      *bytes_read = 4;
+    }
+
+  return ret;
+}
+
+static ULONGEST
+read_length (bfd * abfd, char *buf, int *bytes_read, int dwarf64)
+{
+  if (dwarf64)
+    {
+      *bytes_read = 8;
+      return read_8u (abfd, &buf);
+    }
+  else
+    {
+      *bytes_read = 4;
+      return read_4u (abfd, &buf);
+    }
+}
+
+static void
+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;
+
+  /* Don't allow remember/restore between CIE and FDE programs.  */
+  fs->regs.prev = NULL;
+
+  while (insn_ptr < insn_end && fs->pc < context->ra)
+    {
+      unsigned char insn = *insn_ptr++;
+      ULONGEST reg, uoffset;
+      LONGEST offset;
+      int bytes_read;
+
+      if (insn & DW_CFA_advance_loc)
+       fs->pc += (insn & 0x3f) * fs->code_align;
+      else if (insn & DW_CFA_offset)
+       {
+         reg = insn & 0x3f;
+         uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+         offset = (long) uoffset * fs->data_align;
+         fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+         fs->regs.reg[reg].loc.offset = offset;
+       }
+      else if (insn & DW_CFA_restore)
+       {
+         reg = insn & 0x3f;
+         fs->regs.reg[reg].how = REG_UNSAVED;
+       }
+      else
+       switch (insn)
+         {
+         case DW_CFA_set_loc:
+           fs->pc = read_encoded_pointer (objfile->obfd, &insn_ptr,
+                                          fs->addr_encoding);
+           break;
+
+         case DW_CFA_advance_loc1:
+           fs->pc += read_1u (objfile->obfd, &insn_ptr);
+           break;
+         case DW_CFA_advance_loc2:
+           fs->pc += read_2u (objfile->obfd, &insn_ptr);
+           break;
+         case DW_CFA_advance_loc4:
+           fs->pc += read_4u (objfile->obfd, &insn_ptr);
+           break;
+
+         case DW_CFA_offset_extended:
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           offset = (long) uoffset *fs->data_align;
+           fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+           fs->regs.reg[reg].loc.offset = offset;
+           break;
+
+         case DW_CFA_restore_extended:
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           fs->regs.reg[reg].how = REG_UNSAVED;
+           break;
+
+         case DW_CFA_undefined:
+         case DW_CFA_same_value:
+         case DW_CFA_nop:
+           break;
+
+         case DW_CFA_register:
+           {
+             ULONGEST reg2;
+             reg = read_uleb128 (objfile->obfd, &insn_ptr);
+             reg2 = read_uleb128 (objfile->obfd, &insn_ptr);
+             fs->regs.reg[reg].how = REG_SAVED_REG;
+             fs->regs.reg[reg].loc.reg = reg2;
+           }
+           break;
+
+         case DW_CFA_remember_state:
+           {
+             struct frame_state_regs *new_rs;
+             if (unused_rs)
+               {
+                 new_rs = unused_rs;
+                 unused_rs = unused_rs->prev;
+               }
+             else
+               new_rs = xmalloc (sizeof (struct frame_state_regs));
+
+             *new_rs = fs->regs;
+             fs->regs.prev = new_rs;
+           }
+           break;
+
+         case DW_CFA_restore_state:
+           {
+             struct frame_state_regs *old_rs = fs->regs.prev;
+             fs->regs = *old_rs;
+             old_rs->prev = unused_rs;
+             unused_rs = old_rs;
+           }
+           break;
+
+         case DW_CFA_def_cfa:
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           fs->cfa_reg = reg;
+           fs->cfa_offset = uoffset;
+           fs->cfa_how = CFA_REG_OFFSET;
+           break;
+
+         case DW_CFA_def_cfa_register:
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           fs->cfa_reg = reg;
+           fs->cfa_how = CFA_REG_OFFSET;
+           break;
+
+         case DW_CFA_def_cfa_offset:
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           fs->cfa_offset = uoffset;
+           break;
+
+         case DW_CFA_def_cfa_expression:
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           fs->cfa_exp = insn_ptr;
+           fs->cfa_how = CFA_EXP;
+           insn_ptr += uoffset;
+           break;
+
+         case DW_CFA_expression:
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           fs->regs.reg[reg].how = REG_SAVED_EXP;
+           fs->regs.reg[reg].loc.exp = insn_ptr;
+           insn_ptr += uoffset;
+           break;
+
+           /* From the 2.1 draft.  */
+         case DW_CFA_offset_extended_sf:
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           offset = read_sleb128 (objfile->obfd, &insn_ptr);
+           offset *= fs->data_align;
+           fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+           fs->regs.reg[reg].loc.offset = offset;
+           break;
+
+         case DW_CFA_def_cfa_sf:
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           offset = read_sleb128 (objfile->obfd, &insn_ptr);
+           fs->cfa_offset = offset;
+           fs->cfa_reg = reg;
+           fs->cfa_how = CFA_REG_OFFSET;
+           break;
+
+         case DW_CFA_def_cfa_offset_sf:
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           fs->cfa_offset = uoffset;
+           /* cfa_how deliberately not set.  */
+           break;
+
+         case DW_CFA_GNU_window_save:
+           /* ??? Hardcoded for SPARC register window configuration.  */
+           for (reg = 16; reg < 32; ++reg)
+             {
+               fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+               fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
+             }
+           break;
+
+         case DW_CFA_GNU_args_size:
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           context->args_size = uoffset;
+           break;
+
+         case DW_CFA_GNU_negative_offset_extended:
+           /* Obsoleted by DW_CFA_offset_extended_sf, but used by
+              older PowerPC code.  */
+           reg = read_uleb128 (objfile->obfd, &insn_ptr);
+           uoffset = read_uleb128 (objfile->obfd, &insn_ptr);
+           offset = (long) uoffset *fs->data_align;
+           fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+           fs->regs.reg[reg].loc.offset = -offset;
+           break;
+
+         default:
+           error ("dwarf cfi error: unknown cfa instruction %d.", insn);
+         }
+    }
+}
+
+static struct fde_unit *
+get_fde_for_addr (CORE_ADDR pc)
+{
+  size_t lo, hi;
+  struct fde_unit *fde = NULL;
+  lo = 0;
+  hi = fde_chunks.elems;
+
+  while (lo < hi)
+    {
+      size_t i = (lo + hi) / 2;
+      fde = fde_chunks.array[i];
+      if (pc < fde->initial_location)
+       hi = i;
+      else if (pc >= fde->initial_location + fde->address_range)
+       lo = i + 1;
+      else
+       return fde;
+    }
+  return 0;
+}
+
+static void
+frame_state_for (struct context *context, struct frame_state *fs)
+{
+  struct fde_unit *fde;
+  struct cie_unit *cie;
+  unsigned char *aug, *insn, *end;
+
+  context->args_size = 0;
+  context->lsda = 0;
+
+  if ((fde = get_fde_for_addr (context->ra - 1)) != NULL)
+    {
+      fs->pc = fde->initial_location;
+
+      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
+get_reg (char *reg, struct context *context, int regnum)
+{
+  switch (context->reg[regnum].how)
+    {
+    case REG_CTX_UNSAVED:
+      read_register_gen (regnum, reg);
+      break;
+    case REG_CTX_SAVED_OFFSET:
+      target_read_memory (context->cfa + context->reg[regnum].loc.offset,
+                         reg, REGISTER_RAW_SIZE (regnum));
+      break;
+    case REG_CTX_SAVED_REG:
+      read_register_gen (context->reg[regnum].loc.reg, reg);
+      break;
+    case REG_CTX_SAVED_ADDR:
+      target_read_memory (context->reg[regnum].loc.addr,
+                         reg, REGISTER_RAW_SIZE (regnum));
+      break;
+    case REG_CTX_VALUE:
+      memcpy (reg, &context->reg[regnum].loc.addr,
+             REGISTER_RAW_SIZE (regnum));
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "get_reg: unknown register rule");
+    }
+}
+
+/* Decode a DW_OP stack program.  Return the top of stack.  Push INITIAL
+   onto the stack to start.  */
+static CORE_ADDR
+execute_stack_op (struct objfile *objfile,
+                 char *op_ptr, char *op_end, struct context *context,
+                 CORE_ADDR initial)
+{
+  CORE_ADDR stack[64];         /* ??? Assume this is enough. */
+  int stack_elt;
+
+  stack[0] = initial;
+  stack_elt = 1;
+
+  while (op_ptr < op_end)
+    {
+      enum dwarf_location_atom op = *op_ptr++;
+      ULONGEST result, reg;
+      LONGEST offset;
+
+      switch (op)
+       {
+       case DW_OP_lit0:
+       case DW_OP_lit1:
+       case DW_OP_lit2:
+       case DW_OP_lit3:
+       case DW_OP_lit4:
+       case DW_OP_lit5:
+       case DW_OP_lit6:
+       case DW_OP_lit7:
+       case DW_OP_lit8:
+       case DW_OP_lit9:
+       case DW_OP_lit10:
+       case DW_OP_lit11:
+       case DW_OP_lit12:
+       case DW_OP_lit13:
+       case DW_OP_lit14:
+       case DW_OP_lit15:
+       case DW_OP_lit16:
+       case DW_OP_lit17:
+       case DW_OP_lit18:
+       case DW_OP_lit19:
+       case DW_OP_lit20:
+       case DW_OP_lit21:
+       case DW_OP_lit22:
+       case DW_OP_lit23:
+       case DW_OP_lit24:
+       case DW_OP_lit25:
+       case DW_OP_lit26:
+       case DW_OP_lit27:
+       case DW_OP_lit28:
+       case DW_OP_lit29:
+       case DW_OP_lit30:
+       case DW_OP_lit31:
+         result = op - DW_OP_lit0;
+         break;
+
+       case DW_OP_addr:
+         result = read_pointer (objfile->obfd, &op_ptr);
+         break;
+
+       case DW_OP_const1u:
+         result = read_1u (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_const1s:
+         result = read_1s (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_const2u:
+         result = read_2u (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_const2s:
+         result = read_2s (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_const4u:
+         result = read_4u (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_const4s:
+         result = read_4s (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_const8u:
+         result = read_8u (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_const8s:
+         result = read_8s (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_constu:
+         result = read_uleb128 (objfile->obfd, &op_ptr);
+         break;
+       case DW_OP_consts:
+         result = read_sleb128 (objfile->obfd, &op_ptr);
+         break;
+
+       case DW_OP_reg0:
+       case DW_OP_reg1:
+       case DW_OP_reg2:
+       case DW_OP_reg3:
+       case DW_OP_reg4:
+       case DW_OP_reg5:
+       case DW_OP_reg6:
+       case DW_OP_reg7:
+       case DW_OP_reg8:
+       case DW_OP_reg9:
+       case DW_OP_reg10:
+       case DW_OP_reg11:
+       case DW_OP_reg12:
+       case DW_OP_reg13:
+       case DW_OP_reg14:
+       case DW_OP_reg15:
+       case DW_OP_reg16:
+       case DW_OP_reg17:
+       case DW_OP_reg18:
+       case DW_OP_reg19:
+       case DW_OP_reg20:
+       case DW_OP_reg21:
+       case DW_OP_reg22:
+       case DW_OP_reg23:
+       case DW_OP_reg24:
+       case DW_OP_reg25:
+       case DW_OP_reg26:
+       case DW_OP_reg27:
+       case DW_OP_reg28:
+       case DW_OP_reg29:
+       case DW_OP_reg30:
+       case DW_OP_reg31:
+         get_reg ((char *) &result, context, op - DW_OP_reg0);
+         break;
+       case DW_OP_regx:
+         reg = read_uleb128 (objfile->obfd, &op_ptr);
+         get_reg ((char *) &result, context, reg);
+         break;
+
+       case DW_OP_breg0:
+       case DW_OP_breg1:
+       case DW_OP_breg2:
+       case DW_OP_breg3:
+       case DW_OP_breg4:
+       case DW_OP_breg5:
+       case DW_OP_breg6:
+       case DW_OP_breg7:
+       case DW_OP_breg8:
+       case DW_OP_breg9:
+       case DW_OP_breg10:
+       case DW_OP_breg11:
+       case DW_OP_breg12:
+       case DW_OP_breg13:
+       case DW_OP_breg14:
+       case DW_OP_breg15:
+       case DW_OP_breg16:
+       case DW_OP_breg17:
+       case DW_OP_breg18:
+       case DW_OP_breg19:
+       case DW_OP_breg20:
+       case DW_OP_breg21:
+       case DW_OP_breg22:
+       case DW_OP_breg23:
+       case DW_OP_breg24:
+       case DW_OP_breg25:
+       case DW_OP_breg26:
+       case DW_OP_breg27:
+       case DW_OP_breg28:
+       case DW_OP_breg29:
+       case DW_OP_breg30:
+       case DW_OP_breg31:
+         offset = read_sleb128 (objfile->obfd, &op_ptr);
+         get_reg ((char *) &result, context, op - DW_OP_breg0);
+         result += offset;
+         break;
+       case DW_OP_bregx:
+         reg = read_uleb128 (objfile->obfd, &op_ptr);
+         offset = read_sleb128 (objfile->obfd, &op_ptr);
+         get_reg ((char *) &result, context, reg);
+         result += offset;
+         break;
+
+       case DW_OP_dup:
+         if (stack_elt < 1)
+           internal_error (__FILE__, __LINE__, "execute_stack_op error");
+         result = stack[stack_elt - 1];
+         break;
+
+       case DW_OP_drop:
+         if (--stack_elt < 0)
+           internal_error (__FILE__, __LINE__, "execute_stack_op error");
+         goto no_push;
+
+       case DW_OP_pick:
+         offset = *op_ptr++;
+         if (offset >= stack_elt - 1)
+           internal_error (__FILE__, __LINE__, "execute_stack_op error");
+         result = stack[stack_elt - 1 - offset];
+         break;
+
+       case DW_OP_over:
+         if (stack_elt < 2)
+           internal_error (__FILE__, __LINE__, "execute_stack_op error");
+         result = stack[stack_elt - 2];
+         break;
+
+       case DW_OP_rot:
+         {
+           CORE_ADDR t1, t2, t3;
+
+           if (stack_elt < 3)
+             internal_error (__FILE__, __LINE__, "execute_stack_op error");
+           t1 = stack[stack_elt - 1];
+           t2 = stack[stack_elt - 2];
+           t3 = stack[stack_elt - 3];
+           stack[stack_elt - 1] = t2;
+           stack[stack_elt - 2] = t3;
+           stack[stack_elt - 3] = t1;
+           goto no_push;
+         }
+
+       case DW_OP_deref:
+       case DW_OP_deref_size:
+       case DW_OP_abs:
+       case DW_OP_neg:
+       case DW_OP_not:
+       case DW_OP_plus_uconst:
+         /* Unary operations.  */
+         if (--stack_elt < 0)
+           internal_error (__FILE__, __LINE__, "execute_stack_op error");
+         result = stack[stack_elt];
+
+         switch (op)
+           {
+           case DW_OP_deref:
+             {
+               char *ptr = (char *) result;
+               result = read_pointer (objfile->obfd, &ptr);
+             }
+             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");
+                 }
+             }
+             break;
+
+           case DW_OP_abs:
+             if (result < 0)
+               result = -result;
+             break;
+           case DW_OP_neg:
+             result = -result;
+             break;
+           case DW_OP_not:
+             result = ~result;
+             break;
+           case DW_OP_plus_uconst:
+             result += read_uleb128 (objfile->obfd, &op_ptr);
+             break;
+           }
+         break;
+
+       case DW_OP_and:
+       case DW_OP_div:
+       case DW_OP_minus:
+       case DW_OP_mod:
+       case DW_OP_mul:
+       case DW_OP_or:
+       case DW_OP_plus:
+       case DW_OP_le:
+       case DW_OP_ge:
+       case DW_OP_eq:
+       case DW_OP_lt:
+       case DW_OP_gt:
+       case DW_OP_ne:
+         {
+           /* Binary operations.  */
+           CORE_ADDR first, second;
+           if ((stack_elt -= 2) < 0)
+             internal_error (__FILE__, __LINE__, "execute_stack_op error");
+           second = stack[stack_elt];
+           first = stack[stack_elt + 1];
+
+           switch (op)
+             {
+             case DW_OP_and:
+               result = second & first;
+               break;
+             case DW_OP_div:
+               result = (LONGEST) second / (LONGEST) first;
+               break;
+             case DW_OP_minus:
+               result = second - first;
+               break;
+             case DW_OP_mod:
+               result = (LONGEST) second % (LONGEST) first;
+               break;
+             case DW_OP_mul:
+               result = second * first;
+               break;
+             case DW_OP_or:
+               result = second | first;
+               break;
+             case DW_OP_plus:
+               result = second + first;
+               break;
+             case DW_OP_shl:
+               result = second << first;
+               break;
+             case DW_OP_shr:
+               result = second >> first;
+               break;
+             case DW_OP_shra:
+               result = (LONGEST) second >> first;
+               break;
+             case DW_OP_xor:
+               result = second ^ first;
+               break;
+             case DW_OP_le:
+               result = (LONGEST) first <= (LONGEST) second;
+               break;
+             case DW_OP_ge:
+               result = (LONGEST) first >= (LONGEST) second;
+               break;
+             case DW_OP_eq:
+               result = (LONGEST) first == (LONGEST) second;
+               break;
+             case DW_OP_lt:
+               result = (LONGEST) first < (LONGEST) second;
+               break;
+             case DW_OP_gt:
+               result = (LONGEST) first > (LONGEST) second;
+               break;
+             case DW_OP_ne:
+               result = (LONGEST) first != (LONGEST) second;
+               break;
+             }
+         }
+         break;
+
+       case DW_OP_skip:
+         offset = read_2s (objfile->obfd, &op_ptr);
+         op_ptr += offset;
+         goto no_push;
+
+       case DW_OP_bra:
+         if (--stack_elt < 0)
+           internal_error (__FILE__, __LINE__, "execute_stack_op error");
+         offset = read_2s (objfile->obfd, &op_ptr);
+         if (stack[stack_elt] != 0)
+           op_ptr += offset;
+         goto no_push;
+
+       case DW_OP_nop:
+         goto no_push;
+
+       default:
+         internal_error (__FILE__, __LINE__, "execute_stack_op error");
+       }
+
+      /* Most things push a result value.  */
+      if ((size_t) stack_elt >= sizeof (stack) / sizeof (*stack))
+       internal_error (__FILE__, __LINE__, "execute_stack_op error");
+      stack[++stack_elt] = result;
+    no_push:;
+    }
+
+  /* We were executing this program to get a value.  It should be
+     at top of stack.  */
+  if (--stack_elt < 0)
+    internal_error (__FILE__, __LINE__, "execute_stack_op error");
+  return stack[stack_elt];
+}
+
+static void
+update_context (struct context *context, struct frame_state *fs, int chain)
+{
+  struct context *orig_context;
+  CORE_ADDR cfa;
+  long i;
+
+  orig_context = context_alloc ();
+  context_cpy (orig_context, context);
+  /* Compute this frame's CFA.  */
+  switch (fs->cfa_how)
+    {
+    case CFA_REG_OFFSET:
+      get_reg ((char *) &cfa, context, fs->cfa_reg);
+      cfa += fs->cfa_offset;
+      break;
+
+    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.  */
+      {
+       char *exp = fs->cfa_exp;
+       ULONGEST len;
+
+       len = read_uleb128 (fs->objfile->obfd, &exp);
+       cfa = (CORE_ADDR) execute_stack_op (fs->objfile, exp,
+                                           exp + len, context, 0);
+       break;
+      }
+    }
+  context->cfa = cfa;
+
+  if (!chain)
+    orig_context->cfa = cfa;
+
+  /* Compute the addresses of all registers saved in this frame.  */
+  for (i = 0; i < NUM_REGS; ++i)
+    switch (fs->regs.reg[i].how)
+      {
+      case REG_UNSAVED:
+       if (i == SP_REGNUM)
+         {
+           context->reg[i].how = REG_CTX_VALUE;
+           context->reg[i].loc.addr = cfa;
+         }
+       else
+         context->reg[i].how = REG_CTX_UNSAVED;
+       break;
+      case REG_SAVED_OFFSET:
+       context->reg[i].how = REG_CTX_SAVED_OFFSET;
+       context->reg[i].loc.offset = fs->regs.reg[i].loc.offset;
+       break;
+      case REG_SAVED_REG:
+       switch (orig_context->reg[fs->regs.reg[i].loc.reg].how)
+         {
+         case REG_CTX_UNSAVED:
+           context->reg[i].how = REG_CTX_UNSAVED;
+           break;
+         case REG_CTX_SAVED_OFFSET:
+           context->reg[i].how = REG_CTX_SAVED_OFFSET;
+           context->reg[i].loc.offset = orig_context->cfa - context->cfa +
+             orig_context->reg[fs->regs.reg[i].loc.reg].loc.offset;
+           break;
+         case REG_CTX_SAVED_REG:
+           context->reg[i].how = REG_CTX_SAVED_REG;
+           context->reg[i].loc.reg =
+             orig_context->reg[fs->regs.reg[i].loc.reg].loc.reg;
+           break;
+         case REG_CTX_SAVED_ADDR:
+           context->reg[i].how = REG_CTX_SAVED_ADDR;
+           context->reg[i].loc.addr =
+             orig_context->reg[fs->regs.reg[i].loc.reg].loc.addr;
+         default:
+           internal_error (__FILE__, __LINE__,
+                           "cfi_update_context: unknown register rule");
+         }
+       break;
+      case REG_SAVED_EXP:
+       {
+         char *exp = fs->regs.reg[i].loc.exp;
+         ULONGEST len;
+         CORE_ADDR val;
+
+         len = read_uleb128 (fs->objfile->obfd, &exp);
+         val = execute_stack_op (fs->objfile, exp, exp + len,
+                                 orig_context, cfa);
+         context->reg[i].how = REG_CTX_SAVED_ADDR;
+         context->reg[i].loc.addr = val;
+       }
+       break;
+      default:
+       internal_error (__FILE__, __LINE__,
+                       "cfi_update_context: unknown register rule");
+
+      }
+  get_reg ((char *) &context->ra, context, fs->retaddr_column);
+  unwind_tmp_obstack_free ();
+}
+
+static int
+is_cie (ULONGEST cie_id, int dwarf64)
+{
+  return dwarf64 ? (cie_id == 0xffffffffffffffff) : (cie_id == 0xffffffff);
+}
+
+static int
+compare_fde_unit (const void *a, const void *b)
+{
+  struct fde_unit **first, **second;
+  first = (struct fde_unit **) a;
+  second = (struct fde_unit **) b;
+  if ((*first)->initial_location > (*second)->initial_location)
+    return 1;
+  else if ((*first)->initial_location < (*second)->initial_location)
+    return -1;
+  else
+    return 0;
+}
+
+/*  Build the cie_chunks and fde_chunks tables from informations
+    in .debug.frame section.  */
+void
+dwarf2_build_frame_info (struct objfile *objfile)
+{
+  bfd *abfd = objfile->obfd;
+  char *start = NULL;
+  char *end = NULL;
+
+  obstack_init (&unwind_tmp_obstack);
+
+  dwarf_frame_buffer = 0;
+
+  if (dwarf_frame_offset)
+    {
+      dwarf_frame_buffer = dwarf2_read_section (objfile,
+                                               dwarf_frame_offset,
+                                               dwarf_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 = dwarf_frame_buffer;
+      end = dwarf_frame_buffer + dwarf_eh_frame_size;
+    }
+
+  if (start)
+    {
+      while (start < end)
+       {
+         unsigned long length;
+         ULONGEST cie_id;
+         ULONGEST unit_offset = start - dwarf_frame_buffer;
+         int bytes_read;
+         int dwarf64;
+         char *block_end;
+
+         length = read_initial_length (abfd, start, &bytes_read);
+         start += bytes_read;
+         dwarf64 = (bytes_read == 12);
+         block_end = start + length;
+
+         cie_id = read_length (abfd, start, &bytes_read, dwarf64);
+         start += bytes_read;
+
+         if (is_cie (cie_id, dwarf64))
+           {
+             struct cie_unit *cie = cie_unit_alloc ();
+             char *aug;
+
+             cie->objfile = objfile;
+             cie->next = cie_chunks;
+             cie_chunks = cie;
+
+             cie->objfile = objfile;
+
+             cie->offset = unit_offset;
+
+             start++;          /* version */
+
+             cie->augmentation = aug = start;
+             while (*start)
+               start++;
+             start++;          /* skip past NUL */
+
+             cie->code_align = read_uleb128 (abfd, &start);
+             cie->data_align = read_sleb128 (abfd, &start);
+             cie->ra = read_1u (abfd, &start);
+
+             if (*aug == 'z')
+               {
+                 int xtra = read_uleb128 (abfd, &start);
+                 start += xtra;
+                 ++aug;
+               }
+
+             while (*aug != '\0')
+               {
+                 if (aug[0] == 'e' && aug[1] == 'h')
+                   {
+                     start += sizeof (void *);
+                     aug += 2;
+                   }
+                 else if (aug[0] == 'R')
+                   {
+                     cie->addr_encoding = *start++;
+                     aug += 1;
+                   }
+                 else if (aug[0] == 'P')
+                   {
+                     CORE_ADDR ptr;
+                     ptr = read_encoded_pointer (abfd, &start,
+                                                 cie->addr_encoding);
+                     aug += 1;
+                   }
+                 else
+                   warning ("unknown augmentation");
+               }
+
+             cie->data = start;
+             cie->data_length = block_end - start;
+           }
+         else
+           {
+             struct fde_unit *fde;
+             struct cie_unit *cie;
+
+             fde_chunks_need_space ();
+             fde = fde_unit_alloc ();
+
+             fde_chunks.array[fde_chunks.elems++] = fde;
+             fde->initial_location = read_pointer (abfd, &start);
+             fde->address_range = read_pointer (abfd, &start);
+
+             for (cie = cie_chunks;
+                  cie && (cie->offset != cie_id); cie = cie->next);
+             if (!cie)
+               error ("dwarf cfi error: can't find CIE pointer");
+             fde->cie_ptr = cie;
+
+             if (cie->augmentation[0] == 'z')
+                 read_uleb128 (abfd, &start);
+
+             fde->data = start;
+             fde->data_length = block_end - start;
+           }
+         start = block_end;
+       }
+      qsort (fde_chunks.array, fde_chunks.elems,
+            sizeof (struct fde_unit *), compare_fde_unit);
+    }
+}
+\f
+
+/* Return the frame address.  */
+CORE_ADDR
+cfi_read_fp ()
+{
+  struct context *context;
+  struct frame_state *fs;
+  CORE_ADDR cfa;
+
+  context = context_alloc ();
+  fs = frame_state_alloc ();
+
+  context->ra = read_pc () + 1;
+
+  frame_state_for (context, fs);
+  update_context (context, fs, 0);
+
+  cfa = context->cfa;
+  unwind_tmp_obstack_free ();
+  return cfa;
+}
+
+/* Store the frame address.  */
+void
+cfi_write_fp (CORE_ADDR val)
+{
+  struct context *context;
+  struct frame_state *fs;
+
+  context = context_alloc ();
+  fs = frame_state_alloc ();
+
+  context->ra = read_pc () + 1;
+
+  frame_state_for (context, fs);
+
+  if (fs->cfa_how == CFA_REG_OFFSET)
+    {
+      val -= fs->cfa_offset;
+      write_register_gen (fs->cfa_reg, (char *) &val);
+    }
+  else
+    warning ("Can't write fp.");
+
+  unwind_tmp_obstack_free ();
+}
+
+/* Restore the machine to the state it had before the current frame
+   was created.  */
+void
+cfi_pop_frame (struct frame_info *fi)
+{
+  char regbuf[MAX_REGISTER_RAW_SIZE];
+  int regnum;
+
+  fi = get_current_frame ();
+
+  for (regnum = 0; regnum < NUM_REGS; regnum++)
+    {
+      get_reg (regbuf, UNWIND_CONTEXT (fi), regnum);
+      write_register_bytes (REGISTER_BYTE (regnum), regbuf,
+                           REGISTER_RAW_SIZE (regnum));
+    }
+  write_register (PC_REGNUM, UNWIND_CONTEXT (fi)->ra);
+
+  flush_cached_frames ();
+}
+
+/* Determine the address of the calling function's frame.  */
+CORE_ADDR
+cfi_frame_chain (struct frame_info *fi)
+{
+  struct context *context;
+  struct frame_state *fs;
+  CORE_ADDR cfa;
+
+  context = context_alloc ();
+  fs = frame_state_alloc ();
+  context_cpy (context, UNWIND_CONTEXT (fi));
+
+  /* outermost frame */
+  if (context->ra == 0)
+    {
+      unwind_tmp_obstack_free ();
+      return 0;
+    }
+
+  frame_state_for (context, fs);
+  update_context (context, fs, 1);
+
+  cfa = context->cfa;
+  unwind_tmp_obstack_free ();
+  return cfa;
+}
+
+/* Sets the pc of the frame.  */
+void
+cfi_init_frame_pc (int fromleaf, struct frame_info *fi)
+{
+  if (fi->next)
+    get_reg ((char *) &(fi->pc), UNWIND_CONTEXT (fi->next), PC_REGNUM);
+  else
+    fi->pc = read_pc ();
+}
+
+/* Initialize unwind context informations of the frame.  */
+void
+cfi_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+  struct frame_state *fs;
+
+  fs = frame_state_alloc ();
+  fi->context = frame_obstack_alloc (sizeof (struct context));
+  UNWIND_CONTEXT (fi)->reg =
+    frame_obstack_alloc (sizeof (struct context_reg) * NUM_REGS);
+  memset (UNWIND_CONTEXT (fi)->reg, 0,
+         sizeof (struct context_reg) * NUM_REGS);
+
+  if (fi->next)
+    {
+      context_cpy (UNWIND_CONTEXT (fi), UNWIND_CONTEXT (fi->next));
+      frame_state_for (UNWIND_CONTEXT (fi), fs);
+      update_context (UNWIND_CONTEXT (fi), fs, 1);
+    }
+  else
+    {
+      UNWIND_CONTEXT (fi)->ra = fi->pc + 1;
+      frame_state_for (UNWIND_CONTEXT (fi), fs);
+      update_context (UNWIND_CONTEXT (fi), fs, 0);
+    }
+  unwind_tmp_obstack_free ();
+}
+
+/* Obtain return address of the frame.  */
+CORE_ADDR
+cfi_get_ra (struct frame_info *fi)
+{
+  return UNWIND_CONTEXT (fi)->ra;
+}
+
+/* Find register number REGNUM relative to FRAME and put its
+   (raw) contents in *RAW_BUFFER.  Set *OPTIMIZED if the variable
+   was optimized out (and thus can't be fetched).  If the variable
+   was fetched from memory, set *ADDRP to where it was fetched from,
+   otherwise it was fetched from a register.
+
+   The argument RAW_BUFFER must point to aligned memory.  */
+void
+cfi_get_saved_register (char *raw_buffer,
+                       int *optimized,
+                       CORE_ADDR * addrp,
+                       struct frame_info *frame,
+                       int regnum, enum lval_type *lval)
+{
+  if (!target_has_registers)
+    error ("No registers.");
+
+  /* Normal systems don't optimize out things with register numbers.  */
+  if (optimized != NULL)
+    *optimized = 0;
+
+  if (addrp)                   /* default assumption: not found in memory */
+    *addrp = 0;
+
+  if (!frame->next)
+    {
+      read_register_gen (regnum, raw_buffer);
+      if (lval != NULL)
+       *lval = lval_register;
+      if (addrp != NULL)
+       *addrp = REGISTER_BYTE (regnum);
+    }
+  else
+    {
+      frame = frame->next;
+      switch (UNWIND_CONTEXT (frame)->reg[regnum].how)
+       {
+       case REG_CTX_UNSAVED:
+         read_register_gen (regnum, raw_buffer);
+         if (lval != NULL)
+           *lval = not_lval;
+         if (optimized != NULL)
+           *optimized = 1;
+         break;
+       case REG_CTX_SAVED_OFFSET:
+         target_read_memory (UNWIND_CONTEXT (frame)->cfa +
+                             UNWIND_CONTEXT (frame)->reg[regnum].loc.offset,
+                             raw_buffer, REGISTER_RAW_SIZE (regnum));
+         if (lval != NULL)
+           *lval = lval_memory;
+         if (addrp != NULL)
+           *addrp =
+             UNWIND_CONTEXT (frame)->cfa +
+             UNWIND_CONTEXT (frame)->reg[regnum].loc.offset;
+         break;
+       case REG_CTX_SAVED_REG:
+         read_register_gen (UNWIND_CONTEXT (frame)->reg[regnum].loc.reg,
+                            raw_buffer);
+         if (lval != NULL)
+           *lval = lval_register;
+         if (addrp != NULL)
+           *addrp =
+             REGISTER_BYTE (UNWIND_CONTEXT (frame)->reg[regnum].loc.reg);
+         break;
+       case REG_CTX_SAVED_ADDR:
+         target_read_memory (UNWIND_CONTEXT (frame)->reg[regnum].loc.addr,
+                             raw_buffer, REGISTER_RAW_SIZE (regnum));
+         if (lval != NULL)
+           *lval = lval_memory;
+         if (addrp != NULL)
+           *addrp = UNWIND_CONTEXT (frame)->reg[regnum].loc.addr;
+         break;
+       case REG_CTX_VALUE:
+         memcpy (raw_buffer, &UNWIND_CONTEXT (frame)->reg[regnum].loc.addr,
+                 REGISTER_RAW_SIZE (regnum));
+         if (lval != NULL)
+           *lval = not_lval;
+         if (optimized != NULL)
+           *optimized = 0;
+         break;
+       default:
+         internal_error (__FILE__, __LINE__,
+                         "cfi_get_saved_register: unknown register rule");
+       }
+    }
+}
+
+/*  Return the register that the function uses for a frame pointer,
+    plus any necessary offset to be applied to the register before
+    any frame pointer offsets.  */
+void
+cfi_virtual_frame_pointer (CORE_ADDR pc, int *frame_reg,
+                          LONGEST * frame_offset)
+{
+  struct context *context;
+  struct frame_state *fs;
+
+  context = context_alloc ();
+  fs = frame_state_alloc ();
+
+  context->ra = read_pc () + 1;
+
+  frame_state_for (context, fs);
+
+  if (fs->cfa_how == CFA_REG_OFFSET)
+    {
+      *frame_reg = fs->cfa_reg;
+      *frame_offset = fs->cfa_offset;
+    }
+  else
+    error ("dwarf cfi error: CFA is not defined as CFA_REG_OFFSET");
+
+  unwind_tmp_obstack_free ();
+}
diff --git a/gdb/dwarf2cfi.h b/gdb/dwarf2cfi.h
new file mode 100644 (file)
index 0000000..f4c675a
--- /dev/null
@@ -0,0 +1,66 @@
+/* Stack unwinding code based on dwarf2 frame info for GDB, the GNU debugger.
+   Copyright 2001
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef DWARF2CFI_H
+#define DWARF2CFI_H
+
+/* Return the frame address.  */
+CORE_ADDR cfi_read_fp ();
+
+/* Store the frame address.  */
+void cfi_write_fp (CORE_ADDR val);
+
+/* Restore the machine to the state it had before the current frame
+   was created.  */
+void cfi_pop_frame (struct frame_info *);
+
+/* Determine the address of the calling function's frame.  */
+CORE_ADDR cfi_frame_chain (struct frame_info *fi);
+
+/* Sets the pc of the frame.  */
+void cfi_init_frame_pc (int fromleaf, struct frame_info *fi);
+
+/* Initialize unwind context informations of the frame.  */
+void cfi_init_extra_frame_info (int fromleaf, struct frame_info *fi);
+
+/* Obtain return address of the frame.  */
+CORE_ADDR cfi_get_ra (struct frame_info *fi);
+
+/* Find register number REGNUM relative to FRAME and put its
+   (raw) contents in *RAW_BUFFER.  Set *OPTIMIZED if the variable
+   was optimized out (and thus can't be fetched).  If the variable
+   was fetched from memory, set *ADDRP to where it was fetched from,
+   otherwise it was fetched from a register.
+
+   The argument RAW_BUFFER must point to aligned memory.  */
+void cfi_get_saved_register (char *raw_buffer,
+                            int *optimized,
+                            CORE_ADDR * addrp,
+                            struct frame_info *frame,
+                            int regnum, enum lval_type *lval);
+
+/*  Return the register that the function uses for a frame pointer,
+    plus any necessary offset to be applied to the register before
+    any frame pointer offsets.  */
+void cfi_virtual_frame_pointer (CORE_ADDR pc, int *frame_regnum,
+                               LONGEST * frame_offset);
+
+#endif
index 2ac7e6ada6c467a8d7070625d9d587a0aee5b9e5..a788efbadc1c178593398dfafeb66bdb6c05bf05 100644 (file)
@@ -132,6 +132,8 @@ static file_ptr dwarf_aranges_offset;
 static file_ptr dwarf_loc_offset;
 static file_ptr dwarf_macinfo_offset;
 static file_ptr dwarf_str_offset;
+file_ptr dwarf_frame_offset;
+file_ptr dwarf_eh_frame_offset;
 
 static unsigned int dwarf_info_size;
 static unsigned int dwarf_abbrev_size;
@@ -141,6 +143,8 @@ static unsigned int dwarf_aranges_size;
 static unsigned int dwarf_loc_size;
 static unsigned int dwarf_macinfo_size;
 static unsigned int dwarf_str_size;
+unsigned int dwarf_frame_size;
+unsigned int dwarf_eh_frame_size;
 
 /* names of the debugging sections */
 
@@ -152,6 +156,8 @@ static unsigned int dwarf_str_size;
 #define LOC_SECTION      ".debug_loc"
 #define MACINFO_SECTION  ".debug_macinfo"
 #define STR_SECTION      ".debug_str"
+#define FRAME_SECTION    ".debug_frame"
+#define EH_FRAME_SECTION ".eh_frame"
 
 /* local data types */
 
@@ -587,7 +593,7 @@ static void dwarf2_psymtab_to_symtab (struct partial_symtab *);
 
 static void psymtab_to_symtab_1 (struct partial_symtab *);
 
-static char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int);
+char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int);
 
 static void dwarf2_read_abbrevs (bfd *, unsigned int);
 
@@ -807,6 +813,7 @@ dwarf2_has_info (bfd *abfd)
 {
   dwarf_info_offset = dwarf_abbrev_offset = dwarf_line_offset = 0;
   dwarf_str_offset = 0;
+  dwarf_frame_offset = dwarf_eh_frame_offset = 0;
   bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
   if (dwarf_info_offset && dwarf_abbrev_offset)
     {
@@ -865,6 +872,16 @@ dwarf2_locate_sections (bfd *ignore_abfd, asection *sectp, PTR ignore_ptr)
       dwarf_str_offset = sectp->filepos;
       dwarf_str_size = bfd_get_section_size_before_reloc (sectp);
     }
+  else if (STREQ (sectp->name, FRAME_SECTION))
+    {
+      dwarf_frame_offset = sectp->filepos;
+      dwarf_frame_size = bfd_get_section_size_before_reloc (sectp);
+    }
+  else if (STREQ (sectp->name, EH_FRAME_SECTION))
+    {
+      dwarf_eh_frame_offset = sectp->filepos;
+      dwarf_eh_frame_size = bfd_get_section_size_before_reloc (sectp);
+    }
 }
 
 /* Build a partial symbol table.  */
@@ -3045,7 +3062,7 @@ make_cleanup_free_die_list (struct die_info *dies)
 /* Read the contents of the section at OFFSET and of size SIZE from the
    object file specified by OBJFILE into the psymbol_obstack and return it.  */
 
-static char *
+char *
 dwarf2_read_section (struct objfile *objfile, file_ptr offset,
                     unsigned int size)
 {
index 84807c066f398d4b9095fde1ffce1b0850dee8e3..068d412b6e517539ce9eec3153ff8faa1e68101f 100644 (file)
@@ -656,6 +656,9 @@ elf_symfile_read (struct objfile *objfile, int mainline)
                            ei.lnoffset, ei.lnsize);
     }
 
+  if (DWARF2_BUILD_FRAME_INFO_P ())
+    DWARF2_BUILD_FRAME_INFO(objfile);
+
   /* Install any minimal symbols that have been collected as the current
      minimal symbols for this objfile. */
 
index 66ffa5c26b2f3e65944e4d89966757093324c649..f4c51e07b42ed4ed84880cd7c9e1c2aa6fb1cde2 100644 (file)
@@ -96,6 +96,10 @@ struct frame_info
        initialized by INIT_EXTRA_FRAME_INFO */
     struct frame_extra_info *extra_info;
 
+    /* If dwarf2 unwind frame informations is used, this structure holds all
+       related unwind data.  */
+    struct unwind_contect *context;
+
     /* Pointers to the next (down, inner) and previous (up, outer)
        frame_info's in the frame cache.  */
     struct frame_info *next; /* down, inner */
index 83895a4594de6d7e353e10a48cfb72c436e32722..ffd1ac57c73f467c1c635d62e375b5ec3bbf9251 100644 (file)
@@ -256,6 +256,7 @@ struct gdbarch
   gdbarch_in_solib_call_trampoline_ftype *in_solib_call_trampoline;
   gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p;
   gdbarch_construct_inferior_arguments_ftype *construct_inferior_arguments;
+  gdbarch_dwarf2_build_frame_info_ftype *dwarf2_build_frame_info;
 };
 
 
@@ -396,6 +397,7 @@ struct gdbarch startup_gdbarch =
   0,
   generic_in_function_epilogue_p,
   construct_inferior_arguments,
+  0,
   /* startup_gdbarch() */
 };
 
@@ -759,6 +761,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of in_solib_call_trampoline, invalid_p == 0 */
   /* Skip verify of in_function_epilogue_p, invalid_p == 0 */
   /* Skip verify of construct_inferior_arguments, invalid_p == 0 */
+  /* Skip verify of dwarf2_build_frame_info, has predicate */
   buf = ui_file_xstrdup (log, &dummy);
   make_cleanup (xfree, buf);
   if (strlen (buf) > 0)
@@ -1003,6 +1006,20 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                         (long) current_gdbarch->do_registers_info
                         /*DO_REGISTERS_INFO ()*/);
 #endif
+#ifdef DWARF2_BUILD_FRAME_INFO
+#if GDB_MULTI_ARCH
+  /* Macro might contain `[{}]' when not multi-arch */
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: %s # %s\n",
+                      "DWARF2_BUILD_FRAME_INFO(objfile)",
+                      XSTRING (DWARF2_BUILD_FRAME_INFO (objfile)));
+#endif
+  if (GDB_MULTI_ARCH)
+    fprintf_unfiltered (file,
+                        "gdbarch_dump: DWARF2_BUILD_FRAME_INFO = 0x%08lx\n",
+                        (long) current_gdbarch->dwarf2_build_frame_info
+                        /*DWARF2_BUILD_FRAME_INFO ()*/);
+#endif
 #ifdef DWARF2_REG_TO_REGNUM
   fprintf_unfiltered (file,
                       "gdbarch_dump: %s # %s\n",
@@ -4308,6 +4325,30 @@ set_gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch,
   gdbarch->construct_inferior_arguments = construct_inferior_arguments;
 }
 
+int
+gdbarch_dwarf2_build_frame_info_p (struct gdbarch *gdbarch)
+{
+  return gdbarch->dwarf2_build_frame_info != 0;
+}
+
+void
+gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch, struct objfile *objfile)
+{
+  if (gdbarch->dwarf2_build_frame_info == 0)
+    internal_error (__FILE__, __LINE__,
+                    "gdbarch: gdbarch_dwarf2_build_frame_info invalid");
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_dwarf2_build_frame_info called\n");
+  gdbarch->dwarf2_build_frame_info (objfile);
+}
+
+void
+set_gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch,
+                                     gdbarch_dwarf2_build_frame_info_ftype dwarf2_build_frame_info)
+{
+  gdbarch->dwarf2_build_frame_info = dwarf2_build_frame_info;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules. */
index 22945959eff9fcaa4de752b7d390dccc6762bc36..21e531755fc36e88f8c9e75728e5de524ed1fcab 100644 (file)
@@ -42,7 +42,7 @@
 
 struct frame_info;
 struct value;
-
+struct objfile;
 
 extern struct gdbarch *current_gdbarch;
 
@@ -2166,6 +2166,43 @@ typedef char * (gdbarch_construct_inferior_arguments_ftype) (struct gdbarch *gdb
 extern char * gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv);
 extern void set_gdbarch_construct_inferior_arguments (struct gdbarch *gdbarch, gdbarch_construct_inferior_arguments_ftype *construct_inferior_arguments);
 
+#if defined (DWARF2_BUILD_FRAME_INFO)
+/* Legacy for systems yet to multi-arch DWARF2_BUILD_FRAME_INFO */
+#if !defined (DWARF2_BUILD_FRAME_INFO_P)
+#define DWARF2_BUILD_FRAME_INFO_P() (1)
+#endif
+#endif
+
+/* Default predicate for non- multi-arch targets. */
+#if (!GDB_MULTI_ARCH) && !defined (DWARF2_BUILD_FRAME_INFO_P)
+#define DWARF2_BUILD_FRAME_INFO_P() (0)
+#endif
+
+extern int gdbarch_dwarf2_build_frame_info_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DWARF2_BUILD_FRAME_INFO_P)
+#error "Non multi-arch definition of DWARF2_BUILD_FRAME_INFO"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DWARF2_BUILD_FRAME_INFO_P)
+#define DWARF2_BUILD_FRAME_INFO_P() (gdbarch_dwarf2_build_frame_info_p (current_gdbarch))
+#endif
+
+/* Default (function) for non- multi-arch platforms. */
+#if (!GDB_MULTI_ARCH) && !defined (DWARF2_BUILD_FRAME_INFO)
+#define DWARF2_BUILD_FRAME_INFO(objfile) (internal_error (__FILE__, __LINE__, "DWARF2_BUILD_FRAME_INFO"), 0)
+#endif
+
+typedef void (gdbarch_dwarf2_build_frame_info_ftype) (struct objfile *objfile);
+extern void gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch, struct objfile *objfile);
+extern void set_gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch, gdbarch_dwarf2_build_frame_info_ftype *dwarf2_build_frame_info);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DWARF2_BUILD_FRAME_INFO)
+#error "Non multi-arch definition of DWARF2_BUILD_FRAME_INFO"
+#endif
+#if GDB_MULTI_ARCH
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DWARF2_BUILD_FRAME_INFO)
+#define DWARF2_BUILD_FRAME_INFO(objfile) (gdbarch_dwarf2_build_frame_info (current_gdbarch, objfile))
+#endif
+#endif
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 
 
index 16b01a5fea38f2046d1fd9e15f9852833930f546..d0a2569c70baaef0ae319eb18aa15281d556ce12 100755 (executable)
@@ -569,6 +569,7 @@ m:::int:in_function_epilogue_p:CORE_ADDR addr:addr::0:generic_in_function_epilog
 # ARGC is the number of elements in the vector.
 # ARGV is an array of strings, one per argument.
 m::CONSTRUCT_INFERIOR_ARGUMENTS:char *:construct_inferior_arguments:int argc, char **argv:argc, argv:::construct_inferior_arguments::0
+F:2:DWARF2_BUILD_FRAME_INFO:void:dwarf2_build_frame_info:struct objfile *objfile:objfile:::0
 EOF
 }
 
@@ -675,7 +676,7 @@ cat <<EOF
 
 struct frame_info;
 struct value;
-
+struct objfile;
 
 extern struct gdbarch *current_gdbarch;
 
index a6bf3f6da8f16f891a936e2743bae6f22dbb6f27..8af5aeaff14313dc852e68f75252e80bffaf7d09 100644 (file)
@@ -300,6 +300,7 @@ dwarf_build_psymtabs (struct objfile *, int, file_ptr, unsigned int,
 extern int dwarf2_has_info (bfd * abfd);
 
 extern void dwarf2_build_psymtabs (struct objfile *, int);
+extern void dwarf2_build_frame_info (struct objfile *);
 
 /* From mdebugread.c */
 
index 8a645520f3ed14d91887af36181099414cb8eed4..dcf5ffdbda9c4fb6eb58c0dc4eb20d64c707eec8 100644 (file)
@@ -974,6 +974,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
    number of bytes in BREAKPOINT but not always.  */
   set_gdbarch_decr_pc_after_break (gdbarch, 1);
 
+/* Use dwarf2 debug frame informations.  */
+  set_gdbarch_dwarf2_build_frame_info (gdbarch, dwarf2_build_frame_info);
   return gdbarch;
 }