#include <config.h>
#include <stddef.h> /* NULL size_t */
#include <stdio.h> /* debug printf */
#if defined(_WIN32) && defined(HAVE_STDAFX_H)
#include "stdafx.h"
#endif /* HAVE_STDAFX_H */
#include "dwarf.h"
#include "libdwarf.h"
#include "libdwarf_private.h"
#include "dwarf_base_types.h"
#include "dwarf_opaque.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarf_arange.h"
#include "dwarf_global.h" /* for _dwarf_fixup_* */
#include "dwarf_string.h"
static
void
free_aranges_chain(Dwarf_Debug dbg, Dwarf_Chain head)
{
Dwarf_Chain cur = head;
Dwarf_Chain next = 0;
if
(!head) {
return
;
}
next = head->ch_next;
for
( ;cur; cur = next) {
void
*item = cur->ch_item;
int
type = cur->ch_itemtype;
next = cur->ch_next;
if
(item && type) {
dwarf_dealloc(dbg,item,type);
cur->ch_item = 0;
dwarf_dealloc(dbg,cur,DW_DLA_CHAIN);
}
}
}
static
int
_dwarf_get_aranges_list(Dwarf_Debug dbg,
Dwarf_Chain * chain_out,
Dwarf_Signed * chain_count_out,
Dwarf_Error * error)
{
Dwarf_Small *arange_ptr = 0;
Dwarf_Small *arange_ptr_start = 0;
Dwarf_Small *header_ptr = 0;
Dwarf_Unsigned version = 0;
Dwarf_Off info_offset = 0;
Dwarf_Small address_size = 0;
Dwarf_Small segment_sel_size = 0;
Dwarf_Signed arange_count = 0;
Dwarf_Arange arange = 0;
Dwarf_Unsigned section_size = 0;
Dwarf_Byte_Ptr arange_end_section = 0;
Dwarf_Chain curr_chain = NULL;
Dwarf_Chain head_chain = NULL;
Dwarf_Chain *plast = &head_chain;
if
(!dbg->de_debug_aranges.dss_size) {
return
DW_DLV_NO_ENTRY;
}
arange_ptr = dbg->de_debug_aranges.dss_data;
arange_ptr_start = arange_ptr;
section_size = dbg->de_debug_aranges.dss_size;
arange_end_section = arange_ptr + section_size;
do
{
Dwarf_Unsigned area_length = 0;
Dwarf_Unsigned remainder = 0;
Dwarf_Unsigned range_entry_size = 0;
int
local_length_size;
int
local_extension_size = 0;
Dwarf_Small *end_this_arange = 0;
int
res = 0;
header_ptr = arange_ptr;
if
(header_ptr >= arange_end_section) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error,DW_DLE_ARANGES_HEADER_ERROR);
return
DW_DLV_ERROR;
}
res = _dwarf_read_area_length_ck_wrapper(dbg,&area_length,
&arange_ptr,&local_length_size,&local_extension_size,
section_size,arange_end_section,error);
if
(res != DW_DLV_OK) {
free_aranges_chain(dbg,head_chain);
return
res;
}
if
(area_length > dbg->de_debug_aranges.dss_size ||
(area_length +local_length_size+local_extension_size)
> dbg->de_debug_aranges.dss_size ) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error,DW_DLE_ARANGES_HEADER_ERROR);
return
DW_DLV_ERROR;
}
if
((area_length + local_length_size + local_extension_size) >
dbg->de_debug_aranges.dss_size) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ARANGES_HEADER_ERROR);
return
DW_DLV_ERROR;
}
end_this_arange = arange_ptr + area_length;
if
(end_this_arange > arange_end_section) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error,DW_DLE_ARANGES_HEADER_ERROR);
return
DW_DLV_ERROR;
}
if
(!area_length) {
continue
;
}
res = _dwarf_read_unaligned_ck_wrapper(dbg,&version,
arange_ptr,DWARF_HALF_SIZE,end_this_arange,error);
if
(res != DW_DLV_OK) {
free_aranges_chain(dbg,head_chain);
return
res;
}
arange_ptr += DWARF_HALF_SIZE;
if
(arange_ptr >= end_this_arange) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ARANGES_HEADER_ERROR);
return
DW_DLV_ERROR;
}
if
(version != DW_ARANGES_VERSION2) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
return
DW_DLV_ERROR;
}
res = _dwarf_read_unaligned_ck_wrapper(dbg,&info_offset,
arange_ptr,local_length_size,end_this_arange,error);
if
(res != DW_DLV_OK) {
free_aranges_chain(dbg,head_chain);
return
res;
}
arange_ptr += local_length_size;
if
(arange_ptr >= end_this_arange) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ARANGES_HEADER_ERROR);
return
DW_DLV_ERROR;
}
if
(info_offset >= dbg->de_debug_info.dss_size) {
FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
"arange info offset.a"
);
if
(info_offset >= dbg->de_debug_info.dss_size) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
return
DW_DLV_ERROR;
}
}
address_size = *(Dwarf_Small *) arange_ptr;
if
(address_size >
sizeof
(Dwarf_Addr)) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR);
return
DW_DLV_ERROR;
}
if
(address_size == 0) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ZERO);
return
DW_DLV_ERROR;
}
arange_ptr = arange_ptr +
sizeof
(Dwarf_Small);
if
(arange_ptr >= end_this_arange) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
return
DW_DLV_ERROR;
}
segment_sel_size = *(Dwarf_Small *) arange_ptr;
if
(segment_sel_size > 0) {
free_aranges_chain(dbg,head_chain);
_dwarf_error_string(dbg, error,
DW_DLE_SEGMENT_SIZE_BAD,
"DW_DLE_SEGMENT_SIZE_BAD: "
"segment selector size > 0 is not supported"
);
return
DW_DLV_ERROR;
}
arange_ptr = arange_ptr +
sizeof
(Dwarf_Small);
if
(arange_ptr > end_this_arange) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
return
DW_DLV_ERROR;
}
range_entry_size = 2*address_size + segment_sel_size;
remainder = (Dwarf_Unsigned) ((arange_ptr - header_ptr) %
(range_entry_size));
if
(remainder != 0) {
arange_ptr = arange_ptr + (2 * address_size) - remainder;
}
do
{
Dwarf_Addr range_address = 0;
Dwarf_Unsigned segment_selector = 0;
Dwarf_Unsigned range_length = 0;
res = _dwarf_read_unaligned_ck_wrapper(dbg,&range_address,
arange_ptr,address_size,end_this_arange,error);
if
(res != DW_DLV_OK) {
free_aranges_chain(dbg,head_chain);
return
res;
}
arange_ptr += address_size;
res = _dwarf_read_unaligned_ck_wrapper(dbg,&range_length,
arange_ptr,address_size,end_this_arange,error);
if
(res != DW_DLV_OK) {
free_aranges_chain(dbg,head_chain);
return
res;
}
arange_ptr += address_size;
{
arange = (Dwarf_Arange)
_dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
if
(arange == NULL) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return
DW_DLV_ERROR;
}
arange->ar_segment_selector = segment_selector;
arange->ar_segment_selector_size =
segment_sel_size;
arange->ar_address = range_address;
arange->ar_length = range_length;
arange->ar_info_offset = info_offset;
arange->ar_dbg = dbg;
arange_count++;
curr_chain = (Dwarf_Chain)
_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if
(curr_chain == NULL) {
dwarf_dealloc(dbg,arange,DW_DLA_ARANGE);
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return
DW_DLV_ERROR;
}
curr_chain->ch_item = arange;
curr_chain->ch_itemtype = DW_DLA_ARANGE;
(*plast) = curr_chain;
plast = &(curr_chain->ch_next);
}
}
while
(end_this_arange >= (arange_ptr + range_entry_size));
if
(end_this_arange < arange_ptr) {
Dwarf_Unsigned pad_count = arange_ptr - end_this_arange;
Dwarf_Unsigned offset = arange_ptr - arange_ptr_start;
dwarfstring aramsg;
dwarfstring_constructor(&aramsg);
dwarfstring_append_printf_u(&aramsg,
"DW_DLE_ARANGE_LENGTH_BAD."
" 0x%"
DW_PR_XZEROS DW_PR_DUx,
pad_count);
dwarfstring_append_printf_u(&aramsg,
" pad bytes at offset 0x%"
DW_PR_XZEROS DW_PR_DUx
" in .debug_aranges"
,
offset);
dwarf_insert_harmless_error(dbg,
dwarfstring_string(&aramsg));
dwarfstring_destructor(&aramsg);
}
arange_ptr = end_this_arange;
}
while
(arange_ptr < arange_end_section);
if
(arange_ptr != arange_end_section) {
free_aranges_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
return
DW_DLV_ERROR;
}
*chain_out = head_chain;
*chain_count_out = arange_count;
return
DW_DLV_OK;
}
int
dwarf_get_aranges(Dwarf_Debug dbg,
Dwarf_Arange ** aranges,
Dwarf_Signed * returned_count, Dwarf_Error * error)
{
Dwarf_Signed arange_count = 0;
Dwarf_Arange *arange_block = 0;
Dwarf_Chain curr_chain = NULL;
Dwarf_Chain head_chain = NULL;
Dwarf_Signed i = 0;
int
res = DW_DLV_ERROR;
CHECK_DBG(dbg,error,
"dwarf_get_aranges()"
);
res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error);
if
(res != DW_DLV_OK) {
return
res;
}
res = _dwarf_load_debug_info(dbg, error);
if
(res != DW_DLV_OK) {
return
res;
}
res = _dwarf_get_aranges_list(dbg,&head_chain,
&arange_count,error);
if
(res != DW_DLV_OK) {
free_aranges_chain(dbg,head_chain);
return
res;
}
arange_block = (Dwarf_Arange *)
_dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
if
(arange_block == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
free_aranges_chain(dbg,head_chain);
return
DW_DLV_ERROR;
}
curr_chain = head_chain;
for
(i = 0; i < arange_count; i++) {
Dwarf_Chain prev = 0;
*(arange_block + i) = curr_chain->ch_item;
curr_chain->ch_item = 0;
prev = curr_chain;
curr_chain = curr_chain->ch_next;
dwarf_dealloc(dbg, prev, DW_DLA_CHAIN);
}
*aranges = arange_block;
*returned_count = (arange_count);
return
DW_DLV_OK;
}
#if 0 /* _dwarf_get_aranges_addr_offsets Unused */
int
_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
Dwarf_Addr ** addrs,
Dwarf_Off ** offsets,
Dwarf_Signed * count,
Dwarf_Error * error)
{
Dwarf_Signed i = 0;
Dwarf_Chain curr_chain = NULL;
Dwarf_Chain head_chain = NULL;
Dwarf_Signed arange_count = 0;
Dwarf_Addr *arange_addrs = 0;
Dwarf_Off *arange_offsets = 0;
int
res = DW_DLV_ERROR;
if
(error != NULL)
*error = NULL;
if
(IS_INVALID_DBG(dbg)) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
return
DW_DLV_ERROR;
}
res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error);
if
(res != DW_DLV_OK) {
return
res;
}
res = _dwarf_load_debug_info(dbg, error);
if
(res != DW_DLV_OK) {
return
res;
}
res = _dwarf_get_aranges_list(dbg,&head_chain,
&arange_count,error);
if
(res != DW_DLV_OK) {
return
res;
}
arange_addrs = (Dwarf_Addr *)
_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
if
(arange_addrs == NULL) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return
DW_DLV_ERROR;
}
arange_offsets = (Dwarf_Off *)
_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
if
(arange_offsets == NULL) {
free_aranges_chain(dbg,head_chain);
dwarf_dealloc(dbg,arange_addrs,DW_DLA_ADDR);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return
DW_DLV_ERROR;
}
curr_chain = head_chain;
for
(i = 0; i < arange_count; i++) {
Dwarf_Arange ar = curr_chain->ch_item;
int
itemtype = curr_chain->ch_itemtype;
Dwarf_Chain prev = 0;
if
(!ar) {
arange_addrs[i] = 0;
arange_offsets[i] = 0;
continue
;
}
curr_chain->ch_item = 0;
arange_addrs[i] = ar->ar_address;
arange_offsets[i] = ar->ar_info_offset;
prev = curr_chain;
curr_chain = curr_chain->ch_next;
if
(itemtype) {
dwarf_dealloc(dbg, ar, itemtype);
}
dwarf_dealloc(dbg, prev, DW_DLA_CHAIN);
}
*count = arange_count;
*offsets = arange_offsets;
*addrs = arange_addrs;
return
DW_DLV_OK;
}
#endif /* 0 */
int
dwarf_get_arange(Dwarf_Arange * aranges,
Dwarf_Unsigned arange_count,
Dwarf_Addr address,
Dwarf_Arange * returned_arange, Dwarf_Error * error)
{
Dwarf_Arange curr_arange = 0;
Dwarf_Unsigned i = 0;
if
(!aranges) {
_dwarf_error(NULL, error, DW_DLE_ARANGES_NULL);
return
DW_DLV_ERROR;
}
for
(i = 0; i < arange_count; i++) {
curr_arange = *(aranges + i);
if
(address >= curr_arange->ar_address &&
address <
curr_arange->ar_address + curr_arange->ar_length) {
*returned_arange = curr_arange;
return
DW_DLV_OK;
}
}
return
DW_DLV_NO_ENTRY;
}
int
dwarf_get_cu_die_offset(Dwarf_Arange arange,
Dwarf_Off * returned_offset,
Dwarf_Error * error)
{
Dwarf_Debug dbg = 0;
Dwarf_Off offset = 0;
Dwarf_Unsigned headerlen = 0;
int
cres = 0;
if
(arange == NULL) {
_dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
return
DW_DLV_ERROR;
}
dbg = arange->ar_dbg;
offset = arange->ar_info_offset;
if
(!dbg->de_debug_info.dss_data) {
int
res = _dwarf_load_debug_info(dbg, error);
if
(res != DW_DLV_OK) {
return
res;
}
}
cres = _dwarf_length_of_cu_header(dbg, offset,
TRUE, &headerlen,error);
if
(cres != DW_DLV_OK) {
return
cres;
}
*returned_offset = headerlen + offset;
return
DW_DLV_OK;
}
int
dwarf_get_arange_cu_header_offset(Dwarf_Arange arange,
Dwarf_Off * cu_header_offset_returned,
Dwarf_Error * error)
{
Dwarf_Debug dbg = 0;
if
(arange == NULL) {
_dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
return
DW_DLV_ERROR;
}
dbg = arange->ar_dbg;
if
(!dbg->de_debug_info.dss_data) {
int
res = _dwarf_load_debug_info(dbg, error);
if
(res != DW_DLV_OK) {
return
res;
}
}
*cu_header_offset_returned = arange->ar_info_offset;
return
DW_DLV_OK;
}
int
dwarf_get_arange_info_b(Dwarf_Arange arange,
Dwarf_Unsigned* segment,
Dwarf_Unsigned* segment_entry_size,
Dwarf_Addr * start,
Dwarf_Unsigned* length,
Dwarf_Off * cu_die_offset,
Dwarf_Error * error)
{
if
(arange == NULL) {
_dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
return
DW_DLV_ERROR;
}
if
(segment != NULL) {
*segment = arange->ar_segment_selector;
}
if
(segment_entry_size != NULL) {
*segment_entry_size = arange->ar_segment_selector_size;
}
if
(start != NULL)
*start = arange->ar_address;
if
(length != NULL)
*length = arange->ar_length;
if
(cu_die_offset != NULL) {
Dwarf_Debug dbg = arange->ar_dbg;
Dwarf_Off offset = arange->ar_info_offset;
Dwarf_Unsigned headerlen = 0;
int
cres = 0;
if
(!dbg->de_debug_info.dss_data) {
int
res = _dwarf_load_debug_info(dbg, error);
if
(res != DW_DLV_OK) {
return
res;
}
}
cres = _dwarf_length_of_cu_header(dbg, offset,
TRUE, &headerlen,error);
if
(cres != DW_DLV_OK) {
return
cres;
}
*cu_die_offset = offset + headerlen;
}
return
DW_DLV_OK;
}