diff -r 1af5c1be89f8 -r 92d87f2e53c2 tools/elf4rom/libs/dwarf-20071209/libdwarf/dwarf_frame.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/elf4rom/libs/dwarf-20071209/libdwarf/dwarf_frame.c Fri Jan 15 09:07:44 2010 +0000 @@ -0,0 +1,2359 @@ +/* + + Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, + Mountain View, CA 94043, or: + + http://www.sgi.com + + For further information regarding this notice, see: + + http://oss.sgi.com/projects/GenInfo/NoticeExplan + +*/ +/* The address of the Free Software Foundation is + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. + SGI has moved from the Crittenden Lane address. +*/ + + + + + +#include "config.h" +#include "dwarf_incl.h" +#include +#include +#include "dwarf_frame.h" +#include "dwarf_arange.h" /* Using Arange as a way to build a + list */ + +#define FDE_NULL_CHECKS_AND_SET_DBG(fde,dbg ) \ + do { \ + if ((fde) == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); \ + return (DW_DLV_ERROR); \ + } \ + (dbg)= (fde)->fd_dbg; \ + if ((dbg) == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);\ + return (DW_DLV_ERROR); \ + } } while (0) + + +#define MIN(a,b) (((a) < (b))? a:b) + +static void _dwarf_init_regrule_table(struct Dwarf_Reg_Rule_s *t1reg, + int last_reg_num, + int initial_value); +static int dwarf_initialize_fde_table(Dwarf_Debug dbg, + struct Dwarf_Frame_s *fde_table, + unsigned table_real_data_size, + Dwarf_Error * error); +static void dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table); + +#if 0 +/* Only used for debugging libdwarf. */ +static void dump_frame_rule(char *msg, + struct Dwarf_Reg_Rule_s *reg_rule); +#endif + + + +/* + This function is the heart of the debug_frame stuff. Don't even + think of reading this without reading both the Libdwarf and + consumer API carefully first. This function basically executes + frame instructions contained in a Cie or an Fde, but does in a + number of different ways depending on the information sought. + Start_instr_ptr points to the first byte of the frame instruction + stream, and final_instr_ptr to the to the first byte after the + last. + + The offsets returned in the frame instructions are factored. That + is they need to be multiplied by either the code_alignment_factor + or the data_alignment_factor, as appropriate to obtain the actual + offset. This makes it possible to expand an instruction stream + without the corresponding Cie. However, when an Fde frame instr + sequence is being expanded there must be a valid Cie with a pointer + to an initial table row. + + + If successful, returns DW_DLV_OK + And sets returned_count thru the pointer + if make_instr is true. + If make_instr is false returned_count + should NOT be used by the caller (returned_count + is set to 0 thru the pointer by this routine...) + If unsuccessful, returns DW_DLV_ERROR + and sets returned_error to the error code + + It does not do a whole lot of input validation being a private + function. Please make sure inputs are valid. + + (1) If make_instr is true, it makes a list of pointers to + Dwarf_Frame_Op structures containing the frame instructions + executed. A pointer to this list is returned in ret_frame_instr. + Make_instr is true only when a list of frame instructions is to be + returned. In this case since we are not interested in the contents + of the table, the input Cie can be NULL. This is the only case + where the inpute Cie can be NULL. + + (2) If search_pc is true, frame instructions are executed till + either a location is reached that is greater than the search_pc_val + provided, or all instructions are executed. At this point the + last row of the table generated is returned in a structure. + A pointer to this structure is supplied in table. + + (3) This function is also used to create the initial table row + defined by a Cie. In this case, the Dwarf_Cie pointer cie, is + NULL. For an FDE, however, cie points to the associated Cie. + + make_instr - make list of frame instr? 0/1 + ret_frame_instr - Ptr to list of ptrs to frame instrs + search_pc - Search for a pc value? 0/1 + search_pc_val - Search for this pc value + initial_loc - Initial code location value. + start_instr_ptr - Ptr to start of frame instrs. + final_instr_ptr - Ptr just past frame instrs. + table - Ptr to struct with last row. + cie - Ptr to Cie used by the Fde. + +*/ + +int +_dwarf_exec_frame_instr(Dwarf_Bool make_instr, + Dwarf_Frame_Op ** ret_frame_instr, + Dwarf_Bool search_pc, + Dwarf_Addr search_pc_val, + Dwarf_Addr initial_loc, + Dwarf_Small * start_instr_ptr, + Dwarf_Small * final_instr_ptr, + Dwarf_Frame table, + Dwarf_Cie cie, + Dwarf_Debug dbg, + Dwarf_Half reg_num_of_cfa, + Dwarf_Sword * returned_count, + int *returned_error) +{ +#define ERROR_IF_REG_NUM_TOO_HIGH(macreg,machigh_reg) \ + do { \ + if ((macreg) >= (machigh_reg) || (macreg) < 0) { \ + SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH); \ + } \ + } /*CONSTCOND */ while(0) +#define SIMPLE_ERROR_RETURN(code) \ + free(localregtab); \ + *returned_error = code; \ + return DW_DLV_ERROR + + /* Sweeps the frame instructions. */ + Dwarf_Small *instr_ptr; + + /* Register numbers not limited to just 255, thus not using + Dwarf_Small. */ + typedef int reg_num_type; + + Dwarf_Unsigned factored_N_value; + Dwarf_Signed signed_factored_N_value; + Dwarf_Addr current_loc = initial_loc; /* code location/ + pc-value + corresponding to the + frame instructions. + Starts at zero when + the caller has no + value to pass in. */ + + /* Must be min de_pointer_size bytes and must be at least sizeof + Dwarf_ufixed */ + Dwarf_Unsigned adv_loc; + + int reg_count = dbg->de_frame_reg_rules_entry_count; + struct Dwarf_Reg_Rule_s *localregtab = calloc(reg_count, + sizeof(struct + Dwarf_Reg_Rule_s)); + + struct Dwarf_Reg_Rule_s cfa_reg; + + + /* This is used to end executing frame instructions. */ + /* Becomes true when search_pc is true and current_loc */ + /* is greater than search_pc_val. */ + Dwarf_Bool search_over = false; + + /* Used by the DW_FRAME_advance_loc instr */ + /* to hold the increment in pc value. */ + Dwarf_Addr adv_pc; + + /* Contains the length in bytes of */ + /* an leb128 encoded number. */ + Dwarf_Word leb128_length; + + /* Counts the number of frame instructions executed. */ + Dwarf_Word instr_count = 0; + + /* + These contain the current fields of the current frame + instruction. */ + Dwarf_Small fp_base_op = 0; + Dwarf_Small fp_extended_op; + reg_num_type fp_register; + + /* The value in fp_offset may be signed, though we call it + unsigned. This works ok for 2-s complement arithmetic. */ + Dwarf_Unsigned fp_offset; + Dwarf_Off fp_instr_offset; + + /* + Stack_table points to the row (Dwarf_Frame ie) being pushed or + popped by a remember or restore instruction. Top_stack points to + the top of the stack of rows. */ + Dwarf_Frame stack_table; + Dwarf_Frame top_stack = NULL; + + /* + These are used only when make_instr is true. Curr_instr is a + pointer to the current frame instruction executed. + Curr_instr_ptr, head_instr_list, and curr_instr_list are used to + form a chain of Dwarf_Frame_Op structs. Dealloc_instr_ptr is + used to deallocate the structs used to form the chain. + Head_instr_block points to a contiguous list of pointers to the + Dwarf_Frame_Op structs executed. */ + Dwarf_Frame_Op *curr_instr; + Dwarf_Chain curr_instr_item, dealloc_instr_item; + Dwarf_Chain head_instr_chain = NULL; + Dwarf_Chain tail_instr_chain = NULL; + Dwarf_Frame_Op *head_instr_block; + + /* + These are the alignment_factors taken from the Cie provided. + When no input Cie is provided they are set to 1, because only + factored offsets are required. */ + Dwarf_Sword code_alignment_factor = 1; + Dwarf_Sword data_alignment_factor = 1; + + /* + This flag indicates when an actual alignment factor is needed. + So if a frame instruction that computes an offset using an + alignment factor is encountered when this flag is set, an error + is returned because the Cie did not have a valid augmentation. */ + Dwarf_Bool need_augmentation = false; + + Dwarf_Word i; + + /* Initialize first row from associated Cie. Using temp regs + explicity */ + + + if (localregtab == 0) { + SIMPLE_ERROR_RETURN(DW_DLE_ALLOC_FAIL); + } + { + struct Dwarf_Reg_Rule_s *t1reg = localregtab; + struct Dwarf_Reg_Rule_s *t1end = t1reg + reg_count; + + if (cie != NULL && cie->ci_initial_table != NULL) { + struct Dwarf_Reg_Rule_s *t2reg = + cie->ci_initial_table->fr_reg; + + if (reg_count != cie->ci_initial_table->fr_reg_count) { + /* Should never happen, it makes no sense to have the + table sizes change. There is no real allowance for + the set of registers to change dynamically in a + single Dwarf_Debug (except the size can be set near + initial Dwarf_Debug creation time). */ + SIMPLE_ERROR_RETURN + (DW_DLE_FRAME_REGISTER_COUNT_MISMATCH); + } + + for (; t1reg < t1end; t1reg++, t2reg++) { + *t1reg = *t2reg; + } + cfa_reg = cie->ci_initial_table->fr_cfa_rule; + } else { + _dwarf_init_regrule_table(t1reg, + reg_count, + dbg->de_frame_rule_initial_value); + _dwarf_init_regrule_table(&cfa_reg, 1, + dbg->de_frame_rule_initial_value); + } + } + + /* + The idea here is that the code_alignment_factor and + data_alignment_factor which are needed for certain instructions + are valid only when the Cie has a proper augmentation string. So + if the augmentation is not right, only Frame instruction can be + read. */ + if (cie != NULL && cie->ci_augmentation != NULL) { + code_alignment_factor = cie->ci_code_alignment_factor; + data_alignment_factor = cie->ci_data_alignment_factor; + } else { + need_augmentation = !make_instr; + } + + instr_ptr = start_instr_ptr; + while ((instr_ptr < final_instr_ptr) && (!search_over)) { + Dwarf_Small instr = 0; + Dwarf_Small opcode = 0; + reg_num_type reg_no = 0; + + + fp_instr_offset = instr_ptr - start_instr_ptr; + instr = *(Dwarf_Small *) instr_ptr; + instr_ptr += sizeof(Dwarf_Small); + + fp_base_op = (instr & 0xc0) >> 6; + if ((instr & 0xc0) == 0x00) { + opcode = instr; /* is really extended op */ + fp_extended_op = (instr & (~(0xc0))) & 0xff; + } else { + opcode = instr & 0xc0; /* is base op */ + fp_extended_op = 0; + } + + fp_register = 0; + fp_offset = 0; + switch (opcode) { + case DW_CFA_advance_loc: + { + /* base op */ + fp_offset = adv_pc = instr & DW_FRAME_INSTR_OFFSET_MASK; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_pc = adv_pc * code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_pc > search_pc_val); + /* If gone past pc needed, retain old pc. */ + if (!search_over) + current_loc = current_loc + adv_pc; + break; + } + + case DW_CFA_offset: + { /* base op */ + reg_no = + (reg_num_type) (instr & DW_FRAME_INSTR_OFFSET_MASK); + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr = instr_ptr + leb128_length; + + fp_register = reg_no; + fp_offset = factored_N_value; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset_or_block_len = + factored_N_value * data_alignment_factor; + + break; + } + + case DW_CFA_restore: + { /* base op */ + reg_no = (instr & DW_FRAME_INSTR_OFFSET_MASK); + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + fp_register = reg_no; + + if (cie != NULL && cie->ci_initial_table != NULL) + localregtab[reg_no] = + cie->ci_initial_table->fr_reg[reg_no]; + else if (!make_instr) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_MAKE_INSTR_NO_INIT); + } + + break; + } + case DW_CFA_set_loc: + { + Dwarf_Addr new_loc = 0; + + READ_UNALIGNED(dbg, new_loc, Dwarf_Addr, + instr_ptr, dbg->de_pointer_size); + instr_ptr += dbg->de_pointer_size; + if (new_loc != 0 && current_loc != 0) { + /* Pre-relocation or before current_loc is set the + test comparing new_loc and current_loc makes no + sense. Testing for non-zero (above) is a way + (fallible) to check that current_loc, new_loc + are already relocated. */ + if (new_loc <= current_loc) { + /* Within a frame, address must increase. + Seemingly it has not. Seems to be an error. */ + + SIMPLE_ERROR_RETURN + (DW_DLE_DF_NEW_LOC_LESS_OLD_LOC); + } + } + + search_over = search_pc && (new_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) + current_loc = new_loc; + fp_offset = new_loc; + break; + } + + case DW_CFA_advance_loc1: + { + fp_offset = adv_loc = *(Dwarf_Small *) instr_ptr; + instr_ptr += sizeof(Dwarf_Small); + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_loc *= code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) + current_loc = current_loc + adv_loc; + break; + } + + case DW_CFA_advance_loc2: + { + READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned, + instr_ptr, sizeof(Dwarf_Half)); + instr_ptr += sizeof(Dwarf_Half); + fp_offset = adv_loc; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_loc *= code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) + current_loc = current_loc + adv_loc; + break; + } + + case DW_CFA_advance_loc4: + { + READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned, + instr_ptr, sizeof(Dwarf_ufixed)); + instr_ptr += sizeof(Dwarf_ufixed); + fp_offset = adv_loc; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_loc *= code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) + current_loc = current_loc + adv_loc; + break; + } + + case DW_CFA_offset_extended: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);; + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset_or_block_len = factored_N_value * + data_alignment_factor; + + fp_register = reg_no; + fp_offset = factored_N_value; + break; + } + + case DW_CFA_restore_extended: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + if (cie != NULL && cie->ci_initial_table != NULL) { + localregtab[reg_no] = cie->ci_initial_table->fr_reg[reg_no]; + } else { + if (!make_instr) { + SIMPLE_ERROR_RETURN + (DW_DLE_DF_MAKE_INSTR_NO_INIT); + } + } + + fp_register = reg_no; + break; + } + + case DW_CFA_undefined: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + localregtab[reg_no].ru_is_off = 0; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = DW_FRAME_UNDEFINED_VAL; + localregtab[reg_no].ru_offset_or_block_len = 0; + + fp_register = reg_no; + break; + } + + case DW_CFA_same_value: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + localregtab[reg_no].ru_is_off = 0; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = DW_FRAME_SAME_VAL; + localregtab[reg_no].ru_offset_or_block_len = 0; + fp_register = reg_no; + break; + } + + case DW_CFA_register: + { + Dwarf_Unsigned lreg; + reg_num_type reg_noA = 0; + reg_num_type reg_noB = 0; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_noA = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_noA, reg_count); + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_noB = (reg_num_type) lreg; + + if (reg_noB > reg_count) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH); + } + + + localregtab[reg_noA].ru_is_off = 0; + localregtab[reg_noA].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_noA].ru_register = reg_noB; + localregtab[reg_noA].ru_offset_or_block_len = 0; + + fp_register = reg_noA; + fp_offset = reg_noB; + break; + } + + case DW_CFA_remember_state: + { + stack_table = (Dwarf_Frame) + _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1); + if (stack_table == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + for (i = 0; i < reg_count; i++) + stack_table->fr_reg[i] = localregtab[i]; + + if (top_stack != NULL) + stack_table->fr_next = top_stack; + top_stack = stack_table; + + break; + } + + case DW_CFA_restore_state: + { + if (top_stack == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_POP_EMPTY_STACK); + } + stack_table = top_stack; + top_stack = stack_table->fr_next; + + for (i = 0; i < reg_count; i++) + localregtab[i] = stack_table->fr_reg[i]; + + dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME); + break; + } + + case DW_CFA_def_cfa: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_register = reg_no; + cfa_reg.ru_offset_or_block_len = factored_N_value; + + fp_register = reg_no; + fp_offset = factored_N_value; + break; + } + + case DW_CFA_def_cfa_register: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + cfa_reg.ru_register = reg_no; + /* Do NOT set ru_offset_or_block_len or ru_is_off here. + See dwarf2/3 spec. */ + fp_register = reg_no; + break; + } + + case DW_CFA_def_cfa_offset: + { + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_offset_or_block_len = factored_N_value; + + fp_offset = factored_N_value; + break; + } + case DW_CFA_nop: + { + break; + } + /* DWARF3 ops begin here. */ + case DW_CFA_def_cfa_expression: + { + /* A single DW_FORM_block representing a dwarf + expression. The form block establishes the way to + compute the CFA. */ + Dwarf_Unsigned block_len = 0; + + DECODE_LEB128_UWORD(instr_ptr, block_len); + cfa_reg.ru_is_off = 0; /* arbitrary */ + cfa_reg.ru_value_type = DW_EXPR_EXPRESSION; + cfa_reg.ru_offset_or_block_len = block_len; + cfa_reg.ru_block = instr_ptr; + fp_offset = (Dwarf_Unsigned) instr_ptr; + + } + break; + case DW_CFA_expression: + { + /* An unsigned leb128 value is the first operand (a + register number). The second operand is single + DW_FORM_block representing a dwarf expression. The + evaluator pushes the CFA on the evaluation stack + then evaluates the expression to compute the value + of the register contents. */ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned block_len = 0; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + DECODE_LEB128_UWORD(instr_ptr, block_len); + localregtab[lreg].ru_is_off = 0; /* arbitrary */ + localregtab[lreg].ru_value_type = DW_EXPR_EXPRESSION; + localregtab[lreg].ru_offset_or_block_len = block_len; + localregtab[lreg].ru_block = instr_ptr; + fp_offset = (Dwarf_Unsigned) instr_ptr; + fp_register = reg_no; + + } + break; + case DW_CFA_cfa_offset_extended_sf: + { + /* The first operand is an unsigned leb128 register + number. The second is a signed factored offset. + Identical to DW_CFA_offset_extended except the + secondoperand is signed */ + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_register = reg_no; + fp_offset = signed_factored_N_value; + } + break; + case DW_CFA_def_cfa_sf: + { + /* The first operand is an unsigned leb128 register + number. The second is a signed leb128 factored + offset. Identical to DW_CFA_def_cfa except that the + second operand is signed and factored. */ + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_register = reg_no; + cfa_reg.ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_register = reg_no; + fp_offset = signed_factored_N_value; + } + break; + case DW_CFA_def_cfa_offset_sf: + { + /* The operand is a signed leb128 operand representing + a factored offset. Identical to + DW_CFA_def_cfa_offset excep the operand is signed + and factored. */ + + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_offset = signed_factored_N_value; + } + break; + case DW_CFA_val_offset: + { + /* The first operand is an unsigned leb128 register + number. The second is a factored unsigned offset. + Makes the register be a val_offset(N) rule with N = + factored_offset*data_alignment_factor. */ + + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET; + localregtab[reg_no].ru_offset_or_block_len = + factored_N_value * data_alignment_factor; + + fp_offset = factored_N_value; + break; + } + case DW_CFA_val_offset_sf: + { + /* The first operand is an unsigned leb128 register + number. The second is a factored signed offset. + Makes the register be a val_offset(N) rule with N = + factored_offset*data_alignment_factor. */ + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET; + localregtab[reg_no].ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_offset = signed_factored_N_value; + + } + break; + case DW_CFA_val_expression: + { + /* The first operand is an unsigned leb128 register + number. The second is a DW_FORM_block representing a + DWARF expression. The rule for the register number + becomes a val_expression(E) rule. */ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned block_len = 0; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + DECODE_LEB128_UWORD(instr_ptr, block_len); + localregtab[lreg].ru_is_off = 0; /* arbitrary */ + localregtab[lreg].ru_value_type = DW_EXPR_VAL_EXPRESSION; + localregtab[lreg].ru_offset_or_block_len = block_len; + localregtab[lreg].ru_block = instr_ptr; + fp_offset = (Dwarf_Unsigned) instr_ptr; + + instr_ptr += block_len; + fp_register = reg_no; + + } + break; + + /* END DWARF3 new ops. */ + + +#ifdef DW_CFA_GNU_window_save + case DW_CFA_GNU_window_save: + { + /* no information: this just tells unwinder to restore + the window registers from the previous frame's + window save area */ + break; + } +#endif +#ifdef DW_CFA_GNU_args_size + /* single uleb128 is the current arg area size in bytes. No + register exists yet to save this in */ + case DW_CFA_GNU_args_size: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + break; + } +#endif + default: + /* ERROR, we have an opcode we know nothing about. Memory + leak here, but an error like this is not supposed to + happen so we ignore the leak. These used to be ignored, + now we notice and report. */ + SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR); + + } + + if (make_instr) { + instr_count++; + + curr_instr = (Dwarf_Frame_Op *) + _dwarf_get_alloc(dbg, DW_DLA_FRAME_OP, 1); + if (curr_instr == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + curr_instr->fp_base_op = fp_base_op; + curr_instr->fp_extended_op = fp_extended_op; + curr_instr->fp_register = fp_register; + curr_instr->fp_offset = fp_offset; + curr_instr->fp_instr_offset = fp_instr_offset; + + curr_instr_item = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_instr_item == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + curr_instr_item->ch_item = curr_instr; + if (head_instr_chain == NULL) + head_instr_chain = tail_instr_chain = curr_instr_item; + else { + tail_instr_chain->ch_next = curr_instr_item; + tail_instr_chain = curr_instr_item; + } + } + } + + /* + If frame instruction decoding was right we would stop exactly at + final_instr_ptr. */ + if (instr_ptr > final_instr_ptr) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR); + } + + /* Create the last row generated. */ + if (table != NULL) { + + struct Dwarf_Reg_Rule_s *t2reg = table->fr_reg; + struct Dwarf_Reg_Rule_s *t3reg = localregtab; + struct Dwarf_Reg_Rule_s *t3end = t3reg + reg_count; + + table->fr_loc = current_loc; + for (; t3reg < t3end; t3reg++, t2reg++) { + *t2reg = *t3reg; + } + + /* CONSTCOND */ + if (reg_num_of_cfa < reg_count) { + t2reg = table->fr_reg + reg_num_of_cfa; + /* Update both the old DW_FRAME_CFA_COL row and the new + fr_cfa_rule with the cfa_reg, this is the old-style + update. */ + *t2reg = cfa_reg; + } + table->fr_cfa_rule = cfa_reg; + } + + /* Dealloc anything remaining on stack. */ + for (; top_stack != NULL;) { + stack_table = top_stack; + top_stack = top_stack->fr_next; + dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME); + } + + if (make_instr) { + /* Allocate list of pointers to Dwarf_Frame_Op's. */ + head_instr_block = (Dwarf_Frame_Op *) + _dwarf_get_alloc(dbg, DW_DLA_FRAME_BLOCK, instr_count); + if (head_instr_block == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + /* + Store pointers to Dwarf_Frame_Op's in this list and + deallocate the structs that chain the Dwarf_Frame_Op's. */ + curr_instr_item = head_instr_chain; + for (i = 0; i < instr_count; i++) { + *(head_instr_block + i) = + *(Dwarf_Frame_Op *) curr_instr_item->ch_item; + dealloc_instr_item = curr_instr_item; + curr_instr_item = curr_instr_item->ch_next; + dwarf_dealloc(dbg, dealloc_instr_item->ch_item, + DW_DLA_FRAME_OP); + dwarf_dealloc(dbg, dealloc_instr_item, DW_DLA_CHAIN); + } + *ret_frame_instr = head_instr_block; + + *returned_count = (Dwarf_Sword) instr_count; + } else { + *returned_count = 0; + } + free(localregtab); + return DW_DLV_OK; +#undef ERROR_IF_REG_NUM_TOO_HIGH +#undef SIMPLE_ERROR_RETURN +} + +/* Depending on version, either read the return address register + as a ubyte or as an leb number. + The form of this value changed for DWARF3. +*/ +Dwarf_Unsigned +_dwarf_get_return_address_reg(Dwarf_Small * frame_ptr, + int version, unsigned long *size) +{ + Dwarf_Unsigned uvalue = 0; + Dwarf_Word leb128_length = 0; + + if (version == 1) { + *size = 1; + uvalue = *(unsigned char *) frame_ptr; + return uvalue; + } + uvalue = _dwarf_decode_u_leb128(frame_ptr, &leb128_length); + *size = leb128_length; + return uvalue; +} + + +/* Trivial consumer function. +*/ +int +dwarf_get_cie_of_fde(Dwarf_Fde fde, + Dwarf_Cie * cie_returned, Dwarf_Error * error) +{ + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + *cie_returned = fde->fd_cie; + return DW_DLV_OK; + +} + +/* + For g++ .eh_frame fde and cie. + the cie id is different as the + definition of the cie_id in an fde + is the distance back from the address of the + value to the cie. + Or 0 if this is a true cie. + Non standard dwarf, designed this way to be + convenient at run time for an allocated + (mapped into memory as part of the running image) section. +*/ +int +dwarf_get_fde_list_eh(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Error * error) +{ + int res; + + res = + _dwarf_load_section(dbg, + dbg->de_debug_frame_eh_gnu_index, + &dbg->de_debug_frame_eh_gnu, error); + + if (res != DW_DLV_OK) { + return res; + } + + res = + _dwarf_get_fde_list_internal(dbg, + cie_data, + cie_element_count, + fde_data, + fde_element_count, + dbg->de_debug_frame_eh_gnu, + dbg->de_debug_frame_eh_gnu_index, + dbg->de_debug_frame_size_eh_gnu, + /* cie_id_value */ 0, + /* use_gnu_cie_calc= */ 1, + error); + return res; +} + + + +/* + For standard dwarf .debug_frame + cie_id is -1 in a cie, and + is the section offset in the .debug_frame section + of the cie otherwise. Standard dwarf +*/ +int +dwarf_get_fde_list(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Error * error) +{ + int res; + + res = + _dwarf_load_section(dbg, + dbg->de_debug_frame_index, + &dbg->de_debug_frame, error); + + if (res != DW_DLV_OK) { + return res; + } + + res = + _dwarf_get_fde_list_internal(dbg, cie_data, + cie_element_count, + fde_data, + fde_element_count, + dbg->de_debug_frame, + dbg->de_debug_frame_index, + dbg->de_debug_frame_size, + DW_CIE_ID, + /* use_gnu_cie_calc= */ 0, + error); + + return res; +} + + +/* + Only works on dwarf sections, not eh_frame + Given a Dwarf_Die, see if it has a + DW_AT_MIPS_fde attribute and if so use that + to get an fde offset. + Then create a Dwarf_Fde to return thru the ret_fde pointer. + Also creates a cie (pointed at from the Dwarf_Fde). +*/ +int +dwarf_get_fde_for_die(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Fde * ret_fde, Dwarf_Error * error) +{ + Dwarf_Attribute attr; + Dwarf_Unsigned fde_offset = 0; + Dwarf_Signed signdval = 0; + Dwarf_Fde new_fde = 0; + unsigned char *fde_ptr = 0; + unsigned char *cie_ptr = 0; + Dwarf_Unsigned cie_id = 0; + + /* Fields for the current Cie being read. */ + int res; + int resattr; + int sdatares; + + struct cie_fde_prefix_s prefix; + struct cie_fde_prefix_s prefix_c; + + if (die == NULL) { + _dwarf_error(NULL, error, DW_DLE_DIE_NULL); + return (DW_DLV_ERROR); + } + + resattr = dwarf_attr(die, DW_AT_MIPS_fde, &attr, error); + if (resattr != DW_DLV_OK) { + return resattr; + } + + /* why is this formsdata? FIX */ + sdatares = dwarf_formsdata(attr, &signdval, error); + if (sdatares != DW_DLV_OK) { + return sdatares; + } + + res = + _dwarf_load_section(dbg, + dbg->de_debug_frame_index, + &dbg->de_debug_frame, error); + if (res != DW_DLV_OK) { + return res; + } + + fde_offset = signdval; + fde_ptr = (dbg->de_debug_frame + fde_offset); + + + /* First read in the 'common prefix' to figure out what * we are to + do with this entry. */ + memset(&prefix_c, 0, sizeof(prefix_c)); + memset(&prefix, 0, sizeof(prefix)); + res = dwarf_read_cie_fde_prefix(dbg, fde_ptr, + dbg->de_debug_frame, + dbg->de_debug_frame_index, + dbg->de_debug_frame_size, &prefix, + error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) + return res; + fde_ptr = prefix.cf_addr_after_prefix; + cie_id = prefix.cf_cie_id; + /* Pass NULL, not section pointer, for 3rd argument. de_debug_frame + has no eh_frame relevance. */ + res = dwarf_create_fde_from_after_start(dbg, &prefix, + (Dwarf_Small *) NULL, + fde_ptr, + /* use_gnu_cie_calc= */ 0, + /* Dwarf_Cie = */ 0, + &new_fde, error); + + if (res == DW_DLV_ERROR) { + return res; + } else if (res == DW_DLV_NO_ENTRY) { + return res; + } + /* DW_DLV_OK */ + + /* now read the cie corresponding to the fde */ + cie_ptr = new_fde->fd_section_ptr + cie_id; + res = dwarf_read_cie_fde_prefix(dbg, cie_ptr, + dbg->de_debug_frame, + dbg->de_debug_frame_index, + dbg->de_debug_frame_size, + &prefix_c, error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) + return res; + + cie_ptr = prefix_c.cf_addr_after_prefix; + cie_id = prefix_c.cf_cie_id; + + + if (cie_id == DW_CIE_ID) { + int res2 = 0; + Dwarf_Cie new_cie = 0; + + /* Pass NULL, not section pointer, for 3rd argument. + de_debug_frame has no eh_frame relevance. */ + res2 = dwarf_create_cie_from_after_start(dbg, + &prefix_c, + (Dwarf_Small *) NULL, + cie_ptr, + /* cie_count= */ 0, + /* use_gnu_cie_calc= */ + 0, &new_cie, error); + if (res2 == DW_DLV_ERROR) { + dwarf_dealloc(dbg, new_fde, DW_DLA_FDE); + return res; + } else if (res2 == DW_DLV_NO_ENTRY) { + dwarf_dealloc(dbg, new_fde, DW_DLA_FDE); + return res; + } + + + new_fde->fd_cie = new_cie; + + } else { + _dwarf_error(dbg, error, DW_DLE_NO_CIE_FOR_FDE); + return (DW_DLV_ERROR); + } + + *ret_fde = new_fde; + return DW_DLV_OK; +} + +/* A dwarf consumer operation, see the consumer library documentation. +*/ +int +dwarf_get_fde_range(Dwarf_Fde fde, + Dwarf_Addr * low_pc, + Dwarf_Unsigned * func_length, + Dwarf_Ptr * fde_bytes, + Dwarf_Unsigned * fde_byte_length, + Dwarf_Off * cie_offset, + Dwarf_Signed * cie_index, + Dwarf_Off * fde_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + + + /* We have always already done the section load here, so no need to + load the section. We did the section load in order to create the + Dwarf_Fde pointer passed in here. */ + + + if (low_pc != NULL) + *low_pc = fde->fd_initial_location; + if (func_length != NULL) + *func_length = fde->fd_address_range; + if (fde_bytes != NULL) + *fde_bytes = fde->fd_fde_start; + if (fde_byte_length != NULL) + *fde_byte_length = fde->fd_length; + if (cie_offset != NULL) + *cie_offset = fde->fd_cie_offset; + if (cie_index != NULL) + *cie_index = fde->fd_cie_index; + if (fde_offset != NULL) + *fde_offset = fde->fd_fde_start - fde->fd_section_ptr; + + return DW_DLV_OK; +} + +/* IRIX specific function. The exception tables + have C++ destructor information and are + at present undocumented. */ +int +dwarf_get_fde_exception_info(Dwarf_Fde fde, + Dwarf_Signed * + offset_into_exception_tables, + Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + *offset_into_exception_tables = + fde->fd_offset_into_exception_tables; + return DW_DLV_OK; +} + + +/* A consumer code function. + Given a CIE pointer, return the normal CIE data thru + pointers. + Special augmentation data is not returned here. +*/ +int +dwarf_get_cie_info(Dwarf_Cie cie, + Dwarf_Unsigned * bytes_in_cie, + Dwarf_Small * ptr_to_version, + char **augmenter, + Dwarf_Unsigned * code_alignment_factor, + Dwarf_Signed * data_alignment_factor, + Dwarf_Half * return_address_register, + Dwarf_Ptr * initial_instructions, + Dwarf_Unsigned * initial_instructions_length, + Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return (DW_DLV_ERROR); + } + + dbg = cie->ci_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_DBG_NULL); + return (DW_DLV_ERROR); + } + + if (ptr_to_version != NULL) + *ptr_to_version = cie->ci_cie_version_number; + if (augmenter != NULL) + *augmenter = cie->ci_augmentation; + if (code_alignment_factor != NULL) + *code_alignment_factor = cie->ci_code_alignment_factor; + if (data_alignment_factor != NULL) + *data_alignment_factor = cie->ci_data_alignment_factor; + if (return_address_register != NULL) + *return_address_register = cie->ci_return_address_register; + if (initial_instructions != NULL) + *initial_instructions = cie->ci_cie_instr_start; + if (initial_instructions_length != NULL) { + *initial_instructions_length = cie->ci_length + + cie->ci_length_size + + cie->ci_extension_size - + (cie->ci_cie_instr_start - cie->ci_cie_start); + + } + *bytes_in_cie = (cie->ci_length); + return (DW_DLV_OK); +} + +/* Return the register rules for all registers at a given pc. +*/ +static int +_dwarf_get_fde_info_for_a_pc_row(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Frame table, + Dwarf_Half cfa_reg_col_num, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Cie cie = 0; + int dw_err = 0; + Dwarf_Sword icount = 0; + int res = 0; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + + if (pc_requested < fde->fd_initial_location || + pc_requested >= + fde->fd_initial_location + fde->fd_address_range) { + _dwarf_error(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); + return (DW_DLV_ERROR); + } + + cie = fde->fd_cie; + if (cie->ci_initial_table == NULL) { + cie->ci_initial_table = _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1); + + if (cie->ci_initial_table == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + _dwarf_init_regrule_table(cie->ci_initial_table->fr_reg, + dbg->de_frame_reg_rules_entry_count, + dbg->de_frame_rule_initial_value); + _dwarf_init_regrule_table(&cie->ci_initial_table->fr_cfa_rule, + 1, dbg->de_frame_rule_initial_value); + res = _dwarf_exec_frame_instr( /* make_instr= */ false, + /* ret_frame_instr= */ NULL, + /* search_pc */ false, + /* search_pc_val */ 0, + /* location */ 0, + cie->ci_cie_instr_start, + cie->ci_cie_instr_start + + (cie->ci_length + + cie->ci_length_size + + cie->ci_extension_size - + (cie->ci_cie_instr_start - + cie->ci_cie_start)), + cie->ci_initial_table, cie, dbg, + cfa_reg_col_num, &icount, + &dw_err); + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, error, dw_err); + return (res); + } else if (res == DW_DLV_NO_ENTRY) { + return res; + } + } + + { + Dwarf_Small *instr_end = fde->fd_fde_instr_start + + fde->fd_length + + fde->fd_length_size + + fde->fd_extension_size - (fde->fd_fde_instr_start - + fde->fd_fde_start); + + res = _dwarf_exec_frame_instr( /* make_instr= */ false, + /* ret_frame_instr= */ NULL, + /* search_pc */ true, + /* search_pc_val */ pc_requested, + fde->fd_initial_location, + fde->fd_fde_instr_start, + instr_end, + table, + cie, dbg, + cfa_reg_col_num, &icount, + &dw_err); + } + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, error, dw_err); + return (res); + } else if (res == DW_DLV_NO_ENTRY) { + return res; + } + + return DW_DLV_OK; +} + +/* A consumer call for efficiently getting the register info + for all registers in one call. + + The output table rules array is size DW_REG_TABLE_SIZE. + The frame info rules array in fde_table is of size + DW_REG_TABLE_SIZE too. + + This interface really only works well with MIPS/IRIX + where DW_FRAME_CFA_COL is zero (in that case it's safe). + + It is also restricted to the case where + DW_REG_TABLE_SIZE == DW_FRAME_LAST_REG_NUM == + dbg->de_frame_reg_rules_entry_count (true for MIPS/IRIX). + If this condition is not met calling this routine can result in + incorrect output or in memory corruption. + +*/ +int +dwarf_get_fde_info_for_all_regs(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Regtable * reg_table, + Dwarf_Addr * row_pc, + Dwarf_Error * error) +{ + + /* Table size: DW_REG_TABLE_SIZE */ + struct Dwarf_Frame_s fde_table; + Dwarf_Sword i = 0; + struct Dwarf_Reg_Rule_s *rule = NULL; + struct Dwarf_Regtable_Entry_s *out_rule = NULL; + int res = 0; + Dwarf_Debug dbg = 0; + + /* For this interface the size is fixed at compile time. */ + int output_table_real_data_size = DW_REG_TABLE_SIZE; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + res = dwarf_initialize_fde_table(dbg, &fde_table, + output_table_real_data_size, + error); + if (res != DW_DLV_OK) + return res; + + + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, + &fde_table, + DW_FRAME_CFA_COL, error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + out_rule = ®_table->rules[0]; + rule = &fde_table.fr_reg[0]; + for (i = 0; i < output_table_real_data_size; + i++, ++out_rule, ++rule) { + out_rule->dw_offset_relevant = rule->ru_is_off; + out_rule->dw_value_type = rule->ru_value_type; + out_rule->dw_regnum = rule->ru_register; + out_rule->dw_offset = rule->ru_offset_or_block_len; + } + for (; i < DW_REG_TABLE_SIZE; ++i, ++out_rule) { + out_rule->dw_offset_relevant = 0; + out_rule->dw_value_type = DW_EXPR_OFFSET; + out_rule->dw_regnum = DW_FRAME_UNDEFINED_VAL; + out_rule->dw_offset = 0; + } + + /* The test is just in case it's not inside the table. For non-MIPS + it could be outside the table and that is just fine, it was + really a mistake to put it in the table in 1993. */ + /* CONSTCOND */ + if (DW_FRAME_CFA_COL < DW_REG_TABLE_SIZE) { + out_rule = ®_table->rules[DW_FRAME_CFA_COL]; + out_rule->dw_offset_relevant = fde_table.fr_cfa_rule.ru_is_off; + out_rule->dw_value_type = fde_table.fr_cfa_rule.ru_value_type; + out_rule->dw_regnum = fde_table.fr_cfa_rule.ru_register; + out_rule->dw_offset = + fde_table.fr_cfa_rule.ru_offset_or_block_len; + } + + if (row_pc != NULL) + *row_pc = fde_table.fr_loc; + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + +/* A consumer call for efficiently getting the register info + for all registers in one call. + + The output table rules array is size output_table_real_data_size. + (normally DW_REG_TABLE_SIZE). + The frame info rules array in fde_table is normally of size + DW_FRAME_LAST_REG_NUM. +*/ +int +dwarf_get_fde_info_for_all_regs3(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Regtable3 * reg_table, + Dwarf_Addr * row_pc, + Dwarf_Error * error) +{ + + struct Dwarf_Frame_s fde_table; + Dwarf_Sword i = 0; + int res = 0; + struct Dwarf_Reg_Rule_s *rule = NULL; + struct Dwarf_Regtable_Entry3_s *out_rule = NULL; + Dwarf_Debug dbg = 0; + int output_table_real_data_size = reg_table->rt3_reg_table_size; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + output_table_real_data_size = + MIN(output_table_real_data_size, + dbg->de_frame_reg_rules_entry_count); + + res = dwarf_initialize_fde_table(dbg, &fde_table, + output_table_real_data_size, + error); + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, + &fde_table, + DW_FRAME_CFA_COL3, error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + out_rule = ®_table->rt3_rules[0]; + rule = &fde_table.fr_reg[0]; + for (i = 0; i < output_table_real_data_size; + i++, ++out_rule, ++rule) { + out_rule->dw_offset_relevant = rule->ru_is_off; + out_rule->dw_value_type = rule->ru_value_type; + out_rule->dw_regnum = rule->ru_register; + out_rule->dw_offset_or_block_len = rule->ru_offset_or_block_len; + out_rule->dw_block_ptr = rule->ru_block; + } + for (; i < reg_table->rt3_reg_table_size; i++, ++out_rule) { + out_rule->dw_offset_relevant = 0; + out_rule->dw_value_type = DW_EXPR_OFFSET; + out_rule->dw_regnum = DW_FRAME_UNDEFINED_VAL; + out_rule->dw_offset_or_block_len = 0; + out_rule->dw_block_ptr = 0; + } + reg_table->rt3_cfa_rule.dw_offset_relevant = + fde_table.fr_cfa_rule.ru_is_off; + reg_table->rt3_cfa_rule.dw_value_type = + fde_table.fr_cfa_rule.ru_value_type; + reg_table->rt3_cfa_rule.dw_regnum = + fde_table.fr_cfa_rule.ru_register; + reg_table->rt3_cfa_rule.dw_offset_or_block_len = + fde_table.fr_cfa_rule.ru_offset_or_block_len; + reg_table->rt3_cfa_rule.dw_block_ptr = + fde_table.fr_cfa_rule.ru_block; + + if (row_pc != NULL) + *row_pc = fde_table.fr_loc; + + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + + +/* Gets the register info for a single register at a given PC value + for the FDE specified. + +*/ +int +dwarf_get_fde_info_for_reg(Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr pc_requested, + Dwarf_Signed * offset_relevant, + Dwarf_Signed * register_num, + Dwarf_Signed * offset, + Dwarf_Addr * row_pc, Dwarf_Error * error) +{ + struct Dwarf_Frame_s fde_table; + int res; + Dwarf_Debug dbg = 0; + int output_table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + output_table_real_data_size = dbg->de_frame_reg_rules_entry_count; + + res = dwarf_initialize_fde_table(dbg, &fde_table, + output_table_real_data_size, + error); + if (res != DW_DLV_OK) + return res; + + + if (table_column >= output_table_real_data_size) { + dwarf_free_fde_table(&fde_table); + _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD); + return (DW_DLV_ERROR); + } + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = + _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table, + DW_FRAME_CFA_COL, error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + if (fde_table.fr_reg[table_column].ru_value_type != DW_EXPR_OFFSET) { + dwarf_free_fde_table(&fde_table); + _dwarf_error(NULL, error, + DW_DLE_FRAME_REGISTER_UNREPRESENTABLE); + return (DW_DLV_ERROR); + } + + if (register_num != NULL) + *register_num = fde_table.fr_reg[table_column].ru_register; + if (offset != NULL) + *offset = fde_table.fr_reg[table_column].ru_offset_or_block_len; + if (row_pc != NULL) + *row_pc = fde_table.fr_loc; + + *offset_relevant = (fde_table.fr_reg[table_column].ru_is_off); + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + +/* In this interface, table_column of DW_FRAME_CFA_COL + is not meaningful. + Use dwarf_get_fde_info_for_cfa_reg3() to get the CFA. +*/ +int +dwarf_get_fde_info_for_reg3(Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr pc_requested, + Dwarf_Small * value_type, + Dwarf_Signed * offset_relevant, + Dwarf_Signed * register_num, + Dwarf_Signed * offset_or_block_len, + Dwarf_Ptr * block_ptr, + Dwarf_Addr * row_pc_out, + Dwarf_Error * error) +{ + struct Dwarf_Frame_s fde_table; + int res = 0; + + Dwarf_Debug dbg = 0; + int table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + table_real_data_size = dbg->de_frame_reg_rules_entry_count; + res = dwarf_initialize_fde_table(dbg, &fde_table, + table_real_data_size, error); + if (res != DW_DLV_OK) + return res; + if (table_column >= table_real_data_size) { + dwarf_free_fde_table(&fde_table); + _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD); + return (DW_DLV_ERROR); + } + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = + _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table, + DW_FRAME_CFA_COL3, error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + if (register_num != NULL) + *register_num = fde_table.fr_reg[table_column].ru_register; + if (offset_or_block_len != NULL) + *offset_or_block_len = + fde_table.fr_reg[table_column].ru_offset_or_block_len; + if (row_pc_out != NULL) + *row_pc_out = fde_table.fr_loc; + if (block_ptr) + *block_ptr = fde_table.fr_reg[table_column].ru_block; + + /* Without value_type the data cannot be understood, so we insist + on it being present, we don't test it. */ + *value_type = fde_table.fr_reg[table_column].ru_value_type; + *offset_relevant = (fde_table.fr_reg[table_column].ru_is_off); + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; + +} + +/* For latest DWARF, this is the preferred interface. + It more portably deals with the CFA by not + making the CFA a column number, which means + DW_FRAME_CFA_COL becomes an index like DW_CFA_SAME_VALUE, + a special value, not something one uses as an index. */ +int +dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Small * value_type, + Dwarf_Signed * offset_relevant, + Dwarf_Signed * register_num, + Dwarf_Signed * offset_or_block_len, + Dwarf_Ptr * block_ptr, + Dwarf_Addr * row_pc_out, + Dwarf_Error * error) +{ + struct Dwarf_Frame_s fde_table; + int res; + Dwarf_Debug dbg = 0; + + int table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + table_real_data_size = dbg->de_frame_reg_rules_entry_count; + res = dwarf_initialize_fde_table(dbg, &fde_table, + table_real_data_size, error); + if (res != DW_DLV_OK) + return res; + res = + _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table, + DW_FRAME_CFA_COL3, error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + if (register_num != NULL) + *register_num = fde_table.fr_cfa_rule.ru_register; + if (offset_or_block_len != NULL) + *offset_or_block_len = + fde_table.fr_cfa_rule.ru_offset_or_block_len; + if (row_pc_out != NULL) + *row_pc_out = fde_table.fr_loc; + if (block_ptr) + *block_ptr = fde_table.fr_cfa_rule.ru_block; + + /* Without value_type the data cannot be understood, so we insist + on it being present, we don't test it. */ + *value_type = fde_table.fr_cfa_rule.ru_value_type; + *offset_relevant = fde_table.fr_cfa_rule.ru_is_off; + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + + + +/* + Return pointer to the instructions in the dwarf + fde. +*/ +int +dwarf_get_fde_instr_bytes(Dwarf_Fde inFde, Dwarf_Ptr * outinstraddr, + Dwarf_Unsigned * outaddrlen, + Dwarf_Error * error) +{ + Dwarf_Unsigned len = 0; + unsigned char *instrs = 0; + Dwarf_Debug dbg = 0; + + if (inFde == NULL) { + _dwarf_error(dbg, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + dbg = inFde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(dbg, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + + instrs = inFde->fd_fde_instr_start; + + len = (inFde->fd_fde_start + inFde->fd_length + + inFde->fd_length_size + inFde->fd_extension_size) - instrs; + + *outinstraddr = instrs; + *outaddrlen = len; + return DW_DLV_OK; +} + +/* Allows getting an fde from its table via an index. + With more error checking than simply indexing oneself. +*/ +int +dwarf_get_fde_n(Dwarf_Fde * fde_data, + Dwarf_Unsigned fde_index, + Dwarf_Fde * returned_fde, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + + if (fde_data == NULL) { + _dwarf_error(dbg, error, DW_DLE_FDE_PTR_NULL); + return (DW_DLV_ERROR); + } + + FDE_NULL_CHECKS_AND_SET_DBG(*fde_data, dbg); + + if (fde_index >= dbg->de_fde_count) { + return (DW_DLV_NO_ENTRY); + } + *returned_fde = (*(fde_data + fde_index)); + return DW_DLV_OK; +} + + +/* + Lopc and hipc are extensions to the interface to + return the range of addresses that are described + by the returned fde. +*/ +int +dwarf_get_fde_at_pc(Dwarf_Fde * fde_data, + Dwarf_Addr pc_of_interest, + Dwarf_Fde * returned_fde, + Dwarf_Addr * lopc, + Dwarf_Addr * hipc, Dwarf_Error * error) +{ + Dwarf_Debug dbg = NULL; + Dwarf_Fde fde = NULL; + Dwarf_Fde entryfde = NULL; + + if (fde_data == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_PTR_NULL); + return (DW_DLV_ERROR); + } + + /* Assumes fde_data table has at least one entry. */ + entryfde = *fde_data; + FDE_NULL_CHECKS_AND_SET_DBG(entryfde, dbg); + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + { + /* The fde's are sorted by their addresses. Binary search to + find correct fde. */ + Dwarf_Signed low = 0; + Dwarf_Signed high = dbg->de_fde_count - 1L; + Dwarf_Signed middle = 0; + Dwarf_Fde cur_fde; + + while (low <= high) { + middle = (low + high) / 2; + cur_fde = fde_data[middle]; + if (pc_of_interest < cur_fde->fd_initial_location) { + high = middle - 1; + } else if (pc_of_interest >= + (cur_fde->fd_initial_location + + cur_fde->fd_address_range)) { + low = middle + 1; + } else { + fde = fde_data[middle]; + break; + } + } + } + + if (fde) { + if (lopc != NULL) + *lopc = fde->fd_initial_location; + if (hipc != NULL) + *hipc = + fde->fd_initial_location + fde->fd_address_range - 1; + *returned_fde = fde; + return (DW_DLV_OK); + } + + return (DW_DLV_NO_ENTRY); +} + + +/* Expands a single frame instruction block + into a n array of Dwarf_Frame_Op-s. +*/ +int +dwarf_expand_frame_instructions(Dwarf_Debug dbg, + Dwarf_Ptr instruction, + Dwarf_Unsigned i_length, + Dwarf_Frame_Op ** returned_op_list, + Dwarf_Signed * returned_op_count, + Dwarf_Error * error) +{ + Dwarf_Sword instr_count; + int res; + int dw_err; + + if (dbg == 0) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + + if (returned_op_list == 0 || returned_op_count == 0) { + _dwarf_error(dbg, error, DW_DLE_RET_OP_LIST_NULL); + return (DW_DLV_ERROR); + } + + /* The cast to Dwarf_Ptr may get a compiler warning, but it is safe + as it is just an i_length offset from 'instruction' itself. A + caller has made a big mistake if the result is not a valid + pointer. */ + res = _dwarf_exec_frame_instr( /* make_instr= */ true, + returned_op_list, + /* search_pc */ false, + /* search_pc_val */ 0, + /* location */ 0, + instruction, + (Dwarf_Ptr) ((Dwarf_Unsigned) + instruction + i_length), + /* Dwarf_Frame */ NULL, + /* cie_ptr */ NULL, + dbg, + DW_FRAME_CFA_COL, &instr_count, + &dw_err); + if (res != DW_DLV_OK) { + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, error, dw_err); + } + return (res); + } + + *returned_op_count = instr_count; + return DW_DLV_OK; +} + + +/* Used by dwarfdump -v to print offsets, for debugging + dwarf info. + The dwarf_ version is preferred over the obsolete _dwarf version. + _dwarf version kept for compatibility. +*/ +/* ARGSUSED 4 */ +int +_dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde, + Dwarf_Off * fde_off, Dwarf_Off * cie_off, + Dwarf_Error * err) +{ + return _dwarf_fde_section_offset(dbg,in_fde,fde_off, + cie_off,err); +} +/* ARGSUSED 4 */ +int +dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde, + Dwarf_Off * fde_off, Dwarf_Off * cie_off, + Dwarf_Error * err) +{ + char *start = 0; + char *loc = 0; + + + + start = (char *) in_fde->fd_section_ptr; + loc = (char *) in_fde->fd_fde_start; + + *fde_off = (loc - start); + *cie_off = in_fde->fd_cie_offset; + return DW_DLV_OK; +} + +/* Used by dwarfdump -v to print offsets, for debugging + dwarf info. + The dwarf_ version is preferred over the obsolete _dwarf version. + _dwarf version kept for compatibility. +*/ +/* ARGSUSED 4 */ +int +_dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie, + Dwarf_Off * cie_off, Dwarf_Error * err) +{ + return dwarf_cie_section_offset(dbg,in_cie,cie_off,err); +} +/* ARGSUSED 4 */ +int +dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie, + Dwarf_Off * cie_off, Dwarf_Error * err) +{ + char *start = 0; + char *loc = 0; + + start = (char *) in_cie->ci_section_ptr; + loc = (char *) in_cie->ci_cie_start; + + *cie_off = (loc - start); + return DW_DLV_OK; +} + +/* Returns a pointer to target-specific augmentation data thru augdata + and returns the length of the data thru augdata_len. + + It's up to the consumer code to know how to interpret the bytes + of target-specific data (endian issues apply too, these + are just raw bytes pointed to). + See Linux Standard Base Core Specification version 3.0 for + the details on .eh_frame info. + + Returns DW_DLV_ERROR if fde is NULL or some other serious + error. + Returns DW_DLV_NO_ENTRY if there is no target-specific + augmentation data. + + The bytes pointed to are in the Dwarf_Cie, and as long as that + is valid the bytes are there. No 'dealloc' call is needed + for the bytes. +*/ +int +dwarf_get_cie_augmentation_data(Dwarf_Cie cie, + Dwarf_Small ** augdata, + Dwarf_Unsigned * augdata_len, + Dwarf_Error * error) +{ + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return (DW_DLV_ERROR); + } + if (cie->ci_gnu_eh_augmentation_len == 0) { + return DW_DLV_NO_ENTRY; + } + *augdata = (Dwarf_Small *) (cie->ci_gnu_eh_augmentation_bytes); + *augdata_len = cie->ci_gnu_eh_augmentation_len; + return DW_DLV_OK; +} + + +/* Returns a pointer to target-specific augmentation data thru augdata + and returns the length of the data thru augdata_len. + + It's up to the consumer code to know how to interpret the bytes + of target-specific data (endian issues apply too, these + are just raw bytes pointed to). + See Linux Standard Base Core Specification version 3.0 for + the details on .eh_frame info. + + Returns DW_DLV_ERROR if fde is NULL or some other serious + error. + Returns DW_DLV_NO_ENTRY if there is no target-specific + augmentation data. + + The bytes pointed to are in the Dwarf_Fde, and as long as that + is valid the bytes are there. No 'dealloc' call is needed + for the bytes. + +*/ +int +dwarf_get_fde_augmentation_data(Dwarf_Fde fde, + Dwarf_Small * *augdata, + Dwarf_Unsigned * augdata_len, + Dwarf_Error * error) +{ + Dwarf_Cie cie = 0; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + cie = fde->fd_cie; + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return (DW_DLV_ERROR); + } + if (cie->ci_gnu_eh_augmentation_len == 0) { + return DW_DLV_NO_ENTRY; + } + *augdata = (Dwarf_Small *) fde->fd_gnu_eh_augmentation_bytes; + *augdata_len = fde->fd_gnu_eh_augmentation_len; + return DW_DLV_OK; +} + + +/* Initialize with same_value , a value which makes sense + for IRIX/MIPS. + The correct value to use is ABI dependent. + For register-windows machines most + or all registers should get DW_FRAME_UNDEFINED_VAL as the + correct initial value. + Some think DW_FRAME_UNDEFINED_VAL is always the + right value. + + For some ABIs a setting which varies by register + would be more appropriate. + + FIXME. */ + +static void +_dwarf_init_regrule_table(struct Dwarf_Reg_Rule_s *t1reg, + int last_reg_num, int initial_value) +{ + struct Dwarf_Reg_Rule_s *t1end = t1reg + last_reg_num; + + for (; t1reg < t1end; t1reg++) { + t1reg->ru_is_off = 0; + t1reg->ru_value_type = DW_EXPR_OFFSET; + t1reg->ru_register = initial_value; + t1reg->ru_offset_or_block_len = 0; + t1reg->ru_block = 0; + } +} + +#if 0 +/* Used solely for debugging libdwarf. */ +static void +dump_frame_rule(char *msg, struct Dwarf_Reg_Rule_s *reg_rule) +{ + printf + ("%s type %s (0x%x), is_off %d reg %d offset 0x%llx blockp 0x%llx \n", + msg, + (reg_rule->ru_value_type == + DW_EXPR_OFFSET) ? "DW_EXPR_OFFSET" : (reg_rule-> + ru_value_type == + DW_EXPR_VAL_OFFSET) ? + "DW_EXPR_VAL_OFFSET" : (reg_rule->ru_value_type == + DW_EXPR_VAL_EXPRESSION) ? + "DW_EXPR_VAL_EXPRESSION" : (reg_rule->ru_value_type == + DW_EXPR_EXPRESSION) ? + "DW_EXPR_EXPRESSION" : "Unknown", + (unsigned) reg_rule->ru_value_type, (int) reg_rule->ru_is_off, + (int) reg_rule->ru_register, + (unsigned long long) reg_rule->ru_offset_or_block_len, + (unsigned long long) reg_rule->ru_block); + return; +} +#endif + +/* This allows consumers to set the 'initial value' so that + an ISA/ABI specific default can be used, dynamically, + at run time. Useful for dwarfdump and non-MIPS architectures.. + The value defaults to one of + DW_FRAME_SAME_VALUE or DW_FRAME_UNKNOWN_VALUE + but dwarfdump can dump multiple ISA/ABI objects so + we may want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. +*/ + +Dwarf_Half +dwarf_set_frame_rule_inital_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_rule_initial_value; + + dbg->de_frame_rule_initial_value = value; + return orig; +} + +/* This allows consumers to set the array size of the reg rules + table so that + an ISA/ABI specific value can be used, dynamically, + at run time. Useful for non-MIPS archtectures. + The value defaults to DW_FRAME_LAST_REG_NUM. + but dwarfdump can dump multiple ISA/ABI objects so + consumers want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. +*/ + +Dwarf_Half +dwarf_set_frame_rule_table_size(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_reg_rules_entry_count; + + dbg->de_frame_reg_rules_entry_count = value; + return orig; +} + + +static int +dwarf_initialize_fde_table(Dwarf_Debug dbg, + struct Dwarf_Frame_s *fde_table, + unsigned table_real_data_size, + Dwarf_Error * error) +{ + unsigned entry_size = sizeof(struct Dwarf_Frame_s); + + fde_table->fr_loc = 0; + fde_table->fr_reg_count = table_real_data_size; + fde_table->fr_next = 0; + + fde_table->fr_reg = (struct Dwarf_Reg_Rule_s *) + calloc(entry_size, table_real_data_size); + if (fde_table->fr_reg == 0) { + _dwarf_error(dbg, error, DW_DLE_DF_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + return DW_DLV_OK; + +} +static void +dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table) +{ + free(fde_table->fr_reg); + fde_table->fr_reg_count = 0; + fde_table->fr_reg = 0; +} + + +/* Return DW_DLV_OK if we succeed. else return DW_DLV_ERROR. +*/ +int +_dwarf_frame_constructor(Dwarf_Debug dbg, void *frame) +{ + struct Dwarf_Frame_s *fp = frame; + + if (!dbg) { + return DW_DLV_ERROR; + } + + fp->fr_reg = calloc(dbg->de_frame_reg_rules_entry_count, + sizeof(struct Dwarf_Reg_Rule_s)); + if (!fp->fr_reg) { + return DW_DLV_ERROR; + } + fp->fr_reg_count = dbg->de_frame_reg_rules_entry_count; + return DW_DLV_OK; +} + +void +_dwarf_frame_destructor(void *frame) +{ + struct Dwarf_Frame_s *fp = frame; + + if (fp->fr_reg) + free(fp->fr_reg); + fp->fr_reg = 0; + fp->fr_reg_count = 0; +}