#include "config.h"
#include <sys/types.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include "dwarf_incl.h"
#include "dwarf_error.h"
#include "dwarf_alloc.h"
#include "dwarf_util.h"
#include "dwarf_line.h"
#include "dwarf_global.h"
#include "dwarf_arange.h"
#include "dwarf_abbrev.h"
#include "dwarf_die_deliv.h"
#include "dwarf_frame.h"
#include "dwarf_loc.h"
#include "dwarf_funcs.h"
#include "dwarf_types.h"
#include "dwarf_vars.h"
#include "dwarf_weaks.h"
#include "dwarf_harmless.h"
#include "dwarf_tsearch.h"
#include "dwarf_gdbindex.h"
#include "dwarf_xu_index.h"
#include "dwarf_macro5.h"
#include "dwarf_dnames.h"
#include "dwarf_rnglists.h"
#include "dwarf_dsc.h"
#include "dwarfstring.h"
#include "dwarf_str_offsets.h"
#define TRUE 1
#define FALSE 0
#define MULTIPLY_NO 0
#define MULTIPLY_CT 1
#define MULTIPLY_SP 2
struct ial_s {
short ia_struct_size;
short ia_multiply_count;
int (*specialconstructor) (Dwarf_Debug, void *);
void (*specialdestructor) (void *);
};
struct Dwarf_Error_s _dwarf_failsafe_error = {
DW_DLE_FAILSAFE_ERRVAL,
0,
1
};
static signed char global_de_alloc_tree_on = 1;
#ifdef HAVE_GLOBAL_ALLOC_SUMS
static Dwarf_Unsigned global_allocation_count;
static Dwarf_Unsigned global_allocation_total;
static Dwarf_Unsigned global_de_alloc_tree_count;
static Dwarf_Unsigned global_de_alloc_tree_total;
static Dwarf_Unsigned global_de_alloc_tree_early_dealloc_count;
static Dwarf_Unsigned global_de_alloc_tree_early_dealloc_size;
#endif
void _dwarf_alloc_tree_counts( UNUSEDARG Dwarf_Unsigned *allocount,
UNUSEDARG Dwarf_Unsigned *allosum,
UNUSEDARG Dwarf_Unsigned *treecount,
UNUSEDARG Dwarf_Unsigned *treesum,
UNUSEDARG Dwarf_Unsigned *earlydealloccount,
UNUSEDARG Dwarf_Unsigned *earlydeallocsize,
UNUSEDARG Dwarf_Unsigned *unused1,
UNUSEDARG Dwarf_Unsigned *unused2,
UNUSEDARG Dwarf_Unsigned *unused3)
{
#ifdef HAVE_GLOBAL_ALLOC_SUMS
*allocount = global_allocation_count;
*allosum = global_allocation_total;
*treecount = global_de_alloc_tree_count;
*treesum = global_de_alloc_tree_total;
*earlydealloccount =
global_de_alloc_tree_early_dealloc_count;
*earlydeallocsize =
global_de_alloc_tree_early_dealloc_size;
if (unused1) {
*unused1 = 0;
}
if (unused2) {
*unused2 = 0;
}
if (unused3) {
*unused3 = 0;
}
#endif
}
int dwarf_set_de_alloc_flag(int v)
{
int ov = global_de_alloc_tree_on;
global_de_alloc_tree_on = v;
return ov;
}
void
_dwarf_error_destructor(void *m)
{
Dwarf_Error er = (Dwarf_Error)m;
dwarfstring *erm = (dwarfstring *)er->er_msg;
if (! erm) {
return;
}
#if DEBUG
printf("libdwarfdetector DEALLOC Now destruct error string %s\n",dwarfstring_string(erm));
#endif
dwarfstring_destructor(erm);
free(erm);
er->er_msg = 0;
return;
}
struct reserve_size_s {
void *dummy_rsv1;
void *dummy_rsv2;
};
struct reserve_data_s {
void *rd_dbg;
unsigned short rd_length;
unsigned short rd_type;
};
#define DW_RESERVE sizeof(struct reserve_size_s)
static const
struct ial_s alloc_instance_basics[ALLOC_AREA_INDEX_TABLE_MAX] = {
{ 1,MULTIPLY_NO, 0, 0},
{ 1,MULTIPLY_CT, 0, 0},
{ sizeof(Dwarf_Loc),MULTIPLY_NO, 0, 0} ,
{ sizeof(Dwarf_Locdesc),MULTIPLY_NO, 0, 0},
{ 1,MULTIPLY_NO, 0, 0},
{ 1,MULTIPLY_NO, 0, 0},
{ sizeof(Dwarf_Block),MULTIPLY_NO, 0, 0},
{ 1,MULTIPLY_NO, 0, 0} ,
{sizeof(struct Dwarf_Die_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Line_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Attribute_s),MULTIPLY_NO, 0, 0},
{1,MULTIPLY_NO, 0, 0},
{1,MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Error_s),MULTIPLY_NO, 0,
_dwarf_error_destructor},
{sizeof(Dwarf_Ptr),MULTIPLY_CT, 0, 0},
{1,MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Arange_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Abbrev_s),MULTIPLY_NO, 0, 0},
{sizeof(Dwarf_Frame_Op),MULTIPLY_NO, 0, 0} ,
{sizeof(struct Dwarf_Cie_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Fde_s),MULTIPLY_NO, 0,
_dwarf_fde_destructor},
{sizeof(Dwarf_Loc),MULTIPLY_CT, 0, 0},
{sizeof(Dwarf_Frame_Op),MULTIPLY_CT, 0, 0},
{sizeof(struct Dwarf_Global_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_s),MULTIPLY_NO, 0, 0},
{1,MULTIPLY_SP, 0, 0},
{sizeof(Dwarf_Ranges),MULTIPLY_CT, 0,0 },
{ sizeof(struct Dwarf_Abbrev_List_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Chain_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_CU_Context_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Frame_s),MULTIPLY_NO,
_dwarf_frame_constructor,
_dwarf_frame_destructor},
{sizeof(struct Dwarf_Global_Context_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_File_Entry_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Line_Context_s),MULTIPLY_NO,
_dwarf_line_context_constructor,
_dwarf_line_context_destructor},
{sizeof(struct Dwarf_Loc_Chain_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Hash_Table_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_Context_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_Context_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_Context_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_Context_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Global_Context_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Hash_Table_Entry_s),MULTIPLY_CT,0,0 },
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(int),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Rnglists_Head_s),MULTIPLY_NO, 0,
_dwarf_rnglists_head_destructor},
{sizeof(struct Dwarf_Gdbindex_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Xu_Index_Header_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Loc_Expr_Op_s),MULTIPLY_CT, 0, 0},
{sizeof(struct Dwarf_Locdesc_c_s),MULTIPLY_CT, 0, 0},
{sizeof(struct Dwarf_Loc_Head_c_s),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Macro_Context_s),MULTIPLY_NO,
_dwarf_macro_constructor,
_dwarf_macro_destructor},
{sizeof(struct Dwarf_Chain_o),MULTIPLY_NO, 0, 0},
{sizeof(struct Dwarf_Dsc_Head_s),MULTIPLY_NO, 0,
_dwarf_dsc_destructor},
{sizeof(struct Dwarf_Dnames_Head_s),MULTIPLY_NO, 0,
_dwarf_debugnames_destructor},
{sizeof(struct Dwarf_Str_Offsets_Table_s),MULTIPLY_NO, 0,0},
};
static DW_TSHASHTYPE
simple_value_hashfunc(const void *keyp)
{
DW_TSHASHTYPE up = (DW_TSHASHTYPE)(uintptr_t)keyp;
return up;
}
static void
tdestroy_free_node(void *nodep)
{
char * m = (char *)nodep;
char * malloc_addr = m - DW_RESERVE;
struct reserve_data_s * reserve =(struct reserve_data_s *)malloc_addr;
unsigned type = reserve->rd_type;
if (type >= ALLOC_AREA_INDEX_TABLE_MAX) {
return;
}
if(!reserve->rd_dbg) {
return;
}
if(!reserve->rd_type) {
return;
}
if (alloc_instance_basics[type].specialdestructor) {
alloc_instance_basics[type].specialdestructor(m);
}
free(malloc_addr);
}
static int
simple_compare_function(const void *l, const void *r)
{
DW_TSHASHTYPE lp = (DW_TSHASHTYPE)(uintptr_t)l;
DW_TSHASHTYPE rp = (DW_TSHASHTYPE)(uintptr_t)r;
if(lp < rp) {
return -1;
}
if(lp > rp) {
return 1;
}
return 0;
}
char *
_dwarf_get_alloc(Dwarf_Debug dbg,
Dwarf_Small alloc_type, Dwarf_Unsigned count)
{
char * alloc_mem = 0;
Dwarf_Signed basesize = 0;
Dwarf_Signed size = 0;
unsigned int type = alloc_type;
short action = 0;
if (dbg == NULL) {
return NULL;
}
if (type >= ALLOC_AREA_INDEX_TABLE_MAX) {
return NULL;
}
basesize = alloc_instance_basics[alloc_type].ia_struct_size;
action = alloc_instance_basics[alloc_type].ia_multiply_count;
if(action == MULTIPLY_NO) {
size = basesize;
} else if (action == MULTIPLY_CT) {
size = basesize * count;
} else {
size = count *
(sizeof(Dwarf_Addr) > sizeof(Dwarf_Off) ?
sizeof(Dwarf_Addr) : sizeof(Dwarf_Off));
}
size += DW_RESERVE;
alloc_mem = malloc(size);
if (!alloc_mem) {
return NULL;
}
{
char * ret_mem = alloc_mem + DW_RESERVE;
void *key = ret_mem;
struct reserve_data_s *r = (struct reserve_data_s*)alloc_mem;
void *result = 0;
memset(alloc_mem, 0, size);
r->rd_dbg = dbg;
r->rd_type = alloc_type;
r->rd_length = size;
if (alloc_instance_basics[type].specialconstructor) {
int res = alloc_instance_basics[type].
specialconstructor(dbg, ret_mem);
if (res != DW_DLV_OK) {
return NULL;
}
}
#ifdef HAVE_GLOBAL_ALLOC_SUMS
global_allocation_count++;
global_allocation_total += size;
#endif
if (global_de_alloc_tree_on) {
#ifdef HAVE_GLOBAL_ALLOC_SUMS
global_de_alloc_tree_total += size;
global_de_alloc_tree_count++;
#endif
result = dwarf_tsearch((void *)key,
&dbg->de_alloc_tree,simple_compare_function);
if(!result) {
}
}
#if DEBUG
printf("libdwarfdetector ALLOC ret 0x%lx type 0x%x size %lu line %d %s\n",(unsigned long)ret_mem,(unsigned)alloc_type,(unsigned long)size,__LINE__,__FILE__);
#endif
return (ret_mem);
}
}
static int
string_is_in_debug_section(Dwarf_Debug dbg,void * space)
{
void *result = 0;
result = dwarf_tfind((void *)space,
&dbg->de_alloc_tree,simple_compare_function);
if(!result) {
return TRUE;
}
return FALSE;
}
void
dwarf_dealloc_error(Dwarf_Debug dbg, Dwarf_Error err)
{
dwarf_dealloc(dbg,err,DW_DLA_ERROR);
}
void
dwarf_dealloc_die( Dwarf_Die die)
{
Dwarf_Debug dbg = 0;
Dwarf_CU_Context context = 0;
if (!die) {
#ifdef DEBUG
printf("DEALLOC does nothing, die NULL line %d %s\n",
__LINE__,__FILE__);
fflush(stdout);
#endif
return;
}
context = die->di_cu_context;
if (!context) {
#ifdef DEBUG
printf("DEALLOC does nothing, context NULL line %d %s\n",
__LINE__,__FILE__);
fflush(stdout);
#endif
return;
}
dbg = context->cc_dbg;
dwarf_dealloc(dbg,die,DW_DLA_DIE);
}
void
dwarf_dealloc_attribute(Dwarf_Attribute attr)
{
Dwarf_Debug dbg = 0;
if (!attr) {
#ifdef DEBUG
printf("DEALLOC does nothing, attr is NULL line %d %s\n",
__LINE__,__FILE__);
fflush(stdout);
#endif
return;
}
dbg = attr->ar_dbg;
dwarf_dealloc(dbg,attr,DW_DLA_ATTR);
}
void
dwarf_dealloc(Dwarf_Debug dbg,
Dwarf_Ptr space, Dwarf_Unsigned alloc_type)
{
unsigned int type = 0;
char * malloc_addr = 0;
struct reserve_data_s * r = 0;
if (!space) {
#ifdef DEBUG
printf("DEALLOC does nothing, space NULL line %d %s\n",
__LINE__,__FILE__);
fflush(stdout);
abort();
#endif
return;
}
if (!dbg) {
#ifdef DEBUG
printf( "DEALLOC does nothing, dbg NULL line %d %s\n",
__LINE__,__FILE__);
fflush(stdout);
#endif
return;
}
if (dbg->de_alloc_tree) {
if (alloc_type == DW_DLA_STRING &&
string_is_in_debug_section(dbg,space)) {
return;
}
}
malloc_addr = (char *)space - DW_RESERVE;
r =(struct reserve_data_s *)malloc_addr;
if(dbg != r->rd_dbg) {
#ifdef DEBUG
printf("DEALLOC does nothing, dbg 0x%lx rd_dbg 0x%lx space 0x%lx line %d %s\n",
(unsigned long)dbg,
(unsigned long)r->rd_dbg,
(unsigned long)space,
__LINE__,__FILE__);
fflush(stdout);
#endif
return;
}
if(alloc_type != r->rd_type) {
#ifdef DEBUG
printf("DEALLOC does nothing, type 0x%lx rd_type 0x%lx space 0x%lx line %d %s\n",
(unsigned long)alloc_type,
(unsigned long)r->rd_type,
(unsigned long)space,
__LINE__,__FILE__);
fflush(stdout);
#endif
return;
}
if (alloc_type == DW_DLA_ERROR) {
Dwarf_Error ep = (Dwarf_Error)space;
if (ep->er_static_alloc == DE_STATIC) {
_dwarf_failsafe_error.er_errval =
DW_DLE_FAILSAFE_ERRVAL;
#ifdef DEBUG
printf("DEALLOC does nothing, DE_STATIC line %d %s\n",
__LINE__,__FILE__);
fflush(stdout);
#endif
return;
}
if (ep->er_static_alloc == DE_MALLOC) {
free(space);
return;
}
}
type = alloc_type;
#if DEBUG
if(dbg != r->rd_dbg) {
return;
}
#endif
#if DEBUG
printf("libdwarfdetector DEALLOC ret 0x%lx type 0x%x size %lu line %d %s\n",(unsigned long)space,(unsigned)type,(unsigned long)r->rd_length,__LINE__,__FILE__);
#endif
if (type >= ALLOC_AREA_INDEX_TABLE_MAX) {
#ifdef DEBUG
printf("DEALLOC does nothing, type too big %lu line %d %s\n",
(unsigned long)type,
__LINE__,__FILE__);
#endif
return;
}
#ifdef HAVE_GLOBAL_ALLOC_SUMS
global_de_alloc_tree_early_dealloc_count++;
global_de_alloc_tree_early_dealloc_size += r->rd_length;
#endif
if (alloc_instance_basics[type].specialdestructor) {
alloc_instance_basics[type].specialdestructor(space);
}
if (dbg->de_alloc_tree) {
void *key = space;
dwarf_tdelete(key,&dbg->de_alloc_tree,
simple_compare_function);
}
r->rd_dbg = (void *)0xfeadbeef;
r->rd_length = 0;
r->rd_type = 0;
free(malloc_addr);
return;
}
Dwarf_Debug
_dwarf_get_debug(void)
{
Dwarf_Debug dbg;
dbg = (Dwarf_Debug) malloc(sizeof(struct Dwarf_Debug_s));
if (dbg == NULL) {
return (NULL);
}
memset(dbg, 0, sizeof(struct Dwarf_Debug_s));
if (global_de_alloc_tree_on) {
dwarf_initialize_search_hash(&dbg->de_alloc_tree,
simple_value_hashfunc,0);
}
return (dbg);
}
void
dwarf_print_memory_stats(UNUSEDARG Dwarf_Debug dbg)
{
}
static void
rela_free(struct Dwarf_Section_s * sec)
{
if (sec->dss_data_was_malloc) {
free(sec->dss_data);
}
sec->dss_data = 0;
sec->dss_data_was_malloc = 0;
}
static void
freecontextlist(Dwarf_Debug dbg, Dwarf_Debug_InfoTypes dis)
{
Dwarf_CU_Context context = 0;
Dwarf_CU_Context nextcontext = 0;
for (context = dis->de_cu_context_list;
context; context = nextcontext) {
Dwarf_Hash_Table hash_table = context->cc_abbrev_hash_table;
_dwarf_free_abbrev_hash_table_contents(dbg,hash_table);
hash_table->tb_entries = 0;
nextcontext = context->cc_next;
context->cc_next = 0;
dwarf_dealloc(dbg, hash_table, DW_DLA_HASH_TABLE);
context->cc_abbrev_hash_table = 0;
dwarf_dealloc(dbg, context, DW_DLA_CU_CONTEXT);
}
dis->de_cu_context_list = 0;
}
int
_dwarf_free_all_of_one_debug(Dwarf_Debug dbg)
{
unsigned g = 0;
if (dbg == NULL) {
return (DW_DLV_ERROR);
}
if (dbg->de_cu_hashindex_data) {
dwarf_xu_header_free(dbg->de_cu_hashindex_data);
dbg->de_cu_hashindex_data = 0;
}
if (dbg->de_tu_hashindex_data) {
dwarf_xu_header_free(dbg->de_tu_hashindex_data);
dbg->de_tu_hashindex_data = 0;
}
if( dbg->de_printf_callback_null_device_handle) {
fclose(dbg->de_printf_callback_null_device_handle);
dbg->de_printf_callback_null_device_handle = 0;
}
freecontextlist(dbg,&dbg->de_info_reading);
freecontextlist(dbg,&dbg->de_types_reading);
rela_free(&dbg->de_debug_info);
rela_free(&dbg->de_debug_types);
rela_free(&dbg->de_debug_abbrev);
rela_free(&dbg->de_debug_line);
rela_free(&dbg->de_debug_line_str);
rela_free(&dbg->de_debug_loc);
rela_free(&dbg->de_debug_aranges);
rela_free(&dbg->de_debug_macinfo);
rela_free(&dbg->de_debug_macro);
rela_free(&dbg->de_debug_names);
rela_free(&dbg->de_debug_pubnames);
rela_free(&dbg->de_debug_str);
rela_free(&dbg->de_debug_sup);
rela_free(&dbg->de_debug_frame);
rela_free(&dbg->de_debug_frame_eh_gnu);
rela_free(&dbg->de_debug_pubtypes);
rela_free(&dbg->de_debug_funcnames);
rela_free(&dbg->de_debug_typenames);
rela_free(&dbg->de_debug_varnames);
rela_free(&dbg->de_debug_weaknames);
rela_free(&dbg->de_debug_ranges);
rela_free(&dbg->de_debug_str_offsets);
rela_free(&dbg->de_debug_addr);
rela_free(&dbg->de_debug_gdbindex);
rela_free(&dbg->de_debug_cu_index);
rela_free(&dbg->de_debug_tu_index);
dwarf_harmless_cleanout(&dbg->de_harmless_errors);
_dwarf_dealloc_rnglists_context(dbg);
_dwarf_dealloc_loclists_context(dbg);
if (dbg->de_printf_callback.dp_buffer &&
!dbg->de_printf_callback.dp_buffer_user_provided ) {
free(dbg->de_printf_callback.dp_buffer);
}
_dwarf_destroy_group_map(dbg);
if (dbg->de_alloc_tree) {
dwarf_tdestroy(dbg->de_alloc_tree,tdestroy_free_node);
dbg->de_alloc_tree = 0;
}
if (dbg->de_tied_data.td_tied_search) {
dwarf_tdestroy(dbg->de_tied_data.td_tied_search,
_dwarf_tied_destroy_free_node);
dbg->de_tied_data.td_tied_search = 0;
}
free((void *)dbg->de_path);
dbg->de_path = 0;
for (g = 0; g < dbg->de_gnu_global_path_count; ++g) {
free((char *)dbg->de_gnu_global_paths[g]);
dbg->de_gnu_global_paths[g] = 0;
}
free((void*)dbg->de_gnu_global_paths);
dbg->de_gnu_global_paths = 0;
dbg->de_gnu_global_path_count = 0;
memset(dbg, 0, sizeof(*dbg));
free(dbg);
return (DW_DLV_OK);
}
struct Dwarf_Error_s *
_dwarf_special_no_dbg_error_malloc(void)
{
Dwarf_Error e = 0;
Dwarf_Unsigned len = sizeof(struct Dwarf_Error_s);
char *mem = (char *)malloc(len);
if (mem == 0) {
return 0;
}
memset(mem, 0, len);
e = (Dwarf_Error)mem;
e->er_static_alloc = DE_MALLOC;
return e;
}