#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarfstring.h"
struct ranges_entry {
struct ranges_entry *next;
Dwarf_Ranges cur;
};
static void
free_allocated_ranges( struct ranges_entry *base)
{
struct ranges_entry *cur = 0;
struct ranges_entry *next = 0;
for ( cur = base ; cur ; cur = next ) {
next = cur->next;
free(cur);
}
}
static int
read_unaligned_addr_check(Dwarf_Debug dbg,
Dwarf_Addr *addr_out,
Dwarf_Small *rangeptr,
unsigned address_size,
Dwarf_Error *error,
Dwarf_Small *section_end)
{
Dwarf_Addr a = 0;
READ_UNALIGNED_CK(dbg,a,
Dwarf_Addr, rangeptr,
address_size,
error,section_end);
*addr_out = a;
return DW_DLV_OK;
}
#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)
int dwarf_get_ranges_a(Dwarf_Debug dbg,
Dwarf_Off rangesoffset,
Dwarf_Die die,
Dwarf_Ranges ** rangesbuf,
Dwarf_Signed * listlen,
Dwarf_Unsigned * bytecount,
Dwarf_Error * error)
{
Dwarf_Small *rangeptr = 0;
Dwarf_Small *beginrangeptr = 0;
Dwarf_Small *section_end = 0;
unsigned entry_count = 0;
struct ranges_entry *base = 0;
struct ranges_entry *last = 0;
struct ranges_entry *curre = 0;
Dwarf_Ranges * ranges_data_out = 0;
unsigned copyindex = 0;
Dwarf_Half address_size = 0;
int res = DW_DLV_ERROR;
Dwarf_Unsigned ranges_base = 0;
Dwarf_Unsigned addr_base = 0;
Dwarf_Debug localdbg = dbg;
Dwarf_Error localerror = 0;
Dwarf_Half die_version = 3;
UNUSEDARG Dwarf_Half offset_size = 4;
Dwarf_CU_Context cucontext = 0;
if (!dbg) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
return DW_DLV_ERROR;
}
address_size = localdbg->de_pointer_size;
if (die) {
res = dwarf_get_version_of_die(die,&die_version,
&offset_size);
if (res == DW_DLV_ERROR) {
_dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
return DW_DLV_ERROR;
}
if (!die->di_cu_context) {
_dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
return DW_DLV_ERROR;
}
cucontext = die->di_cu_context;
#if 0
if (cucontext->cc_unit_type != DW_UT_skeleton &&
cucontext->cc_version_stamp != DW_CU_VERSION4 &&
cucontext->cc_ranges_base_present) {
ranges_base = cucontext->cc_ranges_base;
}
#endif
address_size = cucontext->cc_address_size;
}
if (die &&dbg->de_tied_data.td_tied_object) {
int restied = 0;
restied = _dwarf_get_ranges_base_attr_from_tied(dbg,
cucontext,
&ranges_base,
&addr_base,
error);
if (restied == DW_DLV_ERROR ) {
if(!error) {
return restied;
}
dwarf_dealloc(localdbg,*error,DW_DLA_ERROR);
*error = 0;
} else if (restied == DW_DLV_NO_ENTRY ) {
} else {
localdbg = dbg->de_tied_data.td_tied_object;
}
}
#if 0
FIXME Implement debug_rnglists!
if (die_version >= DW_CU_VERSION5) {
res = _dwarf_load_section(localdbg,
&localdbg->de_debug_rngslists,&localerror);
} else {
res = _dwarf_load_section(localdbg,
&localdbg->de_debug_ranges,&localerror);
}
#endif
res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges,&localerror);
if (res == DW_DLV_ERROR) {
_dwarf_error_mv_s_to_t(localdbg,&localerror,dbg,error);
return res;
} else if (res == DW_DLV_NO_ENTRY) {
return res;
}
if (rangesoffset == localdbg->de_debug_ranges.dss_size) {
return DW_DLV_NO_ENTRY;
}
if (rangesoffset > localdbg->de_debug_ranges.dss_size) {
dwarfstring m;
dwarfstring_constructor(&m);
dwarfstring_append_printf_u(&m,
"DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
" rangesoffset is 0x%lx ",rangesoffset);
dwarfstring_append_printf_u(&m,
" and section size is 0x%lx.",
localdbg->de_debug_ranges.dss_size);
_dwarf_error_string(dbg, error,
DW_DLE_DEBUG_RANGES_OFFSET_BAD,
dwarfstring_string(&m));
dwarfstring_destructor(&m);
return DW_DLV_ERROR;
}
if (ranges_base >= localdbg->de_debug_ranges.dss_size) {
dwarfstring m;
dwarfstring_constructor(&m);
dwarfstring_append_printf_u(&m,
"DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
" ranges base is 0x%lx ",ranges_base);
dwarfstring_append_printf_u(&m,
" and section size is 0x%lx.",
localdbg->de_debug_ranges.dss_size);
_dwarf_error_string(dbg, error,
DW_DLE_DEBUG_RANGES_OFFSET_BAD,
dwarfstring_string(&m));
dwarfstring_destructor(&m);
return DW_DLV_ERROR;
}
if ((rangesoffset +ranges_base) >=
localdbg->de_debug_ranges.dss_size) {
dwarfstring m;
dwarfstring_constructor(&m);
dwarfstring_append_printf_u(&m,
"DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
" ranges base+offset is 0x%lx ",
ranges_base+rangesoffset);
dwarfstring_append_printf_u(&m,
" and section size is 0x%lx.",
localdbg->de_debug_ranges.dss_size);
_dwarf_error_string(dbg, error,
DW_DLE_DEBUG_RANGES_OFFSET_BAD,
dwarfstring_string(&m));
dwarfstring_destructor(&m);
return DW_DLV_ERROR;
}
section_end = localdbg->de_debug_ranges.dss_data +
localdbg->de_debug_ranges.dss_size;
rangeptr = localdbg->de_debug_ranges.dss_data +
rangesoffset + ranges_base;
beginrangeptr = rangeptr;
for (;;) {
struct ranges_entry * re = 0;
if (rangeptr == section_end) {
break;
}
if (rangeptr > section_end) {
dwarfstring m;
free_allocated_ranges(base);
dwarfstring_constructor(&m);
dwarfstring_append(&m,
"DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
" ranges pointer ran off the end "
"of the section");
_dwarf_error_string(dbg, error,
DW_DLE_DEBUG_RANGES_OFFSET_BAD,
dwarfstring_string(&m));
dwarfstring_destructor(&m);
return DW_DLV_ERROR;
}
re = calloc(sizeof(struct ranges_entry),1);
if (!re) {
free_allocated_ranges(base);
_dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
return DW_DLV_ERROR;
}
if ((rangeptr + (2*address_size)) > section_end) {
free(re);
free_allocated_ranges(base);
_dwarf_error_string(dbg, error,
DW_DLE_DEBUG_RANGES_OFFSET_BAD,
"DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
" Not at the end of the ranges section "
" but there is not enough room in the section "
" for the next ranges entry");
return DW_DLV_ERROR;
}
entry_count++;
res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1,
rangeptr, address_size,error,section_end);
if (res != DW_DLV_OK) {
free(re);
free_allocated_ranges(base);
return res;
}
rangeptr += address_size;
res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2,
rangeptr, address_size,error,section_end);
if (res != DW_DLV_OK) {
free(re);
free_allocated_ranges(base);
return res;
}
rangeptr += address_size;
if (!base) {
base = re;
last = re;
} else {
last->next = re;
last = re;
}
if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
re->cur.dwr_type = DW_RANGES_END;
break;
} else if (re->cur.dwr_addr1 == MAX_ADDR) {
re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION;
} else {
re->cur.dwr_type = DW_RANGES_ENTRY;
}
}
ranges_data_out = (Dwarf_Ranges *)
_dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
if (!ranges_data_out) {
free_allocated_ranges(base);
_dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
return (DW_DLV_ERROR);
}
curre = base;
*rangesbuf = ranges_data_out;
*listlen = entry_count;
for (copyindex = 0; curre && (copyindex < entry_count);
++copyindex,++ranges_data_out) {
*ranges_data_out = curre->cur;
curre = curre->next;
}
free_allocated_ranges(base);
base = 0;
if (bytecount) {
*bytecount = rangeptr - beginrangeptr;
}
return DW_DLV_OK;
}
int dwarf_get_ranges(Dwarf_Debug dbg,
Dwarf_Off rangesoffset,
Dwarf_Ranges ** rangesbuf,
Dwarf_Signed * listlen,
Dwarf_Unsigned * bytecount,
Dwarf_Error * error)
{
Dwarf_Die die = 0;
int res = dwarf_get_ranges_a(dbg,rangesoffset,die,
rangesbuf,listlen,bytecount,error);
return res;
}
void
dwarf_ranges_dealloc(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf,
UNUSEDARG Dwarf_Signed rangecount)
{
dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES);
}