From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jim Blandy To: Jiri Smid Cc: gdb-patches@sources.redhat.com Subject: Re: [RFC/RFA] use of dwarf2 unwind informations Date: Tue, 02 Oct 2001 11:12:00 -0000 Message-id: References: X-SW-Source: 2001-10/msg00032.html Jiri Smid 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 > > * dwarf2cfi.c: New file. > * dwarf2cfi.h: New file. > * dwarf2read.c (dwarf_frame_offset, dwarf_frame_size): New > variables. > (dwarf2_read_section): Change to non static. > (dwarf2_locate_sections): Add frame section recognition. > * elfread.c (elf_symfile_read): Add call of frame informations build. > * frame.h (frame_info): Add pointer to unwind_context. > * symfile.h (dwarf2_build_frame_info): Add declaration. > * gdbarch.sh (DWARF2_BUILD_FRAME_INFO): Add. > * gdbarch.h, gdbarch.c: Regenerate. > (FRAME_SECTION): New define. > * Makefile.in: Add dwarf2cfi_h, dwarf2cfi.o, update dependencies. > > Index: gdb/Makefile.in > =================================================================== > RCS file: /cvs/src/src/gdb/Makefile.in,v > retrieving revision 1.116 > diff -c -3 -p -r1.116 Makefile.in > *** Makefile.in 2001/09/21 12:19:15 1.116 > --- Makefile.in 2001/09/27 09:40:43 > *************** cp_abi_h = cp-abi.h > *** 599,604 **** > --- 599,605 ---- > dcache_h = dcache.h > defs_h = defs.h $(xm_h) $(tm_h) $(nm_h) config.status config.h gdbarch.h ui-file.h > doublest_h = doublest.h $(floatformat_h) > + dwarf2cfi_h = dwarf2cfi.h > event_loop_h = event-loop.h > event_top_h = event-top.h > expression_h = expression.h $(doublest_h) $(symtab_h) > *************** dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbco > *** 1324,1329 **** > --- 1325,1333 ---- > > dstread.o: dstread.c $(gdb_string_h) > > + dwarf2cfi.o: dwarf2cfi.c $(defs_h) $(symtab_h) $(symfile_h) $(objfiles_h) \ > + $(target_h) $(inferior_h) $(regcache_h) $(dwarf2cfi_h) > + > dwarfread.o: dwarfread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ > $(expression_h) $(gdbtypes_h) language.h objfiles.h $(symfile_h) \ > $(symtab_h) $(gdb_string_h) > *************** vax-tdep.o: vax-tdep.c $(OP_INCLUDE)/vax > *** 2078,2087 **** > w65-tdep.o : w65-tdep.c $(gdbcore_h) $(regcache_h) > > x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ > ! $(regcache_h) x86-64-tdep.h i386-tdep.h > > x86-64-tdep.o : x86-64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) $(gdbcmd_h) \ > ! $(arch_utils_h) $(regcache_h) $(symfile_h) x86-64-tdep.h i386-tdep.h > > x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ > $(regcache_h) i387-nat.h x86-64-tdep.h i386-tdep.h > --- 2082,2092 ---- > w65-tdep.o : w65-tdep.c $(gdbcore_h) $(regcache_h) > > x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ > ! $(regcache_h) x86-64-tdep.h i386-tdep.h $(dwarf2cfi_h) > > x86-64-tdep.o : x86-64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) $(gdbcmd_h) \ > ! $(arch_utils_h) $(regcache_h) $(symfile_h) x86-64-tdep.h i386-tdep.h \ > ! $(dwarf2cfi_h) > > x86-64-linux-tdep.o : x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ > $(regcache_h) i387-nat.h x86-64-tdep.h i386-tdep.h > Index: gdb/dwarf2cfi.c > =================================================================== > RCS file: dwarf2cfi.c > diff -N dwarf2cfi.c > *** /dev/null Tue May 5 13:32:27 1998 > --- dwarf2cfi.c Thu Sep 27 02:40:43 2001 > *************** > *** 0 **** > --- 1,1723 ---- > + /* Stack unwinding code based on dwarf2 frame info for GDB, the GNU debugger. > + Copyright 2001 > + Free Software Foundation, Inc. > + Contributed by Jiri Smid, SuSE Labs. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 2 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program; if not, write to the Free Software > + Foundation, Inc., 59 Temple Place - Suite 330, > + Boston, MA 02111-1307, USA. */ > + > + #include "defs.h" > + #include "symtab.h" > + #include "symfile.h" > + #include "objfiles.h" > + #include "target.h" > + #include "elf/dwarf2.h" > + #include "inferior.h" > + #include "regcache.h" > + #include "dwarf2cfi.h" > + > + /* Common Information Entry - holds information that is shared among many > + Frame Descriptors. */ > + struct cie_unit > + { > + /* Offset of this unit in dwarf_frame_buffer. */ > + ULONGEST offset; > + > + /* A null-terminated string that identifies the augmentation to this CIE or > + to the FDEs that use it. */ > + char *augmentation; > + > + /* A constant that is factored out of all advance location instructions. */ > + unsigned int code_align; > + > + /* A constant that is factored out of all offset instructions. */ > + int data_align; > + > + /* A constant that indicates which regiter represents the return address > + of a function. */ > + unsigned char ra; > + > + /* Indicates how addresses are encoded. */ > + unsigned char addr_encoding; > + > + /* Pointer and length of the cie program. */ > + char *data; > + unsigned int data_length; > + > + struct objfile *objfile; > + > + /* Next in chain. */ > + struct cie_unit *next; > + }; > + > + /* Frame Description Entry. */ > + struct fde_unit > + { > + /* Address of the first location associated with this entry. */ > + CORE_ADDR initial_location; > + > + /* Length of program section described by this entry. */ > + CORE_ADDR address_range; > + > + /* Pointer to asociated CIE. */ > + struct cie_unit *cie_ptr; > + > + /* Pointer and length of the cie program. */ > + char *data; > + unsigned int data_length; > + }; > + > + struct fde_array > + { > + struct fde_unit **array; > + int elems; > + int array_size; > + }; > + > + struct context_reg > + { > + union > + { > + unsigned int reg; > + long offset; > + CORE_ADDR addr; > + } > + loc; > + enum > + { > + REG_CTX_UNSAVED, > + REG_CTX_SAVED_OFFSET, > + REG_CTX_SAVED_REG, > + REG_CTX_SAVED_ADDR, > + REG_CTX_VALUE, > + } > + how; > + }; > + > + /* This is the register and unwind state for a particular frame. */ > + struct context > + { > + struct context_reg *reg; > + > + CORE_ADDR cfa; > + CORE_ADDR ra; > + void *lsda; > + int args_size; > + }; > + > + struct frame_state_reg > + { > + union > + { > + unsigned int reg; > + long offset; > + unsigned char *exp; > + } > + loc; > + enum > + { > + REG_UNSAVED, > + REG_SAVED_OFFSET, > + REG_SAVED_REG, > + REG_SAVED_EXP, > + } > + how; > + }; > + > + struct frame_state > + { > + /* Each register save state can be described in terms of a CFA slot, > + another register, or a location expression. */ > + struct frame_state_regs > + { > + struct frame_state_reg *reg; > + > + /* Used to implement DW_CFA_remember_state. */ > + struct frame_state_regs *prev; > + } > + regs; > + > + /* The CFA can be described in terms of a reg+offset or a > + location expression. */ > + long cfa_offset; > + int cfa_reg; > + unsigned char *cfa_exp; > + enum > + { > + CFA_UNSET, > + CFA_REG_OFFSET, > + CFA_EXP, > + } > + cfa_how; > + > + /* The PC described by the current frame state. */ > + CORE_ADDR pc; > + > + /* The information we care about from the CIE/FDE. */ > + int data_align; > + unsigned int code_align; > + unsigned char retaddr_column; > + unsigned char addr_encoding; > + > + struct objfile *objfile; > + }; > + > + #define UNWIND_CONTEXT(fi) ((struct context *) (fi->context)) > + > + > + static struct cie_unit *cie_chunks; > + static struct fde_array fde_chunks; > + /* Obstack for allocating temporary storage used during unwind operations. */ > + static struct obstack unwind_tmp_obstack; > + > + extern file_ptr dwarf_frame_offset; > + extern unsigned int dwarf_frame_size; > + > + static char *dwarf_frame_buffer; > + > + > + extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset, > + unsigned int size); > + > + static struct fde_unit *fde_unit_alloc (void); > + static struct cie_unit *cie_unit_alloc (void); > + static void fde_chunks_need_space (); > + > + static struct context *context_alloc (); > + static struct frame_state *frame_state_alloc (); > + static void unwind_tmp_obstack_free (); > + static void context_cpy (struct context *dst, struct context *src); > + > + static unsigned int read_1u (bfd *abfd, char **p); > + static int read_1s (bfd *abfd, char **p); > + static unsigned int read_2u (bfd *abfd, char **p); > + static int read_2s (bfd *abfd, char **p); > + static unsigned int read_4u (bfd *abfd, char **p); > + static int read_4s (bfd *abfd, char **p); > + static ULONGEST read_8u (bfd *abfd, char **p); > + static LONGEST read_8s (bfd *abfd, char **p); > + > + static ULONGEST read_uleb128 (bfd *abfd, char **p); > + static LONGEST read_sleb128 (bfd *abfd, char **p); > + static CORE_ADDR read_pointer (bfd *abfd, char **p); > + static CORE_ADDR read_encoded_pointer (bfd *abfd, char **p, > + unsigned char encoding); > + > + static LONGEST read_initial_length (bfd *abfd, char *buf, int *bytes_read); > + static ULONGEST read_length (bfd *abfd, char *buf, int *bytes_read, > + int dwarf64); > + static ULONGEST read_address (bfd *abfd, char **p); > + > + > + static int is_cie (ULONGEST cie_id, int dwarf64); > + static int compare_fde_unit (const void *a, const void *b); > + void dwarf2_build_frame_info (struct objfile *objfile); > + > + static void execute_cfa_program (struct objfile *objfile, char *insn_ptr, > + char *insn_end, struct context *context, > + struct frame_state *fs); > + static struct fde_unit *get_fde_for_addr (CORE_ADDR pc); > + static void frame_state_for (struct context *context, struct frame_state *fs); > + static void get_reg (char *reg, struct context *context, int regnum); > + static CORE_ADDR execute_stack_op (struct objfile *objfile, > + char *op_ptr, char *op_end, > + struct context *context, CORE_ADDR initial); > + static void update_context (struct context *context, struct frame_state *fs, > + int chain); > + > + > + /* Memory allocation functions. */ > + static struct fde_unit * > + fde_unit_alloc (void) > + { > + struct fde_unit *fde; > + > + fde = (struct fde_unit *) xmalloc (sizeof (struct fde_unit)); > + memset (fde, 0, sizeof (struct fde_unit)); > + return fde; > + } > + > + static struct cie_unit * > + cie_unit_alloc (void) > + { > + struct cie_unit *cie; > + > + cie = (struct cie_unit *) xmalloc (sizeof (struct cie_unit)); > + memset (cie, 0, sizeof (struct cie_unit)); > + return cie; > + } > + > + static void > + fde_chunks_need_space () > + { > + if (fde_chunks.elems < fde_chunks.array_size) > + return; > + fde_chunks.array_size = > + fde_chunks.array_size ? 2 * fde_chunks.array_size : 1024; > + fde_chunks.array = > + xrealloc (fde_chunks.array, > + sizeof (struct fde_unit) * fde_chunks.array_size); > + } > + > + /* Alocate a new `struct context' on temporary obstack. */ > + static struct context * > + context_alloc () > + { > + struct context *context; > + struct context_reg *reg; > + int regs_size = sizeof (struct context_reg) * NUM_REGS; > + > + context = (struct context *) obstack_alloc (&unwind_tmp_obstack, > + sizeof (struct context)); > + memset (context, 0, sizeof (struct context)); > + context->reg = (struct context_reg *) obstack_alloc (&unwind_tmp_obstack, > + regs_size); > + memset (context->reg, 0, regs_size); > + return context; > + } > + > + /* Alocate a new `struct frame_state' on temporary obstack. */ > + static struct frame_state * > + frame_state_alloc () > + { > + struct frame_state *fs; > + struct frame_state_reg *reg; > + int regs_size = sizeof (struct frame_state_reg) * NUM_REGS; > + > + fs = (struct frame_state *) obstack_alloc (&unwind_tmp_obstack, > + sizeof (struct frame_state)); > + memset (fs, 0, sizeof (struct frame_state)); > + fs->regs.reg = (struct frame_state_reg *) obstack_alloc (&unwind_tmp_obstack, > + regs_size); > + memset (fs->regs.reg, 0, regs_size); > + return fs; > + } > + > + static void > + unwind_tmp_obstack_free () > + { > + obstack_free (&unwind_tmp_obstack, NULL); > + obstack_init (&unwind_tmp_obstack); > + } > + > + static void > + context_cpy (struct context *dst, struct context *src) > + { > + struct context_reg *reg = dst->reg; > + *dst = *src; > + dst->reg = reg; > + *dst->reg = *src->reg; > + } > + > + > + static unsigned int > + read_1u (bfd *abfd, char **p) > + { > + unsigned ret; > + > + ret= bfd_get_8 (abfd, (bfd_byte *) *p); > + (*p) ++; > + return ret; > + } > + > + static int > + read_1s (bfd *abfd, char **p) > + { > + int ret; > + > + ret= bfd_get_signed_8 (abfd, (bfd_byte *) *p); > + (*p) ++; > + return ret; > + } > + > + static unsigned int > + read_2u (bfd *abfd, char **p) > + { > + unsigned ret; > + > + ret= bfd_get_16 (abfd, (bfd_byte *) *p); > + (*p) ++; > + return ret; > + } > + > + static int > + read_2s (bfd *abfd, char **p) > + { > + int ret; > + > + ret= bfd_get_signed_16 (abfd, (bfd_byte *) *p); > + (*p) += 2; > + return ret; > + } > + > + static unsigned int > + read_4u (bfd *abfd, char **p) > + { > + unsigned int ret; > + > + ret= bfd_get_32 (abfd, (bfd_byte *) *p); > + (*p) += 4; > + return ret; > + } > + > + static int > + read_4s (bfd *abfd, char **p) > + { > + int ret; > + > + ret= bfd_get_signed_32 (abfd, (bfd_byte *) *p); > + (*p) += 4; > + return ret; > + } > + > + static ULONGEST > + read_8u (bfd *abfd, char **p) > + { > + ULONGEST ret; > + > + ret = bfd_get_64 (abfd, (bfd_byte *) *p); > + (*p) += 8; > + return ret; > + } > + > + static LONGEST > + read_8s (bfd *abfd, char **p) > + { > + LONGEST ret; > + > + ret = bfd_get_signed_64 (abfd, (bfd_byte *) *p); > + (*p) += 8; > + return ret; > + } > + > + static ULONGEST > + read_uleb128 (bfd *abfd, char **p) > + { > + ULONGEST ret; > + int i, shift; > + unsigned char byte; > + > + ret = 0; > + shift = 0; > + i = 0; > + while (1) > + { > + byte = bfd_get_8 (abfd, (bfd_byte *) *p); > + (*p) ++; > + ret |= ((unsigned long) (byte & 127) << shift); > + if ((byte & 128) == 0) > + { > + break; > + } > + shift += 7; > + } > + return ret; > + } > + > + static LONGEST > + read_sleb128 (bfd *abfd, char **p) > + { > + LONGEST ret; > + int i, shift, size, num_read; > + unsigned char byte; > + > + ret = 0; > + shift = 0; > + size = 32; > + num_read = 0; > + i = 0; > + while (1) > + { > + byte = bfd_get_8 (abfd, (bfd_byte *) *p); > + (*p) ++; > + ret |= ((long) (byte & 127) << shift); > + shift += 7; > + if ((byte & 128) == 0) > + { > + break; > + } > + } > + if ((shift < size) && (byte & 0x40)) > + { > + ret |= -(1 << shift); > + } > + return ret; > + } > + > + static CORE_ADDR > + read_pointer (bfd *abfd, char **p) > + { > + switch (sizeof (CORE_ADDR)) > + { > + case 4: > + return read_4u (abfd, p); > + case 8: > + return read_8u (abfd, p); > + default: > + error ("dwarf cfi error: unsupported target address length."); > + } > + } > + > + static CORE_ADDR > + read_encoded_pointer (bfd *abfd, char **p, unsigned char encoding) > + { > + CORE_ADDR ret; > + > + switch (encoding & 0x0f) > + { > + case DW_EH_PE_absptr: > + ret = read_pointer (abfd, p); > + break; > + > + case DW_EH_PE_uleb128: > + ret = read_uleb128 (abfd, p); > + break; > + case DW_EH_PE_sleb128: > + ret = read_sleb128 (abfd, p); > + break; > + > + case DW_EH_PE_udata2: > + ret = read_2u (abfd, p); > + break; > + case DW_EH_PE_udata4: > + ret = read_4u (abfd, p); > + break; > + case DW_EH_PE_udata8: > + ret = read_8u (abfd, p); > + break; > + > + case DW_EH_PE_sdata2: > + ret = read_2s (abfd, p); > + break; > + case DW_EH_PE_sdata4: > + ret = read_4s (abfd, p); > + break; > + case DW_EH_PE_sdata8: > + ret = read_8s (abfd, p); > + break; > + > + default: > + internal_error (__FILE__, __LINE__, > + "read_encoded_pointer: unknown pointer encoding"); > + } > + > + if (ret != 0) > + switch (encoding & 0xf0) > + { > + case DW_EH_PE_absptr: > + break; > + case DW_EH_PE_pcrel: > + ret += (CORE_ADDR) *p; > + break; > + case DW_EH_PE_textrel: > + case DW_EH_PE_datarel: > + case DW_EH_PE_funcrel: > + default: > + internal_error (__FILE__, __LINE__, > + "read_encoded_pointer: unknown pointer encoding"); > + } > + > + return ret; > + } > + > + static LONGEST > + read_initial_length (bfd * abfd, char *buf, int *bytes_read) > + { > + LONGEST ret = 0; > + > + ret = bfd_get_32 (abfd, (bfd_byte *) buf); > + > + if (ret == 0xffffffff) > + { > + ret = bfd_get_64 (abfd, (bfd_byte *) buf + 4); > + *bytes_read = 12; > + } > + else > + { > + *bytes_read = 4; > + } > + > + return ret; > + } > + > + static ULONGEST > + read_length (bfd * abfd, char *buf, int *bytes_read, int dwarf64) > + { > + if (dwarf64) > + { > + *bytes_read = 8; > + return read_8u (abfd, &buf); > + } > + else > + { > + *bytes_read = 4; > + return read_4u (abfd, &buf); > + } > + } > + > + static void > + execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end, > + struct context *context, struct frame_state *fs) > + { > + struct frame_state_regs *unused_rs = NULL; > + > + /* Don't allow remember/restore between CIE and FDE programs. */ > + fs->regs.prev = NULL; > + > + while (insn_ptr < insn_end && fs->pc < context->ra) > + { > + unsigned char insn = *insn_ptr++; > + ULONGEST reg, uoffset; > + LONGEST offset; > + int bytes_read; > + > + if (insn & DW_CFA_advance_loc) > + fs->pc += (insn & 0x3f) * fs->code_align; > + else if (insn & DW_CFA_offset) > + { > + reg = insn & 0x3f; > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + offset = (long) uoffset * fs->data_align; > + fs->regs.reg[reg].how = REG_SAVED_OFFSET; > + fs->regs.reg[reg].loc.offset = offset; > + } > + else if (insn & DW_CFA_restore) > + { > + reg = insn & 0x3f; > + fs->regs.reg[reg].how = REG_UNSAVED; > + } > + else > + switch (insn) > + { > + case DW_CFA_set_loc: > + fs->pc = read_encoded_pointer (objfile->obfd, &insn_ptr, > + fs->addr_encoding); > + break; > + > + case DW_CFA_advance_loc1: > + fs->pc += read_1u (objfile->obfd, &insn_ptr); > + break; > + case DW_CFA_advance_loc2: > + fs->pc += read_2u (objfile->obfd, &insn_ptr); > + break; > + case DW_CFA_advance_loc4: > + fs->pc += read_4u (objfile->obfd, &insn_ptr); > + break; > + > + case DW_CFA_offset_extended: > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + offset = (long) uoffset *fs->data_align; > + fs->regs.reg[reg].how = REG_SAVED_OFFSET; > + fs->regs.reg[reg].loc.offset = offset; > + break; > + > + case DW_CFA_restore_extended: > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->regs.reg[reg].how = REG_UNSAVED; > + break; > + > + case DW_CFA_undefined: > + case DW_CFA_same_value: > + case DW_CFA_nop: > + break; > + > + case DW_CFA_register: > + { > + ULONGEST reg2; > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + reg2 = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->regs.reg[reg].how = REG_SAVED_REG; > + fs->regs.reg[reg].loc.reg = reg2; > + } > + break; > + > + case DW_CFA_remember_state: > + { > + struct frame_state_regs *new_rs; > + if (unused_rs) > + { > + new_rs = unused_rs; > + unused_rs = unused_rs->prev; > + } > + else > + new_rs = xmalloc (sizeof (struct frame_state_regs)); > + > + *new_rs = fs->regs; > + fs->regs.prev = new_rs; > + } > + break; > + > + case DW_CFA_restore_state: > + { > + struct frame_state_regs *old_rs = fs->regs.prev; > + fs->regs = *old_rs; > + old_rs->prev = unused_rs; > + unused_rs = old_rs; > + } > + break; > + > + case DW_CFA_def_cfa: > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->cfa_reg = reg; > + fs->cfa_offset = uoffset; > + fs->cfa_how = CFA_REG_OFFSET; > + break; > + > + case DW_CFA_def_cfa_register: > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->cfa_reg = reg; > + fs->cfa_how = CFA_REG_OFFSET; > + break; > + > + case DW_CFA_def_cfa_offset: > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->cfa_offset = uoffset; > + break; > + > + case DW_CFA_def_cfa_expression: > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->cfa_exp = insn_ptr; > + fs->cfa_how = CFA_EXP; > + insn_ptr += uoffset; > + break; > + > + case DW_CFA_expression: > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->regs.reg[reg].how = REG_SAVED_EXP; > + fs->regs.reg[reg].loc.exp = insn_ptr; > + insn_ptr += uoffset; > + break; > + > + /* From the 2.1 draft. */ > + case DW_CFA_offset_extended_sf: > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + offset = read_sleb128 (objfile->obfd, &insn_ptr); > + offset *= fs->data_align; > + fs->regs.reg[reg].how = REG_SAVED_OFFSET; > + fs->regs.reg[reg].loc.offset = offset; > + break; > + > + case DW_CFA_def_cfa_sf: > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + offset = read_sleb128 (objfile->obfd, &insn_ptr); > + fs->cfa_offset = offset; > + fs->cfa_reg = reg; > + fs->cfa_how = CFA_REG_OFFSET; > + break; > + > + case DW_CFA_def_cfa_offset_sf: > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + fs->cfa_offset = uoffset; > + /* cfa_how deliberately not set. */ > + break; > + > + case DW_CFA_GNU_window_save: > + /* ??? Hardcoded for SPARC register window configuration. */ > + for (reg = 16; reg < 32; ++reg) > + { > + fs->regs.reg[reg].how = REG_SAVED_OFFSET; > + fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *); > + } > + break; > + > + case DW_CFA_GNU_args_size: > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + context->args_size = uoffset; > + break; > + > + case DW_CFA_GNU_negative_offset_extended: > + /* Obsoleted by DW_CFA_offset_extended_sf, but used by > + older PowerPC code. */ > + reg = read_uleb128 (objfile->obfd, &insn_ptr); > + uoffset = read_uleb128 (objfile->obfd, &insn_ptr); > + offset = (long) uoffset *fs->data_align; > + fs->regs.reg[reg].how = REG_SAVED_OFFSET; > + fs->regs.reg[reg].loc.offset = -offset; > + break; > + > + default: > + error ("dwarf cfi error: unknown cfa instruction %d.", insn); > + } > + } > + } > + > + static struct fde_unit * > + get_fde_for_addr (CORE_ADDR pc) > + { > + size_t lo, hi; > + struct fde_unit *fde = NULL; > + lo = 0; > + hi = fde_chunks.elems; > + > + while (lo < hi) > + { > + size_t i = (lo + hi) / 2; > + fde = fde_chunks.array[i]; > + if (pc < fde->initial_location) > + hi = i; > + else if (pc >= fde->initial_location + fde->address_range) > + lo = i + 1; > + else > + return fde; > + } > + return 0; > + } > + > + static void > + frame_state_for (struct context *context, struct frame_state *fs) > + { > + struct fde_unit *fde; > + struct cie_unit *cie; > + unsigned char *aug, *insn, *end; > + > + context->args_size = 0; > + context->lsda = 0; > + > + if ((fde = get_fde_for_addr (context->ra - 1)) != NULL) > + { > + fs->pc = fde->initial_location; > + > + cie = fde->cie_ptr; > + fs->code_align = cie->code_align; > + fs->data_align = cie->data_align; > + fs->retaddr_column = cie->ra; > + fs->addr_encoding = cie->addr_encoding; > + fs->objfile = cie->objfile; > + > + execute_cfa_program (cie->objfile, cie->data, > + cie->data + cie->data_length, context, fs); > + execute_cfa_program (cie->objfile, fde->data, > + fde->data + fde->data_length, context, fs); > + } > + } > + > + static void > + get_reg (char *reg, struct context *context, int regnum) > + { > + switch (context->reg[regnum].how) > + { > + case REG_CTX_UNSAVED: > + read_register_gen (regnum, reg); > + break; > + case REG_CTX_SAVED_OFFSET: > + target_read_memory (context->cfa + context->reg[regnum].loc.offset, > + reg, REGISTER_RAW_SIZE (regnum)); > + break; > + case REG_CTX_SAVED_REG: > + read_register_gen (context->reg[regnum].loc.reg, reg); > + break; > + case REG_CTX_SAVED_ADDR: > + target_read_memory (context->reg[regnum].loc.addr, > + reg, REGISTER_RAW_SIZE (regnum)); > + break; > + case REG_CTX_VALUE: > + memcpy (reg, &context->reg[regnum].loc.addr, > + REGISTER_RAW_SIZE (regnum)); > + break; > + default: > + internal_error (__FILE__, __LINE__, > + "get_reg: unknown register rule"); > + } > + } > + > + /* Decode a DW_OP stack program. Return the top of stack. Push INITIAL > + onto the stack to start. */ > + static CORE_ADDR > + execute_stack_op (struct objfile *objfile, > + char *op_ptr, char *op_end, struct context *context, > + CORE_ADDR initial) > + { > + CORE_ADDR stack[64]; /* ??? Assume this is enough. */ > + int stack_elt; > + > + stack[0] = initial; > + stack_elt = 1; > + > + while (op_ptr < op_end) > + { > + enum dwarf_location_atom op = *op_ptr++; > + ULONGEST result, reg; > + LONGEST offset; > + > + switch (op) > + { > + case DW_OP_lit0: > + case DW_OP_lit1: > + case DW_OP_lit2: > + case DW_OP_lit3: > + case DW_OP_lit4: > + case DW_OP_lit5: > + case DW_OP_lit6: > + case DW_OP_lit7: > + case DW_OP_lit8: > + case DW_OP_lit9: > + case DW_OP_lit10: > + case DW_OP_lit11: > + case DW_OP_lit12: > + case DW_OP_lit13: > + case DW_OP_lit14: > + case DW_OP_lit15: > + case DW_OP_lit16: > + case DW_OP_lit17: > + case DW_OP_lit18: > + case DW_OP_lit19: > + case DW_OP_lit20: > + case DW_OP_lit21: > + case DW_OP_lit22: > + case DW_OP_lit23: > + case DW_OP_lit24: > + case DW_OP_lit25: > + case DW_OP_lit26: > + case DW_OP_lit27: > + case DW_OP_lit28: > + case DW_OP_lit29: > + case DW_OP_lit30: > + case DW_OP_lit31: > + result = op - DW_OP_lit0; > + break; > + > + case DW_OP_addr: > + result = read_pointer (objfile->obfd, &op_ptr); > + break; > + > + case DW_OP_const1u: > + result = read_1u (objfile->obfd, &op_ptr); > + break; > + case DW_OP_const1s: > + result = read_1s (objfile->obfd, &op_ptr); > + break; > + case DW_OP_const2u: > + result = read_2u (objfile->obfd, &op_ptr); > + break; > + case DW_OP_const2s: > + result = read_2s (objfile->obfd, &op_ptr); > + break; > + case DW_OP_const4u: > + result = read_4u (objfile->obfd, &op_ptr); > + break; > + case DW_OP_const4s: > + result = read_4s (objfile->obfd, &op_ptr); > + break; > + case DW_OP_const8u: > + result = read_8u (objfile->obfd, &op_ptr); > + break; > + case DW_OP_const8s: > + result = read_8s (objfile->obfd, &op_ptr); > + break; > + case DW_OP_constu: > + result = read_uleb128 (objfile->obfd, &op_ptr); > + break; > + case DW_OP_consts: > + result = read_sleb128 (objfile->obfd, &op_ptr); > + break; > + > + case DW_OP_reg0: > + case DW_OP_reg1: > + case DW_OP_reg2: > + case DW_OP_reg3: > + case DW_OP_reg4: > + case DW_OP_reg5: > + case DW_OP_reg6: > + case DW_OP_reg7: > + case DW_OP_reg8: > + case DW_OP_reg9: > + case DW_OP_reg10: > + case DW_OP_reg11: > + case DW_OP_reg12: > + case DW_OP_reg13: > + case DW_OP_reg14: > + case DW_OP_reg15: > + case DW_OP_reg16: > + case DW_OP_reg17: > + case DW_OP_reg18: > + case DW_OP_reg19: > + case DW_OP_reg20: > + case DW_OP_reg21: > + case DW_OP_reg22: > + case DW_OP_reg23: > + case DW_OP_reg24: > + case DW_OP_reg25: > + case DW_OP_reg26: > + case DW_OP_reg27: > + case DW_OP_reg28: > + case DW_OP_reg29: > + case DW_OP_reg30: > + case DW_OP_reg31: > + get_reg ((char *) &result, context, op - DW_OP_reg0); > + break; > + case DW_OP_regx: > + reg = read_uleb128 (objfile->obfd, &op_ptr); > + get_reg ((char *) &result, context, reg); > + break; > + > + case DW_OP_breg0: > + case DW_OP_breg1: > + case DW_OP_breg2: > + case DW_OP_breg3: > + case DW_OP_breg4: > + case DW_OP_breg5: > + case DW_OP_breg6: > + case DW_OP_breg7: > + case DW_OP_breg8: > + case DW_OP_breg9: > + case DW_OP_breg10: > + case DW_OP_breg11: > + case DW_OP_breg12: > + case DW_OP_breg13: > + case DW_OP_breg14: > + case DW_OP_breg15: > + case DW_OP_breg16: > + case DW_OP_breg17: > + case DW_OP_breg18: > + case DW_OP_breg19: > + case DW_OP_breg20: > + case DW_OP_breg21: > + case DW_OP_breg22: > + case DW_OP_breg23: > + case DW_OP_breg24: > + case DW_OP_breg25: > + case DW_OP_breg26: > + case DW_OP_breg27: > + case DW_OP_breg28: > + case DW_OP_breg29: > + case DW_OP_breg30: > + case DW_OP_breg31: > + offset = read_sleb128 (objfile->obfd, &op_ptr); > + get_reg ((char *) &result, context, op - DW_OP_breg0); > + result += offset; > + break; > + case DW_OP_bregx: > + reg = read_uleb128 (objfile->obfd, &op_ptr); > + offset = read_sleb128 (objfile->obfd, &op_ptr); > + get_reg ((char *) &result, context, reg); > + result += offset; > + break; > + > + case DW_OP_dup: > + if (stack_elt < 1) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + result = stack[stack_elt - 1]; > + break; > + > + case DW_OP_drop: > + if (--stack_elt < 0) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + goto no_push; > + > + case DW_OP_pick: > + offset = *op_ptr++; > + if (offset >= stack_elt - 1) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + result = stack[stack_elt - 1 - offset]; > + break; > + > + case DW_OP_over: > + if (stack_elt < 2) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + result = stack[stack_elt - 2]; > + break; > + > + case DW_OP_rot: > + { > + CORE_ADDR t1, t2, t3; > + > + if (stack_elt < 3) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + t1 = stack[stack_elt - 1]; > + t2 = stack[stack_elt - 2]; > + t3 = stack[stack_elt - 3]; > + stack[stack_elt - 1] = t2; > + stack[stack_elt - 2] = t3; > + stack[stack_elt - 3] = t1; > + goto no_push; > + } > + > + case DW_OP_deref: > + case DW_OP_deref_size: > + case DW_OP_abs: > + case DW_OP_neg: > + case DW_OP_not: > + case DW_OP_plus_uconst: > + /* Unary operations. */ > + if (--stack_elt < 0) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + result = stack[stack_elt]; > + > + switch (op) > + { > + case DW_OP_deref: > + { > + char *ptr = (char *) result; > + result = read_pointer (objfile->obfd, &ptr); > + } > + break; > + > + case DW_OP_deref_size: > + { > + char *ptr = (char *) result; > + switch (*op_ptr++) > + { > + case 1: > + result = read_1u (objfile->obfd, &ptr); > + break; > + case 2: > + result = read_2u (objfile->obfd, &ptr); > + break; > + case 4: > + result = read_4u (objfile->obfd, &ptr); > + break; > + case 8: > + result = read_8u (objfile->obfd, &ptr); > + break; > + default: > + internal_error (__FILE__, __LINE__, > + "execute_stack_op error"); > + } > + } > + break; > + > + case DW_OP_abs: > + if (result < 0) > + result = -result; > + break; > + case DW_OP_neg: > + result = -result; > + break; > + case DW_OP_not: > + result = ~result; > + break; > + case DW_OP_plus_uconst: > + result += read_uleb128 (objfile->obfd, &op_ptr); > + break; > + } > + break; > + > + case DW_OP_and: > + case DW_OP_div: > + case DW_OP_minus: > + case DW_OP_mod: > + case DW_OP_mul: > + case DW_OP_or: > + case DW_OP_plus: > + case DW_OP_le: > + case DW_OP_ge: > + case DW_OP_eq: > + case DW_OP_lt: > + case DW_OP_gt: > + case DW_OP_ne: > + { > + /* Binary operations. */ > + CORE_ADDR first, second; > + if ((stack_elt -= 2) < 0) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + second = stack[stack_elt]; > + first = stack[stack_elt + 1]; > + > + switch (op) > + { > + case DW_OP_and: > + result = second & first; > + break; > + case DW_OP_div: > + result = (LONGEST) second / (LONGEST) first; > + break; > + case DW_OP_minus: > + result = second - first; > + break; > + case DW_OP_mod: > + result = (LONGEST) second % (LONGEST) first; > + break; > + case DW_OP_mul: > + result = second * first; > + break; > + case DW_OP_or: > + result = second | first; > + break; > + case DW_OP_plus: > + result = second + first; > + break; > + case DW_OP_shl: > + result = second << first; > + break; > + case DW_OP_shr: > + result = second >> first; > + break; > + case DW_OP_shra: > + result = (LONGEST) second >> first; > + break; > + case DW_OP_xor: > + result = second ^ first; > + break; > + case DW_OP_le: > + result = (LONGEST) first <= (LONGEST) second; > + break; > + case DW_OP_ge: > + result = (LONGEST) first >= (LONGEST) second; > + break; > + case DW_OP_eq: > + result = (LONGEST) first == (LONGEST) second; > + break; > + case DW_OP_lt: > + result = (LONGEST) first < (LONGEST) second; > + break; > + case DW_OP_gt: > + result = (LONGEST) first > (LONGEST) second; > + break; > + case DW_OP_ne: > + result = (LONGEST) first != (LONGEST) second; > + break; > + } > + } > + break; > + > + case DW_OP_skip: > + offset = read_2s (objfile->obfd, &op_ptr); > + op_ptr += offset; > + goto no_push; > + > + case DW_OP_bra: > + if (--stack_elt < 0) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + offset = read_2s (objfile->obfd, &op_ptr); > + if (stack[stack_elt] != 0) > + op_ptr += offset; > + goto no_push; > + > + case DW_OP_nop: > + goto no_push; > + > + default: > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + } > + > + /* Most things push a result value. */ > + if ((size_t) stack_elt >= sizeof (stack) / sizeof (*stack)) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + stack[++stack_elt] = result; > + no_push:; > + } > + > + /* We were executing this program to get a value. It should be > + at top of stack. */ > + if (--stack_elt < 0) > + internal_error (__FILE__, __LINE__, "execute_stack_op error"); > + return stack[stack_elt]; > + } > + > + static void > + update_context (struct context *context, struct frame_state *fs, int chain) > + { > + struct context *orig_context; > + CORE_ADDR cfa; > + long i; > + > + orig_context = context_alloc (); > + context_cpy (orig_context, context); > + /* Compute this frame's CFA. */ > + switch (fs->cfa_how) > + { > + case CFA_REG_OFFSET: > + get_reg ((char *) &cfa, context, fs->cfa_reg); > + cfa += fs->cfa_offset; > + break; > + > + case CFA_EXP: > + /* ??? No way of knowing what register number is the stack pointer > + to do the same sort of handling as above. Assume that if the > + CFA calculation is so complicated as to require a stack program > + that this will not be a problem. */ > + { > + char *exp = fs->cfa_exp; > + ULONGEST len; > + > + len = read_uleb128 (fs->objfile->obfd, &exp); > + cfa = (CORE_ADDR) execute_stack_op (fs->objfile, exp, > + exp + len, context, 0); > + break; > + } > + } > + context->cfa = cfa; > + > + if (!chain) > + orig_context->cfa = cfa; > + > + /* Compute the addresses of all registers saved in this frame. */ > + for (i = 0; i < NUM_REGS; ++i) > + switch (fs->regs.reg[i].how) > + { > + case REG_UNSAVED: > + if (i == SP_REGNUM) > + { > + context->reg[i].how = REG_CTX_VALUE; > + context->reg[i].loc.addr = cfa; > + } > + else > + context->reg[i].how = REG_CTX_UNSAVED; > + break; > + case REG_SAVED_OFFSET: > + context->reg[i].how = REG_CTX_SAVED_OFFSET; > + context->reg[i].loc.offset = fs->regs.reg[i].loc.offset; > + break; > + case REG_SAVED_REG: > + switch (orig_context->reg[fs->regs.reg[i].loc.reg].how) > + { > + case REG_CTX_UNSAVED: > + context->reg[i].how = REG_CTX_UNSAVED; > + break; > + case REG_CTX_SAVED_OFFSET: > + context->reg[i].how = REG_CTX_SAVED_OFFSET; > + context->reg[i].loc.offset = orig_context->cfa - context->cfa + > + orig_context->reg[fs->regs.reg[i].loc.reg].loc.offset; > + break; > + case REG_CTX_SAVED_REG: > + context->reg[i].how = REG_CTX_SAVED_REG; > + context->reg[i].loc.reg = > + orig_context->reg[fs->regs.reg[i].loc.reg].loc.reg; > + break; > + case REG_CTX_SAVED_ADDR: > + context->reg[i].how = REG_CTX_SAVED_ADDR; > + context->reg[i].loc.addr = > + orig_context->reg[fs->regs.reg[i].loc.reg].loc.addr; > + default: > + internal_error (__FILE__, __LINE__, > + "cfi_update_context: unknown register rule"); > + } > + break; > + case REG_SAVED_EXP: > + { > + char *exp = fs->regs.reg[i].loc.exp; > + ULONGEST len; > + CORE_ADDR val; > + > + len = read_uleb128 (fs->objfile->obfd, &exp); > + val = execute_stack_op (fs->objfile, exp, exp + len, > + orig_context, cfa); > + context->reg[i].how = REG_CTX_SAVED_ADDR; > + context->reg[i].loc.addr = val; > + } > + break; > + default: > + internal_error (__FILE__, __LINE__, > + "cfi_update_context: unknown register rule"); > + > + } > + get_reg ((char *) &context->ra, context, fs->retaddr_column); > + unwind_tmp_obstack_free (); > + } > + > + static int > + is_cie (ULONGEST cie_id, int dwarf64) > + { > + return dwarf64 ? (cie_id == 0xffffffffffffffff) : (cie_id == 0xffffffff); > + } > + > + static int > + compare_fde_unit (const void *a, const void *b) > + { > + struct fde_unit **first, **second; > + first = (struct fde_unit **) a; > + second = (struct fde_unit **) b; > + if ((*first)->initial_location > (*second)->initial_location) > + return 1; > + else if ((*first)->initial_location < (*second)->initial_location) > + return -1; > + else > + return 0; > + } > + > + /* Build the cie_chunks and fde_chunks tables from informations > + in .debug.frame section. */ > + void > + dwarf2_build_frame_info (struct objfile *objfile) > + { > + obstack_init (&unwind_tmp_obstack); > + > + if (dwarf_frame_offset) > + { > + bfd *abfd = objfile->obfd; > + char *start; > + char *end; > + > + dwarf_frame_buffer = dwarf2_read_section (objfile, > + dwarf_frame_offset, > + dwarf_frame_size); > + > + start = dwarf_frame_buffer; > + end = dwarf_frame_buffer + dwarf_frame_size; > + > + while (start < end) > + { > + unsigned long length; > + ULONGEST cie_id; > + ULONGEST unit_offset = start - dwarf_frame_buffer; > + int bytes_read; > + int dwarf64; > + char *block_end; > + > + length = read_initial_length (abfd, start, &bytes_read); > + start += bytes_read; > + dwarf64 = (bytes_read == 12); > + block_end = start + length; > + > + cie_id = read_length (abfd, start, &bytes_read, dwarf64); > + start += bytes_read; > + > + if (is_cie (cie_id, dwarf64)) > + { > + struct cie_unit *cie = cie_unit_alloc (); > + char *aug; > + > + cie->objfile = objfile; > + cie->next = cie_chunks; > + cie_chunks = cie; > + > + cie->objfile = objfile; > + > + cie->offset = unit_offset; > + > + start++; /* version */ > + > + cie->augmentation = aug = start; > + while (*start) > + start++; > + start++; /* skip past NUL */ > + > + cie->code_align = read_uleb128 (abfd, &start); > + cie->data_align = read_sleb128 (abfd, &start); > + cie->ra = read_1u (abfd, &start); > + > + if (*aug == 'z') > + { > + int xtra = read_uleb128 (abfd, &start); > + start += xtra; > + ++aug; > + } > + > + while (*aug != '\0') > + { > + if (aug[0] == 'e' && aug[1] == 'h') > + { > + start += sizeof (void *); > + aug += 2; > + } > + else if (aug[0] == 'R') > + { > + cie->addr_encoding = *start++; > + aug += 1; > + } > + else if (aug[0] == 'P') > + { > + CORE_ADDR ptr; > + ptr = read_encoded_pointer (abfd, &start, > + cie->addr_encoding); > + aug += 1; > + } > + else > + warning ("unknown augmentation"); > + } > + > + cie->data = start; > + cie->data_length = block_end - start; > + } > + else > + { > + struct fde_unit *fde; > + struct cie_unit *cie; > + > + fde_chunks_need_space (); > + fde = fde_unit_alloc (); > + > + fde_chunks.array[fde_chunks.elems++] = fde; > + fde->initial_location = read_pointer (abfd, &start); > + fde->address_range = read_pointer (abfd, &start); > + > + for (cie = cie_chunks; > + cie && (cie->offset != cie_id); cie = cie->next); > + if (!cie) > + error ("dwarf cfi error: can't find CIE pointer"); > + fde->cie_ptr = cie; > + > + if (cie->augmentation[0] == 'z') > + read_uleb128 (abfd, &start); > + > + fde->data = start; > + fde->data_length = block_end - start; > + } > + start = block_end; > + } > + qsort (fde_chunks.array, fde_chunks.elems, > + sizeof (struct fde_unit *), compare_fde_unit); > + } > + } > + > + > + /* Return the frame address. */ > + CORE_ADDR > + cfi_read_fp () > + { > + struct context *context; > + struct frame_state *fs; > + CORE_ADDR cfa; > + > + context = context_alloc (); > + fs = frame_state_alloc (); > + > + context->ra = read_pc () + 1; > + > + frame_state_for (context, fs); > + update_context (context, fs, 0); > + > + cfa = context->cfa; > + unwind_tmp_obstack_free (); > + return cfa; > + } > + > + /* Store the frame address. */ > + void > + cfi_write_fp (CORE_ADDR val) > + { > + struct context *context; > + struct frame_state *fs; > + > + context = context_alloc (); > + fs = frame_state_alloc (); > + > + context->ra = read_pc () + 1; > + > + frame_state_for (context, fs); > + > + if (fs->cfa_how == CFA_REG_OFFSET) > + { > + val -= fs->cfa_offset; > + write_register_gen (fs->cfa_reg, (char *) &val); > + } > + else > + warning ("Can't write fp."); > + > + unwind_tmp_obstack_free (); > + } > + > + /* Restore the machine to the state it had before the current frame > + was created. */ > + void > + cfi_pop_frame (struct frame_info *fi) > + { > + char regbuf[MAX_REGISTER_RAW_SIZE]; > + int regnum; > + > + fi = get_current_frame (); > + > + for (regnum = 0; regnum < NUM_REGS; regnum++) > + { > + get_reg (regbuf, UNWIND_CONTEXT (fi), regnum); > + write_register_bytes (REGISTER_BYTE (regnum), regbuf, > + REGISTER_RAW_SIZE (regnum)); > + } > + write_register (PC_REGNUM, UNWIND_CONTEXT (fi)->ra); > + > + flush_cached_frames (); > + } > + > + /* Determine the address of the calling function's frame. */ > + CORE_ADDR > + cfi_frame_chain (struct frame_info *fi) > + { > + struct context *context; > + struct frame_state *fs; > + CORE_ADDR cfa; > + > + context = context_alloc (); > + fs = frame_state_alloc (); > + context_cpy (context, UNWIND_CONTEXT (fi)); > + > + /* outermost frame */ > + if (context->ra == 0) > + { > + unwind_tmp_obstack_free (); > + return 0; > + } > + > + frame_state_for (context, fs); > + update_context (context, fs, 1); > + > + cfa = context->cfa; > + unwind_tmp_obstack_free (); > + return cfa; > + } > + > + /* Sets the pc of the frame. */ > + void > + cfi_init_frame_pc (int fromleaf, struct frame_info *fi) > + { > + if (fi->next) > + get_reg ((char *) &(fi->pc), UNWIND_CONTEXT (fi->next), PC_REGNUM); > + else > + fi->pc = read_pc (); > + } > + > + /* Initialize unwind context informations of the frame. */ > + void > + cfi_init_extra_frame_info (int fromleaf, struct frame_info *fi) > + { > + struct frame_state *fs; > + > + fs = frame_state_alloc (); > + fi->context = frame_obstack_alloc (sizeof (struct context)); > + UNWIND_CONTEXT (fi)->reg = > + frame_obstack_alloc (sizeof (struct context_reg) * NUM_REGS); > + memset (UNWIND_CONTEXT (fi)->reg, 0, > + sizeof (struct context_reg) * NUM_REGS); > + > + if (fi->next) > + { > + context_cpy (UNWIND_CONTEXT (fi), UNWIND_CONTEXT (fi->next)); > + frame_state_for (UNWIND_CONTEXT (fi), fs); > + update_context (UNWIND_CONTEXT (fi), fs, 1); > + } > + else > + { > + UNWIND_CONTEXT (fi)->ra = fi->pc + 1; > + frame_state_for (UNWIND_CONTEXT (fi), fs); > + update_context (UNWIND_CONTEXT (fi), fs, 0); > + } > + unwind_tmp_obstack_free (); > + } > + > + /* Obtain return address of the frame. */ > + CORE_ADDR > + cfi_get_ra (struct frame_info *fi) > + { > + return UNWIND_CONTEXT (fi)->ra; > + } > + > + /* Find register number REGNUM relative to FRAME and put its > + (raw) contents in *RAW_BUFFER. Set *OPTIMIZED if the variable > + was optimized out (and thus can't be fetched). If the variable > + was fetched from memory, set *ADDRP to where it was fetched from, > + otherwise it was fetched from a register. > + > + The argument RAW_BUFFER must point to aligned memory. */ > + void > + cfi_get_saved_register (char *raw_buffer, > + int *optimized, > + CORE_ADDR * addrp, > + struct frame_info *frame, > + int regnum, enum lval_type *lval) > + { > + if (!target_has_registers) > + error ("No registers."); > + > + /* Normal systems don't optimize out things with register numbers. */ > + if (optimized != NULL) > + *optimized = 0; > + > + if (addrp) /* default assumption: not found in memory */ > + *addrp = 0; > + > + if (!frame->next) > + { > + read_register_gen (regnum, raw_buffer); > + if (lval != NULL) > + *lval = lval_register; > + if (addrp != NULL) > + *addrp = REGISTER_BYTE (regnum); > + } > + else > + { > + frame = frame->next; > + switch (UNWIND_CONTEXT (frame)->reg[regnum].how) > + { > + case REG_CTX_UNSAVED: > + read_register_gen (regnum, raw_buffer); > + if (lval != NULL) > + *lval = not_lval; > + if (optimized != NULL) > + *optimized = 1; > + break; > + case REG_CTX_SAVED_OFFSET: > + target_read_memory (UNWIND_CONTEXT (frame)->cfa + > + UNWIND_CONTEXT (frame)->reg[regnum].loc.offset, > + raw_buffer, REGISTER_RAW_SIZE (regnum)); > + if (lval != NULL) > + *lval = lval_memory; > + if (addrp != NULL) > + *addrp = > + UNWIND_CONTEXT (frame)->cfa + > + UNWIND_CONTEXT (frame)->reg[regnum].loc.offset; > + break; > + case REG_CTX_SAVED_REG: > + read_register_gen (UNWIND_CONTEXT (frame)->reg[regnum].loc.reg, > + raw_buffer); > + if (lval != NULL) > + *lval = lval_register; > + if (addrp != NULL) > + *addrp = > + REGISTER_BYTE (UNWIND_CONTEXT (frame)->reg[regnum].loc.reg); > + break; > + case REG_CTX_SAVED_ADDR: > + target_read_memory (UNWIND_CONTEXT (frame)->reg[regnum].loc.addr, > + raw_buffer, REGISTER_RAW_SIZE (regnum)); > + if (lval != NULL) > + *lval = lval_memory; > + if (addrp != NULL) > + *addrp = UNWIND_CONTEXT (frame)->reg[regnum].loc.addr; > + break; > + case REG_CTX_VALUE: > + memcpy (raw_buffer, &UNWIND_CONTEXT (frame)->reg[regnum].loc.addr, > + REGISTER_RAW_SIZE (regnum)); > + if (lval != NULL) > + *lval = not_lval; > + if (optimized != NULL) > + *optimized = 0; > + break; > + default: > + internal_error (__FILE__, __LINE__, > + "cfi_get_saved_register: unknown register rule"); > + } > + } > + } > + > + /* Return the register that the function uses for a frame pointer, > + plus any necessary offset to be applied to the register before > + any frame pointer offsets. */ > + void > + cfi_virtual_frame_pointer (CORE_ADDR pc, int *frame_reg, > + LONGEST * frame_offset) > + { > + struct context *context; > + struct frame_state *fs; > + > + context = context_alloc (); > + fs = frame_state_alloc (); > + > + context->ra = read_pc () + 1; > + > + frame_state_for (context, fs); > + > + if (fs->cfa_how == CFA_REG_OFFSET) > + { > + *frame_reg = fs->cfa_reg; > + *frame_offset = fs->cfa_offset; > + } > + else > + error ("dwarf cfi error: CFA is not defined as CFA_REG_OFFSET"); > + > + unwind_tmp_obstack_free (); > + } > Index: gdb/dwarf2cfi.h > =================================================================== > RCS file: dwarf2cfi.h > diff -N dwarf2cfi.h > *** /dev/null Tue May 5 13:32:27 1998 > --- dwarf2cfi.h Thu Sep 27 02:40:43 2001 > *************** > *** 0 **** > --- 1,66 ---- > + /* Stack unwinding code based on dwarf2 frame info for GDB, the GNU debugger. > + Copyright 2001 > + Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 2 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program; if not, write to the Free Software > + Foundation, Inc., 59 Temple Place - Suite 330, > + Boston, MA 02111-1307, USA. */ > + > + #ifndef DWARF2CFI_H > + #define DWARF2CFI_H > + > + /* Return the frame address. */ > + CORE_ADDR cfi_read_fp (); > + > + /* Store the frame address. */ > + void cfi_write_fp (CORE_ADDR val); > + > + /* Restore the machine to the state it had before the current frame > + was created. */ > + void cfi_pop_frame (struct frame_info *); > + > + /* Determine the address of the calling function's frame. */ > + CORE_ADDR cfi_frame_chain (struct frame_info *fi); > + > + /* Sets the pc of the frame. */ > + void cfi_init_frame_pc (int fromleaf, struct frame_info *fi); > + > + /* Initialize unwind context informations of the frame. */ > + void cfi_init_extra_frame_info (int fromleaf, struct frame_info *fi); > + > + /* Obtain return address of the frame. */ > + CORE_ADDR cfi_get_ra (struct frame_info *fi); > + > + /* Find register number REGNUM relative to FRAME and put its > + (raw) contents in *RAW_BUFFER. Set *OPTIMIZED if the variable > + was optimized out (and thus can't be fetched). If the variable > + was fetched from memory, set *ADDRP to where it was fetched from, > + otherwise it was fetched from a register. > + > + The argument RAW_BUFFER must point to aligned memory. */ > + void cfi_get_saved_register (char *raw_buffer, > + int *optimized, > + CORE_ADDR * addrp, > + struct frame_info *frame, > + int regnum, enum lval_type *lval); > + > + /* Return the register that the function uses for a frame pointer, > + plus any necessary offset to be applied to the register before > + any frame pointer offsets. */ > + void cfi_virtual_frame_pointer (CORE_ADDR pc, int *frame_regnum, > + LONGEST * frame_offset); > + > + #endif > Index: gdb/dwarf2read.c > =================================================================== > RCS file: /cvs/src/src/gdb/dwarf2read.c,v > retrieving revision 1.32 > diff -c -3 -p -r1.32 dwarf2read.c > *** dwarf2read.c 2001/09/20 03:03:39 1.32 > --- dwarf2read.c 2001/09/27 09:40:43 > *************** static file_ptr dwarf_aranges_offset; > *** 131,136 **** > --- 131,137 ---- > static file_ptr dwarf_loc_offset; > static file_ptr dwarf_macinfo_offset; > static file_ptr dwarf_str_offset; > + file_ptr dwarf_frame_offset; > > static unsigned int dwarf_info_size; > static unsigned int dwarf_abbrev_size; > *************** static unsigned int dwarf_aranges_size; > *** 140,145 **** > --- 141,147 ---- > static unsigned int dwarf_loc_size; > static unsigned int dwarf_macinfo_size; > static unsigned int dwarf_str_size; > + unsigned int dwarf_frame_size; > > /* names of the debugging sections */ > > *************** static unsigned int dwarf_str_size; > *** 151,156 **** > --- 153,159 ---- > #define LOC_SECTION ".debug_loc" > #define MACINFO_SECTION ".debug_macinfo" > #define STR_SECTION ".debug_str" > + #define FRAME_SECTION ".debug_frame" > > /* local data types */ > > *************** static void dwarf2_psymtab_to_symtab (st > *** 578,584 **** > > static void psymtab_to_symtab_1 (struct partial_symtab *); > > ! static char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int); > > static void dwarf2_read_abbrevs (bfd *, unsigned int); > > --- 581,587 ---- > > static void psymtab_to_symtab_1 (struct partial_symtab *); > > ! char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int); > > static void dwarf2_read_abbrevs (bfd *, unsigned int); > > *************** dwarf2_locate_sections (bfd *ignore_abfd > *** 849,854 **** > --- 852,862 ---- > dwarf_str_offset = sectp->filepos; > dwarf_str_size = bfd_get_section_size_before_reloc (sectp); > } > + else if (STREQ (sectp->name, FRAME_SECTION)) > + { > + dwarf_frame_offset = sectp->filepos; > + dwarf_frame_size = bfd_get_section_size_before_reloc (sectp); > + } > } > > /* Build a partial symbol table. */ > *************** make_cleanup_free_die_list (struct die_i > *** 3018,3024 **** > /* Read the contents of the section at OFFSET and of size SIZE from the > object file specified by OBJFILE into the psymbol_obstack and return it. */ > > ! static char * > dwarf2_read_section (struct objfile *objfile, file_ptr offset, > unsigned int size) > { > --- 3026,3032 ---- > /* Read the contents of the section at OFFSET and of size SIZE from the > object file specified by OBJFILE into the psymbol_obstack and return it. */ > > ! char * > dwarf2_read_section (struct objfile *objfile, file_ptr offset, > unsigned int size) > { > Index: gdb/elfread.c > =================================================================== > RCS file: /cvs/src/src/gdb/elfread.c,v > retrieving revision 1.16 > diff -c -3 -p -r1.16 elfread.c > *** elfread.c 2001/05/29 10:45:10 1.16 > --- elfread.c 2001/09/27 09:40:44 > *************** > *** 35,40 **** > --- 35,45 ---- > #include "complaints.h" > #include "demangle.h" > > + /* By default don't load dwarf2 unwind frame informations. */ > + #ifndef DWARF2_BUILD_FRAME_INFO > + #define DWARF2_BUILD_FRAME_INFO(objfile) > + #endif > + > extern void _initialize_elfread (void); > > /* The struct elfinfo is available only during ELF symbol table and > *************** elf_symfile_read (struct objfile *objfil > *** 655,660 **** > --- 660,667 ---- > ei.dboffset, ei.dbsize, > ei.lnoffset, ei.lnsize); > } > + > + DWARF2_BUILD_FRAME_INFO(objfile); > > /* Install any minimal symbols that have been collected as the current > minimal symbols for this objfile. */ > Index: gdb/frame.h > =================================================================== > RCS file: /cvs/src/src/gdb/frame.h,v > retrieving revision 1.7 > diff -c -3 -p -r1.7 frame.h > *** frame.h 2001/08/29 00:51:14 1.7 > --- frame.h 2001/09/27 09:40:44 > *************** struct frame_info > *** 96,101 **** > --- 96,105 ---- > initialized by INIT_EXTRA_FRAME_INFO */ > struct frame_extra_info *extra_info; > > + /* If dwarf2 unwind frame informations is used, this structure holds all > + related unwind data. */ > + struct unwind_contect *context; > + > /* Pointers to the next (down, inner) and previous (up, outer) > frame_info's in the frame cache. */ > struct frame_info *next; /* down, inner */ > Index: gdb/gdbarch.c > =================================================================== > RCS file: /cvs/src/src/gdb/gdbarch.c,v > retrieving revision 1.73 > diff -c -3 -p -r1.73 gdbarch.c > *** gdbarch.c 2001/09/05 23:44:43 1.73 > --- gdbarch.c 2001/09/27 09:40:44 > *************** struct gdbarch > *** 251,256 **** > --- 251,257 ---- > gdbarch_software_single_step_ftype *software_single_step; > gdbarch_print_insn_ftype *print_insn; > gdbarch_skip_trampoline_code_ftype *skip_trampoline_code; > + gdbarch_dwarf2_build_frame_info_ftype *dwarf2_build_frame_info; > }; > > > *************** struct gdbarch startup_gdbarch = > *** 387,392 **** > --- 388,394 ---- > 0, > 0, > 0, > + 0, > /* startup_gdbarch() */ > }; > > *************** verify_gdbarch (struct gdbarch *gdbarch) > *** 785,790 **** > --- 787,793 ---- > /* Skip verify of software_single_step, has predicate */ > /* Skip verify of print_insn, invalid_p == 0 */ > /* Skip verify of skip_trampoline_code, invalid_p == 0 */ > + /* Skip verify of dwarf2_build_frame_info, invalid_p == 0 */ > } > > > *************** gdbarch_dump (struct gdbarch *gdbarch, s > *** 1488,1493 **** > --- 1491,1503 ---- > "SKIP_TRAMPOLINE_CODE(pc)", > XSTRING (SKIP_TRAMPOLINE_CODE (pc))); > #endif > + #if defined (DWARF2_BUILD_FRAME_INFO) && GDB_MULTI_ARCH > + /* Macro might contain `[{}]' when not multi-arch */ > + fprintf_unfiltered (file, > + "gdbarch_dump: %s # %s\n", > + "DWARF2_BUILD_FRAME_INFO(objfile)", > + XSTRING (DWARF2_BUILD_FRAME_INFO (objfile))); > + #endif > #ifdef TARGET_ARCHITECTURE > if (TARGET_ARCHITECTURE != NULL) > fprintf_unfiltered (file, > *************** gdbarch_dump (struct gdbarch *gdbarch, s > *** 2234,2239 **** > --- 2244,2256 ---- > (long) current_gdbarch->skip_trampoline_code > /*SKIP_TRAMPOLINE_CODE ()*/); > #endif > + #ifdef DWARF2_BUILD_FRAME_INFO > + if (GDB_MULTI_ARCH) > + fprintf_unfiltered (file, > + "gdbarch_dump: DWARF2_BUILD_FRAME_INFO = 0x%08lx\n", > + (long) current_gdbarch->dwarf2_build_frame_info > + /*DWARF2_BUILD_FRAME_INFO ()*/); > + #endif > if (current_gdbarch->dump_tdep != NULL) > current_gdbarch->dump_tdep (current_gdbarch, file); > } > *************** set_gdbarch_skip_trampoline_code (struct > *** 4381,4386 **** > --- 4398,4421 ---- > gdbarch_skip_trampoline_code_ftype skip_trampoline_code) > { > gdbarch->skip_trampoline_code = skip_trampoline_code; > + } > + > + void > + gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch, struct objfile *objfile) > + { > + if (gdbarch->dwarf2_build_frame_info == 0) > + internal_error (__FILE__, __LINE__, > + "gdbarch: gdbarch_dwarf2_build_frame_info invalid"); > + if (gdbarch_debug >= 2) > + fprintf_unfiltered (gdb_stdlog, "gdbarch_dwarf2_build_frame_info called\n"); > + gdbarch->dwarf2_build_frame_info (objfile); > + } > + > + void > + set_gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch, > + gdbarch_dwarf2_build_frame_info_ftype dwarf2_build_frame_info) > + { > + gdbarch->dwarf2_build_frame_info = dwarf2_build_frame_info; > } > > > Index: gdb/gdbarch.h > =================================================================== > RCS file: /cvs/src/src/gdb/gdbarch.h,v > retrieving revision 1.60 > diff -c -3 -p -r1.60 gdbarch.h > *** gdbarch.h 2001/09/05 23:44:43 1.60 > --- gdbarch.h 2001/09/27 09:40:44 > *************** extern void set_gdbarch_skip_trampoline_ > *** 1983,1988 **** > --- 1983,2000 ---- > #endif > #endif > > + typedef void (gdbarch_dwarf2_build_frame_info_ftype) (struct objfile *objfile); > + extern void gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch, struct objfile *objfile); > + extern void set_gdbarch_dwarf2_build_frame_info (struct gdbarch *gdbarch, gdbarch_dwarf2_build_frame_info_ftype *dwarf2_build_frame_info); > + #if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (DWARF2_BUILD_FRAME_INFO) > + #error "Non multi-arch definition of DWARF2_BUILD_FRAME_INFO" > + #endif > + #if GDB_MULTI_ARCH > + #if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (DWARF2_BUILD_FRAME_INFO) > + #define DWARF2_BUILD_FRAME_INFO(objfile) (gdbarch_dwarf2_build_frame_info (current_gdbarch, objfile)) > + #endif > + #endif > + > extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch); > > > Index: gdb/gdbarch.sh > =================================================================== > RCS file: /cvs/src/src/gdb/gdbarch.sh,v > retrieving revision 1.77 > diff -c -3 -p -r1.77 gdbarch.sh > *** gdbarch.sh 2001/09/05 23:44:43 1.77 > --- gdbarch.sh 2001/09/27 09:40:44 > *************** f:2:ADDR_BITS_REMOVE:CORE_ADDR:addr_bits > *** 541,546 **** > --- 541,547 ---- > F:2:SOFTWARE_SINGLE_STEP:void:software_single_step:enum target_signal sig, int insert_breakpoints_p:sig, insert_breakpoints_p::0:0 > f:2:TARGET_PRINT_INSN:int:print_insn:bfd_vma vma, disassemble_info *info:vma, info:::legacy_print_insn::0 > f:2:SKIP_TRAMPOLINE_CODE:CORE_ADDR:skip_trampoline_code:CORE_ADDR pc:pc:::generic_skip_trampoline_code::0 > + f:2:DWARF2_BUILD_FRAME_INFO:void:dwarf2_build_frame_info:struct objfile *objfile:objfile:::::0 > EOF > } > > Index: gdb/symfile.h > =================================================================== > RCS file: /cvs/src/src/gdb/symfile.h,v > retrieving revision 1.9 > diff -c -3 -p -r1.9 symfile.h > *** symfile.h 2001/03/06 08:21:17 1.9 > --- symfile.h 2001/09/27 09:40:45 > *************** dwarf_build_psymtabs (struct objfile *, > *** 291,296 **** > --- 291,297 ---- > extern int dwarf2_has_info (bfd * abfd); > > extern void dwarf2_build_psymtabs (struct objfile *, int); > + extern void dwarf2_build_frame_info (struct objfile *); > > /* From mdebugread.c */ > > > > -- > Jiri Smid > > --------------------------------------------------------------------- > SuSE CR, s.r.o. e-mail: smid@suse.cz > Drahobejlova 27 tel:+420 2 96542 373 > 190 00 Praha 9 fax:+420 2 96542 374 > Ceska republika http://www.suse.cz > >