* [RFC/RFA] use of dwarf2 unwind informations
@ 2001-09-27 2:48 Jiri Smid
2001-10-02 11:12 ` Jim Blandy
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Jiri Smid @ 2001-09-27 2:48 UTC (permalink / raw)
To: gdb-patches
Hello,
This is code which allows gdb to use dwarf2 frame informations for
stack unwinding.
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))
+ \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;
+
+ 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;
+ *dst = *src;
+ dst->reg = reg;
+ *dst->reg = *src->reg;
+ }
+ \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 (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);
+ }
+ }
+ \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 ();
+ }
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
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/RFA] use of dwarf2 unwind informations
2001-09-27 2:48 [RFC/RFA] use of dwarf2 unwind informations Jiri Smid
@ 2001-10-02 11:12 ` Jim Blandy
2001-10-17 9:08 ` Jim Blandy
2001-12-06 15:26 ` Daniel Jacobowitz
2 siblings, 0 replies; 6+ messages in thread
From: Jim Blandy @ 2001-10-02 11:12 UTC (permalink / raw)
To: Jiri Smid; +Cc: gdb-patches
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))
> + \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;
> +
> + 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;
> + *dst = *src;
> + dst->reg = reg;
> + *dst->reg = *src->reg;
> + }
> + \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 (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);
> + }
> + }
> + \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 ();
> + }
> 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
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/RFA] use of dwarf2 unwind informations
2001-09-27 2:48 [RFC/RFA] use of dwarf2 unwind informations Jiri Smid
2001-10-02 11:12 ` Jim Blandy
@ 2001-10-17 9:08 ` Jim Blandy
2001-10-17 9:19 ` Daniel Berlin
2001-12-06 15:26 ` Daniel Jacobowitz
2 siblings, 1 reply; 6+ messages in thread
From: Jim Blandy @ 2001-10-17 9:08 UTC (permalink / raw)
To: Jiri Smid; +Cc: gdb-patches
Jiri Smid <smid@suse.cz> writes:
> This is code which allows gdb to use dwarf2 frame informations for
> stack unwinding.
It looks good; could you commit this?
I have some initial questions, though:
- How can I get GCC to produce .debug_frame sections to test this?
Do you have a patch for GCC I could use, or is there some flag we
can use to simply have GCC divert its .eh_frame contents to a
.debug_frame section?
- It's my understanding that the .eh_frame format used by GCC and the
.debug_frame format described in the Dwarf2 standard are actually
slightly different. Which one does your patch support?
- Is context_cpy correct? It seems to me that it copies the immediate
contents of the `struct context', but then only copies the first
element of the `reg' array.
- The `read_pointer' function assumes `sizeof (CORE_ADDR)' in GDB
gives the size of pointers appearing the Dwarf 2 information. This
confuses a host type (CORE_ADDR) with what I think is supposed to be
a target-sized address. CORE_ADDR is simply the largest unsigned
integer type GDB can find. I think it should use TARGET_ADDR_BIT /
TARGET_CHAR_BIT, unless the Dwarf 2 info specifies the proper size
somewhere, the way it does for .debug_info data.
... Anyway, I'll keep reading. Thanks very much!
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/RFA] use of dwarf2 unwind informations
2001-10-17 9:08 ` Jim Blandy
@ 2001-10-17 9:19 ` Daniel Berlin
2001-10-17 9:26 ` Daniel Berlin
0 siblings, 1 reply; 6+ messages in thread
From: Daniel Berlin @ 2001-10-17 9:19 UTC (permalink / raw)
To: Jim Blandy; +Cc: Jiri Smid, gdb-patches
Jim Blandy <jimb@zwingli.cygnus.com> writes:
> Jiri Smid <smid@suse.cz> writes:
>> This is code which allows gdb to use dwarf2 frame informations for
>> stack unwinding.
>
> It looks good; could you commit this?
>
> I have some initial questions, though:
>
> - How can I get GCC to produce .debug_frame sections to test this?
> Do you have a patch for GCC I could use, or is there some flag we
> can use to simply have GCC divert its .eh_frame contents to a
> .debug_frame section?
Errr, gcc trunk will produce debug_frame info by default for dwarf2
now.
>
> - It's my understanding that the .eh_frame format used by GCC and the
> .debug_frame format described in the Dwarf2 standard are actually
> slightly different. Which one does your patch support?
It depends.
Unless he changed the code i gave him a whole lot, which reading
through the reading portion, he didn't, it should support both.
>
> - Is context_cpy correct? It seems to me that it copies the immediate
> contents of the `struct context', but then only copies the first
> element of the `reg' array.
>
> - The `read_pointer' function assumes `sizeof (CORE_ADDR)' in GDB
> gives the size of pointers appearing the Dwarf 2 information. This
> confuses a host type (CORE_ADDR) with what I think is supposed to be
> a target-sized address. CORE_ADDR is simply the largest unsigned
> integer type GDB can find. I think it should use TARGET_ADDR_BIT /
> TARGET_CHAR_BIT, unless the Dwarf 2 info specifies the proper size
> somewhere, the way it does for .debug_info data.
>
>
> ... Anyway, I'll keep reading. Thanks very much!
--
"I went to court for a parking ticket. I pleaded insanity. I
said, "Your honor, why would anyone in their right mind park in
the passing lane?"
"-Steven Wright
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/RFA] use of dwarf2 unwind informations
2001-10-17 9:19 ` Daniel Berlin
@ 2001-10-17 9:26 ` Daniel Berlin
0 siblings, 0 replies; 6+ messages in thread
From: Daniel Berlin @ 2001-10-17 9:26 UTC (permalink / raw)
To: Daniel Berlin; +Cc: Jim Blandy, Jiri Smid, gdb-patches
Daniel Berlin <dan@cgsoftware.com> writes:
>
>>
>> - It's my understanding that the .eh_frame format used by GCC and the
>> .debug_frame format described in the Dwarf2 standard are actually
>> slightly different. Which one does your patch support?
>
> It depends.
> Unless he changed the code i gave him a whole lot, which reading
> through the reading portion, he didn't, it should support both.
Note that of course, the only code i'm talking about here is the code
to read the debug_frame section, store the necessary info in a sorted
array, and binary searching the array.
The rest is most certainly Jiri's and i don't mean to imply
otherwise.
--
"All the plants in my house are dead -- I shot them last night.
I was torturing them by watering them with ice cubes.
"-Steven Wright
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/RFA] use of dwarf2 unwind informations
2001-09-27 2:48 [RFC/RFA] use of dwarf2 unwind informations Jiri Smid
2001-10-02 11:12 ` Jim Blandy
2001-10-17 9:08 ` Jim Blandy
@ 2001-12-06 15:26 ` Daniel Jacobowitz
2 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2001-12-06 15:26 UTC (permalink / raw)
To: Jiri Smid; +Cc: gdb-patches
On Thu, Sep 27, 2001 at 11:48:28AM +0200, Jiri Smid wrote:
> Hello,
>
> This is code which allows gdb to use dwarf2 frame informations for
> stack unwinding.
>
> 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.
I see that Jim B approved this in October, but it doesn't look like it
was ever committed. What's the status?
--
Daniel Jacobowitz Carnegie Mellon University
MontaVista Software Debian GNU/Linux Developer
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2001-12-06 23:26 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-09-27 2:48 [RFC/RFA] use of dwarf2 unwind informations Jiri Smid
2001-10-02 11:12 ` Jim Blandy
2001-10-17 9:08 ` Jim Blandy
2001-10-17 9:19 ` Daniel Berlin
2001-10-17 9:26 ` Daniel Berlin
2001-12-06 15:26 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox