/* Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. Portions Copyright 2009-2018 SN Systems Ltd. All rights reserved. Portions Copyright 2007-2021 David Anderson. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU 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 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. */ /* The address of the Free Software Foundation is Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. SGI has moved from the Crittenden Lane address. */ /* Handles the following from print_die.c print_attribute() case DW_AT_specification: case DW_AT_abstract_origin: case DW_AT_type: */ #include #include /* calloc() free() */ #include /* memcmp() memset() strchr() strcmp() strlen() strncmp() */ #include /* FILE decl for dd_esb.h, printf etc */ #ifdef HAVE_STDINT_H #include /* uintptr_t */ #endif /* HAVE_STDINT_H */ #include "dwarf.h" #include "libdwarf.h" #include "libdwarf_private.h" #include "dd_defined_types.h" #include "dd_checkutil.h" #include "dd_glflags.h" #include "dd_globals.h" #include "dd_naming.h" #include "dd_esb.h" /* For flexible string buffer. */ #include "dd_esb_using_functions.h" #include "dd_sanitized.h" #include "print_frames.h" /* for print_expression_operations() . */ #include "dd_macrocheck.h" #include "dd_helpertree.h" #include "dd_opscounttab.h" #include "dd_tag_common.h" #include "dd_attr_form.h" #include "dd_regex.h" #include "dd_safe_strcpy.h" int dd_trace_abstract_origin_etc( Dwarf_Debug dbg, Dwarf_Half tag, Dwarf_Die die, Dwarf_Off dieprint_cu_goffset, Dwarf_Half theform, Dwarf_Half attrnum, Dwarf_Attribute attrib, char **srcfiles, Dwarf_Signed srcfiles_count, struct esb_s *valname, struct esb_s *esb_extra, int die_indent_level, int pd_dwarf_names_print_on_error, Dwarf_Error *err) { char typebuf[ESB_FIXED_ALLOC_SIZE]; struct esb_s lesb; /* A local flag to make it easy to tell if we should append a target die name */ Dwarf_Bool standard_messages = TRUE; /* To support finding target DIE, use these helper locals. */ Dwarf_Unsigned target_goff = 0; #if 0 Dwarf_Bool target_goff_known = FALSE; Dwarf_Unsigned target_gofferror = 0; Dwarf_Bool target_refsig8 = FALSE; #endif Dwarf_Bool target_is_info = FALSE; Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die); int tres = 0; esb_constructor_fixed(&lesb,typebuf, sizeof(typebuf)); tres = get_attr_value(dbg, tag, die, dieprint_cu_goffset,attrib, srcfiles, srcfiles_count, &lesb, glflags.show_form_used,glflags.verbose,err); if (tres == DW_DLV_ERROR) { struct esb_s m; const char *n = get_AT_name(attrnum,pd_dwarf_names_print_on_error); esb_constructor(&m); esb_append(&m, "Cannot get get value for a "); esb_append(&m,n); print_error_and_continue( esb_get_string(&m), tres,*err); esb_destructor(&m); esb_destructor(valname); esb_destructor(esb_extra); return tres; } if (theform == DW_FORM_ref_sig8) { /* SIG8 CHECK */ int res = 0; #if 0 target_refsig8 = TRUE; #endif standard_messages = FALSE; res = dd_print_sig8_target(dbg,attrib, die_indent_level, srcfiles, srcfiles_count, &lesb,err); if (res == DW_DLV_ERROR) { esb_destructor(&lesb); return res; } } esb_empty_string(valname); esb_append(valname, esb_get_string(&lesb)); esb_destructor(&lesb); if (glflags.gf_check_forward_decl || glflags.gf_check_self_references || glflags.gf_search_is_on) { Dwarf_Off die_goff = 0; Dwarf_Off ref_goff = 0; int frres = 0; int suppress_check = 0; Dwarf_Bool is_info2 = TRUE; /* SPECIFIC CHECKS A */ standard_messages = FALSE; frres = dwarf_global_formref_b(attrib, &ref_goff, &is_info2,err); if (frres == DW_DLV_ERROR) { /* myerr will be way less than 1000 */ int myerr = (int)dwarf_errno(*err); if (myerr == DW_DLE_REF_SIG8_NOT_HANDLED) { /* DW_DLE_REF_SIG8_NOT_HANDLED */ /* No offset available, it makes little sense to delve into this sort of reference unless we think a graph of self-refs *across* type-units is possible. Hmm. FIXME? */ suppress_check = 1 ; DWARF_CHECK_COUNT(self_references_result,1); DWARF_CHECK_ERROR(self_references_result, "DW_AT_ref_sig8 not handled so " "self references not fully checked"); DROP_ERROR_INSTANCE(dbg,frres,*err); } else { const char *n = get_AT_name(attrnum, pd_dwarf_names_print_on_error); struct esb_s m; esb_constructor(&m); esb_append(&m, "Cannot get formref global offset " "for a "); esb_append(&m,n); print_error_and_continue( esb_get_string(&m), frres,*err); esb_destructor(&m); esb_destructor(valname); esb_destructor(esb_extra); return frres; } } else if (frres == DW_DLV_NO_ENTRY) { const char *n = get_AT_name(attrnum, pd_dwarf_names_print_on_error); struct esb_s m; esb_constructor(&m); esb_append(&m, "Cannot get formref global offset for a "); esb_append(&m,n); print_error_and_continue( esb_get_string(&m), frres,*err); esb_destructor(&m); esb_destructor(valname); esb_destructor(esb_extra); return frres; } frres = dwarf_dieoffset(die, &die_goff, err); if (frres != DW_DLV_OK) { const char *n = get_AT_name(attrnum, pd_dwarf_names_print_on_error); struct esb_s m; esb_constructor(&m); esb_append(&m, "Cannot get formref dieoffset offset for a "); esb_append(&m,n); print_error_and_continue( esb_get_string(&m), frres,*err); esb_destructor(&m); esb_destructor(valname); esb_destructor(esb_extra); return frres; } if (!suppress_check && glflags.gf_check_self_references && dd_form_refers_local_info(theform) ) { Dwarf_Die ref_die = 0; int ifres = 0; /* SPECIFIC CHECKS B */ standard_messages = FALSE; ResetBucketGroup(glflags.pVisitedInfo); AddEntryIntoBucketGroup(glflags.pVisitedInfo, die_goff,0,0,0, NULL,FALSE); /* Follow reference chain, looking for self references */ frres = dwarf_offdie_b(dbg,ref_goff,is_info2, &ref_die,err); if (frres == DW_DLV_OK) { Dwarf_Off ref_die_cu_goff = 0; Dwarf_Off die_loff = 0; /* CU-relative. */ int fresb = 0; if (dump_visited_info) { const char *atname = get_AT_name(attrnum, pd_dwarf_names_print_on_error); fresb = dwarf_die_CU_offset(die, &die_loff, err); if (fresb == DW_DLV_OK) { dd_do_dump_visited_info(die_indent_level, die_loff,die_goff, dieprint_cu_goffset, atname,esb_get_string(valname)); } else { esb_destructor(valname); esb_destructor(esb_extra); dwarf_dealloc_die(ref_die); return fresb; } } ++die_indent_level; fresb = dwarf_CU_dieoffset_given_die(ref_die, &ref_die_cu_goff, err); /* Check above call return status? FIXME */ if (fresb != DW_DLV_OK) { const char *n = get_AT_name(attrnum, pd_dwarf_names_print_on_error); struct esb_s m; esb_constructor(&m); esb_append(&m, "Cannot get CU dieoffset " "given die for a "); esb_append(&m,n); print_error_and_continue( esb_get_string(&m), frres,*err); dwarf_dealloc_die(ref_die); esb_destructor(&m); esb_destructor(valname); esb_destructor(esb_extra); return frres; } ifres = dd_traverse_one_die(dbg,attrib,ref_die, ref_die_cu_goff, is_info,srcfiles,srcfiles_count, die_indent_level, err); dwarf_dealloc_die(ref_die); ref_die = 0; --die_indent_level; if (ifres != DW_DLV_OK) { esb_destructor(valname); esb_destructor(esb_extra); return ifres; } } DeleteKeyInBucketGroup(glflags.pVisitedInfo, die_goff); if (frres == DW_DLV_ERROR) { esb_destructor(valname); esb_destructor(esb_extra); return frres; } } if (!suppress_check && glflags.gf_check_forward_decl) { /* Check the DW_AT_specification forward references to DIEs. DWARF4 specifications, section 2.13.2. They are legal, this just reports how many are forward decls as 'error' in the final checks output. */ /* SPECIFIC CHECKS C */ standard_messages = FALSE; if (attrnum == DW_AT_specification) { /* Counting DW_AT_specification */ DWARF_CHECK_COUNT(forward_decl_result,1); if (ref_goff > die_goff) { /* Not an error. Just counting the number that are forward as if it might be a problem. */ DWARF_ERROR_COUNT(forward_decl_result,1); } } } /* When doing search, if the attribute is DW_AT_specification or DW_AT_abstract_origin, get any name associated with the DIE referenced in the offset. The 2 more typical cases are: Member functions, where 2 DIES are generated: DIE for the declaration and DIE for the definition and connected via the DW_AT_specification. Inlined functions, where 2 DIES are generated: DIE for the concrete instance and DIE for the abstract instance and connected via the DW_AT_abstract_origin. */ if ( glflags.gf_search_is_on && (attrnum == DW_AT_specification || attrnum == DW_AT_abstract_origin)) { Dwarf_Die ref_die = 0; int srcres = 0; /* SPECIFIC CHECKS D */ standard_messages = FALSE; /* Follow reference chain, looking for the DIE name */ srcres = dwarf_offdie_b(dbg,ref_goff,is_info2, &ref_die,err); if (srcres == DW_DLV_OK) { /* Get the DIE name */ char *name = 0; srcres = dwarf_diename(ref_die,&name,err); if (srcres == DW_DLV_OK) { esb_empty_string(valname); esb_append(valname,name); } if (srcres == DW_DLV_ERROR) { glflags.gf_count_major_errors++; esb_empty_string(valname); esb_append(valname, "