#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarf_frame.h"
#include "dwarf_arange.h"
#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)
#if 0
static void
dump_bytes(const char *msg,Dwarf_Small * start, long len)
{
Dwarf_Small *end = start + len;
Dwarf_Small *cur = start;
printf("%s (0x%lx) ",msg,(unsigned long)start);
for (; cur < end; cur++) {
printf("%02x", *cur);
}
printf("\n");
}
#endif
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);
static void dwarf_init_reg_rules_ru(struct Dwarf_Reg_Rule_s *base,
unsigned first, unsigned last,int initial_value);
static void dwarf_init_reg_rules_dw(struct Dwarf_Regtable_Entry_s *base,
unsigned first, unsigned last,int initial_value);
static void dwarf_init_reg_rules_dw3(struct Dwarf_Regtable_Entry3_s *base,
unsigned first, unsigned last,int initial_value);
#if 0
static void dump_frame_rule(char *msg,
struct Dwarf_Reg_Rule_s *reg_rule);
#endif
int
dwarf_get_frame_section_name(Dwarf_Debug dbg,
const char **sec_name,
Dwarf_Error *error)
{
struct Dwarf_Section_s *sec = 0;
if (error != NULL) {
*error = NULL;
}
sec = &dbg->de_debug_frame;
if (sec->dss_size == 0) {
return DW_DLV_NO_ENTRY;
}
*sec_name = sec->dss_name;
return DW_DLV_OK;
}
int
dwarf_get_frame_section_name_eh_gnu(Dwarf_Debug dbg,
const char **sec_name,
Dwarf_Error *error)
{
struct Dwarf_Section_s *sec = 0;
if (error != NULL) {
*error = NULL;
}
sec = &dbg->de_debug_frame_eh_gnu;
if (sec->dss_size == 0) {
return DW_DLV_NO_ENTRY;
}
*sec_name = sec->dss_name;
return DW_DLV_OK;
}
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_Signed * returned_count,
Dwarf_Bool * has_more_rows,
Dwarf_Addr * subsequent_pc,
Dwarf_Error *error)
{
#define ERROR_IF_REG_NUM_TOO_HIGH(macreg,machigh_reg) \
do { \
if ((macreg) >= (machigh_reg)) { \
SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH); \
} \
} while (0)
#define SIMPLE_ERROR_RETURN(code) \
free(localregtab); \
_dwarf_error(dbg,error,code); \
return DW_DLV_ERROR
Dwarf_Small *instr_ptr = 0;
typedef unsigned reg_num_type;
Dwarf_Unsigned factored_N_value = 0;
Dwarf_Signed signed_factored_N_value = 0;
Dwarf_Addr current_loc = initial_loc;
Dwarf_Unsigned adv_loc = 0;
unsigned 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;
Dwarf_Bool search_over = false;
Dwarf_Addr possible_subsequent_pc = 0;
Dwarf_Addr adv_pc = 0;
Dwarf_Half address_size = (cie)? cie->ci_address_size:
dbg->de_pointer_size;
Dwarf_Unsigned instr_count = 0;
Dwarf_Small fp_base_op = 0;
Dwarf_Small fp_extended_op = 0;
reg_num_type fp_register = 0;
Dwarf_Unsigned fp_offset = 0;
Dwarf_Off fp_instr_offset = 0;
Dwarf_Frame stack_table = NULL;
Dwarf_Frame top_stack = NULL;
Dwarf_Frame_Op *curr_instr = 0;
Dwarf_Chain curr_instr_item = 0;
Dwarf_Chain head_instr_chain = NULL;
Dwarf_Chain tail_instr_chain = NULL;
Dwarf_Frame_Op *head_instr_block = 0;
Dwarf_Signed code_alignment_factor = 1;
Dwarf_Signed data_alignment_factor = 1;
Dwarf_Bool need_augmentation = false;
Dwarf_Unsigned i = 0;
if (localregtab == 0) {
SIMPLE_ERROR_RETURN(DW_DLE_ALLOC_FAIL);
}
{
struct Dwarf_Reg_Rule_s *t1reg = localregtab;
if (cie != NULL && cie->ci_initial_table != NULL) {
unsigned minregcount = 0;
unsigned curreg = 0;
struct Dwarf_Reg_Rule_s *t2reg = cie->ci_initial_table->fr_reg;
if (reg_count != cie->ci_initial_table->fr_reg_count) {
SIMPLE_ERROR_RETURN
(DW_DLE_FRAME_REGISTER_COUNT_MISMATCH);
}
minregcount = MIN(reg_count,cie->ci_initial_table->fr_reg_count);
for (; curreg < minregcount ;curreg++, t1reg++, t2reg++) {
*t1reg = *t2reg;
}
cfa_reg = cie->ci_initial_table->fr_cfa_rule;
} else {
dwarf_init_reg_rules_ru(localregtab,0,reg_count,
dbg->de_frame_rule_initial_value);
dwarf_init_reg_rules_ru(&cfa_reg,0, 1,
dbg->de_frame_rule_initial_value);
}
}
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;
fp_extended_op = (instr & (~(0xc0))) & 0xff;
} else {
opcode = instr & 0xc0;
fp_extended_op = 0;
}
fp_register = 0;
fp_offset = 0;
switch (opcode) {
case DW_CFA_advance_loc:
{
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;
possible_subsequent_pc = current_loc + adv_pc;
search_over = search_pc &&
(possible_subsequent_pc > search_pc_val);
if (!search_over) {
current_loc = possible_subsequent_pc;
}
break;
}
case DW_CFA_offset:
{
reg_no =
(reg_num_type) (instr & DW_FRAME_INSTR_OFFSET_MASK);
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_UWORD_CK(instr_ptr, factored_N_value,
dbg,error,final_instr_ptr);
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:
{
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_CK(dbg, new_loc, Dwarf_Addr,
instr_ptr, address_size,
error,final_instr_ptr);
instr_ptr += address_size;
if (new_loc != 0 && current_loc != 0) {
if (new_loc <= current_loc) {
SIMPLE_ERROR_RETURN
(DW_DLE_DF_NEW_LOC_LESS_OLD_LOC);
}
}
search_over = search_pc && (new_loc > search_pc_val);
possible_subsequent_pc = new_loc;
if (!search_over) {
current_loc = possible_subsequent_pc;
}
fp_offset = new_loc;
break;
}
case DW_CFA_advance_loc1:
{
READ_UNALIGNED_CK(dbg, adv_loc, Dwarf_Unsigned,
instr_ptr, sizeof(Dwarf_Small),
error,final_instr_ptr);
instr_ptr += sizeof(Dwarf_Small);
fp_offset = adv_loc;
if (need_augmentation) {
SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
}
adv_loc *= code_alignment_factor;
possible_subsequent_pc = current_loc + adv_loc;
search_over = search_pc &&
(possible_subsequent_pc > search_pc_val);
if (!search_over) {
current_loc = possible_subsequent_pc;
}
break;
}
case DW_CFA_advance_loc2:
{
READ_UNALIGNED_CK(dbg, adv_loc, Dwarf_Unsigned,
instr_ptr, DWARF_HALF_SIZE,
error,final_instr_ptr);
instr_ptr += DWARF_HALF_SIZE;
fp_offset = adv_loc;
if (need_augmentation) {
SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
}
adv_loc *= code_alignment_factor;
possible_subsequent_pc = current_loc + adv_loc;
search_over = search_pc &&
(possible_subsequent_pc > search_pc_val);
if (!search_over) {
current_loc = possible_subsequent_pc;
}
break;
}
case DW_CFA_advance_loc4:
{
READ_UNALIGNED_CK(dbg, adv_loc, Dwarf_Unsigned,
instr_ptr, DWARF_32BIT_SIZE,
error,final_instr_ptr);
instr_ptr += DWARF_32BIT_SIZE;
fp_offset = adv_loc;
if (need_augmentation) {
SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
}
adv_loc *= code_alignment_factor;
possible_subsequent_pc = current_loc + adv_loc;
search_over = search_pc &&
(possible_subsequent_pc > search_pc_val);
if (!search_over) {
current_loc = possible_subsequent_pc;
}
break;
}
case DW_CFA_MIPS_advance_loc8:
{
READ_UNALIGNED_CK(dbg, adv_loc, Dwarf_Unsigned,
instr_ptr, DWARF_64BIT_SIZE,
error,final_instr_ptr);
instr_ptr += DWARF_64BIT_SIZE;
fp_offset = adv_loc;
if (need_augmentation) {
SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
}
adv_loc *= code_alignment_factor;
possible_subsequent_pc = current_loc + adv_loc;
search_over = search_pc &&
(possible_subsequent_pc > search_pc_val);
if (!search_over) {
current_loc = possible_subsequent_pc;
}
break;
}
case DW_CFA_offset_extended:
{
Dwarf_Unsigned lreg = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_UWORD_CK(instr_ptr, factored_N_value,
dbg,error,final_instr_ptr);
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 = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
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 = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
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 =
dbg->de_frame_undefined_value_number;
localregtab[reg_no].ru_offset_or_block_len = 0;
fp_register = reg_no;
break;
}
case DW_CFA_same_value:
{
Dwarf_Unsigned lreg = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
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 =
dbg->de_frame_same_value_number;
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_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_noA = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_noA, reg_count);
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
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];
stack_table->fr_cfa_rule = cfa_reg;
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];
cfa_reg = stack_table->fr_cfa_rule;
dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME);
break;
}
case DW_CFA_def_cfa:
{
Dwarf_Unsigned lreg = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_UWORD_CK(instr_ptr, factored_N_value,
dbg,error,final_instr_ptr);
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 = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
cfa_reg.ru_register = reg_no;
fp_register = reg_no;
break;
}
case DW_CFA_def_cfa_offset:
{
DECODE_LEB128_UWORD_CK(instr_ptr, factored_N_value,
dbg,error,final_instr_ptr);
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_offset_or_block_len = factored_N_value;
fp_offset = factored_N_value;
break;
}
case DW_CFA_METAWARE_info:
{
DECODE_LEB128_UWORD_CK(instr_ptr, factored_N_value,
dbg,error,final_instr_ptr);
cfa_reg.ru_is_off = 1;
cfa_reg.ru_value_type = DW_EXPR_OFFSET;
cfa_reg.ru_offset_or_block_len = factored_N_value;
break;
}
case DW_CFA_nop:
{
break;
}
case DW_CFA_def_cfa_expression:
{
Dwarf_Unsigned block_len = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, block_len,
dbg,error,final_instr_ptr);
cfa_reg.ru_is_off = 0;
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)(uintptr_t)instr_ptr;
instr_ptr += block_len;
}
break;
case DW_CFA_expression:
{
Dwarf_Unsigned lreg = 0;
Dwarf_Unsigned block_len = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_UWORD_CK(instr_ptr, block_len,
dbg,error,final_instr_ptr);
localregtab[lreg].ru_is_off = 0;
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)(uintptr_t)instr_ptr;
fp_register = reg_no;
instr_ptr += block_len;
}
break;
case DW_CFA_offset_extended_sf:
{
Dwarf_Unsigned lreg = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_SWORD_CK(instr_ptr, signed_factored_N_value,
dbg,error,final_instr_ptr);
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:
{
Dwarf_Unsigned lreg;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_SWORD_CK(instr_ptr, signed_factored_N_value,
dbg,error,final_instr_ptr);
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:
{
DECODE_LEB128_SWORD_CK(instr_ptr, signed_factored_N_value,
dbg,error,final_instr_ptr);
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_offset_or_block_len =
signed_factored_N_value * data_alignment_factor;
fp_offset = signed_factored_N_value;
}
break;
case DW_CFA_val_offset:
{
Dwarf_Unsigned lreg = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_UWORD_CK(instr_ptr, factored_N_value,
dbg,error,final_instr_ptr);
if (need_augmentation) {
SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
}
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:
{
Dwarf_Unsigned lreg = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_SWORD_CK(instr_ptr, signed_factored_N_value,
dbg,error,final_instr_ptr);
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_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:
{
Dwarf_Unsigned lreg = 0;
Dwarf_Unsigned block_len = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
reg_no = (reg_num_type) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
DECODE_LEB128_UWORD_CK(instr_ptr, block_len,
dbg,error,final_instr_ptr);
localregtab[lreg].ru_is_off = 0;
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)(uintptr_t)instr_ptr;
instr_ptr += block_len;
fp_register = reg_no;
}
break;
#ifdef DW_CFA_GNU_window_save
case DW_CFA_GNU_window_save:
{
break;
}
#endif
#ifdef DW_CFA_GNU_args_size
case DW_CFA_GNU_args_size:
{
UNUSEDARG Dwarf_Unsigned lreg = 0;
DECODE_LEB128_UWORD_CK(instr_ptr, lreg,
dbg,error,final_instr_ptr);
break;
}
#endif
default:
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;
curr_instr_item->ch_itemtype = DW_DLA_FRAME_OP;
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 (instr_ptr > final_instr_ptr) {
SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR);
}
if ((instr_ptr == final_instr_ptr) && !search_over) {
if (has_more_rows) {
*has_more_rows = false;
}
if (subsequent_pc) {
*subsequent_pc = 0;
}
} else {
if (has_more_rows) {
*has_more_rows = true;
}
if (subsequent_pc) {
*subsequent_pc = possible_subsequent_pc;
}
}
if (table != NULL) {
struct Dwarf_Reg_Rule_s *t2reg = table->fr_reg;
struct Dwarf_Reg_Rule_s *t3reg = localregtab;
unsigned minregcount = MIN(table->fr_reg_count,reg_count);
unsigned curreg = 0;
table->fr_loc = current_loc;
for (; curreg < minregcount ; curreg++, t3reg++, t2reg++) {
*t2reg = *t3reg;
}
table->fr_cfa_rule = cfa_reg;
}
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) {
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);
}
curr_instr_item = head_instr_chain;
for (i = 0; i < instr_count; i++) {
void *item = curr_instr_item->ch_item;
int itemtype = curr_instr_item->ch_itemtype;
Dwarf_Chain prev_instr = 0;
*(head_instr_block + i) = *(Dwarf_Frame_Op *)item;
prev_instr = curr_instr_item;
curr_instr_item = curr_instr_item->ch_next;
dwarf_dealloc(dbg, item, itemtype);
dwarf_dealloc(dbg, prev_instr, DW_DLA_CHAIN);
}
*ret_frame_instr = head_instr_block;
*returned_count = (Dwarf_Signed) instr_count;
} else {
*returned_count = 0;
}
free(localregtab);
return DW_DLV_OK;
#undef ERROR_IF_REG_NUM_TOO_HIGH
#undef SIMPLE_ERROR_RETURN
}
int
_dwarf_get_return_address_reg(Dwarf_Small *frame_ptr,
int version,
Dwarf_Debug dbg,
Dwarf_Byte_Ptr section_end,
unsigned long *size,
Dwarf_Unsigned *return_address_register,
Dwarf_Error *error)
{
Dwarf_Unsigned uvalue = 0;
Dwarf_Unsigned leb128_length = 0;
if (version == 1) {
if (frame_ptr >= section_end) {
_dwarf_error(NULL, error, DW_DLE_DF_FRAME_DECODING_ERROR);
return DW_DLV_ERROR;
}
*size = 1;
uvalue = *(unsigned char *) frame_ptr;
*return_address_register = uvalue;
return DW_DLV_OK;
}
DECODE_LEB128_UWORD_LEN_CK(frame_ptr,uvalue,leb128_length,
dbg,error,section_end);
*size = leb128_length;
*return_address_register = uvalue;
return DW_DLV_OK;
}
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;
}
int dwarf_get_cie_index(
Dwarf_Cie cie,
Dwarf_Signed* indx,
Dwarf_Error* error )
{
if (cie == NULL)
{
_dwarf_error(NULL, error, DW_DLE_CIE_NULL);
return (DW_DLV_ERROR);
}
*indx = cie->ci_index;
return (DW_DLV_OK);
}
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 = _dwarf_load_section(dbg, &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.dss_data,
dbg->de_debug_frame_eh_gnu.dss_index,
dbg->de_debug_frame_eh_gnu.dss_size,
0,
1,
error);
return res;
}
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 = _dwarf_load_section(dbg, &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.dss_data,
dbg->de_debug_frame.dss_index,
dbg->de_debug_frame.dss_size,
DW_CIE_ID,
0,
error);
return res;
}
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 *fde_start_ptr = 0;
unsigned char *fde_end_ptr = 0;
unsigned char *cie_ptr = 0;
Dwarf_Unsigned cie_id = 0;
int res = 0;
int resattr = 0;
int sdatares = 0;
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;
}
sdatares = dwarf_formsdata(attr, &signdval, error);
if (sdatares != DW_DLV_OK) {
return sdatares;
}
res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error);
if (res != DW_DLV_OK) {
return res;
}
fde_offset = signdval;
fde_start_ptr = dbg->de_debug_frame.dss_data;
fde_ptr = fde_start_ptr + fde_offset;
fde_end_ptr = fde_start_ptr + dbg->de_debug_frame.dss_size;
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.dss_data,
dbg->de_debug_frame.dss_index,
dbg->de_debug_frame.dss_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;
res = dwarf_create_fde_from_after_start(dbg, &prefix,
fde_start_ptr,
fde_ptr,
fde_end_ptr,
0,
0,
&new_fde, error);
if (res == DW_DLV_ERROR) {
return res;
} else if (res == DW_DLV_NO_ENTRY) {
return res;
}
cie_ptr = new_fde->fd_section_ptr + cie_id;
res = dwarf_read_cie_fde_prefix(dbg, cie_ptr,
dbg->de_debug_frame.dss_data,
dbg->de_debug_frame.dss_index,
dbg->de_debug_frame.dss_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 == (Dwarf_Unsigned)DW_CIE_ID) {
int res2 = 0;
Dwarf_Cie new_cie = 0;
res2 = dwarf_create_cie_from_after_start(dbg,
&prefix_c,
fde_start_ptr,
cie_ptr,
fde_end_ptr,
0,
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;
}
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);
}
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;
}
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;
}
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_Half offset_size = 0;
return dwarf_get_cie_info_b(cie,
bytes_in_cie,
ptr_to_version,
augmenter,
code_alignment_factor,
data_alignment_factor,
return_address_register,
initial_instructions,
initial_instructions_length,
&offset_size,
error);
}
int
dwarf_get_cie_info_b(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_Half * offset_size,
Dwarf_Error * error)
{
Dwarf_Debug dbg = 0;
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);
}
if (offset_size) {
*offset_size = cie->ci_length_size;
}
*bytes_in_cie = (cie->ci_length);
return (DW_DLV_OK);
}
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_Bool * has_more_rows,
Dwarf_Addr * subsequent_pc,
Dwarf_Error * error)
{
Dwarf_Debug dbg = 0;
Dwarf_Cie cie = 0;
Dwarf_Signed 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) {
Dwarf_Small *instrstart = cie->ci_cie_instr_start;
Dwarf_Small *instrend = instrstart +cie->ci_length +
cie->ci_length_size +
cie->ci_extension_size -
(cie->ci_cie_instr_start -
cie->ci_cie_start);
if (instrend > cie->ci_cie_end) {
_dwarf_error(dbg, error,DW_DLE_CIE_INSTR_PTR_ERROR);
return DW_DLV_ERROR;
}
cie->ci_initial_table = (Dwarf_Frame)_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_reg_rules_ru(cie->ci_initial_table->fr_reg,
0, cie->ci_initial_table->fr_reg_count,
dbg->de_frame_rule_initial_value);
dwarf_init_reg_rules_ru(&cie->ci_initial_table->fr_cfa_rule,
0,1,dbg->de_frame_rule_initial_value);
res = _dwarf_exec_frame_instr( false,
NULL,
false,
0,
0,
instrstart,
instrend,
cie->ci_initial_table, cie, dbg,
cfa_reg_col_num, &icount,
NULL,NULL,
error);
if (res != DW_DLV_OK) {
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);
if (instr_end > fde->fd_fde_end) {
_dwarf_error(dbg, error,DW_DLE_FDE_INSTR_PTR_ERROR);
return DW_DLV_ERROR;
}
res = _dwarf_exec_frame_instr( false,
NULL,
true,
pc_requested,
fde->fd_initial_location,
fde->fd_fde_instr_start,
instr_end,
table,
cie, dbg,
cfa_reg_col_num, &icount,
has_more_rows,
subsequent_pc,
error);
}
if (res != DW_DLV_OK) {
return res;
}
return DW_DLV_OK;
}
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)
{
struct Dwarf_Frame_s fde_table;
Dwarf_Signed i = 0;
struct Dwarf_Reg_Rule_s *rule = NULL;
struct Dwarf_Regtable_Entry_s *out_rule = NULL;
int res = 0;
Dwarf_Debug dbg = 0;
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;
res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested,
&fde_table, dbg->de_frame_cfa_col_number,NULL,NULL, 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;
}
dwarf_init_reg_rules_dw(®_table->rules[0],i,DW_REG_TABLE_SIZE,
dbg->de_frame_undefined_value_number);
if (dbg->de_frame_cfa_col_number < DW_REG_TABLE_SIZE) {
out_rule = ®_table->rules[dbg->de_frame_cfa_col_number];
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;
}
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_Signed 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);
if (res != DW_DLV_OK) {
return res;
}
res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested,
&fde_table,
dbg->de_frame_cfa_col_number,
NULL,NULL,
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;
}
dwarf_init_reg_rules_dw3(®_table->rt3_rules[0],i,reg_table->rt3_reg_table_size,
dbg->de_frame_undefined_value_number);
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;
}
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 = DW_DLV_ERROR;
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);
}
res =
_dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table,
dbg->de_frame_cfa_col_number,
NULL,NULL,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 (table_column == dbg->de_frame_cfa_col_number) {
if (register_num != NULL)
*register_num = fde_table.fr_cfa_rule.ru_register;
if (offset != NULL)
*offset = fde_table.fr_cfa_rule.ru_offset_or_block_len;
if (row_pc != NULL)
*row_pc = fde_table.fr_loc;
*offset_relevant = fde_table.fr_cfa_rule.ru_is_off;
} else {
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;
}
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)
{
int res = dwarf_get_fde_info_for_reg3_b(fde,
table_column, pc_requested, value_type,
offset_relevant, register_num,
offset_or_block_len,
block_ptr,
row_pc_out,
NULL,NULL,
error);
return res;
}
int
dwarf_get_fde_info_for_reg3_b(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_Bool * has_more_rows,
Dwarf_Addr * subsequent_pc,
Dwarf_Error * error)
{
struct Dwarf_Frame_s * fde_table = &(fde->fd_fde_table);
int res = DW_DLV_ERROR;
Dwarf_Debug dbg = 0;
int table_real_data_size = 0;
FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
if (!fde->fd_have_fde_tab ||
fde->fd_fde_pc_requested != pc_requested) {
if (fde->fd_have_fde_tab) {
dwarf_free_fde_table(fde_table);
fde->fd_have_fde_tab = false;
}
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);
fde->fd_have_fde_tab = false;
_dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD);
return (DW_DLV_ERROR);
}
res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, fde_table,
dbg->de_frame_cfa_col_number,
has_more_rows,subsequent_pc,
error);
if (res != DW_DLV_OK) {
dwarf_free_fde_table(fde_table);
fde->fd_have_fde_tab = false;
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;
}
*value_type = fde_table->fr_reg[table_column].ru_value_type;
*offset_relevant = (fde_table->fr_reg[table_column].ru_is_off);
fde->fd_have_fde_tab = true;
fde->fd_fde_pc_requested = pc_requested;
return DW_DLV_OK;
}
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)
{
Dwarf_Bool has_more_rows = 0;
Dwarf_Addr next_pc = 0;
int res = 0;
res = dwarf_get_fde_info_for_cfa_reg3_b(fde,
pc_requested,
value_type,
offset_relevant,
register_num,
offset_or_block_len,
block_ptr,
row_pc_out,
&has_more_rows,
&next_pc,
error);
return res;
}
int
dwarf_get_fde_info_for_cfa_reg3_b(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_Bool * has_more_rows,
Dwarf_Addr * subsequent_pc,
Dwarf_Error * error)
{
struct Dwarf_Frame_s fde_table;
int res = DW_DLV_ERROR;
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,
dbg->de_frame_cfa_col_number,has_more_rows,
subsequent_pc,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;
}
*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;
}
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;
}
int
dwarf_get_fde_n(Dwarf_Fde * fde_data,
Dwarf_Unsigned fde_index,
Dwarf_Fde * returned_fde, Dwarf_Error * error)
{
Dwarf_Debug dbg = 0;
Dwarf_Unsigned fdecount = 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);
fdecount = fde_data[0]->fd_is_eh?
dbg->de_fde_count_eh:dbg->de_fde_count;
if (fde_index >= fdecount) {
return (DW_DLV_NO_ENTRY);
}
*returned_fde = (*(fde_data + fde_index));
return DW_DLV_OK;
}
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;
Dwarf_Signed fdecount = 0;
if (fde_data == NULL) {
_dwarf_error(NULL, error, DW_DLE_FDE_PTR_NULL);
return (DW_DLV_ERROR);
}
entryfde = *fde_data;
FDE_NULL_CHECKS_AND_SET_DBG(entryfde, dbg);
fdecount = entryfde->fd_is_eh?
dbg->de_fde_count_eh:dbg->de_fde_count;
{
Dwarf_Signed low = 0;
Dwarf_Signed high = fdecount - 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);
}
int
dwarf_expand_frame_instructions(Dwarf_Cie cie,
Dwarf_Ptr instruction,
Dwarf_Unsigned i_length,
Dwarf_Frame_Op ** returned_op_list,
Dwarf_Signed * returned_op_count,
Dwarf_Error * error)
{
Dwarf_Signed instr_count;
int res = DW_DLV_ERROR;
Dwarf_Debug dbg = 0;
Dwarf_Small * instr_start = instruction;
Dwarf_Small * instr_end = (Dwarf_Small *)instruction + i_length;;
if (cie == 0) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
return (DW_DLV_ERROR);
}
dbg = cie->ci_dbg;
if (returned_op_list == 0 || returned_op_count == 0) {
_dwarf_error(dbg, error, DW_DLE_RET_OP_LIST_NULL);
return (DW_DLV_ERROR);
}
if ( instr_end < instr_start) {
_dwarf_error(dbg, error,DW_DLE_FDE_INSTR_PTR_ERROR);
return DW_DLV_ERROR;
}
res = _dwarf_exec_frame_instr( true,
returned_op_list,
false,
0,
0,
instr_start,
instr_end,
NULL,
cie,
dbg,
dbg->de_frame_cfa_col_number, &instr_count,
NULL,NULL,
error);
if (res != DW_DLV_OK) {
return (res);
}
*returned_op_count = instr_count;
return DW_DLV_OK;
}
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);
}
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;
if(!in_fde) {
_dwarf_error(dbg, err, DW_DLE_FDE_NULL);
return DW_DLV_ERROR;
}
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;
}
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);
}
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;
if(!in_cie) {
_dwarf_error(dbg, err, DW_DLE_CIE_NULL);
return DW_DLV_ERROR;
}
start = (char *) in_cie->ci_section_ptr;
loc = (char *) in_cie->ci_cie_start;
*cie_off = (loc - start);
return DW_DLV_OK;
}
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;
}
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);
}
if(!fde->fd_gnu_eh_aug_present) {
return DW_DLV_NO_ENTRY;
}
cie = fde->fd_cie;
if (cie == NULL) {
_dwarf_error(NULL, error, DW_DLE_CIE_NULL);
return (DW_DLV_ERROR);
}
*augdata = (Dwarf_Small *) fde->fd_gnu_eh_augmentation_bytes;
*augdata_len = fde->fd_gnu_eh_augmentation_len;
return DW_DLV_OK;
}
#if 0
static void
dump_frame_rule(char *msg, struct Dwarf_Reg_Rule_s *reg_rule)
{
printf
("%s type %s (0x%" DW_PR_XZEROS DW_PR_DUx
"), is_off %" DW_PR_DUu
" reg %" DW_PR_DUu " offset 0x%" DW_PR_XZEROS DW_PR_DUx
" blockp 0x%" DW_PR_XZEROS DW_PR_DUx "\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",
(Dwarf_Unsigned) reg_rule->ru_value_type,
(Dwarf_Unsigned) reg_rule->ru_is_off,
(Dwarf_Unsigned) reg_rule->ru_register,
(Dwarf_Unsigned) reg_rule->ru_offset_or_block_len,
(Dwarf_Unsigned) reg_rule->ru_block);
return;
}
#endif
Dwarf_Half
dwarf_set_frame_rule_initial_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;
}
Dwarf_Half
dwarf_set_frame_rule_inital_value(Dwarf_Debug dbg, Dwarf_Half value)
{
return dwarf_set_frame_rule_initial_value(dbg,value);
}
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;
if (value < DW_FRAME_LAST_REG_NUM) {
dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM;
}
return orig;
}
Dwarf_Half
dwarf_set_frame_cfa_value(Dwarf_Debug dbg, Dwarf_Half value)
{
Dwarf_Half orig = dbg->de_frame_cfa_col_number;
dbg->de_frame_cfa_col_number = value;
return orig;
}
Dwarf_Half
dwarf_set_frame_same_value(Dwarf_Debug dbg, Dwarf_Half value)
{
Dwarf_Half orig = dbg->de_frame_same_value_number;
dbg->de_frame_same_value_number = value;
return orig;
}
Dwarf_Half
dwarf_set_frame_undefined_value(Dwarf_Debug dbg, Dwarf_Half value)
{
Dwarf_Half orig = dbg->de_frame_same_value_number;
dbg->de_frame_undefined_value_number = value;
return orig;
}
Dwarf_Small dwarf_set_default_address_size(Dwarf_Debug dbg,
Dwarf_Small value )
{
Dwarf_Small orig = dbg->de_pointer_size;
if (value > 0 && value <= sizeof(Dwarf_Addr)) {
dbg->de_pointer_size = value;
}
return orig;
}
static int
init_reg_rules_alloc(Dwarf_Debug dbg,struct Dwarf_Frame_s *f,
unsigned count, Dwarf_Error * error)
{
f->fr_reg_count = count;
f->fr_reg = (struct Dwarf_Reg_Rule_s *)
calloc(sizeof(struct Dwarf_Reg_Rule_s), count);
if (f->fr_reg == 0) {
if (error) {
_dwarf_error(dbg, error, DW_DLE_DF_ALLOC_FAIL);
}
return (DW_DLV_ERROR);
}
dwarf_init_reg_rules_ru(f->fr_reg,0, count,
dbg->de_frame_rule_initial_value);
return DW_DLV_OK;
}
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);
memset(fde_table,0,entry_size);
fde_table->fr_loc = 0;
fde_table->fr_next = 0;
return init_reg_rules_alloc(dbg,fde_table,table_real_data_size,error);
}
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;
}
int
_dwarf_frame_constructor(Dwarf_Debug dbg, void *frame)
{
struct Dwarf_Frame_s *fp = frame;
if (!dbg) {
return DW_DLV_ERROR;
}
return init_reg_rules_alloc(dbg,fp,dbg->de_frame_reg_rules_entry_count, 0);
}
void
_dwarf_frame_destructor(void *frame)
{
struct Dwarf_Frame_s *fp = frame;
dwarf_free_fde_table(fp);
}
void
_dwarf_fde_destructor(void *f)
{
struct Dwarf_Fde_s *fde = f;
if (fde->fd_have_fde_tab) {
dwarf_free_fde_table(&fde->fd_fde_table);
fde->fd_have_fde_tab = false;
}
}
static void
dwarf_init_reg_rules_ru(struct Dwarf_Reg_Rule_s *base,
unsigned first, unsigned last,int initial_value)
{
struct Dwarf_Reg_Rule_s *r = base+first;
unsigned i = first;
for (; i < last; ++i,++r) {
r->ru_is_off = 0;
r->ru_value_type = DW_EXPR_OFFSET;
r->ru_register = initial_value;
r->ru_offset_or_block_len = 0;
r->ru_block = 0;
}
}
static void
dwarf_init_reg_rules_dw(struct Dwarf_Regtable_Entry_s *base,
unsigned first, unsigned last,int initial_value)
{
struct Dwarf_Regtable_Entry_s *r = base+first;
unsigned i = first;
for (; i < last; ++i,++r) {
r->dw_offset_relevant = 0;
r->dw_value_type = DW_EXPR_OFFSET;
r->dw_regnum = initial_value;
r->dw_offset = 0;
}
}
static void
dwarf_init_reg_rules_dw3(struct Dwarf_Regtable_Entry3_s *base,
unsigned first, unsigned last,int initial_value)
{
struct Dwarf_Regtable_Entry3_s *r = base+first;
unsigned i = first;
for (; i < last; ++i,++r) {
r->dw_offset_relevant = 0;
r->dw_value_type = DW_EXPR_OFFSET;
r->dw_regnum = initial_value;
r->dw_offset_or_block_len = 0;
r->dw_block_ptr = 0;
}
}