#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarf_dsc.h"
#define FALSE 0
#define TRUE 1
static int
get_dsc_leb_entries(Dwarf_Debug dbg,
Dwarf_Small * blockpointer,
Dwarf_Unsigned blocklen,
int dounsigned,
struct Dwarf_Dsc_Entry_s *ary,
size_t * arraycount,
Dwarf_Error * error)
{
Dwarf_Small *p = blockpointer;
Dwarf_Small *endp = blockpointer + blocklen;
size_t larraycount = 0;
size_t iarraycount = *arraycount;
if (!ary) {
if (iarraycount) {
_dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
return DW_DLV_ERROR;
}
} else {
if (!iarraycount) {
_dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
return DW_DLV_ERROR;
}
}
if (dounsigned) {
while (p < endp) {
Dwarf_Unsigned dsc = 0;
Dwarf_Unsigned low = 0;
Dwarf_Unsigned high = 0;
UNUSEDARG Dwarf_Unsigned leblen = 0;
if (ary && (larraycount >= iarraycount)) {
_dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
return DW_DLV_ERROR;
}
DECODE_LEB128_UWORD_LEN_CK(p,dsc,
leblen,dbg,error,endp);
if (!dsc) {
DECODE_LEB128_UWORD_LEN_CK(p,low,
leblen, dbg,error,endp);
} else {
DECODE_LEB128_UWORD_LEN_CK(p,low,
leblen, dbg,error,endp);
DECODE_LEB128_UWORD_LEN_CK(p,high,
leblen, dbg,error,endp);
}
if(ary) {
struct Dwarf_Dsc_Entry_s *arye =
ary+larraycount;
arye->dsc_type = dsc;
arye->dsc_low_u = low;
arye->dsc_high_u = high;
}
larraycount++;
}
} else {
while (p < endp) {
Dwarf_Signed dsc = 0;
Dwarf_Signed low = 0;
Dwarf_Signed high = 0;
UNUSEDARG Dwarf_Unsigned leblen = 0;
if (ary && (larraycount >= iarraycount)) {
_dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
return DW_DLV_ERROR;
}
DECODE_LEB128_SWORD_LEN_CK(p,dsc,
leblen,dbg,error,endp);
if (!dsc) {
DECODE_LEB128_SWORD_LEN_CK(p,low,
leblen,dbg,error,endp);
} else {
DECODE_LEB128_SWORD_LEN_CK(p,low,
leblen,dbg,error,endp);
DECODE_LEB128_SWORD_LEN_CK(p,high,
leblen,dbg,error,endp);
}
if(ary) {
struct Dwarf_Dsc_Entry_s *arye =
ary+larraycount;
arye->dsc_type = (Dwarf_Unsigned)dsc;
arye->dsc_low_s = low;
arye->dsc_high_s = high;
}
larraycount++;
}
}
if (ary) {
if(iarraycount != larraycount) {
_dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
return DW_DLV_ERROR;
}
} else {
*arraycount = larraycount;
}
return DW_DLV_OK;
}
int dwarf_discr_list(Dwarf_Debug dbg,
Dwarf_Small * blockpointer,
Dwarf_Unsigned blocklen,
Dwarf_Dsc_Head * dsc_head_out,
Dwarf_Unsigned * dsc_array_length_out,
Dwarf_Error * error)
{
Dwarf_Dsc_Head h = 0;
int res = 0;
size_t arraycount = 0;
struct Dwarf_Dsc_Entry_s *ary = 0;
Dwarf_Small * dscblockp = 0;
Dwarf_Unsigned dscblocklen = 0;
if (!dbg){
_dwarf_error(NULL, error, DW_DLE_DBG_NULL); \
return DW_DLV_ERROR;
}
if (blocklen == 0) {
return DW_DLV_NO_ENTRY;
}
dscblockp = (Dwarf_Small *)calloc(blocklen,sizeof(Dwarf_Small));
if(!dscblockp) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
dscblocklen = blocklen;
memcpy(dscblockp,blockpointer,blocklen);
res = get_dsc_leb_entries(dbg,dscblockp,dscblocklen,
FALSE, 0, &arraycount,error);
if (res != DW_DLV_OK) {
free(dscblockp);
return res;
}
h = (Dwarf_Dsc_Head)_dwarf_get_alloc(dbg,DW_DLA_DSC_HEAD,1);
if(!h) {
free(dscblockp);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
h->dsh_block = dscblockp;
h->dsh_block_len = dscblocklen;
h->dsh_debug = dbg;
ary = (struct Dwarf_Dsc_Entry_s *)calloc(arraycount,
sizeof(struct Dwarf_Dsc_Entry_s));
if(!ary) {
dwarf_dealloc(dbg,h,DW_DLA_DSC_HEAD);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
h->dsh_count = arraycount;
h->dsh_array = ary;
h->dsh_set_unsigned = 0;
h->dsh_set_signed = 0;
*dsc_head_out = h;
*dsc_array_length_out = arraycount;
return DW_DLV_OK;
}
int dwarf_discr_entry_u(Dwarf_Dsc_Head dsh ,
Dwarf_Unsigned entrynum,
Dwarf_Half * out_type,
Dwarf_Unsigned * out_discr_low,
Dwarf_Unsigned * out_discr_high,
UNUSEDARG Dwarf_Error * error)
{
struct Dwarf_Dsc_Entry_s *dse = 0;
if (entrynum >= dsh->dsh_count) {
return DW_DLV_NO_ENTRY;
}
if (!dsh->dsh_set_unsigned) {
int res =0;
int dounsigned = 1;
size_t count = dsh->dsh_count;
res = get_dsc_leb_entries(dsh->dsh_debug,
dsh->dsh_block,
dsh->dsh_block_len,
dounsigned,
dsh->dsh_array,
&count,
error);
if (res != DW_DLV_OK) {
return res;
}
dsh->dsh_set_unsigned = TRUE;
}
if (!dsh->dsh_array) {
_dwarf_error(dsh->dsh_debug, error, DW_DLE_DISCR_ARRAY_ERROR);
return DW_DLV_ERROR;
}
dse = dsh->dsh_array + entrynum;
*out_type = dse->dsc_type;
*out_discr_low = dse->dsc_low_u;
*out_discr_high = dse->dsc_high_u;
return DW_DLV_OK;
}
int dwarf_discr_entry_s(Dwarf_Dsc_Head dsh,
Dwarf_Unsigned entrynum,
Dwarf_Half * out_type,
Dwarf_Signed * out_discr_low,
Dwarf_Signed * out_discr_high,
UNUSEDARG Dwarf_Error * error)
{
struct Dwarf_Dsc_Entry_s *dse = 0;
if (entrynum >= dsh->dsh_count) {
return DW_DLV_NO_ENTRY;
}
if (!dsh->dsh_set_signed) {
int res =0;
int dounsigned = 0;
size_t count = dsh->dsh_count;
res = get_dsc_leb_entries(dsh->dsh_debug,
dsh->dsh_block,
dsh->dsh_block_len,
dounsigned,
dsh->dsh_array,
&count,
error);
if (res != DW_DLV_OK) {
return res;
}
dsh->dsh_set_signed = TRUE;
}
if (!dsh->dsh_array) {
_dwarf_error(dsh->dsh_debug, error, DW_DLE_DISCR_ARRAY_ERROR);
return DW_DLV_ERROR;
}
dse = dsh->dsh_array + entrynum;
*out_type = dse->dsc_type;
*out_discr_low = dse->dsc_low_s;
*out_discr_high = dse->dsc_high_s;
return DW_DLV_OK;
}
void
_dwarf_dsc_destructor(void *m)
{
Dwarf_Dsc_Head h = (Dwarf_Dsc_Head) m;
free(h->dsh_array);
h->dsh_array = 0;
free(h->dsh_block);
h->dsh_block = 0;
h->dsh_count = 0;
}