summaryrefslogtreecommitdiff
path: root/dwarfdump2/print_die.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dwarfdump2/print_die.cc')
-rw-r--r--dwarfdump2/print_die.cc3281
1 files changed, 3281 insertions, 0 deletions
diff --git a/dwarfdump2/print_die.cc b/dwarfdump2/print_die.cc
new file mode 100644
index 0000000..61e1844
--- /dev/null
+++ b/dwarfdump2/print_die.cc
@@ -0,0 +1,3281 @@
+/*
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2009-2010 SN Systems Ltd. All rights reserved.
+ Portions Copyright 2007-2010 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.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+
+$ Header: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/print_die.c,v 1.51 2006/04/01 16:20:21 davea Exp $ */
+/* 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.
+*/
+
+
+#include "globals.h"
+#include "naming.h"
+#include "tag_common.h"
+#include "print_frames.h"
+#include <vector>
+using std::string;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::vector;
+
+
+static bool traverse_one_die(Dwarf_Debug dbg,
+ Dwarf_Attribute attrib, Dwarf_Die die,
+ SrcfilesHolder & hsrcfiles,
+ int die_indent_level);
+
+/* Is this a PU has been invalidated by the SN Systems linker? */
+#define IsInvalidCode(low,high) ((low == error_message_data.elf_max_address) || (low == 0 && high == 0))
+
+static int get_form_values(Dwarf_Attribute attrib,
+ Dwarf_Half & theform, Dwarf_Half & directform);
+static void show_form_itself(bool show_form,
+ int local_verbose,
+ int theform, int directform, string *str_out);
+static bool print_attribute(Dwarf_Debug dbg, Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Attribute actual_addr,
+ bool print_information,
+ int die_indent_level,
+ SrcfilesHolder &srcfiles);
+static void get_location_list(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Attribute attr, string &str_out );
+static void print_exprloc_content(Dwarf_Debug dbg,Dwarf_Die die,
+ Dwarf_Attribute attrib,
+ bool showhextoo, string &str_out);
+static int legal_tag_attr_combination(Dwarf_Half tag, Dwarf_Half attr);
+static bool legal_tag_tree_combination(Dwarf_Half parent_tag,
+ Dwarf_Half child_tag);
+static int _dwarf_print_one_expr_op(Dwarf_Debug dbg,Dwarf_Loc* expr,int index, string &string_out);
+
+
+static int formxdata_print_value(Dwarf_Debug dbg,
+ Dwarf_Attribute attrib, string &str_out,
+ Dwarf_Error * err,bool hexout);
+
+// This following variable is weird. ???
+static bool local_symbols_already_began = false;
+
+typedef string(*encoding_type_func) (unsigned int val,bool doprintingonerr);
+
+Dwarf_Off fde_offset_for_cu_low = DW_DLV_BADOFFSET;
+Dwarf_Off fde_offset_for_cu_high = DW_DLV_BADOFFSET;
+
+/* Indicators to record a pair [low,high], these
+ are used in printing DIEs to accumulate the high
+ and low pc across attributes and to record the pair
+ as soon as both are known. Probably would be better to
+ use variables as arguments to
+ print_attribute(). */
+static Dwarf_Addr lowAddr = 0;
+static Dwarf_Addr highAddr = 0;
+static bool bSawLow = false;
+static bool bSawHigh = false;
+
+/* The following too is related to high and low pc
+attributes of a function. It's misnamed, it really means
+'yes, we have high and low pc' if it is TRUE. Defaulting to TRUE
+seems bogus. */
+static Dwarf_Bool in_valid_code = true;
+
+
+struct operation_descr_s {
+ int op_code;
+ int op_count;
+ string op_1type;
+};
+struct operation_descr_s opdesc[]= {
+ {DW_OP_addr,1,"addr" },
+ {DW_OP_deref,0 },
+ {DW_OP_const1u,1,"1u" },
+ {DW_OP_const1s,1,"1s" },
+ {DW_OP_const2u,1,"2u" },
+ {DW_OP_const2s,1,"2s" },
+ {DW_OP_const4u,1,"4u" },
+ {DW_OP_const4s,1,"4s" },
+ {DW_OP_const8u,1,"8u" },
+ {DW_OP_const8s,1,"8s" },
+ {DW_OP_constu,1,"uleb" },
+ {DW_OP_consts,1,"sleb" },
+ {DW_OP_dup,0,""},
+ {DW_OP_drop,0,""},
+ {DW_OP_over,0,""},
+ {DW_OP_pick,1,"1u"},
+ {DW_OP_swap,0,""},
+ {DW_OP_rot,0,""},
+ {DW_OP_xderef,0,""},
+ {DW_OP_abs,0,""},
+ {DW_OP_and,0,""},
+ {DW_OP_div,0,""},
+ {DW_OP_minus,0,""},
+ {DW_OP_mod,0,""},
+ {DW_OP_mul,0,""},
+ {DW_OP_neg,0,""},
+ {DW_OP_not,0,""},
+ {DW_OP_or,0,""},
+ {DW_OP_plus,0,""},
+ {DW_OP_plus_uconst,1,"uleb"},
+ {DW_OP_shl,0,""},
+ {DW_OP_shr,0,""},
+ {DW_OP_shra,0,""},
+ {DW_OP_xor,0,""},
+ {DW_OP_skip,1,"2s"},
+ {DW_OP_bra,1,"2s"},
+ {DW_OP_eq,0,""},
+ {DW_OP_ge,0,""},
+ {DW_OP_gt,0,""},
+ {DW_OP_le,0,""},
+ {DW_OP_lt,0,""},
+ {DW_OP_ne,0,""},
+ /* lit0 thru reg31 handled specially, no operands */
+ /* breg0 thru breg31 handled specially, 1 operand */
+ {DW_OP_regx,1,"uleb"},
+ {DW_OP_fbreg,1,"sleb"},
+ {DW_OP_bregx,2,"uleb"},
+ {DW_OP_piece,1,"uleb"},
+ {DW_OP_deref_size,1,"1u"},
+ {DW_OP_xderef_size,1,"1u"},
+ {DW_OP_nop,0,""},
+ {DW_OP_push_object_address,0,""},
+ {DW_OP_call2,1,"2u"},
+ {DW_OP_call4,1,"4u"},
+ {DW_OP_call_ref,1,"off"},
+ {DW_OP_form_tls_address,0,""},
+ {DW_OP_call_frame_cfa,0,""},
+ {DW_OP_bit_piece,2,"uleb"},
+ {DW_OP_implicit_value,2,"uleb"},
+ {DW_OP_stack_value,0,""},
+ {DW_OP_GNU_uninit,0,""},
+ {DW_OP_GNU_encoded_addr,1,"addr"},
+ {DW_OP_GNU_implicit_pointer,1,"addr" },
+ {DW_OP_GNU_entry_value,1,"val" },
+ /* terminator */
+ {0,0,""}
+};
+
+static void
+print_die_and_children_internal(DieHolder &die_in,
+ Dwarf_Bool is_info,
+ vector<DieHolder> &dieVec,
+ int &indent_level,
+ SrcfilesHolder & srcfiles);
+
+static bool
+print_as_info_or_cu()
+{
+ return (info_flag || cu_name_flag);
+}
+
+static int
+print_one_die_section(Dwarf_Debug dbg,bool is_info);
+
+/* process each compilation unit in .debug_info */
+void
+print_infos(Dwarf_Debug dbg,bool is_info)
+{
+ int nres = 0;
+ if(is_info) {
+ error_message_data.current_section_id = DEBUG_INFO;
+ nres = print_one_die_section(dbg,true);
+ if (nres == DW_DLV_ERROR) {
+ string errmsg = dwarf_errmsg(err);
+ Dwarf_Unsigned myerr = dwarf_errno(err);
+
+ cerr << program_name << " ERROR: " <<
+ "attempting to print .debug_info: " <<
+ errmsg << " (" << myerr << ")" << endl;
+ cerr << "attempting to continue." << endl;
+ }
+ return;
+ }
+ error_message_data.current_section_id = DEBUG_TYPES;
+ nres = print_one_die_section(dbg,false);
+ if (nres == DW_DLV_ERROR) {
+ string errmsg = dwarf_errmsg(err);
+ Dwarf_Unsigned myerr = dwarf_errno(err);
+
+ cerr << program_name << " ERROR: " <<
+ "attempting to print .debug_types: " <<
+ errmsg << " (" << myerr << ")" << endl;
+ cerr << "attempting to continue." << endl;
+ }
+}
+
+static void
+print_std_cu_hdr( Dwarf_Unsigned cu_header_length,
+ Dwarf_Unsigned abbrev_offset,
+ Dwarf_Half version_stamp,
+ Dwarf_Half address_size)
+{
+ if(dense) {
+ cout << " cu_header_length" <<
+ BracketSurround(IToHex0N(cu_header_length,10));
+ cout << " version_stamp" <<
+ BracketSurround(IToHex0N(version_stamp,6));
+ cout << " abbrev_offset" <<
+ BracketSurround(IToHex0N(abbrev_offset,10));
+ cout << " address_size" <<
+ BracketSurround(IToHex0N(address_size,4));
+ } else {
+ cout << " cu_header_length = " <<
+ IToHex0N(cu_header_length,10) <<
+ " " << IToDec(cu_header_length) << endl;
+ cout << " version_stamp = " <<
+ IToHex0N(version_stamp,6) <<
+ " " <<
+ " " << IToDec(version_stamp) << endl;
+ cout << " abbrev_offset = " <<
+ IToHex0N(abbrev_offset,10) <<
+ " " << IToDec(abbrev_offset) << endl;
+ cout << " address_size = " <<
+ IToHex0N(address_size,4) <<
+ " " <<
+ " " << IToDec(address_size) << endl;
+ }
+}
+static void
+print_std_cu_signature( Dwarf_Sig8 *signature,Dwarf_Unsigned typeoffset)
+{
+ if(dense) {
+ string sig8str;
+ format_sig8_string(signature,sig8str);
+ cout << " signature" <<
+ BracketSurround(sig8str);
+ cout << " typeoffset" <<
+ BracketSurround(IToHex0N(typeoffset,10));
+ } else {
+ string sig8str;
+ format_sig8_string(signature,sig8str);
+ cout << " signature = " <<
+ sig8str << endl;
+ cout << " typeoffset = " <<
+ IToHex0N(typeoffset,10) <<
+ " " << IToDec(typeoffset) << endl;
+ }
+}
+
+static int
+print_one_die_section(Dwarf_Debug dbg,bool is_info)
+{
+ Dwarf_Unsigned cu_header_length = 0;
+ Dwarf_Unsigned abbrev_offset = 0;
+ Dwarf_Half version_stamp = 0;
+ Dwarf_Half address_size = 0;
+ Dwarf_Half extension_size = 0;
+ Dwarf_Half length_size = 0;
+ Dwarf_Sig8 signature;
+ Dwarf_Unsigned typeoffset = 0;
+ Dwarf_Unsigned next_cu_offset = 0;
+ int nres = DW_DLV_OK;
+ int cu_count = 0;
+ unsigned loop_count = 0;
+ Dwarf_Bool local_is_info = (is_info)?true:false;
+ if (print_as_info_or_cu() && do_print_dwarf) {
+ if(is_info) {
+ cout << endl;
+ cout << ".debug_info" << endl;
+ }
+ }
+ /* Loop until it fails. */
+ for (;;++loop_count) {
+ nres = dwarf_next_cu_header_c(dbg, is_info,
+ &cu_header_length, &version_stamp,
+ &abbrev_offset, &address_size,
+ &length_size, &extension_size,
+ &signature, &typeoffset,
+ &next_cu_offset, &err);
+ if(nres == DW_DLV_NO_ENTRY) {
+ return nres;
+ }
+ if(loop_count == 0 && !is_info &&
+ // Do not print this string unless we really have debug_types
+ // for consistency with dwarf2/3 output.
+ // Looks a bit messy here in the code, but few objects have
+ // this section so far.
+ print_as_info_or_cu() && do_print_dwarf) {
+ cout << endl;
+ cout << ".debug_types" << endl;
+ }
+ if(nres != DW_DLV_OK) {
+ return nres;
+ }
+ if(cu_count >= break_after_n_units) {
+ cout << "Break at " << cu_count << endl;
+ break;
+ }
+ Dwarf_Die cu_die = 0;
+ int sres = dwarf_siblingof_b(dbg, NULL,is_info, &cu_die, &err);
+ if (sres != DW_DLV_OK) {
+ print_error(dbg, "siblingof cu header", sres, err);
+ }
+ /* Get the CU offset for easy error reporting */
+ dwarf_die_offsets(cu_die,
+ &error_message_data.DIE_overall_offset,
+ &error_message_data.DIE_offset,&err);
+ DieHolder thcu_die(dbg,cu_die);
+ if (cu_name_flag) {
+ if(should_skip_this_cu(thcu_die,err)) {
+ ++cu_count;
+ cu_offset = next_cu_offset;
+ continue;
+ }
+ }
+ string producer_name;
+ get_producer_name(thcu_die,err,producer_name);
+
+ update_compiler_target(producer_name);
+ if (producer_children_flag) {
+ string cu_short_name;
+ string cu_long_name;
+ get_cu_name(thcu_die,err,cu_short_name,cu_long_name);
+ add_cu_name_compiler_target(cu_long_name);
+ }
+ if(!checking_this_compiler()) {
+ ++cu_count;
+ cu_offset = next_cu_offset;
+ continue;
+ }
+ error_message_data.seen_CU = false;
+ error_message_data.need_CU_name = true;
+ error_message_data.need_CU_base_address = true;
+ error_message_data.need_CU_high_address = true;
+ error_message_data.seen_PU_base_address = false;
+ error_message_data.seen_PU_high_address = false;
+
+ if (info_flag && do_print_dwarf ) {
+ if(verbose){
+ if (dense) {
+ cout << BracketSurround("cu_header");
+ } else {
+ cout << endl;
+ cout << "CU_HEADER:" << endl;
+ }
+ print_std_cu_hdr(cu_header_length, abbrev_offset,
+ version_stamp,address_size);
+ if(! is_info) {
+ print_std_cu_signature(&signature,typeoffset);
+ }
+ if(dense) {
+ cout <<endl;
+ }
+ } else {
+ // For debug_types we really need some header info
+ // to make sense of this.
+ if(!is_info) {
+ if(dense) {
+ cout << BracketSurround("cu_header");
+ } else {
+ cout << endl;
+ cout << "CU_HEADER:" << endl;
+ }
+ print_std_cu_signature(&signature,typeoffset);
+ if(dense) {
+ cout <<endl;
+ }
+ }
+ }
+ }
+ get_abbrev_array_info(dbg,abbrev_offset);
+
+ Dwarf_Die cu_die2 = 0;
+ sres = dwarf_siblingof_b(dbg, NULL,is_info, &cu_die2, &err);
+ if (sres == DW_DLV_OK) {
+ DieHolder hcu_die2(dbg,cu_die2);
+ if (print_as_info_or_cu() || search_is_on) {
+ Dwarf_Signed cnt = 0;
+ char **srcfiles = 0;
+ int srcf = dwarf_srcfiles(hcu_die2.die(),
+ &srcfiles,&cnt, &err);
+ if (srcf != DW_DLV_OK) {
+ srcfiles = 0;
+ cnt = 0;
+ }
+ SrcfilesHolder hsrcfiles(dbg,srcfiles,cnt);
+ /* Get the CU offset for easy error reporting */
+ dwarf_die_offsets(hcu_die2.die(),
+ &error_message_data.DIE_CU_overall_offset,
+ &error_message_data.DIE_CU_offset,
+ &err);
+ print_die_and_children(hcu_die2,is_info, hsrcfiles);
+ }
+ if (dump_ranges_info) {
+ pAddressRangesData->PrintRangesData();
+ }
+
+ if (line_flag || check_decl_file) {
+ print_line_numbers_this_cu(hcu_die2);
+ }
+ } else if (sres == DW_DLV_NO_ENTRY) {
+ /* do nothing I guess. */
+ } else {
+ print_error(dbg, "Regetting cu_die", sres, err);
+ }
+ ++cu_count;
+ cu_offset = next_cu_offset;
+ }
+ return nres;
+}
+
+
+static void
+print_a_die_stack(Dwarf_Debug dbg,SrcfilesHolder & hsrcfiles,int lev,
+ vector<DieHolder> &dieVec)
+{
+ bool ignore_die_stack = false;
+ bool print_information = true;
+ print_one_die(dieVec[lev],print_information,lev,hsrcfiles,
+ ignore_die_stack);
+}
+
+void
+print_die_and_children(DieHolder & in_die_in,
+ Dwarf_Bool is_info,
+ SrcfilesHolder &hsrcfiles)
+{
+ int indent_level = 0;
+
+ vector<DieHolder> dieVec;
+ print_die_and_children_internal(in_die_in,
+ is_info,
+ dieVec,
+ indent_level, hsrcfiles);
+ return;
+}
+
+static void
+print_die_stack(DieHolder &curdie, vector<DieHolder> &dieVec,
+ SrcfilesHolder & hsrcfiles)
+{
+ unsigned lev = 0;
+ bool print_information = true;
+ bool ignore_die_stack = false;
+
+ for(lev = 0; lev < dieVec.size(); ++lev)
+ {
+ print_one_die(dieVec[lev],print_information,lev,hsrcfiles,
+ /* ignore_die_printed_flag= */ignore_die_stack);
+ }
+}
+
+
+// Recursively follow the die tree
+static void
+print_die_and_children_internal(DieHolder & hin_die_in,
+ Dwarf_Bool is_info,
+ vector<DieHolder> &dieVec,
+ int &indent_level,
+ SrcfilesHolder & hsrcfiles)
+{
+ Dwarf_Die child;
+ Dwarf_Error err;
+ int tres;
+ int cdres;
+ DieHolder hin_die(hin_die_in);
+ Dwarf_Debug dbg = hin_die_in.dbg();
+
+ for (;;) {
+ // We loop on siblings, this is the sibling loop.
+ dieVec.push_back(hin_die);
+ Dwarf_Die in_die = hin_die.die();
+ /* Get the CU offset for easy error reporting */
+ dwarf_die_offsets(in_die,
+ &error_message_data.DIE_overall_offset,
+ &error_message_data.DIE_offset,
+ &err);
+ if (check_tag_tree) {
+ DWARF_CHECK_COUNT(tag_tree_result,1);
+ if (indent_level == 0) {
+ Dwarf_Half tag;
+
+ tres = dwarf_tag(in_die, &tag, &err);
+ if (tres != DW_DLV_OK) {
+ DWARF_CHECK_ERROR(tag_tree_result,
+ "Tag-tree root is not DW_TAG_compile_unit");
+ } else if (tag == DW_TAG_compile_unit) {
+ /* OK */
+ } else {
+ DWARF_CHECK_ERROR(tag_tree_result,
+ "tag-tree root is not DW_TAG_compile_unit");
+ }
+ } else {
+ Dwarf_Half tag_parent = 0;
+ Dwarf_Half tag_child = 0;
+ string ctagname("<child tag invalid>");
+ string ptagname("<parent tag invalid>");
+
+ Dwarf_Die tp = dieVec[indent_level - 1].die();
+ int pres = dwarf_tag(tp, &tag_parent, &err);
+ int cres = dwarf_tag(in_die, &tag_child, &err);
+ if (pres != DW_DLV_OK)
+ tag_parent = 0;
+ if (cres != DW_DLV_OK)
+ tag_child = 0;
+ /* Check for specific compiler */
+ if (checking_this_compiler()) {
+ /* Process specific TAGs. */
+ tag_specific_checks_setup(tag_child, indent_level);
+
+ if (cres != DW_DLV_OK || pres != DW_DLV_OK) {
+ if (cres == DW_DLV_OK) {
+ ctagname = get_TAG_name(tag_child,
+ dwarf_names_print_on_error);
+ }
+ if (pres == DW_DLV_OK) {
+ ptagname = get_TAG_name(tag_parent,
+ dwarf_names_print_on_error);
+ }
+ DWARF_CHECK_ERROR3(tag_tree_result,ptagname,
+ ctagname,
+ "Tag-tree relation is not standard..");
+ } else if (legal_tag_tree_combination(tag_parent,
+ tag_child)) {
+ /* OK */
+ } else {
+ DWARF_CHECK_ERROR3(tag_tree_result,
+ get_TAG_name(tag_parent,
+ dwarf_names_print_on_error),
+ get_TAG_name(tag_child,
+ dwarf_names_print_on_error),
+ "tag-tree relation is not standard.");
+ }
+ }
+ }
+ }
+ if (record_dwarf_error && check_verbose_mode) {
+ record_dwarf_error = false;
+ }
+
+ /* here to pre-descent processing of the die */
+ bool retry_print_on_match =
+ print_one_die(hin_die, print_as_info_or_cu(),
+ indent_level, hsrcfiles,
+ /* ignore_die_printed_flag= */ false);
+ if(!print_as_info_or_cu() && retry_print_on_match) {
+ if(display_parent_tree) {
+ print_die_stack(hin_die,dieVec,hsrcfiles);
+ } else {
+ if(display_children_tree) {
+ print_a_die_stack(dbg,hsrcfiles,indent_level,dieVec);
+ }
+ }
+ if(display_children_tree) {
+ stop_indent_level = indent_level;
+ info_flag = true;
+ }
+ }
+ cdres = dwarf_child(in_die, &child, &err);
+
+ /* Check for specific compiler */
+ if (check_abbreviations && checking_this_compiler()) {
+ Dwarf_Half ab_has_child;
+ bool berror = false;
+ Dwarf_Half tag = 0;
+ tres = dwarf_die_abbrev_children_flag(in_die,&ab_has_child);
+ if (tres == DW_DLV_OK) {
+ DWARF_CHECK_COUNT(abbreviations_result,1);
+ tres = dwarf_tag(in_die, &tag, &err);
+ if (tres == DW_DLV_OK) {
+ switch (tag) {
+ case DW_TAG_array_type:
+ case DW_TAG_class_type:
+ case DW_TAG_compile_unit:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_lexical_block:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_union_type:
+ case DW_TAG_entry_point:
+ case DW_TAG_inlined_subroutine:
+ break;
+ default:
+ berror = (cdres == DW_DLV_OK && !ab_has_child) ||
+ (cdres == DW_DLV_NO_ENTRY && ab_has_child);
+ if (berror) {
+ DWARF_CHECK_ERROR(abbreviations_result,
+ "check 'dw_children' flag combination.");
+ }
+ break;
+ }
+ }
+ }
+ }
+
+
+ /* child first: we are doing depth-first walk */
+ if (cdres == DW_DLV_OK) {
+ DieHolder hchild(dbg,child);
+ indent_level++;
+ print_die_and_children_internal(hchild,
+ is_info,
+ dieVec,indent_level,hsrcfiles);
+ indent_level--;
+ if (indent_level == 0) {
+ local_symbols_already_began = false;
+ }
+ } else if (cdres == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_child", cdres, err);
+ }
+
+ /* Stop the display of all children */
+ if (display_children_tree && info_flag &&
+ stop_indent_level == indent_level) {
+ info_flag = false;
+ }
+
+ Dwarf_Die sibling = 0;
+ cdres = dwarf_siblingof_b(dbg, in_die,is_info, &sibling, &err);
+ if (cdres == DW_DLV_OK) {
+ /* print_die_and_children_internal(); We
+ loop around to actually print this, rather than
+ recursing. Recursing is horribly wasteful of stack
+ space. */
+ } else if (cdres == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_siblingof", cdres, err);
+ }
+ DieHolder hsibling(dbg,sibling);
+ /* If we have a sibling, verify that its offset
+ is next to the last processed DIE;
+ An incorrect sibling chain is a nasty bug. */
+ if (cdres == DW_DLV_OK && sibling && check_di_gaps &&
+ checking_this_compiler()) {
+
+ Dwarf_Off glb_off;
+ DWARF_CHECK_COUNT(di_gaps_result,1);
+ if (dwarf_validate_die_sibling(sibling,&glb_off) == DW_DLV_ERROR) {
+ static char msg[128];
+ Dwarf_Off sib_off;
+ dwarf_dieoffset(sibling,&sib_off,&err);
+ sprintf(msg,
+ "GSIB = 0x%" DW_PR_XZEROS DW_PR_DUx
+ " GOFF = 0x%" DW_PR_XZEROS DW_PR_DUx
+ " Gap = %" DW_PR_DUu " bytes",
+ sib_off,glb_off,sib_off-glb_off);
+ DWARF_CHECK_ERROR2(di_gaps_result,
+ "Incorrect sibling chain",msg);
+ }
+ }
+
+
+ /* Here do any post-descent (ie post-dwarf_child) processing of
+ the in_die (just pop stack). */
+ dieVec.pop_back();
+ if (cdres == DW_DLV_OK) {
+ /* Set to process the sibling, loop again. */
+ hin_die = hsibling;
+ } else {
+ /* We are done, no more siblings at this level. */
+ break;
+ }
+ } /* end for loop on siblings */
+ return;
+}
+
+/* Print one die on error and verbose or non check mode */
+#define PRINTING_DIES (do_print_dwarf || (record_dwarf_error && check_verbose_mode))
+
+/* This is called from the debug_line printing and the DIE
+ passed in is a CU DIE.
+ In other cases the DIE passed in is not a CU die.
+ */
+
+bool
+print_one_die(DieHolder & hdie,
+ bool print_information,
+ int die_indent_level,
+ SrcfilesHolder &hsrcfiles,
+ bool ignore_die_printed_flag)
+{
+ Dwarf_Die die = hdie.die();
+ Dwarf_Debug dbg = hdie.dbg();
+ int abbrev_code = dwarf_die_abbrev_code(die);
+ bool attribute_matched = false;
+
+ /* Print using indentation
+ < 1><0x000854ff GOFF=0x00546047> DW_TAG_pointer_type -> 34
+ < 1><0x000854ff> DW_TAG_pointer_type -> 18
+ DW_TAG_pointer_type -> 2
+ */
+ /* Attribute indent. */
+ int nColumn = show_global_offsets ? 34 : 18;
+
+ if (check_abbreviations && checking_this_compiler()) {
+ validate_abbrev_code(dbg,abbrev_code);
+ }
+
+
+ if(!ignore_die_printed_flag && hdie.die_printed()) {
+ /* Seems arbitrary as a return, but ok. */
+ return false;
+ }
+ /* Reset indentation column if no offsets */
+ if (!display_offsets) {
+ nColumn = 2;
+ }
+
+ Dwarf_Half tag = 0;
+ int tres = dwarf_tag(die, &tag, &err);
+ if (tres != DW_DLV_OK) {
+ print_error(dbg, "accessing tag of die!", tres, err);
+ }
+ string tagname = get_TAG_name(tag,dwarf_names_print_on_error);
+
+ tag_specific_checks_setup(tag,die_indent_level);
+ Dwarf_Off overall_offset = 0;
+ int ores = dwarf_dieoffset(die, &overall_offset, &err);
+ if (ores != DW_DLV_OK) {
+ print_error(dbg, "dwarf_dieoffset", ores, err);
+ }
+ Dwarf_Off offset = 0;
+ ores = dwarf_die_CU_offset(die, &offset, &err);
+ if (ores != DW_DLV_OK) {
+ print_error(dbg, "dwarf_die_CU_offset", ores, err);
+ }
+ if (dump_visited_info && check_self_references) {
+ unsigned space = die_indent_level * 2 + 2;
+ cout << BracketSurround(IToDec(die_indent_level,2)) <<
+ BracketSurround(IToHex0N(offset,10)) <<
+ " GOFF=" << IToHex0N(overall_offset,10) <<
+ std::setw(space) << " " << tagname << endl;
+ }
+
+
+ if (PRINTING_DIES && print_information) {
+ if(!ignore_die_printed_flag) {
+ hdie.mark_die_printed();
+ }
+ if (die_indent_level == 0) {
+ if (dense) {
+ cout << endl;
+ } else {
+ cout << endl;
+ cout << "COMPILE_UNIT<header overall offset = "
+ << IToHex0N((overall_offset - offset),10) << ">:" << endl;
+ }
+ } else if (local_symbols_already_began == false &&
+ die_indent_level == 1 && !dense) {
+ cout << endl;
+ // This prints once per top-level DIE.
+ cout <<"LOCAL_SYMBOLS:" << endl;
+ local_symbols_already_began = true;
+ }
+ if (!display_offsets) {
+ /* Print using indentation */
+ unsigned w = die_indent_level * 2 + 2;
+ cout << std::setw(w) << " " << tagname << endl;
+ } else {
+ if (dense) {
+ if (show_global_offsets) {
+ if (die_indent_level == 0) {
+ cout << BracketSurround(IToDec(die_indent_level)) <<
+ BracketSurround(
+ IToHex(overall_offset - offset) +
+ string("+") +
+ IToHex(offset) +
+ string(" GOFF=") +
+ IToHex(overall_offset));
+ } else {
+ cout << BracketSurround(IToDec(die_indent_level)) <<
+ BracketSurround(
+ IToHex(offset) +
+ string(" GOFF=") +
+ IToHex(overall_offset));
+ }
+ } else {
+ if (die_indent_level == 0) {
+ cout << BracketSurround(IToDec(die_indent_level)) <<
+ BracketSurround(
+ IToHex(overall_offset - offset) +
+ string("+") +
+ IToHex(offset));
+ } else {
+ cout << BracketSurround(IToDec(die_indent_level)) <<
+ BracketSurround(IToHex(offset));
+ }
+ }
+ cout << BracketSurround(tagname);
+ if(verbose) {
+ cout << " " << BracketSurround(string("abbrev ") +
+ IToDec(abbrev_code));
+ }
+ } else {
+ if (show_global_offsets) {
+ cout << BracketSurround(IToDec(die_indent_level,2)) <<
+ BracketSurround(
+ IToHex0N(offset,10) +
+ string(" GOFF=") +
+ IToHex0N(overall_offset,10));
+ } else {
+ cout << BracketSurround(IToDec(die_indent_level,2)) <<
+ BracketSurround(IToHex0N(offset,10));
+ }
+ unsigned fldwidth = die_indent_level * 2 + 2;
+ cout << std::setw(fldwidth)<< " " << tagname;
+ if(verbose) {
+ cout << " " << BracketSurround(string("abbrev ") +
+ IToDec(abbrev_code));
+ }
+ cout << endl;
+ }
+ }
+ }
+
+ Dwarf_Signed atcnt = 0;
+ Dwarf_Attribute *atlist = 0;
+ int atres = dwarf_attrlist(die, &atlist, &atcnt, &err);
+ if (atres == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_attrlist", atres, err);
+ } else if (atres == DW_DLV_NO_ENTRY) {
+ /* indicates there are no attrs. It is not an error. */
+ atcnt = 0;
+ }
+
+ /* Reset any loose references to low or high PC */
+ bSawLow = false;
+ bSawHigh = false;
+
+ /* Get the CU offset for easy error reporting */
+ dwarf_die_offsets(hdie.die(),
+ &error_message_data.DIE_CU_overall_offset,
+ &error_message_data.DIE_CU_offset,
+ &err);
+
+ for (Dwarf_Signed i = 0; i < atcnt; i++) {
+ Dwarf_Half attr;
+ int ares;
+
+ ares = dwarf_whatattr(atlist[i], &attr, &err);
+ if (ares == DW_DLV_OK) {
+ /* Print using indentation */
+ if (!dense && PRINTING_DIES && print_information) {
+ unsigned fldwidth = die_indent_level * 2 + 2 +nColumn;
+ cout << std::setw(fldwidth)<< " " ;
+ }
+
+ bool attr_match = print_attribute(dbg, die, attr,
+ atlist[i],
+ print_information,die_indent_level, hsrcfiles);
+ if(print_information == false && attr_match) {
+ attribute_matched = true;
+ }
+ if (record_dwarf_error && check_verbose_mode) {
+ record_dwarf_error = false;
+ }
+ } else {
+ print_error(dbg, "dwarf_whatattr entry missing", ares, err);
+ }
+ }
+
+ for (Dwarf_Signed i = 0; i < atcnt; i++) {
+ dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR);
+ }
+ if (atres == DW_DLV_OK) {
+ dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
+ }
+
+ if (PRINTING_DIES && dense && print_information) {
+ cout << endl ;
+ }
+ return attribute_matched;
+}
+
+/* Encodings have undefined signedness. Accept either
+ signedness. The values are small (they are defined
+ in the DWARF specification), so the
+ form the compiler uses (as long as it is
+ a constant value) is a non-issue.
+
+ If string_out is non-NULL, construct a string output, either
+ an error message or the name of the encoding.
+ The function pointer passed in is to code generated
+ by a script at dwarfdump build time. The code for
+ the val_as_string function is generated
+ from dwarf.h. See <build dir>/dwarf_names.c
+
+ If string_out is non-NULL then attr_name and val_as_string
+ must also be non-NULL.
+
+*/
+static int
+get_small_encoding_integer_and_name(Dwarf_Debug dbg,
+ Dwarf_Attribute attrib,
+ Dwarf_Unsigned * uval_out,
+ const string &attr_name,
+ string * string_out,
+ encoding_type_func val_as_string,
+ Dwarf_Error * err,
+ bool show_form)
+{
+ Dwarf_Unsigned uval = 0;
+ int vres = dwarf_formudata(attrib, &uval, err);
+ if (vres != DW_DLV_OK) {
+ Dwarf_Signed sval = 0;
+ vres = dwarf_formsdata(attrib, &sval, err);
+ if (vres != DW_DLV_OK) {
+ vres = dwarf_global_formref(attrib,&uval,err);
+ if (vres != DW_DLV_OK) {
+ if (string_out != 0) {
+ string b = attr_name + " has a bad form.";
+ *string_out = b;
+ }
+ return vres;
+ }
+ *uval_out = uval;
+ } else {
+ *uval_out = (Dwarf_Unsigned) sval;
+ }
+ } else {
+ *uval_out = uval;
+ }
+ if (string_out) {
+ *string_out = val_as_string((unsigned) uval,
+ dwarf_names_print_on_error);
+ Dwarf_Half theform = 0;
+ Dwarf_Half directform = 0;
+ get_form_values(attrib,theform,directform);
+ show_form_itself(show_form,verbose, theform, directform,string_out);
+ }
+ return DW_DLV_OK;
+}
+
+
+
+
+/* We need a 32-bit signed number here, but there's no portable
+ way of getting that. So use __uint32_t instead. It's supplied
+ in a reliable way by the autoconf infrastructure. */
+static string
+get_FLAG_BLOCK_string(Dwarf_Debug dbg, Dwarf_Attribute attrib)
+{
+ int fres = 0;
+ Dwarf_Block *tempb = 0;
+ __uint32_t * array = 0;
+ Dwarf_Unsigned array_len = 0;
+ __uint32_t * array_ptr;
+ Dwarf_Unsigned array_remain = 0;
+
+ /* first get compressed block data */
+ fres = dwarf_formblock (attrib,&tempb, &err);
+ if (fres != DW_DLV_OK) {
+ string msg("DW_FORM_blockn cannot get block");
+ print_error(dbg,msg,fres,err);
+ return msg;
+ }
+
+ /* uncompress block into int array */
+ void *vd = dwarf_uncompress_integer_block(dbg,
+ 1, /* 'true' (meaning signed ints)*/
+ 32, /* bits per unit */
+ reinterpret_cast<void *>(tempb->bl_data),
+ tempb->bl_len,
+ &array_len, /* len of out array */
+ &err);
+ if (vd == reinterpret_cast<void *>(DW_DLV_BADADDR)) {
+ string msg("DW_AT_SUN_func_offsets cannot uncompress data");
+ print_error(dbg,msg,0,err);
+ return msg;
+ }
+ array = reinterpret_cast<__uint32_t *>(vd);
+ if (array_len == 0) {
+ string msg("DW_AT_SUN_func_offsets has no data");
+ print_error(dbg,msg,0,err);
+ return msg;
+ }
+
+ /* fill in string buffer */
+ array_remain = array_len;
+ array_ptr = array;
+ const unsigned array_lim = 8;
+ string blank(" ");
+ string out_str;
+ while (array_remain > array_lim) {
+ out_str.append("\n");
+ for(unsigned j = 0; j < array_lim; ++j) {
+ out_str.append(blank + IToHex0N(array_ptr[0],10));
+ }
+ array_ptr += array_lim;
+ array_remain -= array_lim;
+ }
+
+ /* now do the last line */
+ if (array_remain > 0) {
+ out_str.append("\n ");
+ while (array_remain > 0) {
+ out_str.append(blank + IToHex0N(*array_ptr,10));
+ array_remain--;
+ array_ptr++;
+ }
+ }
+ /* free array buffer */
+ dwarf_dealloc_uncompressed_block(dbg, array);
+ return out_str;
+}
+
+static const char *
+get_rangelist_type_descr(Dwarf_Ranges *r)
+{
+ switch(r->dwr_type) {
+ case DW_RANGES_ENTRY: return "range entry";
+ case DW_RANGES_ADDRESS_SELECTION: return "addr selection";
+ case DW_RANGES_END: return "range end";
+ }
+ /* Impossible. */
+ return "Unknown";
+}
+
+
+string
+print_ranges_list_to_extra(Dwarf_Debug dbg,
+ Dwarf_Unsigned off,
+ Dwarf_Ranges *rangeset,
+ Dwarf_Signed rangecount,
+ Dwarf_Unsigned bytecount)
+{
+ string out;
+ if(dense) {
+ out.append("< ranges: ");
+ } else {
+ out.append("\t\tranges: ");
+ }
+ out.append(IToDec(rangecount));
+ if(dense) {
+ // This is a goofy difference. Historical.
+ out.append(" ranges at .debug_ranges offset ");
+ } else {
+ out.append(" at .debug_ranges offset ");
+ }
+ out.append(IToDec(off));
+ out.append(" (");
+ out.append(IToHex0N(off,10));
+ out.append(") (");
+ out.append(IToDec(bytecount));
+ out.append(" bytes)");
+ if(dense) {
+ out.append(">");
+ } else {
+ out.append("\n");
+ }
+ for(Dwarf_Signed i = 0; i < rangecount; ++i) {
+ Dwarf_Ranges * r = rangeset +i;
+ const char *type = get_rangelist_type_descr(r);
+ if(dense) {
+ out.append("<[");
+ } else {
+ out.append("\t\t\t[");
+ }
+ out.append(IToDec(i,2));
+ out.append("] ");
+ if(dense) {
+ out.append(type);
+ } else {
+ out.append(LeftAlign(14,type));
+ }
+ out.append(" ");
+ out.append(IToHex0N(r->dwr_addr1,10));
+ out.append(" ");
+ out.append(IToHex0N(r->dwr_addr2,10));
+ if(dense) {
+ out.append(">");
+ } else {
+ out.append("\n");
+ }
+ }
+ return out;
+}
+
+/* This is a slightly simplistic rendering of the FORM
+ issue, it is not precise. However it is really only
+ here so we can detect and report an error (producing
+ incorrect DWARF) by a particular compiler (a quite unusual error,
+ noticed in April 2010).
+ So this simplistic form suffices. See the libdwarf get_loclist_n()
+ function source for the precise test.
+*/
+static bool
+is_location_form(int form)
+{
+ if(form == DW_FORM_block1 ||
+ form == DW_FORM_block2 ||
+ form == DW_FORM_block4 ||
+ form == DW_FORM_block ||
+ form == DW_FORM_data4 ||
+ form == DW_FORM_data8 ||
+ form == DW_FORM_sec_offset) {
+ return true;
+ }
+ return false;
+}
+
+static void
+show_attr_form_error(Dwarf_Debug dbg,unsigned attr,unsigned form,string *out)
+{
+ const char *n = 0;
+ int res;
+ out->append("ERROR: Attribute ");
+ out->append(IToDec(attr));
+ out->append(" (");
+ res = dwarf_get_AT_name(attr,&n);
+ if(res != DW_DLV_OK) {
+ n = "UknownAttribute";
+ }
+ out->append(n);
+ out->append(") ");
+ out->append(" has form ");
+ out->append(IToDec(form));
+ out->append(" (");
+ res = dwarf_get_FORM_name(form,&n);
+ if(res != DW_DLV_OK) {
+ n = "UknownForm";
+ }
+ out->append(n);
+ out->append("), a form which is not appropriate");
+ print_error_and_continue(dbg, out->c_str(), DW_DLV_OK, err);
+}
+
+
+/* Traverse an attribute and following any reference
+ in order to detect self references to DIES (loop). */
+static bool
+traverse_attribute(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attr,
+ Dwarf_Attribute attr_in,
+ bool print_information,
+ SrcfilesHolder & hsrcfiles,
+ int die_indent_level)
+{
+ Dwarf_Attribute attrib = 0;
+ string atname;
+ string valname;
+ int tres = 0;
+ Dwarf_Half tag = 0;
+ bool circular_reference = false;
+ Dwarf_Bool is_info = true;
+
+ is_info=dwarf_get_die_infotypes_flag(die);
+
+ atname = get_AT_name(attr,dwarf_names_print_on_error);
+
+ /* The following gets the real attribute, even in the face of an
+ incorrect doubling, or worse, of attributes. */
+ attrib = attr_in;
+ /* Do not get attr via dwarf_attr: if there are (erroneously)
+ multiple of an attr in a DIE, dwarf_attr will not get the
+ second, erroneous one and dwarfdump will print the first one
+ multiple times. Oops. */
+
+ tres = dwarf_tag(die, &tag, &err);
+ if (tres == DW_DLV_ERROR) {
+ tag = 0;
+ } else if (tres == DW_DLV_NO_ENTRY) {
+ tag = 0;
+ } else {
+ /* ok */
+ }
+
+ switch (attr) {
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_type: {
+ int res = 0;
+ Dwarf_Off die_off = 0;
+ Dwarf_Off ref_off = 0;
+ Dwarf_Die ref_die = 0;
+
+ ++die_indent_level;
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles, valname,
+ show_form_used,verbose);
+ /* Get the global offset for reference */
+ res = dwarf_global_formref(attrib, &ref_off, &err);
+ if (res != DW_DLV_OK) {
+ int errno = dwarf_errno(err);
+ if (errno == DW_DLE_REF_SIG8_NOT_HANDLED ) {
+ // No need to stop, ref_sig8 refers out of
+ // the current section.
+ break;
+ } else {
+ print_error(dbg, "dwarf_global_formref fails in traversal",
+ res, err);
+ }
+ }
+ res = dwarf_dieoffset(die, &die_off, &err);
+ if (res != DW_DLV_OK) {
+ int errno = dwarf_errno(err);
+ if (errno == DW_DLE_REF_SIG8_NOT_HANDLED ) {
+ // No need to stop, ref_sig8 refers out of
+ // the current section.
+ break;
+ } else {
+ print_error(dbg, "dwarf_dieoffset fails in traversal",
+ res, err);
+ }
+ }
+
+ /* Follow reference chain, looking for self references */
+ res = dwarf_offdie_b(dbg,ref_off,is_info,&ref_die,&err);
+ if (res == DW_DLV_OK) {
+ DieHolder hdie(dbg,ref_die);
+ ++die_indent_level;
+ /* Dump visited information */
+ if (dump_visited_info) {
+ Dwarf_Off off = 0;
+ dwarf_die_CU_offset(die, &off, &err);
+ /* Check above call return status? FIXME */
+ cout << BracketSurround(IToDec(die_indent_level,2)) <<
+ "<" << IToHex0N(off,10) <<
+ " GOFF=" << IToHex0N(die_off,10) << "> ";
+ unsigned myindent= die_indent_level * 2 + 2;
+ cout << std::setw(myindent) << " " << atname <<
+ " -> " << valname << endl;
+ }
+ circular_reference = traverse_one_die(dbg,attrib,ref_die,
+ hsrcfiles,die_indent_level);
+ pVisitedOffsetData->DeleteVisitedOffset(die_off);
+ --die_indent_level;
+ }
+ }
+ break;
+ } /* End switch. */
+ return circular_reference;
+}
+
+/* Traverse one DIE in order to detect self references to DIES. */
+static bool
+traverse_one_die(Dwarf_Debug dbg, Dwarf_Attribute attrib, Dwarf_Die die,
+ SrcfilesHolder & hsrcfiles,
+ int die_indent_level)
+{
+ Dwarf_Half tag = 0;
+ Dwarf_Off overall_offset = 0;
+ bool circular_reference = false;
+ bool print_information = false;
+
+ int res = dwarf_tag(die, &tag, &err);
+ if (res != DW_DLV_OK) {
+ print_error(dbg, "accessing tag of die!", res, err);
+ }
+
+ res = dwarf_dieoffset(die, &overall_offset, &err);
+ if (res != DW_DLV_OK) {
+ print_error(dbg, "dwarf_dieoffset", res, err);
+ }
+
+ /* Print visited information */
+ if (dump_visited_info) {
+ Dwarf_Off offset = 0;
+ string tagname;
+ res = dwarf_die_CU_offset(die, &offset, &err);
+ if (res != DW_DLV_OK) {
+ print_error(dbg, "dwarf_die_CU_offsetC", res, err);
+ }
+ tagname = get_TAG_name(tag,dwarf_names_print_on_error);
+ cout << BracketSurround(IToDec(die_indent_level,2)) <<
+ "<" << IToHex0N(offset,10) <<
+ " GOFF=" << IToHex0N(overall_offset,10) << "> ";
+ unsigned myindent= die_indent_level * 2 + 2;
+ cout << std::setw(myindent) << " " << tagname;
+ }
+
+ DWARF_CHECK_COUNT(self_references_result,1);
+ if (pVisitedOffsetData->IsKnownOffset(overall_offset) ) {
+ string valname;
+ Dwarf_Half attr = 0;
+ string atname;
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles,
+ valname, show_form_used,verbose);
+ dwarf_whatattr(attrib, &attr, &err);
+ atname = get_AT_name(attr,dwarf_names_print_on_error);
+
+ /* We have a self reference */
+ DWARF_CHECK_ERROR3(self_references_result,
+ "Invalid self reference to DIE: ",atname,valname);
+ circular_reference = true;
+ } else {
+ Dwarf_Attribute *atlist = 0;
+
+ /* Add current DIE */
+ pVisitedOffsetData->AddVisitedOffset(overall_offset);
+
+ Dwarf_Signed atcnt = 0;
+ res = dwarf_attrlist(die, &atlist, &atcnt, &err);
+ if (res == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_attrlist", res, err);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ /* indicates there are no attrs. It is not an error. */
+ atcnt = 0;
+ }
+
+ for (Dwarf_Signed i = 0; i < atcnt; i++) {
+ Dwarf_Half attr = 0;
+ int ares = dwarf_whatattr(atlist[i], &attr, &err);
+ if (ares == DW_DLV_OK) {
+ circular_reference = traverse_attribute(dbg, die, attr,
+ atlist[i],
+ print_information, hsrcfiles,
+ die_indent_level);
+ } else {
+ print_error(dbg, "dwarf_whatattr entry missing",
+ ares, err);
+ }
+ }
+
+ for (Dwarf_Signed i = 0; i < atcnt; i++) {
+ dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR);
+ }
+ if (res == DW_DLV_OK) {
+ dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
+ }
+
+ /* Delete current DIE */
+ pVisitedOffsetData->DeleteVisitedOffset(overall_offset);
+ }
+ return circular_reference;
+}
+
+
+
+/* Extracted this from print_attribute()
+ to get tolerable indents.
+ In other words to make it readable.
+ It uses global data fields excessively, but so does
+ print_attribute().
+ The majority of the code here is checking for
+ compiler errors. */
+static void
+print_range_attribute(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Attribute attr_in,
+ Dwarf_Half theform,
+ int dwarf_names_print_on_error,
+ bool print_information,
+ string &extra)
+{
+ Dwarf_Error err = 0;
+ Dwarf_Unsigned original_off = 0;
+ int fres = 0;
+
+ fres = dwarf_global_formref(attr_in, &original_off, &err);
+ if( fres == DW_DLV_OK) {
+ Dwarf_Ranges *rangeset = 0;
+ Dwarf_Signed rangecount = 0;
+ Dwarf_Unsigned bytecount = 0;
+ int rres = dwarf_get_ranges_a(dbg,original_off,
+ die,
+ &rangeset,
+ &rangecount,&bytecount,&err);
+ if(rres == DW_DLV_OK) {
+ /* Ignore ranges inside a stripped function */
+ if (check_ranges &&
+ in_valid_code && checking_this_compiler()) {
+ Dwarf_Unsigned off = original_off;
+
+ Dwarf_Signed index = 0;
+ Dwarf_Addr base_address = error_message_data.CU_base_address;
+ Dwarf_Addr lopc = 0;
+ Dwarf_Addr hipc = 0;
+ bool bError = false;
+
+ /* Ignore last entry, is the end-of-list */
+ for (index = 0; index < rangecount - 1; index++) {
+ Dwarf_Ranges *r = rangeset + index;
+
+ if (r->dwr_addr1 == error_message_data.elf_max_address) {
+ /* (0xffffffff,addr), use specific address (current PU address) */
+ base_address = r->dwr_addr2;
+ } else {
+ /* (offset,offset), update using CU address */
+ lopc = r->dwr_addr1 + base_address;
+ hipc = r->dwr_addr2 + base_address;
+ DWARF_CHECK_COUNT(ranges_result,1);
+
+ /* Check the low_pc and high_pc
+ are within a valid range in
+ the .text section */
+ if( pAddressRangesData->IsAddressInAddressRange(lopc)
+ &&
+ pAddressRangesData->IsAddressInAddressRange(hipc)){
+ /* Valid values; do nothing */
+ } else {
+ /* At this point may be we
+ are dealing with a
+ linkonce symbol */
+ if (pLinkOnceData->FindLinkOnceEntry(
+ error_message_data.PU_name,lopc,hipc)) {
+ /* Valid values; do nothing */
+ } else {
+ bError = true;
+ DWARF_CHECK_ERROR(ranges_result,
+ ".debug_ranges: Address outside a "
+ "valid .text range");
+ if (check_verbose_mode) {
+ cout << "Offset = " << IToHex0N(off,10) <<
+ ", Base = " << IToHex0N(base_address,10) <<
+ ", " <<
+ "Low = " << IToHex0N(lopc,10) <<
+ " (" << IToHex0N(r->dwr_addr1,10) <<
+ "), High = " << IToHex0N(hipc,10) <<
+ " (" << IToHex0N(r->dwr_addr2,10) <<
+ ")" << endl;
+ }
+ }
+ }
+ }
+ /* Each entry holds 2 addresses (offsets) */
+ off += error_message_data.elf_address_size * 2;
+ }
+ if (bError && check_verbose_mode) {
+ printf("\n");
+ }
+ }
+ if(print_information) {
+ extra = print_ranges_list_to_extra(dbg,original_off,
+ rangeset,rangecount,bytecount);
+ }
+ dwarf_ranges_dealloc(dbg,rangeset,rangecount);
+ } else if (rres == DW_DLV_ERROR) {
+ if (do_print_dwarf) {
+ printf("\ndwarf_get_ranges() "
+ "cannot find DW_AT_ranges at offset 0x%"
+ DW_PR_XZEROS DW_PR_DUx
+ " (0x%" DW_PR_XZEROS DW_PR_DUx ").",
+ original_off,
+ original_off);
+ } else {
+ DWARF_CHECK_COUNT(ranges_result,1);
+ DWARF_CHECK_ERROR2(ranges_result,
+ get_AT_name(attr,
+ dwarf_names_print_on_error),
+ " cannot find DW_AT_ranges at offset");
+ }
+ } else {
+ /* NO ENTRY */
+ if (do_print_dwarf) {
+ cout << endl;
+ cout << "dwarf_get_ranges() "
+ "finds no DW_AT_ranges at offset 0x% (" <<
+ IToHex0N(original_off,10) <<
+ " " <<
+ IToDec(original_off) <<
+ ").";
+ } else {
+ DWARF_CHECK_COUNT(ranges_result,1);
+ DWARF_CHECK_ERROR2(ranges_result,
+ get_AT_name(attr,
+ dwarf_names_print_on_error),
+ " fails to find DW_AT_ranges at offset");
+ }
+ }
+ } else {
+ if (do_print_dwarf) {
+ char tmp[100];
+
+ snprintf(tmp,sizeof(tmp)," attr 0x%x form 0x%x ",
+ (unsigned)attr,(unsigned)theform);
+ string local(" fails to find DW_AT_ranges offset");
+ local.append(tmp);
+ cout << " " << local << " ";
+ } else {
+ DWARF_CHECK_COUNT(ranges_result,1);
+ DWARF_CHECK_ERROR2(ranges_result,
+ get_AT_name(attr,
+ dwarf_names_print_on_error),
+ " fails to find DW_AT_ranges offset");
+ }
+ }
+}
+
+
+
+
+/* A DW_AT_name in a CU DIE will likely have dots
+ and be entirely sensible. So lets
+ not call things a possible error when they are not.
+ Some assemblers allow '.' in an identifier too.
+ We should check for that, but we don't yet.
+
+ We should check the compiler before checking
+ for 'altabi.' too (FIXME).
+
+ This is a heuristic, not all that reliable.
+
+ Return 0 if it is a vaguely standard identifier.
+ Else return 1, meaning 'it might be a file name
+ or have '.' in it quite sensibly.'
+
+ If we don't do the TAG check we might report "t.c"
+ as a questionable DW_AT_name. Which would be silly.
+*/
+static int
+dot_ok_in_identifier(int tag,Dwarf_Die die, const std::string val)
+{
+ if (strncmp(val.c_str(),"altabi.",7)) {
+ /* Ignore the names of the form 'altabi.name',
+ which apply to one specific compiler. */
+ return 1;
+ }
+ if(tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit ||
+ tag == DW_TAG_imported_unit || tag == DW_TAG_type_unit) {
+ return 1;
+ }
+ return 0;
+}
+
+static string
+trim_quotes(const string &val)
+{
+ if(val[0] == '"') {
+ size_t l = val.size();
+ if(l > 2 && val[l-1] == '"') {
+ string outv = val.substr(1,l-2);
+ return outv;
+ }
+ }
+ return val;
+}
+
+static int
+have_a_search_match(const string &valname,const string &atname)
+{
+ /* valname may have had quotes inserted, but search_match_text
+ will not. So we need to use a new copy, not valname here.
+ */
+ string match;
+ string s2;
+
+ match = trim_quotes(valname);
+ if (!search_match_text.empty()) {
+ if( (match == search_match_text) ||
+ (atname == search_match_text)) {
+ return true;
+ }
+ }
+ if (!search_any_text.empty()) {
+ if(is_strstrnocase(match.c_str(),search_any_text.c_str()) ||
+ is_strstrnocase(atname.c_str(),search_any_text.c_str())) {
+ return true;
+ }
+ }
+#ifdef HAVE_REGEX
+ if (!search_regex_text.empty()) {
+ if(!regexec(&search_re,match.c_str(),0,NULL,0) ||
+ !regexec(&search_re,atname.c_str(),0,NULL,0)) {
+
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+
+
+static bool
+print_attribute(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attr,
+ Dwarf_Attribute attr_in,
+ bool print_information,
+ int die_indent_level,
+ SrcfilesHolder & hsrcfiles)
+{
+ Dwarf_Attribute attrib = 0;
+ Dwarf_Unsigned uval = 0;
+ string atname;
+ string valname;
+ string extra;
+ Dwarf_Half tag = 0;
+ bool found_search_attr = false;
+ bool bTextFound = false;
+ Dwarf_Bool is_info = true;
+
+ is_info=dwarf_get_die_infotypes_flag(die);
+ atname = get_AT_name(attr,dwarf_names_print_on_error);
+
+ /* The following gets the real attribute, even in the face of an
+ incorrect doubling, or worse, of attributes. */
+ attrib = attr_in;
+ /* Do not get attr via dwarf_attr: if there are (erroneously)
+ multiple of an attr in a DIE, dwarf_attr will not get the
+ second, erroneous one and dwarfdump will print the first one
+ multiple times. Oops. */
+
+ int tres = dwarf_tag(die, &tag, &err);
+ if (tres == DW_DLV_ERROR) {
+ tag = 0;
+ } else if (tres == DW_DLV_NO_ENTRY) {
+ tag = 0;
+ } else {
+ /* ok */
+ }
+ if (check_attr_tag && checking_this_compiler()) {
+ string tagname = "<tag invalid>";
+ DWARF_CHECK_COUNT(attr_tag_result,1);
+ if (tres == DW_DLV_ERROR) {
+ DWARF_CHECK_ERROR3(attr_tag_result,tagname,
+ get_AT_name(attr,dwarf_names_print_on_error),
+ "check the tag-attr combination, dwarf_tag failed.");
+ } else if (tres == DW_DLV_NO_ENTRY) {
+ DWARF_CHECK_ERROR3(attr_tag_result,tagname,
+ get_AT_name(attr,dwarf_names_print_on_error),
+ "check the tag-attr combination, dwarf_tag NO ENTRY?.");
+ } else if (legal_tag_attr_combination(tag, attr)) {
+ /* OK */
+ } else {
+ tagname = get_TAG_name(tag,dwarf_names_print_on_error);
+ tag_specific_checks_setup(tag,die_indent_level);
+ DWARF_CHECK_ERROR3(attr_tag_result,tagname,
+ get_AT_name(attr,dwarf_names_print_on_error),
+ "check the tag-attr combination");
+ }
+ }
+
+ switch (attr) {
+ case DW_AT_language:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_language", &valname,
+ get_LANG_name, &err,
+ show_form_used);
+ break;
+ case DW_AT_accessibility:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_accessibility",
+ &valname, get_ACCESS_name,
+ &err,
+ show_form_used);
+ break;
+ case DW_AT_visibility:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_visibility",
+ &valname, get_VIS_name,
+ &err,
+ show_form_used);
+ break;
+ case DW_AT_virtuality:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_virtuality",
+ &valname,
+ get_VIRTUALITY_name, &err,
+ show_form_used);
+ break;
+ case DW_AT_identifier_case:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_identifier",
+ &valname, get_ID_name,
+ &err,
+ show_form_used);
+ break;
+ case DW_AT_inline:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_inline", &valname,
+ get_INL_name, &err,
+ show_form_used);
+ break;
+ case DW_AT_encoding:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_encoding", &valname,
+ get_ATE_name, &err,
+ show_form_used);
+ break;
+ case DW_AT_ordering:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_ordering", &valname,
+ get_ORD_name, &err,
+ show_form_used);
+ break;
+ case DW_AT_calling_convention:
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_calling_convention",
+ &valname, get_CC_name,
+ &err,
+ show_form_used);
+ break;
+ case DW_AT_discr_list: /* DWARF3 */
+ get_small_encoding_integer_and_name(dbg, attrib, &uval,
+ "DW_AT_discr_list",
+ &valname, get_DSC_name,
+ &err,
+ show_form_used);
+ break;
+ case DW_AT_data_member_location:
+ {
+ // Value is a constant or a location
+ // description or location list.
+ // If a constant, it could be signed or
+ // unsigned. Telling whether a constant
+ // or a reference is nontrivial
+ // since DW_FORM_data{4,8}
+ // could be either in DWARF{2,3} */
+ Dwarf_Half theform = 0;
+ Dwarf_Half directform = 0;
+ Dwarf_Half version = 0;
+ Dwarf_Half offset_size = 0;
+
+ get_form_values(attrib,theform,directform);
+ int wres = dwarf_get_version_of_die(die ,
+ &version,&offset_size);
+ if(wres != DW_DLV_OK) {
+ print_error(dbg,"Cannot get DIE context version number",wres,err);
+ break;
+ }
+ Dwarf_Form_Class fc = dwarf_get_form_class(version,attr,
+ offset_size,theform);
+ if(fc == DW_FORM_CLASS_CONSTANT) {
+ wres = formxdata_print_value(dbg,attrib,valname,
+ &err,false);
+ show_form_itself(show_form_used,verbose,
+ theform, directform,&valname);
+ if(wres == DW_DLV_OK){
+ /* String appended already. */
+ break;
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ print_error(dbg,"Cannot get DW_AT_data_member_location, how can it be NO_ENTRY? ",wres,err);
+ break;
+ } else {
+ print_error(dbg,"Cannot get DW_AT_data_member_location ",wres,err);
+ break;
+ }
+ }
+ /* FALL THRU, this is a
+ a location description, or a reference
+ to one, or a mistake. */
+ }
+ /* FALL THRU to location description */
+ case DW_AT_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_use_location:
+ case DW_AT_static_link:
+ case DW_AT_frame_base: {
+ /* value is a location description or location list */
+ Dwarf_Half theform = 0;
+ Dwarf_Half directform = 0;
+ get_form_values(attrib,theform,directform);
+ if(is_location_form(theform)) {
+ get_location_list(dbg, die, attrib, valname);
+ show_form_itself(show_form_used,verbose,
+ theform, directform,&valname);
+ } else if (theform == DW_FORM_exprloc) {
+ bool showhextoo = true;
+ print_exprloc_content(dbg,die,attrib,showhextoo,valname);
+ } else {
+ show_attr_form_error(dbg,attr,theform,&valname);
+ }
+ }
+ break;
+ case DW_AT_SUN_func_offsets: {
+ Dwarf_Half theform = 0;
+ Dwarf_Half directform = 0;
+ get_form_values(attrib,theform,directform);
+ valname = get_FLAG_BLOCK_string(dbg, attrib);
+ show_form_itself(show_form_used,verbose,
+ theform, directform,&valname);
+ }
+ break;
+ case DW_AT_SUN_cf_kind:
+ {
+ Dwarf_Half kind;
+ Dwarf_Unsigned tempud;
+ Dwarf_Error err;
+ Dwarf_Half theform = 0;
+ Dwarf_Half directform = 0;
+ get_form_values(attrib,theform,directform);
+ int wres;
+ wres = dwarf_formudata (attrib,&tempud, &err);
+ if(wres == DW_DLV_OK) {
+ kind = tempud;
+ valname = get_ATCF_name(kind,dwarf_names_print_on_error);
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ valname = "?";
+ } else {
+ print_error(dbg,"Cannot get formudata....",wres,err);
+ valname = "??";
+ }
+ show_form_itself(show_form_used,verbose,
+ theform, directform,&valname);
+ }
+ break;
+ case DW_AT_upper_bound:
+ {
+ Dwarf_Half theform;
+ int rv;
+ rv = dwarf_whatform(attrib,&theform,&err);
+ /* depending on the form and the attribute, process the form */
+ if(rv == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_whatform cannot find attr form",
+ rv, err);
+ } else if (rv == DW_DLV_NO_ENTRY) {
+ break;
+ }
+
+ switch (theform) {
+ case DW_FORM_block1: {
+ Dwarf_Half theform = 0;
+ Dwarf_Half directform = 0;
+ get_form_values(attrib,theform,directform);
+ get_location_list(dbg, die, attrib, valname);
+ show_form_itself(show_form_used,verbose,
+ theform, directform,&valname);
+ }
+ break;
+ default:
+ get_attr_value(dbg, tag, die,
+ attrib, hsrcfiles, valname,show_form_used,
+ verbose);
+ break;
+ }
+ break;
+ }
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ {
+ Dwarf_Half theform;
+ int rv;
+ rv = dwarf_whatform(attrib,&theform,&err);
+ /* Depending on the form and the attribute, process the form */
+ if(rv == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_whatform cannot find attr form",
+ rv, err);
+ } else if (rv == DW_DLV_NO_ENTRY) {
+ break;
+ }
+ if( theform != DW_FORM_addr) {
+ /* New in DWARF4: other forms are not an address
+ but are instead offset from pc.
+ One could test for DWARF4 here before adding
+ this string, but that seems unnecessary as this
+ could not happen with DWARF3 or earlier.
+ A normal consumer would have to add this value to
+ DW_AT_low_pc to get a true pc. */
+ valname.append("<offset-from-lowpc>");
+ }
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles, valname,
+ show_form_used,verbose);
+ /* Update base and high addresses for CU */
+ if (error_message_data.seen_CU &&
+ (error_message_data.need_CU_base_address ||
+ error_message_data.need_CU_high_address)) {
+
+ /* Update base address for CU */
+ if (error_message_data.need_CU_base_address &&
+ attr == DW_AT_low_pc) {
+ dwarf_formaddr(attrib,
+ &error_message_data.CU_base_address, &err);
+ error_message_data.need_CU_base_address = false;
+ }
+
+ /* Update high address for CU */
+ if (error_message_data.need_CU_high_address &&
+ attr == DW_AT_high_pc) {
+ dwarf_formaddr(attrib,
+ &error_message_data.CU_high_address, &err);
+ error_message_data.need_CU_high_address = false;
+ }
+ }
+ /* Record the low and high addresses as we have them */
+ if ((check_decl_file || check_ranges ||
+ check_locations) && theform == DW_FORM_addr) {
+ Dwarf_Addr addr = 0;
+ dwarf_formaddr(attrib, &addr, &err);
+ if (attr == DW_AT_low_pc) {
+ lowAddr = addr;
+ bSawLow = true;
+ /* Record the base address of the last seen PU
+ to be used when checking line information */
+ if (error_message_data.seen_PU && !error_message_data.seen_PU_base_address) {
+ error_message_data.seen_PU_base_address = true;
+ error_message_data.PU_base_address = addr;
+ }
+ } else {
+ highAddr = addr;
+ bSawHigh = true;
+ /* Record the high address of the last seen PU
+ to be used when checking line information */
+ if (error_message_data.seen_PU && !error_message_data.seen_PU_high_address) {
+ error_message_data.seen_PU_high_address = true;
+ error_message_data.PU_high_address = addr;
+ }
+ }
+ /* We have now both low_pc and high_pc values */
+ if (bSawLow && bSawHigh) {
+
+ /* We need to decide if this PU is
+ valid, as the SN Linker marks a stripped
+ function by setting lowpc to -1;
+ also for discarded comdat, both lowpc
+ and highpc are zero */
+ if (error_message_data.need_PU_valid_code) {
+ error_message_data.need_PU_valid_code = false;
+
+ /* To ignore a PU as invalid code,
+ only consider the lowpc and
+ highpc values associated with the
+ DW_TAG_subprogram; other
+ instances of lowpc and highpc,
+ must be ignore (lexical blocks) */
+ in_valid_code = true;
+ if (IsInvalidCode(lowAddr,highAddr) &&
+ tag == DW_TAG_subprogram) {
+ in_valid_code = false;
+ }
+ }
+
+ /* We have a low_pc/high_pc pair;
+ check if they are valid */
+ if (in_valid_code) {
+ DWARF_CHECK_COUNT(ranges_result,1);
+ if (lowAddr != error_message_data.elf_max_address &&
+ lowAddr > highAddr) {
+ DWARF_CHECK_ERROR(ranges_result,
+ ".debug_info: Incorrect values "
+ "for low_pc/high_pc");
+ if (check_verbose_mode) {
+ cout << "Low = " <<
+ IToHex0N(lowAddr,10) <<
+ cout << "High = " <<
+ IToHex0N(highAddr,10) << endl;
+ }
+ }
+ if (check_decl_file || check_ranges ||
+ check_locations) {
+ pAddressRangesData->AddAddressRange(lowAddr,
+ highAddr);
+ }
+ }
+ bSawLow = false;
+ bSawHigh = false;
+ }
+ }
+ }
+ break;
+ case DW_AT_ranges:
+ {
+ Dwarf_Half theform = 0;
+ int rv;
+
+ rv = dwarf_whatform(attrib,&theform,&err);
+ if(rv == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_whatform cannot find attr form",
+ rv, err);
+ } else if (rv == DW_DLV_NO_ENTRY) {
+ break;
+ }
+
+ get_attr_value(dbg, tag,die, attrib, hsrcfiles, valname,
+ show_form_used,verbose);
+ print_range_attribute(dbg,die,attr,attr_in,
+ theform,dwarf_names_print_on_error,print_information,extra);
+ }
+ break;
+ case DW_AT_MIPS_linkage_name:
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles,
+ valname, show_form_used,verbose);
+
+ if (check_locations || check_ranges) {
+ string lname;
+ bool local_show_form = false;
+ int local_verbose = 0;
+ get_attr_value(dbg,tag,die,attrib,hsrcfiles,lname,local_show_form,
+ local_verbose);
+ error_message_data.PU_name = lname;
+ }
+ break;
+ case DW_AT_name:
+ case DW_AT_GNU_template_name:
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles,
+ valname, show_form_used,verbose);
+ if (check_names && checking_this_compiler()) {
+ /* Look for specific name forms, attempting to
+ notice and report 'odd' identifiers. */
+ string lname;
+ bool local_show_form = false;
+ int local_verbose = 0;
+ get_attr_value(dbg,tag,die,attrib,hsrcfiles,lname,local_show_form,
+ local_verbose);
+ DWARF_CHECK_COUNT(names_result,1);
+ if (!strcmp("\"(null)\"",lname.c_str())) {
+ DWARF_CHECK_ERROR(names_result,
+ "string attribute is \"(null)\".");
+ } else {
+ if (!dot_ok_in_identifier(tag,die,valname)
+ && !error_message_data.need_CU_name &&
+ strchr(valname.c_str(),'.')) {
+ /* This is a suggestion there 'might' be
+ a surprising name, not a guarantee of an
+ error. */
+ DWARF_CHECK_ERROR(names_result,
+ "string attribute is invalid.");
+ }
+ }
+ }
+
+ /* If we are in checking mode and we do not have a PU name */
+ if ((check_locations || check_ranges) &&
+ error_message_data.seen_PU && error_message_data.PU_name.empty()) {
+ string lname;
+ bool local_show_form = false;
+ int local_verbose = 0;
+ get_attr_value(dbg,tag,die,attrib,hsrcfiles,lname,
+ local_show_form, local_verbose);
+ error_message_data.PU_name = lname;
+ }
+
+ /* If we are processing the compile unit, record the name */
+ if (error_message_data.seen_CU && error_message_data.need_CU_name) {
+ // Lets not get the form name included.
+ bool local_show_form_used = false;
+ int local_verbose = 0;
+ string localname;
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles,
+ localname, local_show_form_used,local_verbose);
+ error_message_data.CU_name = localname;
+ error_message_data.need_CU_name = false;
+ }
+ break;
+ case DW_AT_producer:
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles,
+ valname, show_form_used,verbose);
+ /* If we are in checking mode, identify the compiler */
+ if (do_check_dwarf || search_is_on) {
+ bool local_show_form = false;
+ int local_verbose = 0;
+ string local_producer;
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles,
+ local_producer, local_show_form,local_verbose);
+ /* Check if this compiler version is a target */
+ update_compiler_target(local_producer);
+ }
+ break;
+
+ /* When dealing with linkonce symbols, the low_pc and high_pc
+ are associated with a specific symbol; SNC always generate a name in
+ the for of DW_AT_MIPS_linkage_name; GCC does not; instead it generates
+ DW_AT_abstract_origin or DW_AT_specification; in that case we have to
+ traverse this attribute in order to get the name for the linkonce */
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_type:
+ get_attr_value(dbg, tag, die, attrib, hsrcfiles ,
+ valname, show_form_used,verbose);
+ if (check_forward_decl || check_self_references) {
+ Dwarf_Off die_off = 0;
+ Dwarf_Off ref_off = 0;
+ int res = 0;
+ int suppress_check = 0;
+
+ /* Get the global offset for reference */
+ res = dwarf_global_formref(attrib, &ref_off, &err);
+ if (res != DW_DLV_OK) {
+ int myerr = 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_dealloc(dbg,err,DW_DLA_ERROR);
+ err = 0;
+ } else {
+ print_error(dbg, "dwarf_die_CU_offsetD", res, err);
+ }
+ }
+ res = dwarf_dieoffset(die, &die_off, &err);
+ if (res != DW_DLV_OK) {
+ print_error(dbg, "ref formwith no ref?!", res, err);
+ }
+
+ if (!suppress_check && check_self_references) {
+ Dwarf_Die ref_die = 0;
+
+ pVisitedOffsetData->reset();
+ pVisitedOffsetData->AddVisitedOffset(die_off);
+
+ /* Follow reference chain, looking for self references */
+ res = dwarf_offdie_b(dbg,ref_off,is_info,&ref_die,&err);
+ if (res == DW_DLV_OK) {
+ DieHolder hdie(dbg,ref_die);
+ ++die_indent_level;
+
+ if (dump_visited_info) {
+ Dwarf_Off off;
+ dwarf_die_CU_offset(die, &off, &err);
+ cout << BracketSurround(IToDec(die_indent_level,2)) <<
+ "<" << IToHex0N(off,10) <<
+ " GOFF=" << IToHex0N(die_off,10) << "> ";
+ unsigned w = die_indent_level * 2 + 2;
+ cout << std::setw(w)<< atname << " -> " << valname << endl ;
+ }
+ traverse_one_die(dbg,attrib,ref_die,hsrcfiles,die_indent_level);
+ --die_indent_level;
+ }
+ pVisitedOffsetData->DeleteVisitedOffset(die_off);
+ }
+
+ if (!suppress_check && check_forward_decl) {
+ if (attr == DW_AT_specification) {
+ /* Check the DW_AT_specification does not make forward
+ references to DIEs.
+ DWARF4 specifications, section 2.13.2,
+ but really they are legal,
+ this test is probably wrong. */
+ DWARF_CHECK_COUNT(forward_decl_result,1);
+ if (ref_off > die_off) {
+ DWARF_CHECK_ERROR2(forward_decl_result,
+ "Invalid forward reference to DIE: ",valname);
+ }
+ }
+ }
+ }
+ /* If we are in checking mode and we do not have a PU name */
+ if ((check_locations || check_ranges) &&
+ error_message_data.seen_PU &&
+ error_message_data.PU_name.empty()) {
+ if (tag == DW_TAG_subprogram) {
+ /* This gets the DW_AT_name if this DIE has one. */
+ Dwarf_Addr low_pc = 0;
+ string proc_name;
+ get_proc_name(dbg,die,proc_name,low_pc);
+ if (!proc_name.empty()) {
+ error_message_data.PU_name = proc_name;
+ }
+ }
+ }
+ break;
+ default:
+ get_attr_value(dbg, tag,die, attrib, hsrcfiles, valname,
+ show_form_used,verbose);
+ break;
+ }
+ if (!print_information) {
+ if (have_a_search_match(valname,atname) ) {
+ if (search_wide_format) {
+ found_search_attr = true;
+ } else {
+ PRINT_CU_INFO();
+ bTextFound = true;
+ }
+ }
+ }
+ if ((PRINTING_DIES && print_information) || bTextFound) {
+ if(!display_offsets) {
+ cout << LeftAlign(28,atname) << endl;
+ } else {
+ if (dense) {
+ cout << " " << atname << BracketSurround(valname);
+ cout << extra;
+ } else {
+ cout << LeftAlign(28,atname) << valname << endl;
+ cout << extra;
+ }
+ }
+ cout.flush();
+ bTextFound = false;
+ }
+ return found_search_attr;
+}
+
+
+// Appends the locdesc to string_out.
+// Does not print.
+int
+dwarfdump_print_one_locdesc(Dwarf_Debug dbg,
+ Dwarf_Locdesc * llbuf,
+ int skip_locdesc_header,
+ string &string_out)
+{
+
+
+ if (!skip_locdesc_header && (verbose || llbuf->ld_from_loclist)) {
+ string_out.append(BracketSurround(
+ string("lowpc=") + IToHex0N(llbuf->ld_lopc,10)));
+ string_out.append(BracketSurround(
+ string("highpc=") + IToHex0N(llbuf->ld_hipc,10)));
+ if (display_offsets && verbose) {
+ string s("from ");
+ s.append(llbuf->ld_from_loclist ?
+ ".debug_loc" : ".debug_info");
+ s.append(" offset ");
+ s.append(IToHex0N(llbuf->ld_section_offset,10));
+ string_out.append(BracketSurround(s));
+ }
+ }
+
+
+ Dwarf_Locdesc *locd = llbuf;
+ int no_of_ops = llbuf->ld_cents;
+ for (int i = 0; i < no_of_ops; i++) {
+ Dwarf_Loc * op = &locd->ld_s[i];
+
+ int res = _dwarf_print_one_expr_op(dbg,op,i,string_out);
+ if(res == DW_DLV_ERROR) {
+ return res;
+ }
+ }
+ return DW_DLV_OK;
+}
+
+static bool
+op_has_no_operands(int op)
+{
+ unsigned i = 0;
+ if(op >= DW_OP_lit0 && op <= DW_OP_reg31) {
+ return true;
+ }
+ for( ; ; ++i) {
+ struct operation_descr_s *odp = opdesc+i;
+ if(odp->op_code == 0) {
+ break;
+ }
+ if(odp->op_code != op) {
+ continue;
+ }
+ if (odp->op_count == 0) {
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+int
+_dwarf_print_one_expr_op(Dwarf_Debug dbg,Dwarf_Loc* expr,int index,
+ string &string_out)
+{
+ if (index > 0) {
+ string_out.append(" ");
+ }
+
+ Dwarf_Small op = expr->lr_atom;
+ string op_name = get_OP_name(op,dwarf_names_print_on_error);
+ string_out.append(op_name);
+
+ Dwarf_Unsigned opd1 = expr->lr_number;
+ if (op_has_no_operands(op)) {
+ /* Nothing to add. */
+ } else if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
+ char small_buf[40];
+ snprintf(small_buf, sizeof(small_buf),
+ "%+" DW_PR_DSd , (Dwarf_Signed) opd1);
+ string_out.append(small_buf);
+ } else {
+ switch (op) {
+ case DW_OP_addr:
+ string_out.append(" ");
+ string_out.append(IToHex0N(opd1,10));
+ break;
+ case DW_OP_const1s:
+ case DW_OP_const2s:
+ case DW_OP_const4s:
+ case DW_OP_const8s:
+ case DW_OP_consts:
+ case DW_OP_skip:
+ case DW_OP_bra:
+ case DW_OP_fbreg:
+ {
+ Dwarf_Signed si = opd1;
+ string_out.append(" ");
+ string_out.append(IToDec(si));
+ }
+ break;
+ case DW_OP_const1u:
+ case DW_OP_const2u:
+ case DW_OP_const4u:
+ case DW_OP_const8u:
+ case DW_OP_constu:
+ case DW_OP_pick:
+ case DW_OP_plus_uconst:
+ case DW_OP_regx:
+ case DW_OP_piece:
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ string_out.append(" ");
+ string_out.append(IToDec(opd1));
+ break;
+ case DW_OP_bregx:
+ {
+ string_out.append(IToHex0N(opd1,10));
+ string_out.append("+");
+ Dwarf_Unsigned opd2 = expr->lr_number2;
+ string_out.append(IToDec(opd2));
+ }
+ break;
+ case DW_OP_call2:
+ string_out.append(IToHex0N(opd1));
+
+ break;
+ case DW_OP_call4:
+ string_out.append(IToHex(opd1));
+
+ break;
+ case DW_OP_call_ref:
+ string_out.append(IToHex0N(opd1,8));
+ break;
+ case DW_OP_bit_piece:
+ {
+ string_out.append(IToHex0N(opd1,8));
+ string_out.append(" offset ");
+ Dwarf_Unsigned opd2 = expr->lr_number2;
+ string_out.append(IToHex0N(opd2,8));
+ }
+ break;
+ case DW_OP_implicit_value:
+ {
+#define IMPLICIT_VALUE_PRINT_MAX 12
+ string_out.append(" ");
+ string_out.append(IToHex0N(opd1,10));
+ // The other operand is a block of opd1 bytes.
+ // FIXME
+ unsigned int print_len = opd1;
+ if(print_len > IMPLICIT_VALUE_PRINT_MAX) {
+ print_len = IMPLICIT_VALUE_PRINT_MAX;
+ }
+#undef IMPLICIT_VALUE_PRINT_MAX
+ if(print_len > 0) {
+ unsigned int i = 0;
+ Dwarf_Unsigned opd2 = expr->lr_number2;
+ const unsigned char *bp =
+ reinterpret_cast<const unsigned char *>(opd2);
+ string_out.append(" contents 0x");
+ for( ; i < print_len; ++i,++bp) {
+ char small_buf[40];
+ snprintf(small_buf, sizeof(small_buf),
+ "%02x", *bp);
+ string_out.append(small_buf);
+ }
+ }
+ }
+ case DW_OP_stack_value:
+ break;
+ case DW_OP_GNU_uninit: /* DW_OP_APPLE_uninit */
+ /* No operands. */
+ break;
+ case DW_OP_GNU_encoded_addr:
+ string_out.append(" ");
+ string_out.append(IToHex0N(opd1,10));
+ break;
+ case DW_OP_GNU_implicit_pointer:
+ string_out.append(" ");
+ string_out.append(IToHex0N(opd1,10));
+ break;
+ case DW_OP_GNU_entry_value:
+ string_out.append(" ");
+ string_out.append(IToHex0N(opd1,10));
+ break;
+ /* We do not know what the operands, if any, are. */
+ case DW_OP_HP_unknown:
+ case DW_OP_HP_is_value:
+ case DW_OP_HP_fltconst4:
+ case DW_OP_HP_fltconst8:
+ case DW_OP_HP_mod_range:
+ case DW_OP_HP_unmod_range:
+ case DW_OP_HP_tls:
+ case DW_OP_INTEL_bit_piece:
+ break;
+ default:
+ string_out.append(string(" dwarf_op unknown: ") +
+ IToHex((unsigned)op));
+ break;
+ }
+ }
+ return DW_DLV_OK;
+}
+
+/* Fill buffer with location lists
+ Return DW_DLV_OK if no errors.
+*/
+/*ARGSUSED*/ static void
+get_location_list(Dwarf_Debug dbg,
+ Dwarf_Die die, Dwarf_Attribute attr,
+ string &locstr)
+{
+ Dwarf_Locdesc *llbuf = 0;
+ Dwarf_Locdesc **llbufarray = 0;
+ Dwarf_Signed no_of_elements;
+ Dwarf_Error err;
+ int i;
+ int lres = 0;
+ int llent = 0;
+ int skip_locdesc_header = 0;
+ Dwarf_Addr base_address = error_message_data.CU_base_address;
+ Dwarf_Addr lopc = 0;
+ Dwarf_Addr hipc = 0;
+ bool bError = false;
+
+
+
+ if (use_old_dwarf_loclist) {
+ lres = dwarf_loclist(attr, &llbuf, &no_of_elements, &err);
+ if (lres == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_loclist", lres, err);
+ } else if (lres == DW_DLV_NO_ENTRY) {
+ return;
+ }
+ dwarfdump_print_one_locdesc(dbg, llbuf,skip_locdesc_header,locstr);
+ dwarf_dealloc(dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
+ return;
+ }
+
+ lres = dwarf_loclist_n(attr, &llbufarray, &no_of_elements, &err);
+ if (lres == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_loclist", lres, err);
+ } else if (lres == DW_DLV_NO_ENTRY) {
+ return;
+ }
+
+ for (llent = 0; llent < no_of_elements; ++llent) {
+ llbuf = llbufarray[llent];
+ Dwarf_Off offset = 0;
+
+ /* If we have a location list refering to the .debug_loc
+ Check for specific compiler we are validating. */
+ if (check_locations && in_valid_code &&
+ llbuf->ld_from_loclist && checking_this_compiler()) {
+ /* To calculate the offset, we use:
+ sizeof(Dwarf_Half) -> number of expression list
+ 2 * address_size -> low_pc and high_pc */
+ offset = llbuf->ld_section_offset -
+ llbuf->ld_cents * sizeof(Dwarf_Half) -
+ 2 * error_message_data.elf_address_size;
+
+ if (llbuf->ld_lopc == error_message_data.elf_max_address) {
+ /* (0xffffffff,addr), use specific address
+ (current PU address) */
+ base_address = llbuf->ld_hipc;
+ } else {
+ /* (offset,offset), update using CU address */
+ lopc = llbuf->ld_lopc + base_address;
+ hipc = llbuf->ld_hipc + base_address;
+
+ DWARF_CHECK_COUNT(locations_result,1);
+
+ /* Check the low_pc and high_pc are within
+ a valid range in the .text section */
+ if(pAddressRangesData->IsAddressInAddressRange(lopc) &&
+ pAddressRangesData->IsAddressInAddressRange(hipc)) {
+ /* Valid values; do nothing */
+ } else {
+ /* At this point may be we are dealing with
+ a linkonce symbol */
+ if (pLinkOnceData->FindLinkOnceEntry(
+ error_message_data.PU_name,lopc,hipc)) {
+ /* Valid values; do nothing */
+ } else {
+ bError = true;
+ DWARF_CHECK_ERROR(locations_result,
+ ".debug_loc: Address outside a "
+ "valid .text range");
+ if (check_verbose_mode) {
+ cout << "Offset = " << IToHex0N(offset,10) <<
+ ", Base = " << IToHex0N(base_address,10) <<
+ ", " <<
+ "Low = " << IToHex0N(lopc,10) <<
+ " (" << IToHex0N(llbuf->ld_lopc,10) <<
+ "), High = " << IToHex0N(hipc,10) <<
+ " (" << IToHex0N(llbuf->ld_hipc,10) <<
+ ")" << endl;
+ }
+ }
+ }
+ }
+ }
+ if (!dense && llbuf->ld_from_loclist) {
+ if (llent == 0) {
+ locstr.append("<loclist with ");
+ locstr.append(IToDec(no_of_elements));
+ locstr.append(" entries follows>");
+ }
+ locstr.append("\n\t\t\t");
+ locstr.append("[");
+ locstr.append(IToDec(llent,2));
+ locstr.append("]");
+ }
+ lres = dwarfdump_print_one_locdesc(dbg,
+ llbuf,
+ skip_locdesc_header,
+ locstr);
+ if (lres == DW_DLV_ERROR) {
+ return;
+ } else {
+ /* DW_DLV_OK so we add follow-on at end, else is
+ DW_DLV_NO_ENTRY (which is impossible, treat like
+ DW_DLV_OK). */
+ }
+ }
+ if (bError && check_verbose_mode) {
+ cout << endl;
+ }
+
+ for (i = 0; i < no_of_elements; ++i) {
+ dwarf_dealloc(dbg, llbufarray[i]->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(dbg, llbufarray[i], DW_DLA_LOCDESC);
+ }
+ dwarf_dealloc(dbg, llbufarray, DW_DLA_LIST);
+}
+
+/* We think this is an integer. Figure out how to print it.
+ In case the signedness is ambiguous (such as on
+ DW_FORM_data1 (ie, unknown signedness) print two ways.
+*/
+static int
+formxdata_print_value(Dwarf_Debug dbg,
+ Dwarf_Attribute attrib, string &str_out,
+ Dwarf_Error * err,
+ bool hexout)
+{
+ Dwarf_Signed tempsd = 0;
+ Dwarf_Unsigned tempud = 0;
+ Dwarf_Error serr = 0;
+ int ures = dwarf_formudata(attrib, &tempud, err);
+ int sres = dwarf_formsdata(attrib, &tempsd, &serr);
+
+ if(ures == DW_DLV_OK) {
+ if(sres == DW_DLV_OK) {
+ if(tempud == static_cast<Dwarf_Unsigned>(tempsd)
+ && tempsd >= 0) {
+ /* Data is the same value, and not negative
+ so makes no difference which we print. */
+ if(hexout) {
+ str_out.append(IToHex0N(tempud,10));
+ } else {
+ str_out.append(IToDec(tempud));
+ }
+ } else {
+ if(hexout) {
+ str_out.append(IToHex0N(tempud,10));
+ } else {
+ str_out.append(IToDec(tempud));
+ }
+ str_out.append("(as signed = ");
+ str_out.append(IToDec(tempsd));
+ str_out.append(")");
+ }
+ } else if (sres == DW_DLV_NO_ENTRY) {
+ if(hexout) {
+ str_out.append(IToHex0N(tempud,10));
+ } else {
+ str_out.append(IToDec(tempud));
+ }
+ } else /* DW_DLV_ERROR */{
+ if(hexout) {
+ str_out.append(IToHex0N(tempud,10));
+ } else {
+ str_out.append(IToDec(tempud));
+ }
+ }
+ goto cleanup;
+ } else {
+ /* ures == DW_DLV_ERROR */
+ if(sres == DW_DLV_OK) {
+ str_out.append(IToDec(tempsd));
+ } else {
+ /* Neither worked. */
+ }
+
+ }
+ cleanup:
+ if(sres == DW_DLV_OK || ures == DW_DLV_OK) {
+ if(sres == DW_DLV_ERROR) {
+ dwarf_dealloc(dbg,serr,DW_DLA_ERROR);
+ }
+ if(ures == DW_DLV_ERROR) {
+ dwarf_dealloc(dbg,*err,DW_DLA_ERROR);
+ *err = 0;
+ }
+ return DW_DLV_OK;
+ }
+ if(sres == DW_DLV_ERROR || ures == DW_DLV_ERROR) {
+ if(sres == DW_DLV_ERROR && ures == DW_DLV_ERROR) {
+ dwarf_dealloc(dbg,serr,DW_DLA_ERROR);
+ return DW_DLV_ERROR;
+ }
+ if(sres == DW_DLV_ERROR) {
+ *err = serr;
+ }
+ return DW_DLV_ERROR;
+ }
+ /* Both are DW_DLV_NO_ENTRY which is crazy, impossible. */
+ return DW_DLV_NO_ENTRY;
+}
+
+static void
+print_exprloc_content(Dwarf_Debug dbg,Dwarf_Die die,
+ Dwarf_Attribute attrib,
+ bool showhextoo, string &str_out)
+{
+ Dwarf_Ptr x = 0;
+ Dwarf_Unsigned tempud = 0;
+ char small_buf[80];
+ Dwarf_Error err = 0;
+ int wres = 0;
+ wres = dwarf_formexprloc(attrib,&tempud,&x,&err);
+ if(wres == DW_DLV_NO_ENTRY) {
+ /* Show nothing? Impossible. */
+ } else if(wres == DW_DLV_ERROR) {
+ print_error(dbg, "Cannot get a DW_FORM_exprbloc....", wres, err);
+ } else {
+ int ares = 0;
+ unsigned u = 0;
+ snprintf(small_buf, sizeof(small_buf),
+ "len 0x%04" DW_PR_DUx ": ",tempud);
+ str_out.append( small_buf);
+ if(showhextoo) {
+ for (u = 0; u < tempud; u++) {
+ snprintf(small_buf, sizeof(small_buf), "%02x",
+ *(u + (unsigned char *) x));
+ str_out.append(small_buf);
+ }
+ str_out.append(": ");
+ }
+ Dwarf_Half address_size = 0;
+ ares = dwarf_get_die_address_size(die,&address_size,&err);
+ if(wres == DW_DLV_NO_ENTRY) {
+ print_error(dbg,"Cannot get die address size for exprloc",
+ ares,err);
+ } else if(wres == DW_DLV_ERROR) {
+ print_error(dbg,"Cannot Get die address size for exprloc",
+ ares,err);
+ } else {
+ string v;
+ get_string_from_locs(dbg,x,tempud,address_size, v);
+ str_out.append(v);
+ }
+ }
+}
+
+
+/* Fill buffer with attribute value.
+ We pass in tag so we can try to do the right thing with
+ broken compiler DW_TAG_enumerator
+
+ We append to str_out. */
+void
+get_attr_value(Dwarf_Debug dbg, Dwarf_Half tag,
+ Dwarf_Die die, Dwarf_Attribute attrib,
+ SrcfilesHolder &hsrcfiles, string &str_out,
+ bool show_form,int local_verbose)
+{
+ Dwarf_Signed tempsd = 0;
+ Dwarf_Unsigned tempud = 0;
+ Dwarf_Half attr = 0;
+ Dwarf_Off off = 0;
+ Dwarf_Off goff = 0;
+ Dwarf_Die die_for_check = 0;
+ Dwarf_Half tag_for_check = 0;
+ Dwarf_Addr addr = 0;
+ int bres = DW_DLV_ERROR;
+ int wres = DW_DLV_ERROR;
+ int dres = DW_DLV_ERROR;
+ Dwarf_Half direct_form = 0;
+ Dwarf_Half theform = 0;
+ Dwarf_Bool is_info = true;
+
+ is_info=dwarf_get_die_infotypes_flag(die);
+ int fres = get_form_values(attrib,theform,direct_form);
+ if (fres == DW_DLV_ERROR) {
+ print_error(dbg, "dwarf_whatform cannot find attr form", fres,
+ err);
+ } else if (fres == DW_DLV_NO_ENTRY) {
+ return;
+ }
+
+ switch (theform) {
+ case DW_FORM_addr:
+ bres = dwarf_formaddr(attrib, &addr, &err);
+ if (bres == DW_DLV_OK) {
+ str_out.append(IToHex0N(addr,10));
+ } else {
+ print_error(dbg, "addr formwith no addr?!", bres, err);
+ }
+ break;
+ case DW_FORM_ref_addr:
+ /* DW_FORM_ref_addr is not accessed thru formref: ** it is an
+ address (global section offset) in ** the .debug_info
+ section. */
+ bres = dwarf_global_formref(attrib, &off, &err);
+ if (bres == DW_DLV_OK) {
+ str_out.append(BracketSurround(
+ string("global die offset ") +
+ IToHex0N(off,10)));
+ } else {
+ print_error(dbg,
+ "DW_FORM_ref_addr form with no reference?!",
+ bres, err);
+ }
+ wres = dwarf_whatattr(attrib, &attr, &err);
+ if (wres == DW_DLV_ERROR) {
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ } else {
+ if (attr == DW_AT_sibling) {
+ /* The value had better be inside the current CU
+ else there is a nasty error here, as a sibling
+ has to be in the same CU, it seems. */
+ Dwarf_Off cuoff = 0;
+ Dwarf_Off culen = 0;
+ DWARF_CHECK_COUNT(tag_tree_result,1);
+ int res = dwarf_die_CU_offset_range(die,&cuoff,
+ &culen,&err);
+ if(res != DW_DLV_OK) {
+ } else {
+ Dwarf_Off cuend = cuoff+culen;
+ if(off < cuoff || off >= cuend) {
+ DWARF_CHECK_ERROR(tag_tree_result,
+ "DW_AT_sibling DW_FORM_ref_addr offset points "
+ "outside of current CU");
+ }
+ }
+ }
+ }
+
+ break;
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ bres = dwarf_formref(attrib, &off, &err);
+ if (bres != DW_DLV_OK) {
+ /* Report incorrect offset */
+ string msg = "reference form with no valid local ref?!";
+ msg.append(", offset=");
+ msg.append(BracketSurround(IToHex0N(off,10)));
+ print_error(dbg, msg, bres, err);
+ }
+ /* Convert the local offset into a relative section offset */
+ if (show_global_offsets) {
+ bres = dwarf_convert_to_global_offset(attrib,
+ off, &goff, &err);
+ if (bres != DW_DLV_OK) {
+ /* Report incorrect offset */
+ string msg = "invalid offset";
+ msg.append(", global die offset=");
+ msg.append(BracketSurround(IToHex0N(goff,10)));
+ print_error(dbg, msg, bres, err);
+ }
+ }
+
+ /* Do references inside <> to distinguish them ** from
+ constants. In dense form this results in <<>>. Ugly for
+ dense form, but better than ambiguous. davea 9/94 */
+ if (show_global_offsets) {
+ str_out.append("<");
+ str_out.append(IToHex0N(off,10));
+ str_out.append(" GOFF=");
+ str_out.append(IToHex0N(goff,10));
+ str_out.append(">");
+ } else {
+ str_out.append(BracketSurround(IToHex0N(off,10)));
+ }
+ if (check_type_offset) {
+ wres = dwarf_whatattr(attrib, &attr, &err);
+ if (wres == DW_DLV_ERROR) {
+
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ }
+ if (attr == DW_AT_type) {
+ dres = dwarf_offdie_b(dbg, cu_offset + off,is_info,
+ &die_for_check, &err);
+ DWARF_CHECK_COUNT(type_offset_result,1);
+ if (dres != DW_DLV_OK) {
+ string msg("DW_AT_type offset does not point to a DIE");
+ msg.append(" for global offset ");
+ msg.append(IToHex(cu_offset + off));
+ msg.append(" cu off ");
+ msg.append(IToHex(cu_offset));
+ msg.append(" local offset ");
+ msg.append(IToHex( off));
+ DWARF_CHECK_ERROR(type_offset_result,msg);
+ } else {
+ int tres2;
+
+ tres2 =
+ dwarf_tag(die_for_check, &tag_for_check, &err);
+ if (tres2 == DW_DLV_OK) {
+ switch (tag_for_check) {
+ case DW_TAG_array_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_set_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_base_type:
+ case DW_TAG_const_type:
+ case DW_TAG_file_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_thrown_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ case DW_TAG_unspecified_type:
+ /* OK */
+ break;
+ default:
+ {
+ string msg("DW_AT_type offset does not point to Type info");
+ msg.append(" we got tag ");
+ msg.append(IToHex(tag_for_check));
+ msg.append(" ");
+ msg.append(get_TAG_name(tag_for_check,
+ dwarf_names_print_on_error));
+ DWARF_CHECK_ERROR(type_offset_result, msg);
+ }
+ break;
+ }
+ dwarf_dealloc(dbg, die_for_check, DW_DLA_DIE);
+ } else {
+ DWARF_CHECK_ERROR(type_offset_result,
+ "DW_AT_type offset does not exist");
+ }
+ }
+ }
+ }
+ break;
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ {
+ Dwarf_Block *tempb;
+ fres = dwarf_formblock(attrib, &tempb, &err);
+ if (fres == DW_DLV_OK) {
+ for (unsigned i = 0; i < tempb->bl_len; i++) {
+ str_out.append(IToHex02(
+ *(i + (unsigned char *) tempb->bl_data)));
+ }
+ dwarf_dealloc(dbg, tempb, DW_DLA_BLOCK);
+ } else {
+ print_error(dbg, "DW_FORM_blockn cannot get block\n", fres,
+ err);
+ }
+ }
+ break;
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ fres = dwarf_whatattr(attrib, &attr, &err);
+ if (fres == DW_DLV_ERROR) {
+ print_error(dbg, "FORM_datan cannot get attr", fres, err);
+ } else if (fres == DW_DLV_NO_ENTRY) {
+ print_error(dbg, "FORM_datan cannot get attr", fres, err);
+ } else {
+ switch (attr) {
+ case DW_AT_ordering:
+ case DW_AT_byte_size:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_inline:
+ case DW_AT_language:
+ case DW_AT_visibility:
+ case DW_AT_virtuality:
+ case DW_AT_accessibility:
+ case DW_AT_address_class:
+ case DW_AT_calling_convention:
+ case DW_AT_discr_list: /* DWARF3 */
+ case DW_AT_encoding:
+ case DW_AT_identifier_case:
+ case DW_AT_MIPS_loop_unroll_factor:
+ case DW_AT_MIPS_software_pipeline_depth:
+ case DW_AT_decl_column:
+ case DW_AT_decl_file:
+ case DW_AT_decl_line:
+ case DW_AT_call_column:
+ case DW_AT_call_file:
+ case DW_AT_call_line:
+ case DW_AT_start_scope:
+ case DW_AT_byte_stride:
+ case DW_AT_bit_stride:
+ case DW_AT_count:
+ case DW_AT_stmt_list:
+ case DW_AT_MIPS_fde:
+ {
+ string emptyattrname;
+ bool show_form_here = false;
+ wres = get_small_encoding_integer_and_name(dbg,
+ attrib,
+ &tempud,
+ emptyattrname,
+ /* err_string */ NULL,
+ (encoding_type_func) 0,
+ &err,show_form_here);
+ if (wres == DW_DLV_OK) {
+ str_out.append(IToHex0N(tempud,10));
+ if (attr == DW_AT_decl_file || attr == DW_AT_call_file) {
+ Dwarf_Unsigned srccount = hsrcfiles.count();
+ char **srcfiles = hsrcfiles.srcfiles();
+ if (srcfiles && tempud > 0 && tempud <= srccount) {
+ /* added by user request */
+ /* srcfiles is indexed starting at 0, but
+ DW_AT_decl_file defines that 0 means no
+ file, so tempud 1 means the 0th entry in
+ srcfiles, thus tempud-1 is the correct
+ index into srcfiles. */
+ string fname = srcfiles[tempud - 1];
+ str_out.append(" ");
+ str_out.append(fname);
+ }
+ /* Validate integrity of files
+ referenced in .debug_line */
+ if(check_decl_file) {
+ DWARF_CHECK_COUNT(decl_file_result,1);
+ /* Zero is always a legal index, it means
+ no source name provided. */
+ if(tempud != 0 && tempud > srccount) {
+ string msg;
+ if(!srcfiles) {
+ msg = "There is a file number=";
+ msg.append(IToDec(tempud));
+ msg.append(" but no source files are known.");
+ } else {
+ msg = "Does not point to valid file info ";
+ msg.append(" filenum=");
+ msg.append(IToDec(tempud));
+ msg.append(" filecount=");
+ msg.append(IToDec(srccount));
+ msg.append(".");
+ }
+ DWARF_CHECK_ERROR2(decl_file_result,
+ get_AT_name(attr,
+ dwarf_names_print_on_error),
+ msg);
+ }
+ }
+ }
+ } else {
+ print_error(dbg, "Cannot get encoding attribute ..",
+ wres, err);
+ }
+ }
+ break;
+ case DW_AT_const_value:
+ wres = formxdata_print_value(dbg,attrib,str_out, &err,
+ false);
+ if(wres == DW_DLV_OK){
+ /* String appended already. */
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ /* nothing? */
+ } else {
+ print_error(dbg,"Cannot get DW_AT_const_value ",wres,err);
+ }
+ break;
+ case DW_AT_upper_bound:
+ case DW_AT_lower_bound:
+ default:
+ wres = formxdata_print_value(dbg,attrib,str_out, &err,
+ (DW_AT_ranges == attr));
+ if (wres == DW_DLV_OK) {
+ /* String appended already. */
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ /* nothing? */
+ } else {
+ print_error(dbg, "Cannot get form data..", wres,
+ err);
+ }
+ break;
+ }
+ }
+ if (cu_name_flag) {
+ if (attr == DW_AT_MIPS_fde) {
+ if (fde_offset_for_cu_low == DW_DLV_BADOFFSET) {
+ fde_offset_for_cu_low
+ = fde_offset_for_cu_high = tempud;
+ } else if (tempud < fde_offset_for_cu_low) {
+ fde_offset_for_cu_low = tempud;
+ } else if (tempud > fde_offset_for_cu_high) {
+ fde_offset_for_cu_high = tempud;
+ }
+ }
+ }
+ break;
+ case DW_FORM_sdata:
+ wres = dwarf_formsdata(attrib, &tempsd, &err);
+ if (wres == DW_DLV_OK) {
+ str_out.append(IToHex0N(tempsd,10));
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ /* nothing? */
+ } else {
+ print_error(dbg, "Cannot get formsdata..", wres, err);
+ }
+ break;
+ case DW_FORM_udata:
+ wres = dwarf_formudata(attrib, &tempud, &err);
+ if (wres == DW_DLV_OK) {
+ str_out.append(IToHex0N(tempud,10));
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ /* nothing? */
+ } else {
+ print_error(dbg, "Cannot get formudata....", wres, err);
+ }
+ break;
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ { char *temps = 0;
+ wres = dwarf_formstring(attrib, &temps, &err);
+ if (wres == DW_DLV_OK) {
+ str_out.append("\"");
+ str_out.append(temps);
+ str_out.append("\"");
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ /* nothing? */
+ } else {
+ print_error(dbg, "Cannot get a formstr (or a formstrp)....",
+ wres, err);
+ }
+ }
+
+ break;
+ case DW_FORM_flag:
+ {
+ Dwarf_Bool tempbool;
+ wres = dwarf_formflag(attrib, &tempbool, &err);
+ if (wres == DW_DLV_OK) {
+ if (tempbool) {
+ str_out.append("yes(");
+ str_out.append(IToDec(tempbool));
+ str_out.append(")");
+ } else {
+ str_out.append("no");
+ }
+ } else if (wres == DW_DLV_NO_ENTRY) {
+ /* nothing? */
+ } else {
+ print_error(dbg, "Cannot get formflag/p....", wres, err);
+ }
+ }
+ break;
+ case DW_FORM_indirect:
+ /* We should not ever get here, since the true form was
+ determined and direct_form has the DW_FORM_indirect if it is
+ used here in this attr. */
+ str_out.append( get_FORM_name(theform,
+ dwarf_names_print_on_error));
+ break;
+ case DW_FORM_exprloc: { /* DWARF4 */
+ int showhextoo = true;
+ print_exprloc_content(dbg,die,attrib,showhextoo,str_out);
+ }
+ break;
+
+ case DW_FORM_sec_offset:{ /* DWARF4 */
+ string emptyattrname;
+ bool show_form_here = false;
+ wres = get_small_encoding_integer_and_name(dbg,
+ attrib,
+ &tempud,
+ emptyattrname,
+ /* err_string */ NULL,
+ (encoding_type_func) 0,
+ &err,show_form_here);
+ if(wres == DW_DLV_NO_ENTRY) {
+ /* Show nothing? */
+ } else if(wres == DW_DLV_ERROR) {
+ print_error(dbg,
+ "Cannot get a DW_FORM_sec_offset....",
+ wres, err);
+ } else {
+ str_out.append(IToHex0N(tempud,10));
+ }
+ }
+
+ break;
+ case DW_FORM_flag_present: /* DWARF4 */
+ str_out.append("yes(1)");
+ break;
+ case DW_FORM_ref_sig8: { /* DWARF4 */
+ Dwarf_Sig8 sig8data;
+ wres = dwarf_formsig8(attrib,&sig8data,&err);
+ if(wres != DW_DLV_OK) {
+ /* Show nothing? */
+ print_error(dbg,
+ "Cannot get a DW_FORM_ref_sig8 ....",
+ wres, err);
+ } else {
+ string sig8str;
+ format_sig8_string(&sig8data,sig8str);
+ str_out.append(sig8str);
+ }
+ }
+ break;
+ default:
+ print_error(dbg, "dwarf_whatform unexpected value", DW_DLV_OK,
+ err);
+ }
+ show_form_itself(show_form,local_verbose,theform, direct_form,&str_out);
+}
+
+void
+format_sig8_string(Dwarf_Sig8 *data,string &out)
+{
+ char small_buf[40];
+ out.append("0x");
+ for( unsigned i = 0; i < sizeof(data->signature); ++i) {
+ if (i == 4) {
+ out.append(" 0x");
+ }
+ snprintf(small_buf,sizeof(small_buf), "%02x",
+ (unsigned char)(data->signature[i]));
+ out.append(small_buf);
+ }
+}
+
+static int
+get_form_values(Dwarf_Attribute attrib,
+ Dwarf_Half & theform, Dwarf_Half & directform)
+{
+ Dwarf_Error err = 0;
+ int res = dwarf_whatform(attrib, &theform, &err);
+ dwarf_whatform_direct(attrib, &directform, &err);
+ return res;
+}
+static void
+show_form_itself(bool local_show_form,
+ int local_verbose,
+ int theform,
+ int directform, string *str_out)
+{
+ if ( local_show_form
+ && directform && directform == DW_FORM_indirect) {
+ str_out->append(" (used DW_FORM_indirect");
+ if(local_verbose) {
+ str_out->append(" ");
+ str_out->append(IToDec(DW_FORM_indirect));
+ }
+ str_out->append( ") ");
+ }
+ if(local_show_form) {
+ str_out->append(" <form ");
+ str_out->append(get_FORM_name(theform,
+ dwarf_names_print_on_error));
+ if(local_verbose) {
+ str_out->append(" ");
+ str_out->append(IToDec(theform));
+ }
+ str_out->append(">");
+ }
+}
+
+
+#include "tmp-ta-table.cc"
+#include "tmp-ta-ext-table.cc"
+
+static int
+legal_tag_attr_combination(Dwarf_Half tag, Dwarf_Half attr)
+{
+ if(tag <= 0) {
+ return false;
+ }
+ if(tag < ATTR_TREE_ROW_COUNT) {
+ int index = attr / BITS_PER_WORD;
+ if ( index < ATTR_TREE_COLUMN_COUNT) {
+ unsigned bitflag = 1 << (attr % BITS_PER_WORD);
+ int known = (
+ (tag_attr_combination_table[tag][index] & bitflag)
+ > 0 ? true : false);
+ if(known) {
+ return true;
+ }
+ }
+ }
+ /* DW_AT_MIPS_fde used to return true as that was
+ convenient for SGI/MIPS users. */
+ if(!suppress_check_extensions_tables) {
+ int r = 0;
+ for ( ; r < ATTR_TREE_EXT_ROW_COUNT; ++r ) {
+ int c = 1;
+ if(tag != tag_attr_combination_ext_table[r][0]) {
+ continue;
+ }
+ for( ; c < ATTR_TREE_EXT_COLUMN_COUNT ; ++c) {
+ if (tag_attr_combination_ext_table[r][c] == attr) {
+ return true;
+ }
+ }
+ }
+ }
+ return (false);
+}
+#include "tmp-tt-table.cc"
+#include "tmp-tt-ext-table.cc"
+
+/* Look only at valid table entries
+ The check here must match the building-logic in
+ tag_tree.cc
+ And must match the tags defined in dwarf.h
+ The tag_tree_combination_table is a table of bit flags. */
+static bool
+legal_tag_tree_combination(Dwarf_Half tag_parent, Dwarf_Half tag_child)
+{
+ if(tag_parent <= 0) {
+ return false;
+ }
+ if ( tag_parent < TAG_TREE_ROW_COUNT) {
+ int index = tag_child / BITS_PER_WORD;
+ if ( index < TAG_TREE_COLUMN_COUNT) {
+ unsigned bitflag = 1 << (tag_child % BITS_PER_WORD);
+ int known = (
+ (tag_tree_combination_table[tag_parent] [index] & bitflag)
+ > 0 ? true : false);
+ if(known) {
+ return true;
+ }
+ }
+ }
+ if(!suppress_check_extensions_tables) {
+ int r = 0;
+ for ( ; r < TAG_TREE_EXT_ROW_COUNT; ++r ) {
+ int c = 1;
+ if(tag_parent != tag_tree_combination_ext_table[r][0]) {
+ continue;
+ }
+ for( ; c < TAG_TREE_EXT_COLUMN_COUNT ; ++c) {
+ if (tag_tree_combination_ext_table[r][c] == tag_child) {
+ return true;
+ }
+ }
+ }
+ }
+ return (false);
+}
+
+