#include "config.h"
#include <stdio.h>
#include <limits.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarf_macro.h"
#define LEFTPAREN '('
#define RIGHTPAREN ')'
#define SPACE ' '
char *
dwarf_find_macro_value_start(char *str)
{
char *lcp;
int funclike = 0;
for (lcp = str; *lcp; ++lcp) {
switch (*lcp) {
case LEFTPAREN:
funclike = 1;
break;
case RIGHTPAREN:
return lcp + 2;
case SPACE:
if (!funclike) {
return lcp + 1;
}
break;
}
}
return lcp;
}
struct macro_stack_s {
Dwarf_Signed *st_base;
long st_max;
long st_next_to_use;
int st_was_fault;
};
static void _dwarf_reset_index_macro_stack(struct macro_stack_s *ms);
static void
free_macro_stack(Dwarf_Debug dbg, struct macro_stack_s *ms)
{
dwarf_dealloc(dbg,ms->st_base,DW_DLA_STRING);
_dwarf_reset_index_macro_stack(ms);
}
#define STARTERMAX 10
static void
_dwarf_reset_index_macro_stack(struct macro_stack_s *ms)
{
ms->st_base = 0;
ms->st_max = 0;
ms->st_next_to_use = 0;
ms->st_was_fault = 0;
}
static int
_dwarf_macro_stack_push_index(Dwarf_Debug dbg, Dwarf_Signed indx,
struct macro_stack_s *ms)
{
if (!ms->st_max || ms->st_next_to_use >= ms->st_max) {
long new_size = ms->st_max;
Dwarf_Signed *newbase = 0;
if (!new_size) {
new_size = STARTERMAX;
}
new_size = new_size * 2;
newbase =
(Dwarf_Signed *)_dwarf_get_alloc(dbg, DW_DLA_STRING,
new_size * sizeof(Dwarf_Signed));
if (!newbase) {
ms->st_was_fault = 1;
return DW_DLV_ERROR;
}
if (ms->st_base) {
memcpy(newbase, ms->st_base,
ms->st_next_to_use * sizeof(Dwarf_Signed));
dwarf_dealloc(dbg, ms->st_base, DW_DLA_STRING);
}
ms->st_base = newbase;
ms->st_max = new_size;
}
ms->st_base[ms->st_next_to_use] = indx;
++ms->st_next_to_use;
return DW_DLV_OK;
}
static Dwarf_Signed
_dwarf_macro_stack_pop_index(struct macro_stack_s *ms)
{
if (ms->st_was_fault) {
return -1;
}
if (ms->st_next_to_use > 0) {
ms->st_next_to_use--;
return (ms->st_base[ms->st_next_to_use]);
} else {
ms->st_was_fault = 1;
}
return -1;
}
int
dwarf_get_macro_details(Dwarf_Debug dbg,
Dwarf_Off macro_offset,
Dwarf_Unsigned maximum_count,
Dwarf_Signed * entry_count,
Dwarf_Macro_Details ** details,
Dwarf_Error * error)
{
Dwarf_Small *macro_base = 0;
Dwarf_Small *macro_end = 0;
Dwarf_Small *pnext = 0;
Dwarf_Unsigned endloc = 0;
unsigned char uc = 0;
unsigned long depth = 0;
int res = 0;
unsigned long str_space = 0;
int done = 0;
unsigned long space_needed = 0;
unsigned long string_offset = 0;
Dwarf_Small *return_data = 0;
Dwarf_Small *pdata = 0;
unsigned long final_count = 0;
Dwarf_Signed fileindex = -1;
Dwarf_Small *latest_str_loc = 0;
struct macro_stack_s msdata;
unsigned long count = 0;
unsigned long max_count = (unsigned long) maximum_count;
_dwarf_reset_index_macro_stack(&msdata);
if (dbg == NULL) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
free_macro_stack(dbg,&msdata);
return (DW_DLV_ERROR);
}
res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error);
if (res != DW_DLV_OK) {
free_macro_stack(dbg,&msdata);
return res;
}
if (!dbg->de_debug_abbrev.dss_size) {
free_macro_stack(dbg,&msdata);
return (DW_DLV_NO_ENTRY);
}
macro_base = dbg->de_debug_macinfo.dss_data;
if (macro_base == NULL) {
free_macro_stack(dbg,&msdata);
return (DW_DLV_NO_ENTRY);
}
if (macro_offset >= dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
return (DW_DLV_NO_ENTRY);
}
macro_end = macro_base + dbg->de_debug_macinfo.dss_size;
pnext = macro_base + macro_offset;
if (maximum_count == 0) {
max_count = ULONG_MAX;
}
endloc = (pnext - macro_base);
if (endloc >= dbg->de_debug_macinfo.dss_size) {
if (endloc == dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
return DW_DLV_NO_ENTRY;
}
_dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
free_macro_stack(dbg,&msdata);
return (DW_DLV_ERROR);
}
for (count = 0; !done && count < max_count; ++count) {
unsigned long slen = 0;
UNUSEDARG Dwarf_Unsigned utemp = 0;
uc = *pnext;
++pnext;
switch (uc) {
case DW_MACINFO_define:
case DW_MACINFO_undef:
case DW_MACINFO_vendor_ext:
DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
macro_end);
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
res = _dwarf_check_string_valid(dbg,
macro_base,pnext,macro_end,
DW_DLE_MACINFO_STRING_BAD,error);
if (res != DW_DLV_OK) {
return res;
}
slen = strlen((char *) pnext) + 1;
pnext += slen;
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
str_space += slen;
break;
case DW_MACINFO_start_file:
DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
macro_end);
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
macro_end);
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
++depth;
break;
case DW_MACINFO_end_file:
if (--depth == 0) {
}
break;
case 0:
done = 1;
break;
default:
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
endloc = (pnext - macro_base);
if (endloc == dbg->de_debug_macinfo.dss_size) {
done = 1;
} else if (endloc > dbg->de_debug_macinfo.dss_size) {
_dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
free_macro_stack(dbg,&msdata);
return (DW_DLV_ERROR);
}
}
string_offset = count * sizeof(Dwarf_Macro_Details);
space_needed = string_offset + str_space + 2;
return_data = pdata =
(Dwarf_Small *)_dwarf_get_alloc(dbg, DW_DLA_STRING, space_needed);
latest_str_loc = pdata + string_offset;
if (pdata == 0) {
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE);
return (DW_DLV_ERROR);
}
pnext = macro_base + macro_offset;
done = 0;
for (final_count = 0; !done && final_count < count; ++final_count) {
unsigned long slen = 0;
Dwarf_Unsigned v1 = 0;
Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata +
(final_count * sizeof (Dwarf_Macro_Details)));
endloc = (pnext - macro_base);
if (endloc > dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
return (DW_DLV_ERROR);
}
uc = *pnext;
pdmd->dmd_offset = (pnext - macro_base);
pdmd->dmd_type = uc;
pdmd->dmd_fileindex = fileindex;
pdmd->dmd_lineno = 0;
pdmd->dmd_macro = 0;
++pnext;
switch (uc) {
case DW_MACINFO_define:
case DW_MACINFO_undef:
case DW_MACINFO_vendor_ext:
DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
macro_end);
pdmd->dmd_lineno = v1;
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
res = _dwarf_check_string_valid(dbg,
macro_base,pnext,macro_end,
DW_DLE_MACINFO_STRING_BAD,error);
if (res != DW_DLV_OK) {
return res;
}
slen = strlen((char *) pnext) + 1;
strcpy((char *) latest_str_loc, (char *) pnext);
pdmd->dmd_macro = (char *) latest_str_loc;
latest_str_loc += slen;
pnext += slen;
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
break;
case DW_MACINFO_start_file:
DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
macro_end);
pdmd->dmd_lineno = v1;
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
macro_end);
pdmd->dmd_fileindex = v1;
(void) _dwarf_macro_stack_push_index(dbg, fileindex,
&msdata);
fileindex = v1;
if (((Dwarf_Unsigned)(pnext - macro_base)) >=
dbg->de_debug_macinfo.dss_size) {
free_macro_stack(dbg,&msdata);
dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
_dwarf_error(dbg, error,
DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
break;
case DW_MACINFO_end_file:
fileindex = _dwarf_macro_stack_pop_index(&msdata);
break;
case 0:
done = 1;
break;
default:
dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
free_macro_stack(dbg,&msdata);
_dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
return (DW_DLV_ERROR);
}
}
*entry_count = count;
*details = (Dwarf_Macro_Details *) return_data;
free_macro_stack(dbg,&msdata);
return DW_DLV_OK;
}