X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fdwarf2cfi.c;h=085c91cd311f9ed35d40ee33b423830d46a2cd7c;hb=5ef165c2ea8fea1f72c392c3dddc687ca58b1b87;hp=783d1c014e0eea20efa3cbe314e8d4097edddfad;hpb=6c3eb89063d0db649eaecefe767b46d50fa91176;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/dwarf2cfi.c b/gdb/dwarf2cfi.c index 783d1c014e..085c91cd31 100644 --- a/gdb/dwarf2cfi.c +++ b/gdb/dwarf2cfi.c @@ -1,5 +1,7 @@ /* Stack unwinding code based on dwarf2 frame info for GDB, the GNU debugger. - Copyright 2001, 2002 Free Software Foundation, Inc. + + Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Jiri Smid, SuSE Labs. Based on code written by Daniel Berlin (dan@dberlin.org). @@ -21,6 +23,7 @@ Boston, MA 02111-1307, USA. */ #include "defs.h" +#include "gdbcore.h" #include "symtab.h" #include "symfile.h" #include "objfiles.h" @@ -29,12 +32,13 @@ #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 dwarf_frame_buffer. */ + /* Offset of this unit in .debug_frame or .eh_frame. */ ULONGEST offset; /* A null-terminated string that identifies the augmentation to this CIE or @@ -88,37 +92,6 @@ struct fde_array 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 @@ -176,7 +149,16 @@ struct frame_state struct objfile *objfile; }; -#define UNWIND_CONTEXT(fi) ((struct context *) (fi->context)) +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))) static struct cie_unit *cie_chunks; @@ -188,21 +170,20 @@ extern file_ptr dwarf_frame_offset; extern unsigned int dwarf_frame_size; extern file_ptr dwarf_eh_frame_offset; extern unsigned int dwarf_eh_frame_size; - -static char *dwarf_frame_buffer; +extern asection *dwarf_frame_section; +extern asection *dwarf_eh_frame_section; + extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset, - unsigned int size); + 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 struct context *context_alloc (); -static struct frame_state *frame_state_alloc (); +static void unwind_tmp_obstack_init (); 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); @@ -218,6 +199,8 @@ 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, @@ -235,11 +218,12 @@ 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); + 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) @@ -262,7 +246,7 @@ cie_unit_alloc (void) } static void -fde_chunks_need_space () +fde_chunks_need_space (void) { if (fde_chunks.elems < fde_chunks.array_size) return; @@ -274,8 +258,8 @@ fde_chunks_need_space () } /* Alocate a new `struct context' on temporary obstack. */ -static struct context * -context_alloc () +struct context * +context_alloc (void) { struct context *context; @@ -291,8 +275,8 @@ context_alloc () } /* Alocate a new `struct frame_state' on temporary obstack. */ -static struct frame_state * -frame_state_alloc () +struct frame_state * +frame_state_alloc (void) { struct frame_state *fs; @@ -301,40 +285,37 @@ frame_state_alloc () 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); + 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 () +unwind_tmp_obstack_init (void) { - obstack_free (&unwind_tmp_obstack, NULL); 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; - /* Structure dst contains a pointer to an array of - * registers of a given frame as well as src does. This - * array was already allocated before dst was passed to - * context_cpy but the pointer to it was overriden by - * '*dst = *src' and the array was lost. This led to the - * situation, that we've had a copy of src placed in dst, - * but both of them pointed to the same regs array and - * thus we've sometimes blindly rewritten it. Now we save - * the pointer before copying src to dst, return it back - * after that and copy the registers into their new place - * finally. --- mludvig@suse.cz */ + /* 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); } @@ -343,8 +324,8 @@ read_1u (bfd *abfd, char **p) { unsigned ret; - ret= bfd_get_8 (abfd, (bfd_byte *) *p); - (*p) ++; + ret = bfd_get_8 (abfd, (bfd_byte *) * p); + (*p)++; return ret; } @@ -353,8 +334,8 @@ read_1s (bfd *abfd, char **p) { int ret; - ret= bfd_get_signed_8 (abfd, (bfd_byte *) *p); - (*p) ++; + ret = bfd_get_signed_8 (abfd, (bfd_byte *) * p); + (*p)++; return ret; } @@ -363,8 +344,8 @@ read_2u (bfd *abfd, char **p) { unsigned ret; - ret= bfd_get_16 (abfd, (bfd_byte *) *p); - (*p) ++; + ret = bfd_get_16 (abfd, (bfd_byte *) * p); + (*p) += 2; return ret; } @@ -373,7 +354,7 @@ read_2s (bfd *abfd, char **p) { int ret; - ret= bfd_get_signed_16 (abfd, (bfd_byte *) *p); + ret = bfd_get_signed_16 (abfd, (bfd_byte *) * p); (*p) += 2; return ret; } @@ -383,7 +364,7 @@ read_4u (bfd *abfd, char **p) { unsigned int ret; - ret= bfd_get_32 (abfd, (bfd_byte *) *p); + ret = bfd_get_32 (abfd, (bfd_byte *) * p); (*p) += 4; return ret; } @@ -393,7 +374,7 @@ read_4s (bfd *abfd, char **p) { int ret; - ret= bfd_get_signed_32 (abfd, (bfd_byte *) *p); + ret = bfd_get_signed_32 (abfd, (bfd_byte *) * p); (*p) += 4; return ret; } @@ -403,7 +384,7 @@ read_8u (bfd *abfd, char **p) { ULONGEST ret; - ret = bfd_get_64 (abfd, (bfd_byte *) *p); + ret = bfd_get_64 (abfd, (bfd_byte *) * p); (*p) += 8; return ret; } @@ -413,7 +394,7 @@ read_8s (bfd *abfd, char **p) { LONGEST ret; - ret = bfd_get_signed_64 (abfd, (bfd_byte *) *p); + ret = bfd_get_signed_64 (abfd, (bfd_byte *) * p); (*p) += 8; return ret; } @@ -430,8 +411,8 @@ read_uleb128 (bfd *abfd, char **p) i = 0; while (1) { - byte = bfd_get_8 (abfd, (bfd_byte *) *p); - (*p) ++; + byte = bfd_get_8 (abfd, (bfd_byte *) * p); + (*p)++; ret |= ((unsigned long) (byte & 127) << shift); if ((byte & 128) == 0) { @@ -456,8 +437,8 @@ read_sleb128 (bfd *abfd, char **p) i = 0; while (1) { - byte = bfd_get_8 (abfd, (bfd_byte *) *p); - (*p) ++; + byte = bfd_get_8 (abfd, (bfd_byte *) * p); + (*p)++; ret |= ((long) (byte & 127) << shift); shift += 7; if ((byte & 128) == 0) @@ -482,10 +463,15 @@ read_pointer (bfd *abfd, char **p) case 8: return read_8u (abfd, p); default: - error ("dwarf cfi error: unsupported target address length."); + 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) { @@ -526,30 +512,46 @@ read_encoded_pointer (bfd *abfd, char **p, unsigned char encoding) default: internal_error (__FILE__, __LINE__, - "read_encoded_pointer: unknown pointer encoding"); + "read_encoded_pointer: unknown pointer encoding [in module %s]", + bfd_get_filename (abfd)); } - 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; +} + +/* 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) +read_initial_length (bfd *abfd, char *buf, int *bytes_read) { LONGEST ret = 0; @@ -569,7 +571,7 @@ read_initial_length (bfd * abfd, char *buf, int *bytes_read) } static ULONGEST -read_length (bfd * abfd, char *buf, int *bytes_read, int dwarf64) +read_length (bfd *abfd, char *buf, int *bytes_read, int dwarf64) { if (dwarf64) { @@ -584,8 +586,8 @@ read_length (bfd * abfd, char *buf, int *bytes_read, int dwarf64) } static void -execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end, - struct context *context, struct frame_state *fs) +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; @@ -604,7 +606,7 @@ execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end, { reg = insn & 0x3f; uoffset = read_uleb128 (objfile->obfd, &insn_ptr); - offset = (long) uoffset * fs->data_align; + offset = (long) uoffset *fs->data_align; fs->regs.reg[reg].how = REG_SAVED_OFFSET; fs->regs.reg[reg].loc.offset = offset; } @@ -619,6 +621,12 @@ execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end, 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: @@ -766,7 +774,9 @@ execute_cfa_program ( struct objfile *objfile, char *insn_ptr, char *insn_end, break; default: - error ("dwarf cfi error: unknown cfa instruction %d.", insn); + error + ("dwarf cfi error: unknown cfa instruction %d [in module %s]", + insn, objfile->name); } } } @@ -806,28 +816,23 @@ frame_state_for (struct context *context, struct frame_state *fs) if (fde == NULL) return; - + fs->pc = fde->initial_location; - if (fde->cie_ptr) - { - 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); - } - else - internal_error (__FILE__, __LINE__, - "%s(): Internal error: fde->cie_ptr==NULL !", - __func__); + 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 @@ -836,14 +841,14 @@ get_reg (char *reg, struct context *context, int regnum) switch (context->reg[regnum].how) { case REG_CTX_UNSAVED: - read_register_gen (regnum, reg); + 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: - read_register_gen (context->reg[regnum].loc.reg, 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, @@ -854,8 +859,7 @@ get_reg (char *reg, struct context *context, int regnum) REGISTER_RAW_SIZE (regnum)); break; default: - internal_error (__FILE__, __LINE__, - "get_reg: unknown register rule"); + internal_error (__FILE__, __LINE__, "get_reg: unknown register rule"); } } @@ -1035,25 +1039,33 @@ execute_stack_op (struct objfile *objfile, case DW_OP_dup: if (stack_elt < 1) - internal_error (__FILE__, __LINE__, "execute_stack_op error"); + 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"); + 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"); + 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"); + internal_error (__FILE__, __LINE__, + "execute_stack_op error [in module %s]", + objfile->name); result = stack[stack_elt - 2]; break; @@ -1062,7 +1074,9 @@ execute_stack_op (struct objfile *objfile, CORE_ADDR t1, t2, t3; if (stack_elt < 3) - internal_error (__FILE__, __LINE__, "execute_stack_op error"); + 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]; @@ -1080,39 +1094,32 @@ execute_stack_op (struct objfile *objfile, case DW_OP_plus_uconst: /* Unary operations. */ if (--stack_elt < 0) - internal_error (__FILE__, __LINE__, "execute_stack_op error"); + internal_error (__FILE__, __LINE__, + "execute_stack_op error [in module %s]", + objfile->name); result = stack[stack_elt]; switch (op) { case DW_OP_deref: { - char *ptr = (char *) result; - result = read_pointer (objfile->obfd, &ptr); + 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: { - 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"); - } + 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; @@ -1151,7 +1158,9 @@ execute_stack_op (struct objfile *objfile, /* Binary operations. */ CORE_ADDR first, second; if ((stack_elt -= 2) < 0) - internal_error (__FILE__, __LINE__, "execute_stack_op error"); + internal_error (__FILE__, __LINE__, + "execute_stack_op error [in module %s]", + objfile->name); second = stack[stack_elt]; first = stack[stack_elt + 1]; @@ -1208,8 +1217,11 @@ execute_stack_op (struct objfile *objfile, case DW_OP_ne: result = (LONGEST) first != (LONGEST) second; break; - default: /* This label is here just to avoid warning. */ - break; + default: + error + ("execute_stack_op: Unknown DW_OP_ value [in module %s]", + objfile->name); + break; } } break; @@ -1221,7 +1233,9 @@ execute_stack_op (struct objfile *objfile, case DW_OP_bra: if (--stack_elt < 0) - internal_error (__FILE__, __LINE__, "execute_stack_op error"); + 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; @@ -1231,12 +1245,16 @@ execute_stack_op (struct objfile *objfile, goto no_push; default: - internal_error (__FILE__, __LINE__, "execute_stack_op error"); + 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"); + internal_error (__FILE__, __LINE__, + "execute_stack_op error [in module %s]", + objfile->name); stack[++stack_elt] = result; no_push:; } @@ -1244,7 +1262,8 @@ execute_stack_op (struct objfile *objfile, /* 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"); + internal_error (__FILE__, __LINE__, + "execute_stack_op error [in module %s]", objfile->name); return stack[stack_elt]; } @@ -1252,11 +1271,14 @@ static void update_context (struct context *context, struct frame_state *fs, int chain) { struct context *orig_context; - CORE_ADDR cfa; + 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) { @@ -1267,9 +1289,9 @@ update_context (struct context *context, struct frame_state *fs, int chain) 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. */ + 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; @@ -1324,9 +1346,10 @@ update_context (struct context *context, struct frame_state *fs, int chain) 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__, - "%s: unknown register rule", __func__); + internal_error (__FILE__, __LINE__, "bad switch 0x%02X", + orig_context->reg[fs->regs.reg[i].loc.reg].how); } break; case REG_SAVED_EXP: @@ -1343,8 +1366,8 @@ update_context (struct context *context, struct frame_state *fs, int chain) } break; default: - internal_error (__FILE__, __LINE__, - "%s: unknown register rule", __func__); + 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 (); @@ -1371,39 +1394,48 @@ compare_fde_unit (const void *a, const void *b) } /* Build the cie_chunks and fde_chunks tables from informations - in .debug_frame section. */ -void -dwarf2_build_frame_info (struct objfile *objfile) + 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; - int from_eh = 0; + 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; - obstack_init (&unwind_tmp_obstack); + unwind_tmp_obstack_init (); - dwarf_frame_buffer = 0; + frame_buffer = dwarf2_read_section (objfile, frame_offset, frame_size, + frame_section); - if (dwarf_frame_offset) - { - dwarf_frame_buffer = dwarf2_read_section (objfile, - dwarf_frame_offset, - dwarf_frame_size); - - start = dwarf_frame_buffer; - end = dwarf_frame_buffer + dwarf_frame_size; - } - else if (dwarf_eh_frame_offset) - { - dwarf_frame_buffer = dwarf2_read_section (objfile, - dwarf_eh_frame_offset, - dwarf_eh_frame_size); + start = frame_buffer; + end = frame_buffer + frame_size; - start = dwarf_frame_buffer; - end = dwarf_frame_buffer + dwarf_eh_frame_size; - - from_eh = 1; - } + 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) { @@ -1411,9 +1443,8 @@ dwarf2_build_frame_info (struct objfile *objfile) { unsigned long length; ULONGEST cie_id; - ULONGEST unit_offset = start - dwarf_frame_buffer; - int bytes_read; - int dwarf64; + ULONGEST unit_offset = start - frame_buffer; + int bytes_read, dwarf64; char *block_end; length = read_initial_length (abfd, start, &bytes_read); @@ -1421,10 +1452,16 @@ dwarf2_build_frame_info (struct objfile *objfile) 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 ((from_eh && cie_id == 0) || is_cie (cie_id, dwarf64)) + if ((eh_frame && cie_id == 0) || is_cie (cie_id, dwarf64)) { struct cie_unit *cie = cie_unit_alloc (); char *aug; @@ -1440,84 +1477,188 @@ dwarf2_build_frame_info (struct objfile *objfile) start++; /* version */ cie->augmentation = aug = start; - while (*start) - start++; - start++; /* skip past NUL */ + 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') { - int xtra = read_uleb128 (abfd, &start); - start += xtra; + 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') { - start += sizeof (void *); - aug += 2; + aug_data += sizeof (void *); + aug++; } else if (aug[0] == 'R') + cie->addr_encoding = *aug_data++; + else if (aug[0] == 'P') { - cie->addr_encoding = *start++; - aug += 1; + 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] == 'P') + else if (aug[0] == 'L' && eh_frame) { - CORE_ADDR ptr; - ptr = read_encoded_pointer (abfd, &start, - cie->addr_encoding); - aug += 1; + 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 ("%s(): unknown augmentation", __func__); + warning ("CFI warning: unknown augmentation \"%c\"" + " in \"%s\" of\n" + "\t%s", aug[0], curr_section_name, + objfile->name); + aug++; } - cie->data = start; - cie->data_length = block_end - start; + 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); - fde_chunks_need_space (); - fde = fde_unit_alloc (); + 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)); + } - fde_chunks.array[fde_chunks.elems++] = fde; - - fde->initial_location = read_pointer (abfd, &start) - + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - fde->address_range = read_pointer (abfd, &start); + init_loc = read_encoded_pointer (abfd, &start, + cie->addr_encoding); - cie = cie_chunks; - while(cie) - { - if (cie->objfile == objfile) + switch (pointer_encoding (cie->addr_encoding, objfile)) { - if (from_eh && (cie->offset == (unit_offset + bytes_read - cie_id))) - break; - if (!from_eh && (cie->offset == cie_id)) - break; + 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)); } - cie = cie->next; - } - - if (!cie) - error ("%s(): can't find CIE pointer", __func__); - fde->cie_ptr = cie; + /* 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 (); - if (cie->augmentation[0] == 'z') - read_uleb128 (abfd, &start); + fde_chunks.array[fde_chunks.elems++] = fde; - fde->data = start; - fde->data_length = block_end - start; + 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; } @@ -1525,16 +1666,43 @@ dwarf2_build_frame_info (struct objfile *objfile) 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 () +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 (); @@ -1544,7 +1712,9 @@ cfi_read_fp () update_context (context, fs, 0); cfa = context->cfa; + unwind_tmp_obstack_free (); + return cfa; } @@ -1556,6 +1726,8 @@ cfi_write_fp (CORE_ADDR val) struct context *context; struct frame_state *fs; + unwind_tmp_obstack_init (); + context = context_alloc (); fs = frame_state_alloc (); @@ -1566,7 +1738,7 @@ cfi_write_fp (CORE_ADDR val) if (fs->cfa_how == CFA_REG_OFFSET) { val -= fs->cfa_offset; - write_register_gen (fs->cfa_reg, (char *) &val); + deprecated_write_register_gen (fs->cfa_reg, (char *) &val); } else warning ("Can't write fp."); @@ -1579,16 +1751,14 @@ cfi_write_fp (CORE_ADDR val) void cfi_pop_frame (struct frame_info *fi) { - char regbuf[MAX_REGISTER_RAW_SIZE]; + char regbuf[MAX_REGISTER_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)); + deprecated_write_register_bytes (REGISTER_BYTE (regnum), regbuf, + REGISTER_RAW_SIZE (regnum)); } write_register (PC_REGNUM, UNWIND_CONTEXT (fi)->ra); @@ -1603,6 +1773,8 @@ cfi_frame_chain (struct frame_info *fi) struct frame_state *fs; CORE_ADDR cfa; + unwind_tmp_obstack_init (); + context = context_alloc (); fs = frame_state_alloc (); context_cpy (context, UNWIND_CONTEXT (fi)); @@ -1619,18 +1791,24 @@ cfi_frame_chain (struct frame_info *fi) cfa = context->cfa; unwind_tmp_obstack_free (); - + return cfa; } /* Sets the pc of the frame. */ -void +CORE_ADDR cfi_init_frame_pc (int fromleaf, struct frame_info *fi) { - if (fi->next) - get_reg ((char *) &(fi->pc), UNWIND_CONTEXT (fi->next), PC_REGNUM); + 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 - fi->pc = read_pc (); + return read_pc (); } /* Initialize unwind context informations of the frame. */ @@ -1639,25 +1817,30 @@ cfi_init_extra_frame_info (int fromleaf, struct frame_info *fi) { struct frame_state *fs; + unwind_tmp_obstack_init (); + fs = frame_state_alloc (); - fi->context = frame_obstack_alloc (sizeof (struct context)); + deprecated_set_frame_context (fi, + frame_obstack_zalloc (sizeof + (struct context))); UNWIND_CONTEXT (fi)->reg = - frame_obstack_alloc (sizeof (struct context_reg) * NUM_REGS); + frame_obstack_zalloc (sizeof (struct context_reg) * NUM_REGS); memset (UNWIND_CONTEXT (fi)->reg, 0, sizeof (struct context_reg) * NUM_REGS); - if (fi->next) + if (get_next_frame (fi)) { - context_cpy (UNWIND_CONTEXT (fi), UNWIND_CONTEXT (fi->next)); + 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 = fi->pc + 1; + 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 (); } @@ -1678,7 +1861,7 @@ cfi_get_ra (struct frame_info *fi) void cfi_get_saved_register (char *raw_buffer, int *optimized, - CORE_ADDR * addrp, + CORE_ADDR *addrp, struct frame_info *frame, int regnum, enum lval_type *lval) { @@ -1692,9 +1875,9 @@ cfi_get_saved_register (char *raw_buffer, if (addrp) /* default assumption: not found in memory */ *addrp = 0; - if (!frame->next) + if (!get_next_frame (frame)) { - read_register_gen (regnum, raw_buffer); + deprecated_read_register_gen (regnum, raw_buffer); if (lval != NULL) *lval = lval_register; if (addrp != NULL) @@ -1702,11 +1885,11 @@ cfi_get_saved_register (char *raw_buffer, } else { - frame = frame->next; + frame = get_next_frame (frame); switch (UNWIND_CONTEXT (frame)->reg[regnum].how) { case REG_CTX_UNSAVED: - read_register_gen (regnum, raw_buffer); + deprecated_read_register_gen (regnum, raw_buffer); if (lval != NULL) *lval = not_lval; if (optimized != NULL) @@ -1724,8 +1907,8 @@ cfi_get_saved_register (char *raw_buffer, 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); + deprecated_read_register_gen (UNWIND_CONTEXT (frame)->reg[regnum]. + loc.reg, raw_buffer); if (lval != NULL) *lval = lval_register; if (addrp != NULL) @@ -1750,7 +1933,8 @@ cfi_get_saved_register (char *raw_buffer, break; default: internal_error (__FILE__, __LINE__, - "cfi_get_saved_register: unknown register rule"); + "cfi_get_saved_register: unknown register rule 0x%02X", + UNWIND_CONTEXT (frame)->reg[regnum].how); } } } @@ -1765,6 +1949,8 @@ cfi_virtual_frame_pointer (CORE_ADDR pc, int *frame_reg, struct context *context; struct frame_state *fs; + unwind_tmp_obstack_init (); + context = context_alloc (); fs = frame_state_alloc ();