#include "config.h"
#include <stdio.h>
#include <limits.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_macro5.h"
#define TRUE 1
#define FALSE 0
static const Dwarf_Small dwarf_udata_string_form[] = {DW_FORM_udata,DW_FORM_string};
static const Dwarf_Small dwarf_udata_udata_form[] = {DW_FORM_udata,DW_FORM_udata};
static const Dwarf_Small dwarf_udata_strp_form[] = {DW_FORM_udata,DW_FORM_strp};
static const Dwarf_Small dwarf_udata_strp_sup_form[] = {DW_FORM_udata,DW_FORM_strp_sup};
static const Dwarf_Small dwarf_secoffset_form[] = {DW_FORM_sec_offset};
static const Dwarf_Small dwarf_udata_strx_form[] = {DW_FORM_udata,DW_FORM_strx};
struct Dwarf_Macro_Forms_s dw5formsarray[] = {
{0,0,0},
{DW_MACRO_define,2,dwarf_udata_string_form},
{DW_MACRO_undef,2,dwarf_udata_string_form},
{DW_MACRO_start_file,2,dwarf_udata_udata_form},
{DW_MACRO_end_file,0,0},
{DW_MACRO_define_strp,2,dwarf_udata_strp_form},
{DW_MACRO_undef_strp,2,dwarf_udata_strp_form},
{DW_MACRO_import,1,dwarf_secoffset_form},
{DW_MACRO_define_sup,2,dwarf_udata_strp_sup_form},
{DW_MACRO_undef_sup,2,dwarf_udata_strp_sup_form},
{DW_MACRO_import_sup,1,dwarf_secoffset_form},
{DW_MACRO_define_strx,2,dwarf_udata_strx_form},
{DW_MACRO_undef_strx,2,dwarf_udata_strx_form},
};
static const struct Dwarf_Macro_OperationsList_s dwarf_default_macro_opslist = {
13, dw5formsarray
};
static int _dwarf_internal_macro_context_by_offset(Dwarf_Debug dbg,
Dwarf_Unsigned offset,
Dwarf_Unsigned * version_out,
Dwarf_Macro_Context * macro_context_out,
Dwarf_Unsigned *macro_ops_count_out,
Dwarf_Unsigned *macro_ops_data_length,
char **srcfiles,
Dwarf_Signed srcfilescount,
const char *comp_dir,
const char *comp_name,
Dwarf_CU_Context cu_context,
Dwarf_Error * error);
static int _dwarf_internal_macro_context(Dwarf_Die die,
Dwarf_Bool offset_specified,
Dwarf_Unsigned offset,
Dwarf_Unsigned * version_out,
Dwarf_Macro_Context * macro_context_out,
Dwarf_Unsigned *macro_unit_offset_out,
Dwarf_Unsigned *macro_ops_count_out,
Dwarf_Unsigned *macro_ops_data_length,
Dwarf_Error * error);
static int
is_std_moperator(Dwarf_Small op)
{
if (op >= 1 && op <= DW_MACRO_undef_strx) {
return TRUE;
}
return FALSE;
}
static int
_dwarf_skim_forms(Dwarf_Debug dbg,
Dwarf_Macro_Context mcontext,
Dwarf_Small *mdata_start,
unsigned formcount,
const Dwarf_Small *forms,
Dwarf_Small *section_end,
Dwarf_Unsigned *forms_length,
Dwarf_Error *error)
{
unsigned i = 0;
Dwarf_Small curform = 0 ;
Dwarf_Unsigned totallen = 0;
Dwarf_Unsigned v = 0;
Dwarf_Unsigned ret_value = 0;
Dwarf_Unsigned length;
Dwarf_Small *mdata = mdata_start;
Dwarf_Unsigned leb128_length = 0;
for( ; i < formcount; ++i) {
curform = forms[i];
if (mdata >= section_end) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return DW_DLV_ERROR;
}
switch(curform) {
default:
_dwarf_error(dbg,error,
DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE);
return DW_DLV_ERROR;
case DW_FORM_block1:
v = *(Dwarf_Small *) mdata;
totallen += v+1;
mdata += v+1;
break;
case DW_FORM_block2:
READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned,
mdata, DWARF_HALF_SIZE,
error,section_end);
v = ret_value + DWARF_HALF_SIZE;
totallen += v;
mdata += v;
break;
case DW_FORM_block4:
READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned,
mdata, DWARF_32BIT_SIZE,
error,section_end);
v = ret_value + DWARF_32BIT_SIZE;
totallen += v;
mdata += v;
break;
case DW_FORM_data1:
v = 1;
totallen += v;
mdata += v;
break;
case DW_FORM_data2:
v = 2;
totallen += v;
mdata += v;
break;
case DW_FORM_data4:
v = 4;
totallen += v;
mdata += v;
break;
case DW_FORM_data8:
v = 8;
totallen += v;
mdata += v;
break;
case DW_FORM_data16:
v = 8;
totallen += v;
mdata += v;
break;
case DW_FORM_string: {
int res = _dwarf_check_string_valid(dbg,
mdata,mdata, section_end,
DW_DLE_MACRO_STRING_BAD,error);
if(res != DW_DLV_OK) {
return res;
}
v = strlen((char *) mdata) + 1;
totallen += v;
mdata += v;
}
break;
case DW_FORM_block:
DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length,
dbg, error,section_end);
v = length + leb128_length;
totallen += v;
break;
case DW_FORM_flag:
v = 1;
totallen += v;
mdata += v;
break;
case DW_FORM_sec_offset:
v = mcontext->mc_offset_size;
totallen += v;
mdata += v;
break;
case DW_FORM_sdata:
DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length,
dbg, error,section_end);
totallen += v;
break;
case DW_FORM_strx:
DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length,
dbg, error,section_end);
totallen += leb128_length;;
break;
case DW_FORM_strp:
v = mcontext->mc_offset_size;
mdata += v;
totallen += v;
break;
case DW_FORM_udata:
DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length,
dbg, error,section_end);
totallen += leb128_length;
break;
}
}
if (mdata > section_end) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return DW_DLV_ERROR;
}
*forms_length = totallen;
return DW_DLV_OK;
}
#if 0
static void
dump_bytes(Dwarf_Small * start, long len)
{
Dwarf_Small *end = start + len;
Dwarf_Small *cur = start;
unsigned pos = 0;
printf("dump %ld bytes, start at 0x%lx\n",len,(unsigned long)start);
printf("0x");
for (; cur < end;pos++, cur++) {
if (!(pos %4)) {
printf(" ");
}
printf("%02x",*cur);
}
printf("\n");
}
Dwarf_Bool
is_defundef(unsigned op)
{
switch(op){
case DW_MACRO_define:
case DW_MACRO_undef:
case DW_MACRO_define_strp:
case DW_MACRO_undef_strp:
case DW_MACRO_define_strx:
case DW_MACRO_undef_strx:
case DW_MACRO_define_sup:
case DW_MACRO_undef_sup:
return TRUE;
}
return FALSE;
}
#endif
static int
_dwarf_get_macro_ops_count_internal(Dwarf_Macro_Context macro_context,
Dwarf_Bool build_ops_array,
Dwarf_Error *error)
{
Dwarf_Debug dbg = 0;
Dwarf_Small *mdata = 0;
Dwarf_Small *section_end = 0;
Dwarf_Small *section_base = 0;
Dwarf_Unsigned opcount = 0;
Dwarf_Unsigned known_ops_count = 0;
struct Dwarf_Macro_Operator_s *opsarray = 0;
struct Dwarf_Macro_Operator_s *curopsentry = 0;
int res = 0;
dbg = macro_context->mc_dbg;
if (build_ops_array) {
known_ops_count = macro_context->mc_macro_ops_count;
opsarray = (struct Dwarf_Macro_Operator_s *)
calloc(known_ops_count,sizeof(struct Dwarf_Macro_Operator_s));
if(!opsarray) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
curopsentry = opsarray;
macro_context->mc_ops = opsarray;
}
section_base = dbg->de_debug_macro.dss_data;
section_end = section_base + dbg->de_debug_macro.dss_size;
mdata = macro_context->mc_macro_ops;
while (mdata < section_end) {
Dwarf_Small op = 0;
op = *mdata;
++opcount;
++mdata;
if (!op) {
Dwarf_Unsigned opslen = 0;
opslen = mdata - macro_context->mc_macro_ops;
macro_context->mc_macro_ops_count = opcount;
macro_context->mc_ops_data_length = opslen;
macro_context->mc_total_length = opslen +
macro_context->mc_macro_header_length;
return DW_DLV_OK;
}
if (is_std_moperator(op)) {
struct Dwarf_Macro_Forms_s * ourform =
dw5formsarray + op;
unsigned formcount = ourform->mf_formcount;
const Dwarf_Small *forms = ourform->mf_formbytes;
Dwarf_Unsigned forms_length = 0;
res = _dwarf_skim_forms(dbg,macro_context,mdata,
formcount,forms,
section_end,
&forms_length,error);
if ( res != DW_DLV_OK) {
return res;
}
if(build_ops_array) {
curopsentry->mo_opcode = op;
curopsentry->mo_form = ourform;
curopsentry->mo_data = mdata;
}
mdata += forms_length;
} else {
_dwarf_error(dbg, error, DW_DLE_MACRO_OP_UNHANDLED);
return DW_DLV_ERROR;
}
if (mdata > section_end) {
_dwarf_error(dbg, error, DW_DLE_MACRO_PAST_END);
return DW_DLV_ERROR;
}
if (build_ops_array) {
curopsentry++;
}
}
_dwarf_error(dbg, error, DW_DLE_MACRO_PAST_END);
return DW_DLV_ERROR;
}
int
dwarf_get_macro_op(Dwarf_Macro_Context macro_context,
Dwarf_Unsigned op_number,
Dwarf_Unsigned * op_start_section_offset,
Dwarf_Half * macro_operator,
Dwarf_Half * forms_count,
const Dwarf_Small ** formcode_array,
Dwarf_Error *error)
{
struct Dwarf_Macro_Operator_s *curop = 0;
Dwarf_Debug dbg = 0;
if (!macro_context || macro_context->mc_sentinel != 0xada) {
if(macro_context) {
dbg = macro_context->mc_dbg;
}
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER);
return DW_DLV_ERROR;
}
dbg = macro_context->mc_dbg;
if (op_number >= macro_context->mc_macro_ops_count) {
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX);
return DW_DLV_ERROR;
}
curop = macro_context->mc_ops + op_number;
*op_start_section_offset =
((curop->mo_data -1) - macro_context->mc_macro_header) +
macro_context->mc_section_offset;
*macro_operator = curop->mo_opcode;
if (curop->mo_form) {
*forms_count = curop->mo_form->mf_formcount;
*formcode_array = curop->mo_form->mf_formbytes;
} else {
*forms_count = 0;
*formcode_array = 0;
}
return DW_DLV_OK;
}
int
dwarf_get_macro_defundef(Dwarf_Macro_Context macro_context,
Dwarf_Unsigned op_number,
Dwarf_Unsigned * line_number,
Dwarf_Unsigned * index,
Dwarf_Unsigned * offset,
Dwarf_Half * forms_count,
const char ** macro_string,
Dwarf_Error *error)
{
Dwarf_Debug dbg = 0;
Dwarf_Small *mdata = 0;
int res = 0;
Dwarf_Small *startptr = 0;
Dwarf_Small *endptr = 0;
Dwarf_Half lformscount = 0;
struct Dwarf_Macro_Operator_s *curop = 0;
unsigned macop = 0;
if (!macro_context || macro_context->mc_sentinel != 0xada) {
if(macro_context) {
dbg = macro_context->mc_dbg;
}
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER);
return DW_DLV_ERROR;
}
dbg = macro_context->mc_dbg;
if (op_number >= macro_context->mc_macro_ops_count) {
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX);
return DW_DLV_ERROR;
}
curop = macro_context->mc_ops + op_number;
macop = curop->mo_opcode;
startptr = macro_context->mc_macro_header;
endptr = startptr + macro_context->mc_total_length;
mdata = curop->mo_data;
lformscount = curop->mo_form->mf_formcount;
if (lformscount != 2) {
return DW_DLV_NO_ENTRY;
}
switch(macop){
case DW_MACRO_define:
case DW_MACRO_undef: {
Dwarf_Unsigned linenum = 0;
const char * content = 0;
DECODE_LEB128_UWORD_CK(mdata,linenum,
dbg, error,endptr);
content = (const char *)mdata;
res = _dwarf_check_string_valid(dbg,
startptr,mdata, endptr,
DW_DLE_MACRO_STRING_BAD,error);
if(res != DW_DLV_OK) {
return res;
}
*line_number = linenum;
*index = 0;
*offset = 0;
*forms_count = lformscount;
*macro_string = content;
}
return DW_DLV_OK;
case DW_MACRO_define_strp:
case DW_MACRO_undef_strp: {
Dwarf_Unsigned linenum = 0;
Dwarf_Unsigned stringoffset = 0;
Dwarf_Small form1 = curop->mo_form->mf_formbytes[1];
char * localstr = 0;
DECODE_LEB128_UWORD_CK(mdata,linenum,
dbg, error,endptr);
READ_UNALIGNED_CK(dbg,stringoffset,Dwarf_Unsigned,
mdata,macro_context->mc_offset_size,
error,endptr);
res = _dwarf_extract_local_debug_str_string_given_offset(dbg,
form1,
stringoffset,
&localstr,
error);
*index = 0;
*line_number = linenum;
*offset = stringoffset;
*forms_count = lformscount;
if (res == DW_DLV_ERROR) {
*macro_string = "<Error: getting local .debug_str>";
return res;
} else if (res == DW_DLV_NO_ENTRY) {
*macro_string = "<Error: NO_ENTRY on .debug_string (strp)>";
} else {
*macro_string = (const char *)localstr;
}
}
return DW_DLV_OK;
case DW_MACRO_define_strx:
case DW_MACRO_undef_strx: {
Dwarf_Unsigned linenum = 0;
Dwarf_Unsigned stringindex = 0;
Dwarf_Unsigned offsettostr= 0;
int ress = 0;
Dwarf_Byte_Ptr mdata_copy = 0;
Dwarf_Small form1 = curop->mo_form->mf_formbytes[1];
DECODE_LEB128_UWORD_CK(mdata,linenum, dbg, error,endptr);
*line_number = linenum;
mdata_copy = mdata;
DECODE_LEB128_UWORD_CK(mdata_copy,stringindex, dbg, error,endptr);
*index = stringindex;
*forms_count = lformscount;
ress = _dwarf_extract_string_offset_via_str_offsets(dbg,
mdata_copy,
endptr,
DW_AT_macros,
form1,
macro_context->mc_cu_context,
&offsettostr,
error);
if (ress == DW_DLV_ERROR) {
return ress;
}
if (ress == DW_DLV_OK) {
char *localstr = 0;
*index = stringindex;
*offset = offsettostr;
ress = _dwarf_extract_local_debug_str_string_given_offset(dbg,
form1,
offsettostr,
&localstr,
error);
if(ress == DW_DLV_ERROR) {
return ress;
} else if (ress == DW_DLV_NO_ENTRY){
*macro_string = "<:No string available>";
} else {
*macro_string = (const char *)localstr;
}
} else {
*index = stringindex;
*offset = 0;
*macro_string = "<.debug_str_offsets not available>";
}
}
return DW_DLV_OK;
case DW_MACRO_define_sup:
case DW_MACRO_undef_sup: {
Dwarf_Unsigned linenum = 0;
Dwarf_Unsigned supoffset = 0;
char *localstring = 0;
int resup = 0;
Dwarf_Error lerr = 0;
DECODE_LEB128_UWORD_CK(mdata,linenum,
dbg, error,endptr);
READ_UNALIGNED_CK(dbg,supoffset,Dwarf_Unsigned,
mdata,macro_context->mc_offset_size,
error,endptr);
*line_number = linenum;
*index = 0;
*offset = supoffset;
*forms_count = lformscount;
resup = _dwarf_get_string_from_tied(dbg, supoffset,
&localstring, &lerr);
if (resup != DW_DLV_OK) {
if (resup == DW_DLV_ERROR) {
int myerrno = dwarf_errno(lerr);
if(myerrno == DW_DLE_NO_TIED_FILE_AVAILABLE) {
*macro_string =
(char *)"<DW_FORM_str_sup-no-tied_file>";
} else {
_dwarf_error(dbg,error,myerrno);
*macro_string =
(char *)"<Error: DW_FORM_str_sup-got-error>";
}
dwarf_dealloc(dbg,lerr,DW_DLA_ERROR);
} else {
*macro_string = "<DW_FORM_str_sup-no-entry>";
}
return resup;
}
*macro_string = (const char *)localstring;
return resup;
}
default:
_dwarf_error(dbg,error,DW_DLE_MACRO_OP_UNHANDLED);
return DW_DLV_ERROR;
}
return DW_DLV_NO_ENTRY;
}
static void
specialcat(char *targ,char *src,int trimtarg)
{
char *last = 0;
while( *targ) {
last = targ;
targ++;
}
if (trimtarg ) {
if(last && *last == '/') {
*last = 0;
targ = last;
}
}
while (*src) {
*targ = *src;
targ++;
src++;
}
*targ = 0;
}
static const char *
construct_from_dir_and_name(const char *dir,
const char *name)
{
int truelen = 0;
char *final = 0;
truelen = strlen(dir) + strlen(name) + 1 +1;
final = (char *)malloc(truelen);
if(!final) {
return NULL;
}
final[0] = 0;
specialcat(final,(char *)dir,1);
strcat(final,"/");
specialcat(final,(char *)name,0);
return final;
}
static const char *
construct_at_path_from_parts(Dwarf_Macro_Context mc)
{
if (mc->mc_file_path) {
return mc->mc_file_path;
}
if(!mc->mc_at_comp_dir || !mc->mc_at_comp_dir[0]) {
return mc->mc_at_name;
}
if (!mc->mc_at_name || !mc->mc_at_name[0]) {
return NULL;
}
if(_dwarf_file_name_is_full_path((Dwarf_Small *)mc->mc_at_name)) {
return mc->mc_at_name;
}
mc->mc_file_path = construct_from_dir_and_name(
mc->mc_at_comp_dir,mc->mc_at_name);
return mc->mc_file_path;
}
int
dwarf_get_macro_startend_file(Dwarf_Macro_Context macro_context,
Dwarf_Unsigned op_number,
Dwarf_Unsigned * line_number,
Dwarf_Unsigned * name_index_to_line_tab,
const char ** src_file_name,
Dwarf_Error *error)
{
Dwarf_Debug dbg = 0;
Dwarf_Small *mdata = 0;
unsigned macop = 0;
struct Dwarf_Macro_Operator_s *curop = 0;
Dwarf_Byte_Ptr startptr = 0;
Dwarf_Byte_Ptr endptr = 0;
if (!macro_context || macro_context->mc_sentinel != 0xada) {
if(macro_context) {
dbg = macro_context->mc_dbg;
}
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER);
return DW_DLV_ERROR;
}
dbg = macro_context->mc_dbg;
if (op_number >= macro_context->mc_macro_ops_count) {
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX);
return DW_DLV_ERROR;
}
startptr = macro_context->mc_macro_header;
endptr = startptr + macro_context->mc_total_length;
curop = macro_context->mc_ops + op_number;
macop = curop->mo_opcode;
mdata = curop->mo_data;
if (macop != DW_MACRO_start_file && macop != DW_MACRO_end_file) {
return DW_DLV_NO_ENTRY;
}
if (macop == DW_MACRO_start_file) {
Dwarf_Unsigned linenum = 0;
Dwarf_Unsigned srcindex = 0;
Dwarf_Signed trueindex = 0;
DECODE_LEB128_UWORD_CK(mdata,linenum, dbg, error,endptr);
DECODE_LEB128_UWORD_CK(mdata,srcindex, dbg, error,endptr);
*line_number = linenum;
*name_index_to_line_tab = srcindex;
if(macro_context->mc_version_number >= 5) {
trueindex = srcindex;
if (trueindex < 0) {
*src_file_name = "<source-file-index-low-no-name-available>";
return DW_DLV_OK;
}
if (trueindex < macro_context->mc_srcfiles_count) {
*src_file_name = macro_context->mc_srcfiles[trueindex];
return DW_DLV_OK;
} else {
*src_file_name =
"<src-index-high-no-source-file-name-available>";
return DW_DLV_OK;
}
} else {
trueindex = srcindex;
if (trueindex < 0 ) {
*src_file_name = "<source-file-index-low-no-name-available>";
return DW_DLV_OK;
}
if (trueindex > (macro_context->mc_srcfiles_count+1)) {
*src_file_name =
"<source-file-index-high-no-name-available>";
return DW_DLV_OK;
}
--trueindex;
if (trueindex > macro_context->mc_srcfiles_count) {
*src_file_name =
"<adjusted-source-file-index-high-no-name-available>";
}
if (srcindex > 0 &&
trueindex < macro_context->mc_srcfiles_count) {
*src_file_name = macro_context->mc_srcfiles[trueindex];
} else {
const char *mcatcomp = construct_at_path_from_parts(
macro_context);
if(mcatcomp) {
*src_file_name = mcatcomp;
} else {
*src_file_name = "<no-source-file-name-available>";
}
}
}
} else {
}
return DW_DLV_OK;
}
int
dwarf_get_macro_import(Dwarf_Macro_Context macro_context,
Dwarf_Unsigned op_number,
Dwarf_Unsigned * target_offset,
Dwarf_Error *error)
{
Dwarf_Unsigned supoffset = 0;
Dwarf_Debug dbg = 0;
unsigned macop = 0;
struct Dwarf_Macro_Operator_s *curop = 0;
Dwarf_Small *mdata = 0;
Dwarf_Byte_Ptr startptr = 0;
Dwarf_Byte_Ptr endptr = 0;
if (!macro_context || macro_context->mc_sentinel != 0xada) {
if(macro_context) {
dbg = macro_context->mc_dbg;
}
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER);
return DW_DLV_ERROR;
}
startptr = macro_context->mc_macro_header;
endptr = startptr + macro_context->mc_total_length;
dbg = macro_context->mc_dbg;
if (op_number >= macro_context->mc_macro_ops_count) {
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX);
return DW_DLV_ERROR;
}
curop = macro_context->mc_ops + op_number;
macop = curop->mo_opcode;
mdata = curop->mo_data;
if (macop != DW_MACRO_import && macop != DW_MACRO_import_sup) {
return DW_DLV_NO_ENTRY;
}
READ_UNALIGNED_CK(dbg,supoffset,Dwarf_Unsigned,
mdata,macro_context->mc_offset_size,
error,endptr);
*target_offset = supoffset;
return DW_DLV_OK;
}
static int
valid_macro_form(Dwarf_Half form)
{
switch(form) {
case DW_FORM_block:
case DW_FORM_block1:
case DW_FORM_block2:
case DW_FORM_block4:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
case DW_FORM_data8:
case DW_FORM_data16:
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_flag:
case DW_FORM_sec_offset:
case DW_FORM_string:
case DW_FORM_strp:
case DW_FORM_strx:
return TRUE;
}
return FALSE;
}
static int
validate_opcode(Dwarf_Debug dbg,
struct Dwarf_Macro_Forms_s *curform,
Dwarf_Error * error)
{
unsigned i = 0;
struct Dwarf_Macro_Forms_s *stdfptr = 0;
if (curform->mf_code >= DW_MACRO_lo_user) {
return DW_DLV_OK;
}
if (curform->mf_code > DW_MACRO_undef_strx) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_BAD);
return (DW_DLV_ERROR);
}
if (!curform->mf_code){
_dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_BAD);
return (DW_DLV_ERROR);
}
stdfptr = &dwarf_default_macro_opslist.mol_data[curform->mf_code];
if (curform->mf_formcount != stdfptr->mf_formcount) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_FORM_BAD);
return (DW_DLV_ERROR);
}
for(i = 0; i < curform->mf_formcount; ++i) {
if (curform->mf_formbytes[i] != stdfptr->mf_formbytes[1]) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_FORM_BAD);
return (DW_DLV_ERROR);
}
}
return DW_DLV_OK;
}
static int
read_operands_table(Dwarf_Macro_Context macro_context,
Dwarf_Small * macro_header,
Dwarf_Small * macro_data,
Dwarf_Small * section_base,
Dwarf_Unsigned section_size,
Dwarf_Unsigned *table_size_out,
Dwarf_Error *error)
{
Dwarf_Small* table_data_start = macro_data;
Dwarf_Unsigned local_size = 0;
Dwarf_Unsigned cur_offset = 0;
Dwarf_Small operand_table_count = 0;
unsigned i = 0;
struct Dwarf_Macro_Forms_s *curformentry = 0;
Dwarf_Debug dbg = 0;
Dwarf_Byte_Ptr startptr = 0;
Dwarf_Byte_Ptr endptr = 0;
if (!macro_context || macro_context->mc_sentinel != 0xada) {
if(macro_context) {
dbg = macro_context->mc_dbg;
}
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER);
return DW_DLV_ERROR;
}
dbg = macro_context->mc_dbg;
cur_offset = (1+ macro_data) - macro_header;
if (cur_offset >= section_size) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return (DW_DLV_ERROR);
}
startptr = macro_context->mc_macro_header;
endptr = startptr + macro_context->mc_total_length;
READ_UNALIGNED_CK(dbg,operand_table_count,Dwarf_Small,
macro_data,sizeof(Dwarf_Small),error,endptr);
macro_data += sizeof(Dwarf_Small);
local_size = operand_table_count * 4;
cur_offset = (local_size+ macro_data) - section_base;
if (cur_offset >= section_size) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return (DW_DLV_ERROR);
}
table_data_start = macro_data;
for (i = 0; i < operand_table_count; ++i) {
UNUSEDARG Dwarf_Small opcode_number = 0;
Dwarf_Unsigned formcount = 0;
READ_UNALIGNED_CK(dbg,opcode_number,Dwarf_Small,
macro_data,sizeof(Dwarf_Small),error,endptr);
macro_data += sizeof(Dwarf_Small);
DECODE_LEB128_UWORD_CK(macro_data,formcount,
dbg, error, endptr);
cur_offset = (formcount+ macro_data) - section_base;
if (cur_offset >= section_size) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return (DW_DLV_ERROR);
}
macro_data += formcount;
}
macro_data = table_data_start;
macro_context->mc_opcode_forms = (struct Dwarf_Macro_Forms_s *)
calloc(operand_table_count,
sizeof(struct Dwarf_Macro_Forms_s));
macro_context->mc_opcode_count = operand_table_count;
if(!macro_context->mc_opcode_forms) {
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
curformentry = macro_context->mc_opcode_forms;
for (i = 0; i < operand_table_count; ++i,++curformentry) {
Dwarf_Small opcode_number = 0;
Dwarf_Unsigned formcount = 0;
int res = 0;
cur_offset = (2 + macro_data) - section_base;
if (cur_offset >= section_size) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return (DW_DLV_ERROR);
}
READ_UNALIGNED_CK(dbg,opcode_number,Dwarf_Small,
macro_data,sizeof(Dwarf_Small),
error,endptr);
macro_data += sizeof(Dwarf_Small);
DECODE_LEB128_UWORD_CK(macro_data,formcount,
dbg, error, endptr);
curformentry->mf_code = opcode_number;
curformentry->mf_formcount = formcount;
cur_offset = (formcount+ macro_data) - section_base;
if (cur_offset >= section_size) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return (DW_DLV_ERROR);
}
curformentry->mf_formbytes = macro_data;
macro_data += formcount;
if (opcode_number > DW_MACRO_undef_strx ) {
Dwarf_Half k = 0;
for(k = 0; k < formcount; ++k) {
if (!valid_macro_form(curformentry->mf_formbytes[k])) {
_dwarf_error(dbg, error, DW_DLE_MACRO_OP_UNHANDLED);
return (DW_DLV_ERROR);
}
}
}
res = validate_opcode(macro_context->mc_dbg,curformentry, error);
if(res != DW_DLV_OK) {
return res;
}
}
*table_size_out = macro_data - table_data_start;
return DW_DLV_OK;
}
static void
dealloc_macro_srcfiles(char ** srcfiles,
Dwarf_Signed srcfiles_count)
{
Dwarf_Signed i = 0;
if (!srcfiles || !srcfiles_count) {
return;
}
for (i = 0; i < srcfiles_count; ++i) {
if (srcfiles[i]) {
free(srcfiles[i]);
srcfiles[i] = 0;
}
}
free(srcfiles);
}
static int
translate_srcfiles_to_srcfiles2(char **srcfiles,
Dwarf_Signed srcfiles_count,
char **srcfiles2)
{
Dwarf_Signed i = 0;
for(i = 0; i < srcfiles_count; ++i) {
char * ostr = 0;
char * newstr = 0;
size_t slen = 0;
ostr = srcfiles[i];
slen = strlen(ostr);
newstr = calloc(1,slen+1);
if (!newstr) {
return DW_DLV_ERROR;
}
strcpy(newstr,ostr);
srcfiles2[i] = newstr;
}
return DW_DLV_OK;
}
static void
drop_srcfiles(Dwarf_Debug dbg,char ** srcfiles,
Dwarf_Signed srcfiles_count)
{
Dwarf_Signed i = 0;
for (i = 0; i < srcfiles_count; ++i) {
if(srcfiles[i]) {
dwarf_dealloc(dbg, srcfiles[i], DW_DLA_STRING);
}
}
dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST);
}
static int
_dwarf_internal_macro_context(Dwarf_Die die,
Dwarf_Bool offset_specified,
Dwarf_Unsigned offset_in,
Dwarf_Unsigned * version_out,
Dwarf_Macro_Context * macro_context_out,
Dwarf_Unsigned * macro_unit_offset_out,
Dwarf_Unsigned * macro_ops_count_out,
Dwarf_Unsigned * macro_ops_data_length,
Dwarf_Error * error)
{
Dwarf_CU_Context cu_context = 0;
Dwarf_Debug dbg = 0;
int resattr = DW_DLV_ERROR;
int lres = DW_DLV_ERROR;
int res = DW_DLV_ERROR;
Dwarf_Unsigned macro_offset = 0;
Dwarf_Attribute macro_attr = 0;
Dwarf_Signed srcfiles_count = 0;
Dwarf_Signed srcfiles2_count = 0;
char ** srcfiles = 0;
char ** srcfiles2 = 0;
const char *comp_dir = 0;
const char *comp_name = 0;
if (error != NULL) {
*error = NULL;
}
CHECK_DIE(die, DW_DLV_ERROR);
cu_context = die->di_cu_context;
dbg = cu_context->cc_dbg;
res = _dwarf_load_section(dbg, &dbg->de_debug_macro,error);
if (res != DW_DLV_OK) {
return res;
}
if (!dbg->de_debug_macro.dss_size) {
return (DW_DLV_NO_ENTRY);
}
resattr = dwarf_attr(die, DW_AT_macros, ¯o_attr, error);
if (resattr == DW_DLV_NO_ENTRY) {
resattr = dwarf_attr(die, DW_AT_GNU_macros, ¯o_attr, error);
}
if (resattr != DW_DLV_OK) {
return resattr;
}
if (!offset_specified) {
lres = dwarf_global_formref(macro_attr, ¯o_offset, error);
if (lres != DW_DLV_OK) {
dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR);
return lres;
}
} else {
macro_offset = offset_in;
}
lres = dwarf_srcfiles(die,&srcfiles,&srcfiles_count, error);
if (lres == DW_DLV_ERROR) {
dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR);
return lres;
}
lres = _dwarf_internal_get_die_comp_dir(die, &comp_dir,
&comp_name,error);
if (lres == DW_DLV_ERROR) {
drop_srcfiles(dbg,srcfiles,srcfiles_count);
srcfiles = 0;
srcfiles_count = 0;
dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR);
srcfiles = 0;
return lres;
}
*macro_unit_offset_out = macro_offset;
if (srcfiles_count > 0) {
srcfiles2 = (char **) calloc(srcfiles_count, sizeof(char *));
if (!srcfiles2) {
dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR);
drop_srcfiles(dbg,srcfiles,srcfiles_count);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
lres = translate_srcfiles_to_srcfiles2(srcfiles,
srcfiles_count,srcfiles2);
drop_srcfiles(dbg,srcfiles,srcfiles_count);
srcfiles2_count = srcfiles_count;
srcfiles = 0;
srcfiles_count = 0;
if (lres != DW_DLV_OK) {
dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR);
dealloc_macro_srcfiles(srcfiles2, srcfiles2_count);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return lres;
}
} else {
drop_srcfiles(dbg,srcfiles,srcfiles_count);
srcfiles = 0;
srcfiles_count = 0;
}
dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR);
lres = _dwarf_internal_macro_context_by_offset(dbg,
macro_offset,version_out,macro_context_out,
macro_ops_count_out,
macro_ops_data_length,
srcfiles2,srcfiles2_count,
comp_dir,
comp_name,
cu_context,
error);
return lres;
}
static int
_dwarf_internal_macro_context_by_offset(Dwarf_Debug dbg,
Dwarf_Unsigned offset,
Dwarf_Unsigned * version_out,
Dwarf_Macro_Context * macro_context_out,
Dwarf_Unsigned * macro_ops_count_out,
Dwarf_Unsigned * macro_ops_data_length,
char **srcfiles,
Dwarf_Signed srcfilescount,
const char *comp_dir,
const char *comp_name,
Dwarf_CU_Context cu_context,
Dwarf_Error * error)
{
Dwarf_Unsigned line_table_offset = 0;
Dwarf_Small * macro_header = 0;
Dwarf_Small * macro_data = 0;
Dwarf_Unsigned version = 0;
Dwarf_Unsigned flags = 0;
Dwarf_Small offset_size = 4;
Dwarf_Unsigned cur_offset = 0;
Dwarf_Unsigned section_size = 0;
Dwarf_Small *section_base = 0;
Dwarf_Small *section_end = 0;
Dwarf_Unsigned optablesize = 0;
Dwarf_Unsigned macro_offset = offset;
int res = 0;
Dwarf_Macro_Context macro_context = 0;
Dwarf_Bool build_ops_array = FALSE;
res = _dwarf_load_section(dbg, &dbg->de_debug_macro,error);
if (res != DW_DLV_OK) {
dealloc_macro_srcfiles(srcfiles,srcfilescount);
return res;
}
if (!dbg->de_debug_macro.dss_size) {
dealloc_macro_srcfiles(srcfiles,srcfilescount);
return (DW_DLV_NO_ENTRY);
}
section_base = dbg->de_debug_macro.dss_data;
section_size = dbg->de_debug_macro.dss_size;
if ((3+macro_offset) >= section_size) {
dealloc_macro_srcfiles(srcfiles,srcfilescount);
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return (DW_DLV_ERROR);
}
macro_header = macro_offset + section_base;
macro_data = macro_header;
section_end = section_base +section_size;
macro_context = (Dwarf_Macro_Context)
_dwarf_get_alloc(dbg,DW_DLA_MACRO_CONTEXT,1);
if (!macro_context) {
dealloc_macro_srcfiles(srcfiles,srcfilescount);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
if ((section_base + DWARF_HALF_SIZE + sizeof(Dwarf_Small)) > section_end ) {
dealloc_macro_srcfiles(srcfiles,srcfilescount);
dwarf_dealloc_macro_context(macro_context);
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return DW_DLV_ERROR;
}
macro_context->mc_srcfiles = srcfiles;
macro_context->mc_srcfiles_count = srcfilescount;
macro_context->mc_cu_context = cu_context;
res = _dwarf_read_unaligned_ck_wrapper(dbg,
&version,macro_data,DWARF_HALF_SIZE,section_end,
error);
if (res != DW_DLV_OK) {
dwarf_dealloc_macro_context(macro_context);
return res;
}
macro_data += DWARF_HALF_SIZE;
res = _dwarf_read_unaligned_ck_wrapper(dbg,
&flags,macro_data,sizeof(Dwarf_Small),section_end,
error);
if (res != DW_DLV_OK) {
dwarf_dealloc_macro_context(macro_context);
return res;
}
macro_data += sizeof(Dwarf_Small);
macro_context->mc_at_comp_dir = comp_dir;
macro_context->mc_at_name = comp_name;
macro_context->mc_macro_header = macro_header;
macro_context->mc_section_offset = macro_offset;
macro_context->mc_version_number = version;
macro_context->mc_flags = flags;
macro_context->mc_dbg = dbg;
macro_context->mc_offset_size_flag =
flags& MACRO_OFFSET_SIZE_FLAG?TRUE:FALSE;
macro_context->mc_debug_line_offset_flag =
flags& MACRO_LINE_OFFSET_FLAG?TRUE:FALSE;
macro_context->mc_operands_table_flag =
flags& MACRO_OP_TABLE_FLAG?TRUE:FALSE;
offset_size = macro_context->mc_offset_size_flag?8:4;
macro_context->mc_offset_size = offset_size;
if (macro_context->mc_debug_line_offset_flag) {
cur_offset = (offset_size+ macro_data) - section_base;
if (cur_offset >= section_size) {
dwarf_dealloc_macro_context(macro_context);
_dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD);
return (DW_DLV_ERROR);
}
res = _dwarf_read_unaligned_ck_wrapper(dbg,
&line_table_offset,macro_data,
offset_size,section_end,
error);
if (res != DW_DLV_OK) {
dwarf_dealloc_macro_context(macro_context);
return res;
}
macro_data += offset_size;
macro_context->mc_debug_line_offset = line_table_offset;
}
if (macro_context->mc_operands_table_flag) {
res = read_operands_table(macro_context,
macro_header,
macro_data,
section_base,
section_size,
&optablesize,
error);
if (res != DW_DLV_OK) {
dwarf_dealloc_macro_context(macro_context);
return res;
}
}
macro_data += optablesize;
macro_context->mc_macro_ops = macro_data;
macro_context->mc_macro_header_length =macro_data - macro_header;
build_ops_array = FALSE;
res = _dwarf_get_macro_ops_count_internal(macro_context,
build_ops_array,
error);
if (res != DW_DLV_OK) {
dwarf_dealloc_macro_context(macro_context);
return res;
}
build_ops_array = TRUE;
res = _dwarf_get_macro_ops_count_internal(macro_context,
build_ops_array,
error);
if (res != DW_DLV_OK) {
dwarf_dealloc_macro_context(macro_context);
return res;
}
*macro_ops_count_out = macro_context->mc_macro_ops_count;
*macro_ops_data_length = macro_context->mc_ops_data_length;
*version_out = version;
*macro_context_out = macro_context;
return DW_DLV_OK;
}
int dwarf_macro_context_head(Dwarf_Macro_Context head,
Dwarf_Half * version,
Dwarf_Unsigned * mac_offset,
Dwarf_Unsigned * mac_len,
Dwarf_Unsigned * mac_header_len,
unsigned * flags,
Dwarf_Bool * has_line_offset,
Dwarf_Unsigned * line_offset,
Dwarf_Bool * has_offset_size_64,
Dwarf_Bool * has_operands_table,
Dwarf_Half * opcode_count,
Dwarf_Error *error)
{
if (!head || head->mc_sentinel != 0xada) {
Dwarf_Debug dbg = 0;
if(head) {
dbg = head->mc_dbg;
}
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER);
return DW_DLV_ERROR;
}
*version = head->mc_version_number;
*mac_offset = head->mc_section_offset;
*mac_len = head->mc_total_length;
*mac_header_len = head->mc_macro_header_length;
*flags = head->mc_flags;
*line_offset = head->mc_debug_line_offset;
*has_line_offset = head->mc_debug_line_offset_flag;
*has_offset_size_64 = head->mc_offset_size_flag;
*has_operands_table = head->mc_operands_table_flag;
*opcode_count = head->mc_opcode_count;
return DW_DLV_OK;
}
int dwarf_macro_operands_table(Dwarf_Macro_Context head,
Dwarf_Half index,
Dwarf_Half *opcode_number,
Dwarf_Half *operand_count,
const Dwarf_Small **operand_array,
Dwarf_Error *error)
{
struct Dwarf_Macro_Forms_s * ops = 0;
Dwarf_Debug dbg = 0;
if (!head || head->mc_sentinel != 0xada) {
if(head) {
dbg = head->mc_dbg;
}
_dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER);
return DW_DLV_ERROR;
}
dbg = head->mc_dbg;
if (index >= head->mc_opcode_count) {
_dwarf_error(dbg, error, DW_DLE_BAD_MACRO_INDEX);
return DW_DLV_ERROR;
}
ops = head->mc_opcode_forms + index;
*opcode_number = ops->mf_code;
*operand_count = ops->mf_formcount;
*operand_array = ops->mf_formbytes;
return DW_DLV_OK;
}
int
dwarf_get_macro_context(Dwarf_Die cu_die,
Dwarf_Unsigned * version_out,
Dwarf_Macro_Context * macro_context,
Dwarf_Unsigned * macro_unit_offset_out,
Dwarf_Unsigned * macro_ops_count_out,
Dwarf_Unsigned * macro_ops_data_length,
Dwarf_Error * error)
{
int res = 0;
Dwarf_Bool offset_specified = FALSE;
Dwarf_Unsigned offset = 0;
res = _dwarf_internal_macro_context(cu_die,
offset_specified,
offset,
version_out,
macro_context,
macro_unit_offset_out,
macro_ops_count_out,
macro_ops_data_length,
error);
return res;
}
int
dwarf_get_macro_context_by_offset(Dwarf_Die cu_die,
Dwarf_Unsigned offset,
Dwarf_Unsigned * version_out,
Dwarf_Macro_Context * macro_context,
Dwarf_Unsigned * macro_ops_count_out,
Dwarf_Unsigned * macro_ops_data_length,
Dwarf_Error * error)
{
int res = 0;
Dwarf_Bool offset_specified = TRUE;
Dwarf_Unsigned macro_unit_offset_out = 0;
res = _dwarf_internal_macro_context(cu_die,
offset_specified,
offset,
version_out,
macro_context,
¯o_unit_offset_out,
macro_ops_count_out,
macro_ops_data_length,
error);
return res;
}
int dwarf_get_macro_section_name(Dwarf_Debug dbg,
const char **sec_name_out,
UNUSEDARG Dwarf_Error *error)
{
struct Dwarf_Section_s *sec = 0;
sec = &dbg->de_debug_macro;
if (sec->dss_size == 0) {
return DW_DLV_NO_ENTRY;
}
*sec_name_out = sec->dss_name;
return DW_DLV_OK;
}
void
dwarf_dealloc_macro_context(Dwarf_Macro_Context mc)
{
Dwarf_Debug dbg = 0;
if (!mc) {
return;
}
dbg = mc->mc_dbg;
dwarf_dealloc(dbg,mc,DW_DLA_MACRO_CONTEXT);
}
int
_dwarf_macro_constructor(Dwarf_Debug dbg, void *m)
{
Dwarf_Macro_Context mc= (Dwarf_Macro_Context)m;
mc->mc_sentinel = 0xada;
mc->mc_dbg = dbg;
return DW_DLV_OK;
}
void
_dwarf_macro_destructor(void *m)
{
Dwarf_Macro_Context mc= (Dwarf_Macro_Context)m;
dealloc_macro_srcfiles(mc->mc_srcfiles, mc->mc_srcfiles_count);
mc->mc_srcfiles = 0;
mc->mc_srcfiles_count = 0;
free((void *)mc->mc_file_path);
mc->mc_file_path = 0;
free(mc->mc_ops);
mc->mc_ops = 0;
free(mc->mc_opcode_forms);
mc->mc_opcode_forms = 0;
memset(mc,0,sizeof(*mc));
mc->mc_sentinel = 0xdeadbeef;
}