#include "config.h"
#include "dwarf_incl.h"
#include <stdio.h>
#include <stdlib.h>
#include "dwarf_frame.h"
#include "dwarf_arange.h" list */
static int dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
Dwarf_Cie cur_cie_ptr,
Dwarf_Cie * cie_ptr_to_use_out,
Dwarf_Cie head_cie_ptr);
static void dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
Dwarf_Cie head_cie_ptr);
static int dwarf_create_cie_from_start(Dwarf_Debug dbg,
Dwarf_Small * cie_ptr_val,
Dwarf_Small * section_ptr,
Dwarf_Unsigned section_index,
Dwarf_Unsigned section_length,
Dwarf_Small * frame_ptr_end,
Dwarf_Unsigned cie_id_value,
Dwarf_Unsigned cie_count,
int use_gnu_cie_calc,
Dwarf_Cie * cie_ptr_to_use_out,
Dwarf_Error * error);
static Dwarf_Small *get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
int use_gnu_cie_calc,
Dwarf_Small * section_ptr,
Dwarf_Small * cie_id_addr);
static int get_gcc_eh_augmentation(Dwarf_Debug dbg,
Dwarf_Small * frame_ptr,
unsigned long
*size_of_augmentation_data,
enum Dwarf_augmentation_type augtype,
Dwarf_Small * section_pointer,
Dwarf_Small * fde_eh_encoding_out,
char *augmentation);
static int
gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
unsigned char *pers_hand_enc_out,
unsigned char *lsda_enc_out,
unsigned char *fde_begin_enc_out,
Dwarf_Addr * gnu_pers_addr_out);
static int read_encoded_ptr(Dwarf_Debug dbg,
Dwarf_Small * input_field,
int gnu_encoding,
Dwarf_Unsigned * addr,
Dwarf_Small ** input_field_out);
static int qsort_compare(const void *elem1, const void *elem2);
static void
chain_up_fde(Dwarf_Fde newone, Dwarf_Fde * head, Dwarf_Fde * cur)
{
if (*head == NULL)
*head = newone;
else {
(*cur)->fd_next = newone;
}
*cur = newone;
}
static void
chain_up_cie(Dwarf_Cie newone, Dwarf_Cie * head, Dwarf_Cie * cur)
{
if (*head == NULL)
*head = newone;
else {
(*cur)->ci_next = newone;
}
*cur = newone;
}
#if 0
static void
print_prefix(struct cie_fde_prefix_s *prefix, int line)
{
printf("prefix-print, prefix at 0x%lx, line %d\n",
(long) prefix, line);
printf(" start addr 0x%lx after prefix 0x%lx\n",
(long) prefix->cf_start_addr,
(long) prefix->cf_addr_after_prefix);
printf(" length 0x%llx, len size %d ext size %d\n", (long long)
(unsigned long long) prefix->cf_length,
prefix->cf_local_length_size,
prefix->cf_local_extension_size);
printf(" cie_id 0x%llx cie_id cie_id_addr 0x%lx\n",
(unsigned long long) prefix->cf_cie_id,
(long) prefix->cf_cie_id_addr);
printf
(" sec ptr 0x%lx sec index %lld sec len 0x%llx sec past end 0x%lx\n",
(long) prefix->cf_section_ptr,
(long long) prefix->cf_section_index,
(unsigned long long) prefix->cf_section_length,
(long) prefix->cf_section_ptr + prefix->cf_section_length);
}
#endif
int
_dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
Dwarf_Signed * cie_element_count,
Dwarf_Fde ** fde_data,
Dwarf_Signed * fde_element_count,
Dwarf_Small * section_ptr,
Dwarf_Unsigned section_index,
Dwarf_Unsigned section_length,
Dwarf_Unsigned cie_id_value,
int use_gnu_cie_calc, Dwarf_Error * error)
{
Dwarf_Small *frame_ptr = section_ptr;
Dwarf_Small *frame_ptr_end = section_ptr + section_length;
Dwarf_Cie head_cie_ptr = NULL;
Dwarf_Cie cur_cie_ptr = NULL;
Dwarf_Word cie_count = 0;
Dwarf_Cie *cie_list_ptr = 0;
Dwarf_Fde head_fde_ptr = NULL;
Dwarf_Fde cur_fde_ptr = NULL;
Dwarf_Word fde_count = 0;
Dwarf_Fde *fde_list_ptr = NULL;
Dwarf_Word i = 0;
int res = 0;
if (frame_ptr == 0) {
return DW_DLV_NO_ENTRY;
}
while (frame_ptr < frame_ptr_end) {
struct cie_fde_prefix_s prefix;
memset(&prefix, 0, sizeof(prefix));
res = dwarf_read_cie_fde_prefix(dbg,
frame_ptr, section_ptr,
section_index,
section_length, &prefix, error);
if (res == DW_DLV_ERROR) {
dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
return res;
}
if (res == DW_DLV_NO_ENTRY)
break;
frame_ptr = prefix.cf_addr_after_prefix;
if (frame_ptr >= frame_ptr_end) {
dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
_dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
return DW_DLV_ERROR;
}
if (prefix.cf_cie_id == cie_id_value) {
Dwarf_Cie cie_ptr_to_use = 0;
res = dwarf_find_existing_cie_ptr(prefix.cf_start_addr,
cur_cie_ptr,
&cie_ptr_to_use,
head_cie_ptr);
if (res == DW_DLV_OK) {
cur_cie_ptr = cie_ptr_to_use;
} else if (res == DW_DLV_NO_ENTRY) {
res = dwarf_create_cie_from_after_start(dbg,
&prefix,
frame_ptr,
cie_count,
use_gnu_cie_calc,
&cie_ptr_to_use,
error);
if (res == DW_DLV_ERROR) {
dealloc_fde_cie_list_internal(head_fde_ptr,
head_cie_ptr);
return res;
}
cie_count++;
chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
&cur_cie_ptr);
} else {
dealloc_fde_cie_list_internal(head_fde_ptr,
head_cie_ptr);
return res;
}
frame_ptr = cie_ptr_to_use->ci_cie_start +
cie_ptr_to_use->ci_length +
cie_ptr_to_use->ci_length_size +
cie_ptr_to_use->ci_extension_size;
continue;
} else {
res = 0;
Dwarf_Cie cie_ptr_to_use = 0;
Dwarf_Fde fde_ptr_to_use = 0;
Dwarf_Small *cieptr_val =
get_cieptr_given_offset(prefix.cf_cie_id,
use_gnu_cie_calc,
section_ptr,
prefix.cf_cie_id_addr);
res = dwarf_find_existing_cie_ptr(cieptr_val,
cur_cie_ptr,
&cie_ptr_to_use,
head_cie_ptr);
if (res == DW_DLV_OK) {
cur_cie_ptr = cie_ptr_to_use;
} else if (res == DW_DLV_NO_ENTRY) {
res = dwarf_create_cie_from_start(dbg,
cieptr_val,
section_ptr,
section_index,
section_length,
frame_ptr_end,
cie_id_value,
cie_count,
use_gnu_cie_calc,
&cie_ptr_to_use,
error);
if (res == DW_DLV_ERROR) {
dealloc_fde_cie_list_internal(head_fde_ptr,
head_cie_ptr);
return res;
} else if (res == DW_DLV_NO_ENTRY) {
return res;
}
++cie_count;
chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
&cur_cie_ptr);
} else {
return res;
}
res = dwarf_create_fde_from_after_start(dbg,
&prefix,
frame_ptr,
use_gnu_cie_calc,
cie_ptr_to_use,
&fde_ptr_to_use,
error);
if (res == DW_DLV_ERROR) {
return res;
}
chain_up_fde(fde_ptr_to_use, &head_fde_ptr, &cur_fde_ptr);
fde_count++;
frame_ptr = fde_ptr_to_use->fd_fde_start +
fde_ptr_to_use->fd_length +
fde_ptr_to_use->fd_length_size +
fde_ptr_to_use->fd_extension_size;
continue;
}
}
if (cie_count > 0) {
cie_list_ptr = (Dwarf_Cie *)
_dwarf_get_alloc(dbg, DW_DLA_LIST, cie_count);
} else {
dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
return (DW_DLV_NO_ENTRY);
}
if (cie_list_ptr == NULL) {
dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
cur_cie_ptr = head_cie_ptr;
for (i = 0; i < cie_count; i++) {
*(cie_list_ptr + i) = cur_cie_ptr;
cur_cie_ptr = cur_cie_ptr->ci_next;
}
if (fde_count > 0) {
fde_list_ptr = (Dwarf_Fde *)
_dwarf_get_alloc(dbg, DW_DLA_LIST, fde_count);
} else {
dwarf_fde_cie_list_dealloc(dbg, cie_list_ptr, cie_count,
0,
0);
dealloc_fde_cie_list_internal(head_fde_ptr,
0);
return (DW_DLV_NO_ENTRY);
}
if (fde_list_ptr == NULL) {
dwarf_fde_cie_list_dealloc(dbg, cie_list_ptr, cie_count,
0,
0);
dealloc_fde_cie_list_internal(head_fde_ptr,
0);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
cur_fde_ptr = head_fde_ptr;
for (i = 0; i < fde_count; i++) {
*(fde_list_ptr + i) = cur_fde_ptr;
cur_fde_ptr = cur_fde_ptr->fd_next;
}
*cie_data = cie_list_ptr;
*cie_element_count = cie_count;
dbg->de_cie_data = cie_list_ptr;
dbg->de_cie_count = cie_count;
*fde_data = fde_list_ptr;
*fde_element_count = fde_count;
dbg->de_fde_data = fde_list_ptr;
dbg->de_fde_count = fde_count;
qsort((void *) fde_list_ptr, fde_count, sizeof(Dwarf_Ptr),
qsort_compare);
return (DW_DLV_OK);
}
int
dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
struct cie_fde_prefix_s *prefix,
Dwarf_Small * frame_ptr,
Dwarf_Unsigned cie_count,
int use_gnu_cie_calc,
Dwarf_Cie * cie_ptr_out,
Dwarf_Error * error)
{
Dwarf_Cie new_cie = 0;
Dwarf_Small eh_fde_encoding = 0;
Dwarf_Small *augmentation = 0;
Dwarf_Sword data_alignment_factor = -1;
Dwarf_Word code_alignment_factor = 4;
Dwarf_Unsigned return_address_register = 31;
int local_length_size = 0;
Dwarf_Word leb128_length = 0;
Dwarf_Unsigned cie_aug_data_len = 0;
Dwarf_Small *cie_aug_data = 0;
Dwarf_Addr gnu_personality_handler_addr = 0;
unsigned char gnu_personality_handler_encoding = 0;
unsigned char gnu_lsda_encoding = 0;
unsigned char gnu_fde_begin_encoding = 0;
enum Dwarf_augmentation_type augt = aug_unknown;
Dwarf_Small version = *(Dwarf_Small *) frame_ptr;
frame_ptr++;
if (version != DW_CIE_VERSION && version != DW_CIE_VERSION3 && version != DW_CIE_VERSION4) {
_dwarf_error(dbg, error, DW_DLE_FRAME_VERSION_BAD);
return (DW_DLV_ERROR);
}
augmentation = frame_ptr;
frame_ptr = frame_ptr + strlen((char *) frame_ptr) + 1;
augt = _dwarf_get_augmentation_type(dbg,
augmentation, use_gnu_cie_calc);
if (augt == aug_eh) {
Dwarf_Unsigned exception_table_addr;
READ_UNALIGNED(dbg, exception_table_addr,
Dwarf_Unsigned, frame_ptr, local_length_size);
frame_ptr += local_length_size;
}
{
Dwarf_Unsigned lreg = 0;
unsigned long size = 0;
DECODE_LEB128_UWORD(frame_ptr, lreg);
code_alignment_factor = (Dwarf_Word) lreg;
data_alignment_factor =
(Dwarf_Sword) _dwarf_decode_s_leb128(frame_ptr,
&leb128_length);
frame_ptr = frame_ptr + leb128_length;
return_address_register =
_dwarf_get_return_address_reg(frame_ptr, version, &size);
if (return_address_register > DW_FRAME_LAST_REG_NUM) {
_dwarf_error(dbg, error, DW_DLE_CIE_RET_ADDR_REG_ERROR);
return (DW_DLV_ERROR);
}
frame_ptr += size;
}
switch (augt) {
case aug_empty_string:
break;
case aug_irix_mti_v1:
break;
case aug_irix_exception_table:{
Dwarf_Unsigned lreg = 0;
Dwarf_Word length_of_augmented_fields;
DECODE_LEB128_UWORD(frame_ptr, lreg);
length_of_augmented_fields = (Dwarf_Word) lreg;
frame_ptr += length_of_augmented_fields;
}
break;
case aug_eh:{
int err = 0;
unsigned long increment = 0;
if (!use_gnu_cie_calc) {
_dwarf_error(dbg, error,
DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
err = get_gcc_eh_augmentation(dbg, frame_ptr, &increment,
augt,
prefix->cf_section_ptr,
&eh_fde_encoding,
(char *) augmentation);
if (err == DW_DLV_ERROR) {
_dwarf_error(dbg, error,
DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
frame_ptr += increment;
break;
}
case aug_gcc_eh_z:{
int res;
Dwarf_Unsigned adlen = 0;
DECODE_LEB128_UWORD(frame_ptr, adlen);
cie_aug_data_len = adlen;
cie_aug_data = frame_ptr;
res = gnu_aug_encodings(dbg,
(char *) augmentation,
cie_aug_data,
cie_aug_data_len,
&gnu_personality_handler_encoding,
&gnu_lsda_encoding,
&gnu_fde_begin_encoding,
&gnu_personality_handler_addr);
if (res != DW_DLV_OK) {
_dwarf_error(dbg, error,
DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return res;
}
frame_ptr += adlen;
break;
}
default:{
frame_ptr = prefix->cf_start_addr +
prefix->cf_length + prefix->cf_local_length_size
+ prefix->cf_local_extension_size;
break;
}
}
new_cie = (Dwarf_Cie) _dwarf_get_alloc(dbg, DW_DLA_CIE, 1);
if (new_cie == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
new_cie->ci_cie_version_number = version;
new_cie->ci_initial_table = NULL;
new_cie->ci_length = (Dwarf_Word) prefix->cf_length;
new_cie->ci_length_size = prefix->cf_local_length_size;
new_cie->ci_extension_size = prefix->cf_local_extension_size;
new_cie->ci_augmentation = (char *) augmentation;
new_cie->ci_data_alignment_factor =
(Dwarf_Sbyte) data_alignment_factor;
new_cie->ci_code_alignment_factor =
(Dwarf_Small) code_alignment_factor;
new_cie->ci_return_address_register = return_address_register;
new_cie->ci_cie_start = prefix->cf_start_addr;
new_cie->ci_cie_instr_start = frame_ptr;
new_cie->ci_dbg = dbg;
new_cie->ci_augmentation_type = augt;
new_cie->ci_gnu_eh_augmentation_len = cie_aug_data_len;
new_cie->ci_gnu_eh_augmentation_bytes = cie_aug_data;
new_cie->ci_gnu_personality_handler_encoding =
gnu_personality_handler_encoding;
new_cie->ci_gnu_personality_handler_addr =
gnu_personality_handler_addr;
new_cie->ci_gnu_lsda_encoding = gnu_lsda_encoding;
new_cie->ci_gnu_fde_begin_encoding = gnu_fde_begin_encoding;
new_cie->ci_index = cie_count;
new_cie->ci_section_ptr = prefix->cf_section_ptr;
*cie_ptr_out = new_cie;
return DW_DLV_OK;
}
int
dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
struct cie_fde_prefix_s *prefix,
Dwarf_Small * frame_ptr,
int use_gnu_cie_calc,
Dwarf_Cie cie_ptr_in,
Dwarf_Fde * fde_ptr_out,
Dwarf_Error * error)
{
Dwarf_Fde new_fde = 0;
Dwarf_Cie cieptr = cie_ptr_in;
Dwarf_Small *saved_frame_ptr = 0;
Dwarf_Small *initloc = frame_ptr;
Dwarf_Signed offset_into_exception_tables
= (Dwarf_Signed) DW_DLX_NO_EH_OFFSET;
Dwarf_Small *fde_aug_data = 0;
Dwarf_Unsigned fde_aug_data_len = 0;
Dwarf_Addr cie_base_offset = prefix->cf_cie_id;
Dwarf_Addr initial_location = 0;
Dwarf_Addr address_range = 0;
enum Dwarf_augmentation_type augt = cieptr->ci_augmentation_type;
if (augt == aug_gcc_eh_z) {
{
Dwarf_Small *fp_updated = 0;
int res = res = read_encoded_ptr(dbg, frame_ptr,
cieptr->
ci_gnu_fde_begin_encoding,
&initial_location,
&fp_updated);
if (res != DW_DLV_OK) {
_dwarf_error(dbg, error,
DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
frame_ptr = fp_updated;
res = read_encoded_ptr(dbg, frame_ptr,
cieptr->ci_gnu_fde_begin_encoding,
&address_range, &fp_updated);
if (res != DW_DLV_OK) {
_dwarf_error(dbg, error,
DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
frame_ptr = fp_updated;
}
{
Dwarf_Unsigned adlen = 0;
DECODE_LEB128_UWORD(frame_ptr, adlen);
fde_aug_data_len = adlen;
fde_aug_data = frame_ptr;
frame_ptr += adlen;
}
} else {
READ_UNALIGNED(dbg, initial_location, Dwarf_Addr,
frame_ptr, dbg->de_pointer_size);
frame_ptr += dbg->de_pointer_size;
READ_UNALIGNED(dbg, address_range, Dwarf_Addr,
frame_ptr, dbg->de_pointer_size);
frame_ptr += dbg->de_pointer_size;
}
switch (augt) {
case aug_irix_mti_v1:
case aug_empty_string:
break;
case aug_irix_exception_table:{
Dwarf_Unsigned lreg = 0;
Dwarf_Word length_of_augmented_fields = 0;
DECODE_LEB128_UWORD(frame_ptr, lreg);
length_of_augmented_fields = (Dwarf_Word) lreg;
saved_frame_ptr = frame_ptr;
READ_UNALIGNED(dbg, offset_into_exception_tables,
Dwarf_Addr, frame_ptr, sizeof(Dwarf_sfixed));
SIGN_EXTEND(offset_into_exception_tables,
sizeof(Dwarf_sfixed));
frame_ptr = saved_frame_ptr + length_of_augmented_fields;
}
break;
case aug_eh:{
Dwarf_Unsigned eh_table_value = 0;
if (!use_gnu_cie_calc) {
_dwarf_error(dbg, error,
DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
return DW_DLV_ERROR;
}
READ_UNALIGNED(dbg, eh_table_value,
Dwarf_Unsigned, frame_ptr,
dbg->de_pointer_size);
frame_ptr += dbg->de_pointer_size;
}
break;
case aug_gcc_eh_z:{
}
break;
default:;
}
new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1);
if (new_fde == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
new_fde->fd_length = prefix->cf_length;
new_fde->fd_length_size = prefix->cf_local_length_size;
new_fde->fd_extension_size = prefix->cf_local_extension_size;
new_fde->fd_cie_offset = cie_base_offset;
new_fde->fd_cie_index = cieptr->ci_index;
new_fde->fd_cie = cieptr;
new_fde->fd_initial_location = initial_location;
new_fde->fd_initial_loc_pos = initloc;
new_fde->fd_address_range = address_range;
new_fde->fd_fde_start = prefix->cf_start_addr;
new_fde->fd_fde_instr_start = frame_ptr;
new_fde->fd_dbg = dbg;
new_fde->fd_offset_into_exception_tables =
offset_into_exception_tables;
new_fde->fd_section_ptr = prefix->cf_section_ptr;
new_fde->fd_section_index = prefix->cf_section_index;
new_fde->fd_section_length = prefix->cf_section_length;
new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data;
new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len;
*fde_ptr_out = new_fde;
return DW_DLV_OK;
}
static int
qsort_compare(const void *elem1, const void *elem2)
{
Dwarf_Fde fde1 = *(Dwarf_Fde *) elem1;
Dwarf_Fde fde2 = *(Dwarf_Fde *) elem2;
Dwarf_Addr addr1 = fde1->fd_initial_location;
Dwarf_Addr addr2 = fde2->fd_initial_location;
if (addr1 < addr2) {
return -1;
} else if (addr1 > addr2) {
return 1;
}
return 0;
}
int
dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
Dwarf_Small * frame_ptr_in,
Dwarf_Small * section_ptr_in,
Dwarf_Unsigned section_index_in,
Dwarf_Unsigned section_length_in,
struct cie_fde_prefix_s *data_out,
Dwarf_Error * error)
{
Dwarf_Unsigned length = 0;
int local_length_size = 0;
int local_extension_size = 0;
Dwarf_Small *frame_ptr = frame_ptr_in;
Dwarf_Small *cie_ptr_addr = 0;
Dwarf_Unsigned cie_id = 0;
READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
frame_ptr, local_length_size,
local_extension_size);
if (length % local_length_size != 0) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
return (DW_DLV_ERROR);
}
if (length == 0) {
return DW_DLV_NO_ENTRY;
}
cie_ptr_addr = frame_ptr;
READ_UNALIGNED(dbg, cie_id, Dwarf_Unsigned,
frame_ptr, local_length_size);
SIGN_EXTEND(cie_id, local_length_size);
frame_ptr += local_length_size;
data_out->cf_start_addr = frame_ptr_in;
data_out->cf_addr_after_prefix = frame_ptr;
data_out->cf_length = length;
data_out->cf_local_length_size = local_length_size;
data_out->cf_local_extension_size = local_extension_size;
data_out->cf_cie_id = cie_id;
data_out->cf_cie_id_addr = cie_ptr_addr;
data_out->cf_section_ptr = section_ptr_in;
data_out->cf_section_index = section_index_in;
data_out->cf_section_length = section_length_in;
return DW_DLV_OK;
}
static void
dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
Dwarf_Cie head_cie_ptr)
{
Dwarf_Fde curfde = 0;
Dwarf_Cie curcie = 0;
Dwarf_Fde nextfde = 0;
Dwarf_Cie nextcie = 0;
for (curfde = head_fde_ptr; curfde; curfde = nextfde) {
nextfde = curfde->fd_next;
dwarf_dealloc(curfde->fd_dbg, curfde, DW_DLA_FDE);
}
for (curcie = head_cie_ptr; curcie; curcie = nextcie) {
Dwarf_Frame frame = curcie->ci_initial_table;
nextcie = curcie->ci_next;
if (frame)
dwarf_dealloc(curcie->ci_dbg, frame, DW_DLA_FRAME);
dwarf_dealloc(curcie->ci_dbg, curcie, DW_DLA_CIE);
}
}
static int
dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
Dwarf_Cie cur_cie_ptr,
Dwarf_Cie * cie_ptr_to_use_out,
Dwarf_Cie head_cie_ptr)
{
Dwarf_Cie next = 0;
if (cur_cie_ptr && cie_ptr == cur_cie_ptr->ci_cie_start) {
*cie_ptr_to_use_out = cur_cie_ptr;
return DW_DLV_OK;
}
for (next = head_cie_ptr; next; next = next->ci_next) {
if (cie_ptr == next->ci_cie_start) {
*cie_ptr_to_use_out = next;
return DW_DLV_OK;
}
}
return DW_DLV_NO_ENTRY;
}
static int
dwarf_create_cie_from_start(Dwarf_Debug dbg,
Dwarf_Small * cie_ptr_val,
Dwarf_Small * section_ptr,
Dwarf_Unsigned section_index,
Dwarf_Unsigned section_length,
Dwarf_Small * frame_ptr_end,
Dwarf_Unsigned cie_id_value,
Dwarf_Unsigned cie_count,
int use_gnu_cie_calc,
Dwarf_Cie * cie_ptr_to_use_out,
Dwarf_Error * error)
{
struct cie_fde_prefix_s prefix;
int res = 0;
Dwarf_Small *frame_ptr = cie_ptr_val;
if (frame_ptr < section_ptr || frame_ptr > frame_ptr_end) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
return DW_DLV_ERROR;
}
memset(&prefix, 0, sizeof(prefix));
res = dwarf_read_cie_fde_prefix(dbg, frame_ptr, section_ptr,
section_index, section_length,
&prefix, error);
if (res == DW_DLV_ERROR) {
return res;
}
if (res == DW_DLV_NO_ENTRY) {
_dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR);
return DW_DLV_ERROR;
}
if (prefix.cf_cie_id != cie_id_value) {
_dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR);
return DW_DLV_ERROR;
}
frame_ptr = prefix.cf_addr_after_prefix;
res = dwarf_create_cie_from_after_start(dbg,
&prefix,
frame_ptr,
cie_count,
use_gnu_cie_calc,
cie_ptr_to_use_out, error);
return res;
}
#if 0
static void
dump_bytes(Dwarf_Small * start, long len)
{
Dwarf_Small *end = start + len;
Dwarf_Small *cur = start;
for (; cur < end; cur++) {
printf(" byte %d, data %02x\n", (int) (cur - start), *cur);
}
}
#endif
static int
gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
unsigned char *pers_hand_enc_out,
unsigned char *lsda_enc_out,
unsigned char *fde_begin_enc_out,
Dwarf_Addr * gnu_pers_addr_out)
{
char *nc = 0;
Dwarf_Small *cur_aug_p = aug_data;
Dwarf_Small *end_aug_p = aug_data + aug_data_len;
for (nc = augmentation; *nc; ++nc) {
char c = *nc;
switch (c) {
case 'z':
continue;
case 'L':
if (cur_aug_p > end_aug_p) {
return DW_DLV_ERROR;
}
*lsda_enc_out = *(unsigned char *) cur_aug_p;
++cur_aug_p;
break;
case 'R':
if (cur_aug_p >= end_aug_p) {
return DW_DLV_ERROR;
}
*fde_begin_enc_out = *(unsigned char *) cur_aug_p;
++cur_aug_p;
break;
case 'P':{
int res = 0;
Dwarf_Small *updated_aug_p = 0;
unsigned char encoding = 0;
if (cur_aug_p >= end_aug_p) {
return DW_DLV_ERROR;
}
encoding = *(unsigned char *) cur_aug_p;
*pers_hand_enc_out = encoding;
++cur_aug_p;
if (cur_aug_p > end_aug_p) {
return DW_DLV_ERROR;
}
res = read_encoded_ptr(dbg,
cur_aug_p,
encoding,
gnu_pers_addr_out,
&updated_aug_p);
if (res != DW_DLV_OK) {
return res;
}
cur_aug_p = updated_aug_p;
if (cur_aug_p > end_aug_p) {
return DW_DLV_ERROR;
}
}
break;
default:
return DW_DLV_ERROR;
}
}
return DW_DLV_OK;
}
static int
read_encoded_ptr(Dwarf_Debug dbg,
Dwarf_Small * input_field,
int gnu_encoding,
Dwarf_Unsigned * addr,
Dwarf_Small ** input_field_updated)
{
Dwarf_Word length = 0;
int value_type = gnu_encoding & 0xf;
if (gnu_encoding == 0xff) {
*addr = 0;
*input_field_updated = input_field;
return DW_DLV_OK;
}
switch (value_type) {
case DW_EH_PE_absptr:{
Dwarf_Unsigned ret_value = 0;
READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
input_field, dbg->de_pointer_size);
*addr = ret_value;
*input_field_updated = input_field + dbg->de_pointer_size;
}
break;
case DW_EH_PE_uleb128:{
Dwarf_Unsigned val = _dwarf_decode_u_leb128(input_field,
&length);
*addr = val;
*input_field_updated = input_field + length;
}
break;
case DW_EH_PE_udata2:{
Dwarf_Unsigned ret_value = 0;
READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
input_field, 2);
*addr = ret_value;
*input_field_updated = input_field + 2;
}
break;
case DW_EH_PE_udata4:{
Dwarf_Unsigned ret_value = 0;
READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
input_field, sizeof(Dwarf_ufixed));
*addr = ret_value;
*input_field_updated = input_field + sizeof(Dwarf_ufixed);
}
break;
case DW_EH_PE_udata8:{
Dwarf_Unsigned ret_value = 0;
READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
input_field, sizeof(Dwarf_Unsigned));
*addr = ret_value;
*input_field_updated = input_field + sizeof(Dwarf_Unsigned);
}
break;
case DW_EH_PE_sleb128:{
Dwarf_Signed val = _dwarf_decode_s_leb128(input_field,
&length);
*addr = (Dwarf_Unsigned) val;
*input_field_updated = input_field + length;
}
break;
case DW_EH_PE_sdata2:{
Dwarf_Unsigned val = 0;
READ_UNALIGNED(dbg, val, Dwarf_Unsigned, input_field, 2);
SIGN_EXTEND(val, 2);
*addr = (Dwarf_Unsigned) val;
*input_field_updated = input_field + 2;
}
break;
case DW_EH_PE_sdata4:{
Dwarf_Unsigned val = 0;
READ_UNALIGNED(dbg, val,
Dwarf_Unsigned, input_field,
sizeof(Dwarf_ufixed));
SIGN_EXTEND(val, sizeof(Dwarf_ufixed));
*addr = (Dwarf_Unsigned) val;
*input_field_updated = input_field + sizeof(Dwarf_ufixed);
}
break;
case DW_EH_PE_sdata8:{
Dwarf_Unsigned val = 0;
READ_UNALIGNED(dbg, val,
Dwarf_Unsigned, input_field,
sizeof(Dwarf_Unsigned));
*addr = (Dwarf_Unsigned) val;
*input_field_updated = input_field + sizeof(Dwarf_Unsigned);
}
break;
default:
return DW_DLV_ERROR;
};
return DW_DLV_OK;
}
enum Dwarf_augmentation_type
_dwarf_get_augmentation_type(Dwarf_Debug dbg,
Dwarf_Small * augmentation_string,
int is_gcc_eh_frame)
{
#pragma unused(dbg)
enum Dwarf_augmentation_type t = aug_unknown;
char *ag_string = (char *) augmentation_string;
if (ag_string[0] == 0) {
t = aug_empty_string;
} else if (strcmp(ag_string, DW_DEBUG_FRAME_AUGMENTER_STRING) == 0) {
t = aug_irix_mti_v1;
} else if (ag_string[0] == 'z') {
if (is_gcc_eh_frame) {
t = aug_gcc_eh_z;
} else if (ag_string[1] == 0) {
t = aug_irix_exception_table;
}
} else if (strncmp(ag_string, "eh", 2) == 0) {
t = aug_eh;
}
return t;
}
static int
get_gcc_eh_augmentation(Dwarf_Debug dbg, Dwarf_Small * frame_ptr,
unsigned long *size_of_augmentation_data,
enum Dwarf_augmentation_type augtype,
Dwarf_Small * section_pointer,
Dwarf_Small * fde_eh_encoding_out,
char *augmentation)
{
#pragma unused(dbg, section_pointer, fde_eh_encoding_out)
char *suffix = 0;
unsigned long augdata_size = 0;
if (augtype == aug_gcc_eh_z) {
Dwarf_Word leb128_length = 0;
_dwarf_decode_u_leb128(frame_ptr, &leb128_length);
augdata_size += leb128_length;
frame_ptr += leb128_length;
suffix = augmentation + 1;
} else {
suffix = augmentation + 2;
}
for (; *suffix; ++suffix) {
return DW_DLV_ERROR;
}
*size_of_augmentation_data = augdata_size;
return DW_DLV_OK;
}
static Dwarf_Small *
get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
int use_gnu_cie_calc,
Dwarf_Small * section_ptr,
Dwarf_Small * cie_id_addr)
{
Dwarf_Small *cieptr = 0;
if (use_gnu_cie_calc) {
cieptr = (Dwarf_Small *) ((Dwarf_Unsigned) cie_id_addr) -
((Dwarf_Unsigned) cie_id_value);
} else {
cieptr = (section_ptr + cie_id_value);
}
return cieptr;
}
void
dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg,
Dwarf_Cie * cie_data,
Dwarf_Signed cie_element_count,
Dwarf_Fde * fde_data,
Dwarf_Signed fde_element_count)
{
Dwarf_Signed i = 0;
for (i = 0; i < cie_element_count; ++i) {
Dwarf_Frame frame = cie_data[i]->ci_initial_table;
if (frame)
dwarf_dealloc(dbg, frame, DW_DLA_FRAME);
dwarf_dealloc(dbg, cie_data[i], DW_DLA_CIE);
}
for (i = 0; i < fde_element_count; ++i) {
dwarf_dealloc(dbg, fde_data[i], DW_DLA_FDE);
}
if (cie_data)
dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
if (fde_data)
dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
}