#include "config.h"
#include "dwarf_incl.h"
#include <stdio.h>
#include <stdlib.h>
#include "dwarf_frame.h"
#include "dwarf_arange.h"
#define ERROR_IF_REG_NUM_TOO_HIGH(reg) \
do { \
if (reg >= DW_FRAME_LAST_REG_NUM) { \
*returned_error = DW_DLE_DF_REG_NUM_TOO_HIGH; \
return DW_DLV_ERROR; \
} \
} while(0)
#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
static void dump_frame_rule(char *msg,
struct Dwarf_Reg_Rule_s *reg_rule);
#endif
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)
{
Dwarf_Small *instr_ptr;
Dwarf_Small instr, opcode;
Dwarf_Small reg_no, reg_noA, reg_noB;
Dwarf_Unsigned factored_N_value;
Dwarf_Signed signed_factored_N_value;
Dwarf_Addr current_loc = initial_loc;
Dwarf_Unsigned adv_loc;
struct Dwarf_Reg_Rule_s reg[DW_FRAME_LAST_REG_NUM];
struct Dwarf_Reg_Rule_s cfa_reg;
Dwarf_Bool search_over = false;
Dwarf_Addr adv_pc;
Dwarf_Word leb128_length;
Dwarf_Word instr_count = 0;
Dwarf_Small fp_base_op = 0;
Dwarf_Small fp_extended_op;
Dwarf_Half fp_register;
Dwarf_Unsigned fp_offset;
Dwarf_Off fp_instr_offset;
Dwarf_Frame stack_table;
Dwarf_Frame top_stack = NULL;
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;
Dwarf_Sword code_alignment_factor = 1;
Dwarf_Sword data_alignment_factor = 1;
Dwarf_Bool need_augmentation = false;
Dwarf_Word i;
struct Dwarf_Reg_Rule_s *t1reg;
struct Dwarf_Reg_Rule_s *t1end;
struct Dwarf_Reg_Rule_s *t2reg;
t1reg = reg;
t1end = t1reg + DW_FRAME_LAST_REG_NUM;
if (cie != NULL && cie->ci_initial_table != NULL) {
t2reg = cie->ci_initial_table->fr_reg;
for (; t1reg < t1end; t1reg++, t2reg++) {
*t1reg = *t2reg;
}
cfa_reg = cie->ci_initial_table->fr_cfa_rule;
} else {
_dwarf_init_regrule_table(t1reg,
dbg->de_frame_reg_rules_entry_count,
dbg->de_frame_rule_initial_value);
_dwarf_init_regrule_table(&cfa_reg, 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)) {
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) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
adv_pc = adv_pc * code_alignment_factor;
search_over = search_pc &&
(current_loc + adv_pc > search_pc_val);
if (!search_over)
current_loc = current_loc + adv_pc;
break;
}
case DW_CFA_offset:{
reg_no = (instr & DW_FRAME_INSTR_OFFSET_MASK);
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
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) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
reg[reg_no].ru_is_off = 1;
reg[reg_no].ru_value_type = DW_EXPR_OFFSET;
reg[reg_no].ru_register = reg_num_of_cfa;
reg[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);
fp_register = reg_no;
if (cie != NULL && cie->ci_initial_table != NULL)
reg[reg_no] = cie->ci_initial_table->fr_reg[reg_no];
else if (!make_instr) {
*returned_error = (DW_DLE_DF_MAKE_INSTR_NO_INIT);
return DW_DLV_ERROR;
}
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) {
if (new_loc <= current_loc) {
*returned_error =
(DW_DLE_DF_NEW_LOC_LESS_OLD_LOC);
return DW_DLV_ERROR;
}
}
search_over = search_pc && (new_loc > search_pc_val);
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) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
adv_loc *= code_alignment_factor;
search_over = search_pc &&
(current_loc + adv_loc > search_pc_val);
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) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
adv_loc *= code_alignment_factor;
search_over = search_pc &&
(current_loc + adv_loc > search_pc_val);
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) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
adv_loc *= code_alignment_factor;
search_over = search_pc &&
(current_loc + adv_loc > search_pc_val);
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 = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
factored_N_value =
_dwarf_decode_u_leb128(instr_ptr, &leb128_length);
instr_ptr += leb128_length;
if (need_augmentation) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
reg[reg_no].ru_is_off = 1;
reg[reg_no].ru_value_type = DW_EXPR_OFFSET;
reg[reg_no].ru_register = reg_num_of_cfa;
reg[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 = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
if (cie != NULL && cie->ci_initial_table != NULL) {
reg[reg_no] = cie->ci_initial_table->fr_reg[reg_no];
} else {
if (!make_instr) {
*returned_error =
(DW_DLE_DF_MAKE_INSTR_NO_INIT);
return DW_DLV_ERROR;
}
}
fp_register = reg_no;
break;
}
case DW_CFA_undefined:{
Dwarf_Unsigned lreg;
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
reg[reg_no].ru_is_off = 0;
reg[reg_no].ru_value_type = DW_EXPR_OFFSET;
reg[reg_no].ru_register = DW_FRAME_UNDEFINED_VAL;
reg[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 = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
reg[reg_no].ru_is_off = 0;
reg[reg_no].ru_value_type = DW_EXPR_OFFSET;
reg[reg_no].ru_register = DW_FRAME_SAME_VAL;
reg[reg_no].ru_offset_or_block_len = 0;
fp_register = reg_no;
break;
}
case DW_CFA_register:{
Dwarf_Unsigned lreg;
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_noA = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_noB = (Dwarf_Small) lreg;
if (reg_noB > DW_FRAME_LAST_REG_NUM) {
*returned_error = (DW_DLE_DF_REG_NUM_TOO_HIGH);
return DW_DLV_ERROR;
}
reg[reg_noA].ru_is_off = 0;
reg[reg_noA].ru_value_type = DW_EXPR_OFFSET;
reg[reg_noA].ru_register = reg_noB;
reg[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) {
*returned_error = (DW_DLE_DF_ALLOC_FAIL);
return DW_DLV_ERROR;
}
for (i = 0; i <= DW_FRAME_LAST_REG_NUM; i++)
stack_table->fr_reg[i] = reg[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) {
*returned_error = (DW_DLE_DF_POP_EMPTY_STACK);
return DW_DLV_ERROR;
}
stack_table = top_stack;
top_stack = stack_table->fr_next;
for (i = 0; i < DW_FRAME_LAST_REG_NUM; i++)
reg[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 = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
factored_N_value =
_dwarf_decode_u_leb128(instr_ptr, &leb128_length);
instr_ptr += leb128_length;
if (need_augmentation) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
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 = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
cfa_reg.ru_register = reg_no;
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) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
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;
}
case DW_CFA_def_cfa_expression:
{
Dwarf_Unsigned block_len = 0;
DECODE_LEB128_UWORD(instr_ptr, block_len)
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) instr_ptr;
}
break;
case DW_CFA_expression:
{
Dwarf_Unsigned lreg = 0;
Dwarf_Unsigned block_len = 0;
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
DECODE_LEB128_UWORD(instr_ptr, block_len)
reg[lreg].ru_is_off = 0;
reg[lreg].ru_value_type = DW_EXPR_EXPRESSION;
reg[lreg].ru_offset_or_block_len = block_len;
reg[lreg].ru_block = instr_ptr;
fp_offset = (Dwarf_Unsigned) instr_ptr;
fp_register = lreg;
}
break;
case DW_CFA_cfa_offset_extended_sf:
{
Dwarf_Unsigned lreg;
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
signed_factored_N_value =
_dwarf_decode_s_leb128(instr_ptr, &leb128_length);
instr_ptr += leb128_length;
if (need_augmentation) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
reg[reg_no].ru_is_off = 1;
reg[reg_no].ru_value_type = DW_EXPR_OFFSET;
reg[reg_no].ru_register = reg_num_of_cfa;
reg[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(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
signed_factored_N_value =
_dwarf_decode_s_leb128(instr_ptr, &leb128_length);
instr_ptr += leb128_length;
if (need_augmentation) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
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:
{
signed_factored_N_value =
_dwarf_decode_s_leb128(instr_ptr, &leb128_length);
instr_ptr += leb128_length;
if (need_augmentation) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
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;
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
factored_N_value =
_dwarf_decode_u_leb128(instr_ptr, &leb128_length);
instr_ptr += leb128_length;
if (need_augmentation) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
reg[reg_no].ru_is_off = 1;
reg[reg_no].ru_register = reg_num_of_cfa;
reg[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET;
reg[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;
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
signed_factored_N_value =
_dwarf_decode_s_leb128(instr_ptr, &leb128_length);
instr_ptr += leb128_length;
if (need_augmentation) {
*returned_error = (DW_DLE_DF_NO_CIE_AUGMENTATION);
return DW_DLV_ERROR;
}
reg[reg_no].ru_is_off = 1;
reg[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET;
reg[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(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
ERROR_IF_REG_NUM_TOO_HIGH(reg_no);
DECODE_LEB128_UWORD(instr_ptr, block_len)
reg[lreg].ru_is_off = 0;
reg[lreg].ru_value_type = DW_EXPR_VAL_EXPRESSION;
reg[lreg].ru_offset_or_block_len = block_len;
reg[lreg].ru_block = instr_ptr;
fp_offset = (Dwarf_Unsigned) instr_ptr;
fp_register = lreg;
}
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:{
Dwarf_Unsigned lreg;
DECODE_LEB128_UWORD(instr_ptr, lreg)
reg_no = (Dwarf_Small) lreg;
break;
}
#endif
default:
*returned_error = DW_DLE_DF_FRAME_DECODING_ERROR;
return DW_DLV_ERROR;
}
if (make_instr) {
instr_count++;
curr_instr = (Dwarf_Frame_Op *)
_dwarf_get_alloc(dbg, DW_DLA_FRAME_OP, 1);
if (curr_instr == NULL) {
*returned_error = (DW_DLE_DF_ALLOC_FAIL);
return DW_DLV_ERROR;
}
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) {
*returned_error = (DW_DLE_DF_ALLOC_FAIL);
return DW_DLV_ERROR;
}
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 (instr_ptr > final_instr_ptr) {
*returned_error = (DW_DLE_DF_FRAME_DECODING_ERROR);
return DW_DLV_ERROR;
}
if (table != NULL) {
t1reg = reg;
t1end = t1reg + DW_FRAME_LAST_REG_NUM;
table->fr_loc = current_loc;
t2reg = table->fr_reg;
for (; t1reg < t1end; t1reg++, t2reg++) {
*t2reg = *t1reg;
}
if (reg_num_of_cfa < DW_FRAME_LAST_REG_NUM) {
t2reg = table->fr_reg + reg_num_of_cfa;
*t2reg = cfa_reg;
}
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) {
*returned_error = DW_DLE_DF_ALLOC_FAIL;
return DW_DLV_ERROR;
}
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;
}
return DW_DLV_OK;
}
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;
}
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_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,
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;
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,
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 *cie_ptr = 0;
Dwarf_Unsigned cie_id = 0;
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;
}
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);
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;
res = dwarf_create_fde_from_after_start(dbg, &prefix, fde_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,
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;
res2 = dwarf_create_cie_from_after_start(dbg,
&prefix_c, cie_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_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);
}
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( false,
NULL,
false,
0,
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( false,
NULL,
true,
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;
}
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_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;
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,
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;
}
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;
}
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);
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;
}
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);
}
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;
}
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);
}
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;
*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;
}
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;
*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;
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;
}
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);
}
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);
}
{
int low = 0;
int high = dbg->de_fde_count - 1;
int 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_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);
}
res = _dwarf_exec_frame_instr( true,
returned_op_list,
false,
0,
0,
instruction,
(Dwarf_Ptr) ((Dwarf_Unsigned)
instruction + i_length),
NULL,
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;
}
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 0
res =
_dwarf_load_section(dbg,
dbg->de_debug_frame_index,
&dbg->de_debug_frame, err);
if (res != DW_DLV_OK) {
return res;
}
#endif
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)
{
char *start = 0;
char *loc = 0;
#if 0
res =
_dwarf_load_section(dbg,
dbg->de_debug_frame_index,
&dbg->de_debug_frame, err);
if (res != DW_DLV_OK) {
return res;
}
#endif
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);
}
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;
}
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
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
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;
}
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 *)
malloc(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;
}
int
_dwarf_frame_constructor(Dwarf_Debug dbg, void *frame)
{
struct Dwarf_Frame_s *fp = frame;
if (!dbg) {
return DW_DLV_ERROR;
}
fp->fr_reg = malloc(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;
}