This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


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

Re: [RFC/RFA] use of dwarf2 unwind informations



Jiri Smid <smid@suse.cz> writes:
>   This is code which allows gdb to use dwarf2 frame informations for
> stack unwinding.

This is great.  Thank you very much!

I think this patch falls to me and Elena to review, since CFI is
debugging information.  I won't have time to look at it until the end
of the week.  But the ability to read and use Dwarf 2 CFI is something
we've wanted for a long time, so I'm looking forward to looking this
over.

Just skimming things, it looks like the new module, dwarf2cfi.c,
exports a bunch of methods a gdbarch'ed target can use (`cfi_read_fp',
`cfi_init_extra_frame_info', and so on) to use the CFI for stuff we've
traditionally accomplished with prolog analysis.

Why is DWARF2_BUILD_FRAME_INFO a function pointer?  It seems to me
that its only purpose is to determine whether GDB reads the CFI;
shouldn't it be a boolean setting, like READ_DWARF2_CALL_FRAME_INFO_P?



> Index: gdb/ChangeLog
> from  Jiri Smid  <smid@suse.cz>
> 
> 	* dwarf2cfi.c: New file.
> 	* dwarf2cfi.h: New file.
> 	* dwarf2read.c (dwarf_frame_offset, dwarf_frame_size): New
> 	variables.
> 	(dwarf2_read_section): Change to non static.
> 	(dwarf2_locate_sections): Add frame section recognition.
> 	* 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.
> 	(FRAME_SECTION): New define.
> 	* Makefile.in: Add dwarf2cfi_h, dwarf2cfi.o, update dependencies.
> 
> Index: gdb/Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/Makefile.in,v
> retrieving revision 1.116
> diff -c -3 -p -r1.116 Makefile.in
> *** Makefile.in	2001/09/21 12:19:15	1.116
> --- Makefile.in	2001/09/27 09:40:43
> *************** cp_abi_h =	cp-abi.h
> *** 599,604 ****
> --- 599,605 ----
>   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)
> *************** dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbco
> *** 1324,1329 ****
> --- 1325,1333 ----
>   
>   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)
> *************** vax-tdep.o: vax-tdep.c $(OP_INCLUDE)/vax
> *** 2078,2087 ****
>   w65-tdep.o : w65-tdep.c $(gdbcore_h) $(regcache_h)
>   
>   x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
> ! 	$(regcache_h) x86-64-tdep.h i386-tdep.h
>   
>   x86-64-tdep.o : x86-64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) $(gdbcmd_h) \
> ! 	$(arch_utils_h) $(regcache_h) $(symfile_h) x86-64-tdep.h i386-tdep.h
>   
>   x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
>   	$(regcache_h) i387-nat.h x86-64-tdep.h i386-tdep.h
> --- 2082,2092 ----
>   w65-tdep.o : w65-tdep.c $(gdbcore_h) $(regcache_h)
>   
>   x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
> ! 	$(regcache_h) x86-64-tdep.h i386-tdep.h $(dwarf2cfi_h)
>   
>   x86-64-tdep.o : x86-64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) $(gdbcmd_h) \
> ! 	$(arch_utils_h) $(regcache_h) $(symfile_h) x86-64-tdep.h i386-tdep.h \
> ! 	$(dwarf2cfi_h)
>   
>   x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
>   	$(regcache_h) i387-nat.h x86-64-tdep.h i386-tdep.h
> Index: gdb/dwarf2cfi.c
> ===================================================================
> RCS file: dwarf2cfi.c
> diff -N dwarf2cfi.c
> *** /dev/null	Tue May  5 13:32:27 1998
> --- dwarf2cfi.c	Thu Sep 27 02:40:43 2001
> ***************
> *** 0 ****
> --- 1,1723 ----
> + /* 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))
> + 
> + 
> + 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;
> + 
> + static char *dwarf_frame_buffer;
> + 
> + 
> + 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);
> + 
> + 
> + /* 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;
> +   *dst = *src;
> +   dst->reg = reg;
> +   *dst->reg = *src->reg;
> + }
> + 
> + 
> + 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 (sizeof (CORE_ADDR))
> +     {
> +     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)
> + {
> +   obstack_init (&unwind_tmp_obstack);
> + 
> +   if (dwarf_frame_offset)
> +     {
> +       bfd *abfd = objfile->obfd;
> +       char *start;
> +       char *end;
> + 
> +       dwarf_frame_buffer = dwarf2_read_section (objfile,
> + 						dwarf_frame_offset,
> + 						dwarf_frame_size);
> + 
> +       start = dwarf_frame_buffer;
> +       end = dwarf_frame_buffer + dwarf_frame_size;
> + 
> +       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);
> +     }
> + }
> + 
> + 
> + /* 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 ();
> + }
> Index: gdb/dwarf2cfi.h
> ===================================================================
> RCS file: dwarf2cfi.h
> diff -N dwarf2cfi.h
> *** /dev/null	Tue May  5 13:32:27 1998
> --- dwarf2cfi.h	Thu Sep 27 02:40:43 2001
> ***************
> *** 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: gdb/dwarf2read.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/dwarf2read.c,v
> retrieving revision 1.32
> diff -c -3 -p -r1.32 dwarf2read.c
> *** dwarf2read.c	2001/09/20 03:03:39	1.32
> --- dwarf2read.c	2001/09/27 09:40:43
> *************** static file_ptr dwarf_aranges_offset;
> *** 131,136 ****
> --- 131,137 ----
>   static file_ptr dwarf_loc_offset;
>   static file_ptr dwarf_macinfo_offset;
>   static file_ptr dwarf_str_offset;
> + file_ptr dwarf_frame_offset;
>   
>   static unsigned int dwarf_info_size;
>   static unsigned int dwarf_abbrev_size;
> *************** static unsigned int dwarf_aranges_size;
> *** 140,145 ****
> --- 141,147 ----
>   static unsigned int dwarf_loc_size;
>   static unsigned int dwarf_macinfo_size;
>   static unsigned int dwarf_str_size;
> + unsigned int dwarf_frame_size;
>   
>   /* names of the debugging sections */
>   
> *************** static unsigned int dwarf_str_size;
> *** 151,156 ****
> --- 153,159 ----
>   #define LOC_SECTION      ".debug_loc"
>   #define MACINFO_SECTION  ".debug_macinfo"
>   #define STR_SECTION      ".debug_str"
> + #define FRAME_SECTION    ".debug_frame"
>   
>   /* local data types */
>   
> *************** static void dwarf2_psymtab_to_symtab (st
> *** 578,584 ****
>   
>   static void psymtab_to_symtab_1 (struct partial_symtab *);
>   
> ! static char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int);
>   
>   static void dwarf2_read_abbrevs (bfd *, unsigned int);
>   
> --- 581,587 ----
>   
>   static void psymtab_to_symtab_1 (struct partial_symtab *);
>   
> ! char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int);
>   
>   static void dwarf2_read_abbrevs (bfd *, unsigned int);
>   
> *************** dwarf2_locate_sections (bfd *ignore_abfd
> *** 849,854 ****
> --- 852,862 ----
>         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);
> +     }
>   }
>   
>   /* Build a partial symbol table.  */
> *************** make_cleanup_free_die_list (struct die_i
> *** 3018,3024 ****
>   /* 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 *
>   dwarf2_read_section (struct objfile *objfile, file_ptr offset,
>   		     unsigned int size)
>   {
> --- 3026,3032 ----
>   /* 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.  */
>   
> ! char *
>   dwarf2_read_section (struct objfile *objfile, file_ptr offset,
>   		     unsigned int size)
>   {
> Index: gdb/elfread.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/elfread.c,v
> retrieving revision 1.16
> diff -c -3 -p -r1.16 elfread.c
> *** elfread.c	2001/05/29 10:45:10	1.16
> --- elfread.c	2001/09/27 09:40:44
> ***************
> *** 35,40 ****
> --- 35,45 ----
>   #include "complaints.h"
>   #include "demangle.h"
>   
> + /*  By default don't load dwarf2 unwind frame informations.  */
> + #ifndef DWARF2_BUILD_FRAME_INFO
> + #define DWARF2_BUILD_FRAME_INFO(objfile)
> + #endif
> + 
>   extern void _initialize_elfread (void);
>   
>   /* The struct elfinfo is available only during ELF symbol table and
> *************** elf_symfile_read (struct objfile *objfil
> *** 655,660 ****
> --- 660,667 ----
>   			    ei.dboffset, ei.dbsize,
>   			    ei.lnoffset, ei.lnsize);
>       }
> + 
> +   DWARF2_BUILD_FRAME_INFO(objfile);
>   
>     /* Install any minimal symbols that have been collected as the current
>        minimal symbols for this objfile. */
> Index: gdb/frame.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/frame.h,v
> retrieving revision 1.7
> diff -c -3 -p -r1.7 frame.h
> *** frame.h	2001/08/29 00:51:14	1.7
> --- frame.h	2001/09/27 09:40:44
> *************** struct frame_info
> *** 96,101 ****
> --- 96,105 ----
>          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: gdb/gdbarch.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbarch.c,v
> retrieving revision 1.73
> diff -c -3 -p -r1.73 gdbarch.c
> *** gdbarch.c	2001/09/05 23:44:43	1.73
> --- gdbarch.c	2001/09/27 09:40:44
> *************** struct gdbarch
> *** 251,256 ****
> --- 251,257 ----
>     gdbarch_software_single_step_ftype *software_single_step;
>     gdbarch_print_insn_ftype *print_insn;
>     gdbarch_skip_trampoline_code_ftype *skip_trampoline_code;
> +   gdbarch_dwarf2_build_frame_info_ftype *dwarf2_build_frame_info;
>   };
>   
>   
> *************** struct gdbarch startup_gdbarch =
> *** 387,392 ****
> --- 388,394 ----
>     0,
>     0,
>     0,
> +   0,
>     /* startup_gdbarch() */
>   };
>   
> *************** verify_gdbarch (struct gdbarch *gdbarch)
> *** 785,790 ****
> --- 787,793 ----
>     /* Skip verify of software_single_step, has predicate */
>     /* Skip verify of print_insn, invalid_p == 0 */
>     /* Skip verify of skip_trampoline_code, invalid_p == 0 */
> +   /* Skip verify of dwarf2_build_frame_info, invalid_p == 0 */
>   }
>   
>   
> *************** gdbarch_dump (struct gdbarch *gdbarch, s
> *** 1488,1493 ****
> --- 1491,1503 ----
>                         "SKIP_TRAMPOLINE_CODE(pc)",
>                         XSTRING (SKIP_TRAMPOLINE_CODE (pc)));
>   #endif
> + #if defined (DWARF2_BUILD_FRAME_INFO) && 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
>   #ifdef TARGET_ARCHITECTURE
>     if (TARGET_ARCHITECTURE != NULL)
>       fprintf_unfiltered (file,
> *************** gdbarch_dump (struct gdbarch *gdbarch, s
> *** 2234,2239 ****
> --- 2244,2256 ----
>                           (long) current_gdbarch->skip_trampoline_code
>                           /*SKIP_TRAMPOLINE_CODE ()*/);
>   #endif
> + #ifdef DWARF2_BUILD_FRAME_INFO
> +   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
>     if (current_gdbarch->dump_tdep != NULL)
>       current_gdbarch->dump_tdep (current_gdbarch, file);
>   }
> *************** set_gdbarch_skip_trampoline_code (struct
> *** 4381,4386 ****
> --- 4398,4421 ----
>                                     gdbarch_skip_trampoline_code_ftype skip_trampoline_code)
>   {
>     gdbarch->skip_trampoline_code = skip_trampoline_code;
> + }
> + 
> + 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;
>   }
>   
>   
> Index: gdb/gdbarch.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbarch.h,v
> retrieving revision 1.60
> diff -c -3 -p -r1.60 gdbarch.h
> *** gdbarch.h	2001/09/05 23:44:43	1.60
> --- gdbarch.h	2001/09/27 09:40:44
> *************** extern void set_gdbarch_skip_trampoline_
> *** 1983,1988 ****
> --- 1983,2000 ----
>   #endif
>   #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: gdb/gdbarch.sh
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbarch.sh,v
> retrieving revision 1.77
> diff -c -3 -p -r1.77 gdbarch.sh
> *** gdbarch.sh	2001/09/05 23:44:43	1.77
> --- gdbarch.sh	2001/09/27 09:40:44
> *************** f:2:ADDR_BITS_REMOVE:CORE_ADDR:addr_bits
> *** 541,546 ****
> --- 541,547 ----
>   F:2:SOFTWARE_SINGLE_STEP:void:software_single_step:enum target_signal sig, int insert_breakpoints_p:sig, insert_breakpoints_p::0:0
>   f:2:TARGET_PRINT_INSN:int:print_insn:bfd_vma vma, disassemble_info *info:vma, info:::legacy_print_insn::0
>   f:2:SKIP_TRAMPOLINE_CODE:CORE_ADDR:skip_trampoline_code:CORE_ADDR pc:pc:::generic_skip_trampoline_code::0
> + f:2:DWARF2_BUILD_FRAME_INFO:void:dwarf2_build_frame_info:struct objfile *objfile:objfile:::::0
>   EOF
>   }
>   
> Index: gdb/symfile.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/symfile.h,v
> retrieving revision 1.9
> diff -c -3 -p -r1.9 symfile.h
> *** symfile.h	2001/03/06 08:21:17	1.9
> --- symfile.h	2001/09/27 09:40:45
> *************** dwarf_build_psymtabs (struct objfile *, 
> *** 291,296 ****
> --- 291,297 ----
>   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 */
>   
> 
> 
> -- 
> Jiri Smid
> 
> ---------------------------------------------------------------------
> SuSE CR, s.r.o.                                 e-mail: smid@suse.cz
> Drahobejlova 27                                tel:+420 2 96542 373
> 190 00 Praha 9                                 fax:+420 2 96542 374
> Ceska republika                                http://www.suse.cz
> 
> 


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