#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"
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
(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;
}
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;
}
}
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) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
return
(DW_DLV_ERROR);
}
if
(ranges_base >= localdbg->de_debug_ranges.dss_size) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
return
(DW_DLV_ERROR);
}
if
((rangesoffset +ranges_base) >=
localdbg->de_debug_ranges.dss_size) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
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) {
free_allocated_ranges(base);
_dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
return
(DW_DLV_ERROR);
break
;
}
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(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
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);
}