+++ /dev/null
-/* Stack unwinding code based on dwarf2 frame info for GDB, the GNU debugger.
-
- Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
-
- Contributed by Jiri Smid, SuSE Labs.
- Based on code written by Daniel Berlin (dan@dberlin.org).
-
- 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 "gdbcore.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"
-#include "gdb_assert.h"
-
-/* Common Information Entry - holds information that is shared among many
- Frame Descriptors. */
-struct cie_unit
-{
- /* Offset of this unit in .debug_frame or .eh_frame. */
- 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 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;
-};
-
-enum ptr_encoding
-{
- PE_absptr = DW_EH_PE_absptr,
- PE_pcrel = DW_EH_PE_pcrel,
- PE_textrel = DW_EH_PE_textrel,
- PE_datarel = DW_EH_PE_datarel,
- PE_funcrel = DW_EH_PE_funcrel
-};
-
-#define UNWIND_CONTEXT(fi) ((struct context *) (deprecated_get_frame_context (fi)))
-\f
-
-static struct cie_unit *cie_chunks;
-static struct fde_array fde_chunks;
-/* Obstack for allocating temporary storage used during unwind operations. */
-static struct obstack unwind_tmp_obstack;
-
-extern file_ptr dwarf_frame_offset;
-extern unsigned int dwarf_frame_size;
-extern file_ptr dwarf_eh_frame_offset;
-extern unsigned int dwarf_eh_frame_size;
-extern asection *dwarf_frame_section;
-extern asection *dwarf_eh_frame_section;
-\f
-
-
-extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset,
- unsigned int size, asection *sectp);
-
-static struct fde_unit *fde_unit_alloc (void);
-static struct cie_unit *cie_unit_alloc (void);
-static void fde_chunks_need_space ();
-
-static void unwind_tmp_obstack_init ();
-static void unwind_tmp_obstack_free ();
-
-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 enum ptr_encoding pointer_encoding (unsigned char encoding,
- struct objfile *objfile);
-
-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 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 (void)
-{
- 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. */
-struct context *
-context_alloc (void)
-{
- struct context *context;
-
- 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. */
-struct frame_state *
-frame_state_alloc (void)
-{
- struct frame_state *fs;
-
- 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_init (void)
-{
- obstack_init (&unwind_tmp_obstack);
-}
-
-static void
-unwind_tmp_obstack_free (void)
-{
- obstack_free (&unwind_tmp_obstack, NULL);
- unwind_tmp_obstack_init ();
-}
-
-void
-context_cpy (struct context *dst, struct context *src)
-{
- int regs_size = sizeof (struct context_reg) * NUM_REGS;
- struct context_reg *dreg;
-
- /* Since `struct context' contains a pointer to an array with
- register values, make sure we end up with a copy of that array,
- and not with a copy of the pointer to that array. */
- dreg = dst->reg;
- *dst = *src;
- dst->reg = dreg;
- memcpy (dst->reg, src->reg, regs_size);
-}
-
-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) += 2;
- return ret;
-}
-
-static int
-read_2s (bfd *abfd, char **p)
-{
- int ret;
-
- ret = bfd_get_signed_16 (abfd, (bfd_byte *) * p);
- (*p) += 2;
- return ret;
-}
-
-static unsigned int
-read_4u (bfd *abfd, char **p)
-{
- unsigned int ret;
-
- ret = bfd_get_32 (abfd, (bfd_byte *) * p);
- (*p) += 4;
- return ret;
-}
-
-static int
-read_4s (bfd *abfd, char **p)
-{
- int ret;
-
- ret = bfd_get_signed_32 (abfd, (bfd_byte *) * p);
- (*p) += 4;
- return ret;
-}
-
-static ULONGEST
-read_8u (bfd *abfd, char **p)
-{
- ULONGEST ret;
-
- ret = bfd_get_64 (abfd, (bfd_byte *) * p);
- (*p) += 8;
- return ret;
-}
-
-static LONGEST
-read_8s (bfd *abfd, char **p)
-{
- LONGEST ret;
-
- ret = bfd_get_signed_64 (abfd, (bfd_byte *) * p);
- (*p) += 8;
- return ret;
-}
-
-static ULONGEST
-read_uleb128 (bfd *abfd, char **p)
-{
- ULONGEST ret;
- int i, shift;
- unsigned char byte;
-
- ret = 0;
- shift = 0;
- i = 0;
- while (1)
- {
- byte = bfd_get_8 (abfd, (bfd_byte *) * p);
- (*p)++;
- ret |= ((unsigned long) (byte & 127) << shift);
- if ((byte & 128) == 0)
- {
- break;
- }
- shift += 7;
- }
- return ret;
-}
-
-static LONGEST
-read_sleb128 (bfd *abfd, char **p)
-{
- LONGEST ret;
- int i, shift, size, num_read;
- unsigned char byte;
-
- ret = 0;
- shift = 0;
- size = 32;
- num_read = 0;
- i = 0;
- while (1)
- {
- byte = bfd_get_8 (abfd, (bfd_byte *) * p);
- (*p)++;
- ret |= ((long) (byte & 127) << shift);
- shift += 7;
- if ((byte & 128) == 0)
- {
- break;
- }
- }
- if ((shift < size) && (byte & 0x40))
- {
- ret |= -(1 << shift);
- }
- return ret;
-}
-
-static CORE_ADDR
-read_pointer (bfd *abfd, char **p)
-{
- switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
- {
- case 4:
- return read_4u (abfd, p);
- case 8:
- return read_8u (abfd, p);
- default:
- error
- ("dwarf cfi error: unsupported target address length [in module %s]",
- bfd_get_filename (abfd));
- }
-}
-
-/* Read the appropriate amount of data from *P and return the
- resulting value based on ENCODING, which the calling function must
- provide. */
-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 [in module %s]",
- bfd_get_filename (abfd));
- }
-
- return ret;
-}
-
-/* The variable 'encoding' carries three different flags:
- - encoding & 0x0f : size of the address (handled in read_encoded_pointer())
- - encoding & 0x70 : type (absolute, relative, ...)
- - encoding & 0x80 : indirect flag (DW_EH_PE_indirect == 0x80). */
-enum ptr_encoding
-pointer_encoding (unsigned char encoding, struct objfile *objfile)
-{
- int ret;
-
- if (encoding & DW_EH_PE_indirect)
- warning
- ("CFI: Unsupported pointer encoding: DW_EH_PE_indirect [in module %s]",
- objfile->name);
-
- switch (encoding & 0x70)
- {
- case DW_EH_PE_absptr:
- case DW_EH_PE_pcrel:
- case DW_EH_PE_textrel:
- case DW_EH_PE_datarel:
- case DW_EH_PE_funcrel:
- ret = encoding & 0x70;
- break;
- default:
- internal_error (__FILE__, __LINE__,
- "CFI: unknown pointer encoding [in module %s]",
- objfile->name);
- }
- 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;
-
- 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);
-
- if (pointer_encoding (fs->addr_encoding, objfile) != PE_absptr)
- warning
- ("CFI: DW_CFA_set_loc uses relative addressing [in module %s]",
- objfile->name);
-
- 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 [in module %s]",
- insn, objfile->name);
- }
- }
-}
-
-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;
-
- context->args_size = 0;
- context->lsda = 0;
-
- fde = get_fde_for_addr (context->ra - 1);
-
- if (fde == NULL)
- return;
-
- fs->pc = fde->initial_location;
-
- gdb_assert (fde->cie_ptr != NULL);
-
- 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:
- deprecated_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:
- deprecated_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++;
- CORE_ADDR result;
- ULONGEST 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 [in module %s]",
- objfile->name);
- result = stack[stack_elt - 1];
- break;
-
- case DW_OP_drop:
- if (--stack_elt < 0)
- internal_error (__FILE__, __LINE__,
- "execute_stack_op error [in module %s]",
- objfile->name);
- goto no_push;
-
- case DW_OP_pick:
- offset = *op_ptr++;
- if (offset >= stack_elt - 1)
- internal_error (__FILE__, __LINE__,
- "execute_stack_op error [in module %s]",
- objfile->name);
- result = stack[stack_elt - 1 - offset];
- break;
-
- case DW_OP_over:
- if (stack_elt < 2)
- internal_error (__FILE__, __LINE__,
- "execute_stack_op error [in module %s]",
- objfile->name);
- 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 [in module %s]",
- objfile->name);
- 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 [in module %s]",
- objfile->name);
- result = stack[stack_elt];
-
- switch (op)
- {
- case DW_OP_deref:
- {
- int len = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
- if (len != 4 && len != 8)
- internal_error (__FILE__, __LINE__,
- "execute_stack_op error [in module %s]",
- objfile->name);
- result = read_memory_unsigned_integer (result, len);
- }
- break;
-
- case DW_OP_deref_size:
- {
- int len = *op_ptr++;
- if (len != 1 && len != 2 && len != 4 && len != 8)
- internal_error (__FILE__, __LINE__,
- "execute_stack_op error [in module %s]",
- objfile->name);
- result = read_memory_unsigned_integer (result, len);
- }
- 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;
- default:
- 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 [in module %s]",
- objfile->name);
- 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;
- default:
- error
- ("execute_stack_op: Unknown DW_OP_ value [in module %s]",
- objfile->name);
- 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 [in module %s]",
- objfile->name);
- 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 [in module %s]",
- objfile->name);
- }
-
- /* Most things push a result value. */
- if ((size_t) stack_elt >= sizeof (stack) / sizeof (*stack))
- internal_error (__FILE__, __LINE__,
- "execute_stack_op error [in module %s]",
- objfile->name);
- 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 [in module %s]", objfile->name);
- return stack[stack_elt];
-}
-
-static void
-update_context (struct context *context, struct frame_state *fs, int chain)
-{
- struct context *orig_context;
- CORE_ADDR cfa = 0;
- long i;
-
- unwind_tmp_obstack_init ();
-
- 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;
- }
- default:
- 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;
- break;
- default:
- internal_error (__FILE__, __LINE__, "bad switch 0x%02X",
- orig_context->reg[fs->regs.reg[i].loc.reg].how);
- }
- 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__, "bad switch 0x%02X",
- fs->regs.reg[i].how);
- }
- 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
- found in .debug_frame and .eh_frame sections. */
-/* We can handle both of these sections almost in the same way, however there
- are some exceptions:
- - CIE ID is -1 in debug_frame, but 0 in eh_frame
- - eh_frame may contain some more information that are used only by gcc
- (eg. personality pointer, LSDA pointer, ...). Most of them we can ignore.
- - In debug_frame FDE's item cie_id contains offset of it's parent CIE.
- In eh_frame FDE's item cie_id is a relative pointer to the parent CIE.
- Anyway we don't need to bother with this, because we are smart enough
- to keep the pointer to the parent CIE of oncomming FDEs in 'last_cie'.
- - Although debug_frame items can contain Augmentation as well as
- eh_frame ones, I have never seen them non-empty. Thus only in eh_frame
- we can encounter for example non-absolute pointers (Aug. 'R').
- -- mludvig */
-static void
-parse_frame_info (struct objfile *objfile, file_ptr frame_offset,
- unsigned int frame_size, asection *frame_section,
- int eh_frame)
-{
- bfd *abfd = objfile->obfd;
- asection *curr_section_ptr;
- char *start = NULL;
- char *end = NULL;
- char *frame_buffer = NULL;
- char *curr_section_name, *aug_data;
- struct cie_unit *last_cie = NULL;
- int last_dup_fde = 0;
- int aug_len, i;
- CORE_ADDR curr_section_vma = 0;
-
- unwind_tmp_obstack_init ();
-
- frame_buffer = dwarf2_read_section (objfile, frame_offset, frame_size,
- frame_section);
-
- start = frame_buffer;
- end = frame_buffer + frame_size;
-
- curr_section_name = eh_frame ? ".eh_frame" : ".debug_frame";
- curr_section_ptr = bfd_get_section_by_name (abfd, curr_section_name);
- if (curr_section_ptr)
- curr_section_vma = curr_section_ptr->vma;
-
- if (start)
- {
- while (start < end)
- {
- unsigned long length;
- ULONGEST cie_id;
- ULONGEST unit_offset = start - frame_buffer;
- int bytes_read, dwarf64;
- char *block_end;
-
- length = read_initial_length (abfd, start, &bytes_read);
- start += bytes_read;
- dwarf64 = (bytes_read == 12);
- block_end = start + length;
-
- if (length == 0)
- {
- start = block_end;
- continue;
- }
-
- cie_id = read_length (abfd, start, &bytes_read, dwarf64);
- start += bytes_read;
-
- if ((eh_frame && cie_id == 0) || 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++); /* Skips last NULL as well */
-
- cie->code_align = read_uleb128 (abfd, &start);
- cie->data_align = read_sleb128 (abfd, &start);
- cie->ra = read_1u (abfd, &start);
-
- /* Augmentation:
- z Indicates that a uleb128 is present to size the
- augmentation section.
- L Indicates the encoding (and thus presence) of
- an LSDA pointer in the FDE augmentation.
- R Indicates a non-default pointer encoding for
- FDE code pointers.
- P Indicates the presence of an encoding + language
- personality routine in the CIE augmentation.
-
- [This info comes from GCC's dwarf2out.c]
- */
- if (*aug == 'z')
- {
- aug_len = read_uleb128 (abfd, &start);
- aug_data = start;
- start += aug_len;
- ++aug;
- }
-
- cie->data = start;
- cie->data_length = block_end - cie->data;
-
- while (*aug != '\0')
- {
- if (aug[0] == 'e' && aug[1] == 'h')
- {
- aug_data += sizeof (void *);
- aug++;
- }
- else if (aug[0] == 'R')
- cie->addr_encoding = *aug_data++;
- else if (aug[0] == 'P')
- {
- CORE_ADDR pers_addr;
- int pers_addr_enc;
-
- pers_addr_enc = *aug_data++;
- /* We don't need pers_addr value and so we
- don't care about it's encoding. */
- pers_addr = read_encoded_pointer (abfd, &aug_data,
- pers_addr_enc);
- }
- else if (aug[0] == 'L' && eh_frame)
- {
- int lsda_addr_enc;
-
- /* Perhaps we should save this to CIE for later use?
- Do we need it for something in GDB? */
- lsda_addr_enc = *aug_data++;
- }
- else
- warning ("CFI warning: unknown augmentation \"%c\""
- " in \"%s\" of\n"
- "\t%s", aug[0], curr_section_name,
- objfile->name);
- aug++;
- }
-
- last_cie = cie;
- }
- else
- {
- struct fde_unit *fde;
- struct cie_unit *cie;
- int dup = 0;
- CORE_ADDR init_loc;
-
- /* We assume that debug_frame is in order
- CIE,FDE,CIE,FDE,FDE,... and thus the CIE for this FDE
- should be stored in last_cie pointer. If not, we'll
- try to find it by the older way. */
- if (last_cie)
- cie = last_cie;
- else
- {
- warning ("CFI: last_cie == NULL. "
- "Perhaps a malformed %s section in '%s'...?\n",
- curr_section_name, objfile->name);
-
- cie = cie_chunks;
- while (cie)
- {
- if (cie->objfile == objfile)
- {
- if (eh_frame &&
- (cie->offset ==
- (unit_offset + bytes_read - cie_id)))
- break;
- if (!eh_frame && (cie->offset == cie_id))
- break;
- }
-
- cie = cie->next;
- }
- if (!cie)
- error ("CFI: can't find CIE pointer [in module %s]",
- bfd_get_filename (abfd));
- }
-
- init_loc = read_encoded_pointer (abfd, &start,
- cie->addr_encoding);
-
- switch (pointer_encoding (cie->addr_encoding, objfile))
- {
- case PE_absptr:
- break;
- case PE_pcrel:
- /* start-frame_buffer gives offset from
- the beginning of actual section. */
- init_loc += curr_section_vma + start - frame_buffer;
- break;
- default:
- warning ("CFI: Unsupported pointer encoding [in module %s]",
- bfd_get_filename (abfd));
- }
-
- /* For relocatable objects we must add an offset telling
- where the section is actually mapped in the memory. */
- init_loc += ANOFFSET (objfile->section_offsets,
- SECT_OFF_TEXT (objfile));
-
- /* If we have both .debug_frame and .eh_frame present in
- a file, we must eliminate duplicate FDEs. For now we'll
- run through all entries in fde_chunks and check it one
- by one. Perhaps in the future we can implement a faster
- searching algorithm. */
- /* eh_frame==2 indicates, that this file has an already
- parsed .debug_frame too. When eh_frame==1 it means, that no
- .debug_frame is present and thus we don't need to check for
- duplicities. eh_frame==0 means, that we parse .debug_frame
- and don't need to care about duplicate FDEs, because
- .debug_frame is parsed first. */
- if (eh_frame == 2)
- for (i = 0; eh_frame == 2 && i < fde_chunks.elems; i++)
- {
- /* We assume that FDEs in .debug_frame and .eh_frame
- have the same order (if they are present, of course).
- If we find a duplicate entry for one FDE and save
- it's index to last_dup_fde it's very likely, that
- we'll find an entry for the following FDE right after
- the previous one. Thus in many cases we'll run this
- loop only once. */
- last_dup_fde = (last_dup_fde + i) % fde_chunks.elems;
- if (fde_chunks.array[last_dup_fde]->initial_location
- == init_loc)
- {
- dup = 1;
- break;
- }
- }
-
- /* Allocate a new entry only if this FDE isn't a duplicate of
- something we have already seen. */
- if (!dup)
- {
- fde_chunks_need_space ();
- fde = fde_unit_alloc ();
-
- fde_chunks.array[fde_chunks.elems++] = fde;
-
- fde->initial_location = init_loc;
- fde->address_range = read_encoded_pointer (abfd, &start,
- cie->
- addr_encoding);
-
- fde->cie_ptr = cie;
-
- /* Here we intentionally ignore augmentation data
- from FDE, because we don't need them. */
- if (cie->augmentation[0] == 'z')
- start += 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);
- }
-}
-
-/* We must parse both .debug_frame section and .eh_frame because
- * not all frames must be present in both of these sections. */
-void
-dwarf2_build_frame_info (struct objfile *objfile)
-{
- int after_debug_frame = 0;
-
- /* If we have .debug_frame then the parser is called with
- eh_frame==0 for .debug_frame and eh_frame==2 for .eh_frame,
- otherwise it's only called once for .eh_frame with argument
- eh_frame==1. */
-
- if (dwarf_frame_offset)
- {
- parse_frame_info (objfile, dwarf_frame_offset,
- dwarf_frame_size, dwarf_frame_section,
- 0 /* = debug_frame */ );
- after_debug_frame = 1;
- }
-
- if (dwarf_eh_frame_offset)
- parse_frame_info (objfile, dwarf_eh_frame_offset, dwarf_eh_frame_size,
- dwarf_eh_frame_section,
- 1 /* = eh_frame */ + after_debug_frame);
-}
-
-/* Return the frame address. */
-CORE_ADDR
-cfi_read_fp (void)
-{
- struct context *context;
- struct frame_state *fs;
- CORE_ADDR cfa;
-
- unwind_tmp_obstack_init ();
-
- 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. This function is not used. */
-
-void
-cfi_write_fp (CORE_ADDR val)
-{
- struct context *context;
- struct frame_state *fs;
-
- unwind_tmp_obstack_init ();
-
- 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;
- deprecated_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_SIZE];
- int regnum;
-
- for (regnum = 0; regnum < NUM_REGS; regnum++)
- {
- get_reg (regbuf, UNWIND_CONTEXT (fi), regnum);
- deprecated_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;
-
- unwind_tmp_obstack_init ();
-
- 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. */
-CORE_ADDR
-cfi_init_frame_pc (int fromleaf, struct frame_info *fi)
-{
- if (get_next_frame (fi))
- {
- CORE_ADDR pc;
- /* FIXME: cagney/2002-12-04: This is straight wrong. It's
- assuming that the PC is CORE_ADDR (a host quantity) in size. */
- get_reg ((void *) &pc, UNWIND_CONTEXT (get_next_frame (fi)), PC_REGNUM);
- return pc;
- }
- else
- return 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;
-
- unwind_tmp_obstack_init ();
-
- fs = frame_state_alloc ();
- deprecated_set_frame_context (fi,
- frame_obstack_zalloc (sizeof
- (struct context)));
- UNWIND_CONTEXT (fi)->reg =
- frame_obstack_zalloc (sizeof (struct context_reg) * NUM_REGS);
- memset (UNWIND_CONTEXT (fi)->reg, 0,
- sizeof (struct context_reg) * NUM_REGS);
-
- if (get_next_frame (fi))
- {
- context_cpy (UNWIND_CONTEXT (fi), UNWIND_CONTEXT (get_next_frame (fi)));
- frame_state_for (UNWIND_CONTEXT (fi), fs);
- update_context (UNWIND_CONTEXT (fi), fs, 1);
- }
- else
- {
- UNWIND_CONTEXT (fi)->ra = get_frame_pc (fi) + 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 (!get_next_frame (frame))
- {
- deprecated_read_register_gen (regnum, raw_buffer);
- if (lval != NULL)
- *lval = lval_register;
- if (addrp != NULL)
- *addrp = REGISTER_BYTE (regnum);
- }
- else
- {
- frame = get_next_frame (frame);
- switch (UNWIND_CONTEXT (frame)->reg[regnum].how)
- {
- case REG_CTX_UNSAVED:
- deprecated_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:
- deprecated_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 0x%02X",
- UNWIND_CONTEXT (frame)->reg[regnum].how);
- }
- }
-}
-
-/* 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;
-
- unwind_tmp_obstack_init ();
-
- 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 ();
-}