summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdwarf/common/dwarf_macro5.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdwarf/common/dwarf_macro5.c')
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_macro5.c1585
1 files changed, 1585 insertions, 0 deletions
diff --git a/usr/src/lib/libdwarf/common/dwarf_macro5.c b/usr/src/lib/libdwarf/common/dwarf_macro5.c
new file mode 100644
index 0000000000..e81818f354
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_macro5.c
@@ -0,0 +1,1585 @@
+/*
+ Copyright (C) 2015-2019 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+*/
+
+#include "config.h"
+#include <stdio.h>
+#include <limits.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_MALLOC_H
+/* Useful include for some Windows compilers. */
+#include <malloc.h>
+#endif /* HAVE_MALLOC_H */
+#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
+
+/* Section 6.3: Macro Information:
+ Each macro unit ends with an entry
+ containing an opcode of 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},
+};
+
+
+
+/* Represents DWARF 5 macro info */
+/* .debug_macro predefined, in order by value */
+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:
+ /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */
+ v = mcontext->mc_offset_size;
+ totallen += v;
+ mdata += v;
+ break;
+ case DW_FORM_sdata:
+ /* Discard the decoded value, we just want the length
+ of the value. */
+ 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:
+ /* Discard the decoded value, we just want the length
+ of the value. */
+ 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 /* FOR DEBUGGING */
+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 /* FOR DEBUGGING */
+
+
+/* On first call (for this macro_context),
+ build_ops_array is FALSE. On second,
+ it is TRUE and we know the count so we allocate and fill in
+ the ops array. */
+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;
+ /* End of ops, this is terminator, count the ending 0
+ as an operator so dwarfdump can print it. */
+ 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;
+ /* ASSERT: op == ourform->mf_code */
+ 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 {
+ /* FIXME Add support for user defined ops. */
+ _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;
+
+ /* ASSERT: *op_start_section_offset ==
+ (curop->mo_data -1) - dbg->de_debug_macro.dss_data */
+ *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 {
+ /* ASSERT: macro_operator == 0 */
+ *forms_count = 0;
+ *formcode_array = 0;
+ }
+ return DW_DLV_OK;
+}
+
+
+/* Here a DW_DLV_NO_ENTRY return means the macro operator
+ is not a def/undef operator. */
+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) {
+ /*_dwarf_error(dbg, error,DW_DLE_MACRO_OPCODE_FORM_BAD);*/
+ 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);
+ /* mdata_copy is for call below */
+
+
+ *index = stringindex;
+ *forms_count = lformscount;
+
+ /* Redoes the index-getting. Gets offset. */
+ ress = _dwarf_extract_string_offset_via_str_offsets(dbg,
+ mdata_copy,
+ endptr,
+ DW_AT_macros, /*arbitrary, unused by called routine. */
+ 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;
+ /* All is ok. */
+ }
+ } 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;
+ /* If NO ENTRY available, return DW_DLV_NO_ENTRY.
+ We suspect this is better than DW_DLV_OK. */
+ return resup;
+ }
+ default:
+ _dwarf_error(dbg,error,DW_DLE_MACRO_OP_UNHANDLED);
+ return DW_DLV_ERROR;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+/* ASSERT: we elsewhere guarantee room to copy into.
+ If trimtarg ==1, trim trailing slash in targ.
+ Caller should not pass in 'src'
+ with leading / */
+static void
+specialcat(char *targ,char *src,int trimtarg)
+{
+ char *last = 0;
+
+ while( *targ) {
+ last = targ;
+ targ++;
+ }
+ /* TARG now points at terminating NUL */
+ /* LAST points at final character in targ. */
+ if (trimtarg ) {
+ if(last && *last == '/') {
+ /* Truncate. */
+ *last = 0;
+ targ = last;
+ /* TARG again points at terminating NUL */
+ }
+ }
+ while (*src) {
+ *targ = *src;
+ targ++;
+ src++;
+ }
+ *targ = 0;
+}
+
+/* If returns NULL caller must handle it. */
+static const char *
+construct_from_dir_and_name(const char *dir,
+ const char *name)
+{
+ int truelen = 0;
+ char *final = 0;
+
+ /* Allow for NUL char and added / */
+ 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;
+}
+
+/* If returns NULL caller must handle it. */
+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;
+ }
+ /* Dwarf_Macro_Context destructor will free this. */
+ 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;
+ /* For DWARF 2,3,4, decrement by 1.
+ FOR DWARF 5 do not decrement. */
+ 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 {
+ /* Unsigned to signed here. */
+ trueindex = srcindex;
+ /* Protects against crazy big srcindex, overflow territory. */
+ if (trueindex < 0 ) {
+ /* Something insane here. */
+ *src_file_name = "<source-file-index-low-no-name-available>";
+ return DW_DLV_OK;
+ }
+ /* Protects against crazy big srcindex, overflow territory. */
+ if (trueindex > (macro_context->mc_srcfiles_count+1)) {
+ /* Something insane here. */
+ *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 {
+ /* DW_MACRO_end_file. No operands. */
+ }
+ return DW_DLV_OK;
+}
+
+/* Target_offset is the offset in a .debug_macro section,
+ of a macro unit header.
+ Returns DW_DLV_NO_ENTRY if the macro operator is not
+ one of the import operators. */
+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) {
+ /* Nothing to check. user level. */
+ 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);
+ /* Estimating minimum size */
+ 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);
+ }
+ /* first, get size of table. */
+ table_data_start = macro_data;
+ for (i = 0; i < operand_table_count; ++i) {
+ /* Compiler warning about unused opcode_number
+ variable should be ignored. */
+ 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);
+ }
+ /* The 1 ubyte forms follow. Step past them. */
+ macro_data += formcount;
+ }
+ /* reset for reread. */
+ macro_data = table_data_start;
+ /* allocate table */
+ 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;
+}
+
+/* This is not the normal srcfiles from dwarf_srcfiles.
+ See translate translate_srcfiles_to_srcfiles2().
+ It is a list, but the contents were directly malloc,
+ not _dwarf_get_alloc.
+*/
+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);
+}
+
+/* This makes the macro context safe from
+ duplicate frees in case of error. */
+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;
+
+ /* The Dwarf_Debug this die belongs to. */
+ 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;
+
+ /* srcfiles uses dwarf_get_alloc for strings
+ so dealloc_macro_srcfiles() here will result in double-dealloc
+ when dwarf_finish() happens to see the string deallocs
+ before the macro context dealloc (the context dealloc
+ will call dealloc_macro_srcfiles() !).
+
+ Also see the comment at _dwarf_macro_destructor() here.
+ */
+ char ** srcfiles2 = 0;
+
+ const char *comp_dir = 0;
+ const char *comp_name = 0;
+
+ /* ***** BEGIN CODE ***** */
+ if (error != NULL) {
+ *error = NULL;
+ }
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ cu_context = die->di_cu_context;
+ dbg = cu_context->cc_dbg;
+
+ /* Doing the load here results in duplication of the
+ section-load call (in the by_offset
+ interface below) but detects the missing section
+ quickly. */
+ 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, &macro_attr, error);
+ if (resattr == DW_DLV_NO_ENTRY) {
+ resattr = dwarf_attr(die, DW_AT_GNU_macros, &macro_attr, error);
+ }
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+ if (!offset_specified) {
+ lres = dwarf_global_formref(macro_attr, &macro_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;
+ /* We cannot use space allocated by
+ _dwarf_get_alloc() in the macro_context
+ we will allocate shortly.
+ So copy from what we have to a similar data set
+ but malloc space directly. */
+
+ 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);
+ /* NO ENTRY or OK we accept, though NO ENTRY means there
+ are no source files available. */
+ 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);
+ /* In case of ERROR or NO_ENTRY srcfiles2 is already freed. */
+ 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;
+ /* The '3' ensures the header initial bytes present too. */
+ 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;
+ }
+ /* Note here so if error return we get these freed eventually. */
+ 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, /* 0 to opcode_count -1 */
+ 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;
+}
+
+/* The base interface to the .debug_macro section data
+ for a specific CU.
+
+ The version number passed back by *version_out
+ may be 4 (a gnu extension of DWARF) or 5. */
+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;
+}
+
+/* Like dwarf_get_macro_context but
+ here we use a specfied offset instead of
+ the offset in the cu_die. */
+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,
+ &macro_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) {
+ /* We don't have such a section at all. */
+ 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;
+ /* See _dwarf_macro_destructor() here */
+ dwarf_dealloc(dbg,mc,DW_DLA_MACRO_CONTEXT);
+}
+
+int
+_dwarf_macro_constructor(Dwarf_Debug dbg, void *m)
+{
+ /* Nothing to do, the space is zeroed out */
+ Dwarf_Macro_Context mc= (Dwarf_Macro_Context)m;
+ /* Arbitrary sentinel. For debugging. */
+ mc->mc_sentinel = 0xada;
+ mc->mc_dbg = dbg;
+ return DW_DLV_OK;
+}
+
+/* Here we free various fields of Dwarf_Macro_Context.
+ The fields do not get dealloc'd.
+ If we had a separate destructor for hand-calling
+ (meaning when an error is detected during creation
+ of a Dwarf_Macro_Context)
+ and one for calling by dwarf_dealloc() then
+ we could have the hand-calling dwarf_dealloc the fields
+ and the one called on the dealloc of a Dwarf_Macro_Context
+ could leave the _dwarf_get_alloc() fields for for
+ normal dwarf_finish() cleanup.
+
+ But for now we share this destructor for both purposes
+ so no fields are _dwarf_get_alloc() and all are free-d
+ here..
+*/
+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));
+ /* Just a recognizable sentinel. For debugging. No real meaning. */
+ mc->mc_sentinel = 0xdeadbeef;
+}