summaryrefslogtreecommitdiff
path: root/dwarfdump/dwarfdump.c
diff options
context:
space:
mode:
Diffstat (limited to 'dwarfdump/dwarfdump.c')
-rw-r--r--dwarfdump/dwarfdump.c2357
1 files changed, 2357 insertions, 0 deletions
diff --git a/dwarfdump/dwarfdump.c b/dwarfdump/dwarfdump.c
new file mode 100644
index 0000000..f8bc309
--- /dev/null
+++ b/dwarfdump/dwarfdump.c
@@ -0,0 +1,2357 @@
+/*
+ Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. 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/dwarfdump.c,v 1.48 2006/04/18 18:05:57 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"
+/* for 'open' */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h> /* For getopt */
+#include "makename.h"
+#include "dwconf.h"
+#include "common.h"
+#include "esb.h" /* For flexible string buffer. */
+
+#ifdef WIN32
+extern int elf_open(char *name,int mode);
+#endif
+
+#define DWARFDUMP_VERSION " Tue Apr 10 11:43:32 PDT 2012 "
+
+extern char *optarg;
+
+
+#define OKAY 0
+#define BYTES_PER_INSTRUCTION 4
+
+static const char* process_args(int argc, char *argv[]);
+
+char * program_name;
+static int check_error = 0;
+
+/* The type of Bucket. */
+#define KIND_RANGES_INFO 1
+#define KIND_SECTIONS_INFO 2
+#define KIND_VISITED_INFO 3
+
+/* pRangesInfo records the DW_AT_high_pc and DW_AT_low_pc
+ and is used to check that line range info falls inside
+ the known valid ranges. The data is per CU, and is
+ reset per CU in tag_specific_checks_setup(). */
+Bucket_Group *pRangesInfo = NULL;
+
+/* pLinkonceInfo records data about the link once sections.
+ If a line range is not valid in the current CU it might
+ be valid in a linkonce section, this data records the
+ linkonce sections. So it is filled in when an
+ object file is read and remains unchanged for an entire
+ object file. */
+Bucket_Group *pLinkonceInfo = NULL;
+/* pVisitedInfo records a recursive traversal of DIE attributes
+ DW_AT_specification DW_AT_abstract_origin DW_AT_type
+ that let DWARF refer (as in a general graph) to
+ arbitrary other DIEs.
+ These traversals use pVisitedInfo to
+ detect any compiler errors that introduce circular references.
+ Printing of the traversals is also done on request.
+ Entries are added and deleted as they are visited in
+ a depth-first traversal. */
+Bucket_Group *pVisitedInfo = NULL;
+
+/* Options to enable debug tracing */
+int nTrace[MAX_TRACE_LEVEL + 1];
+
+/* Build section information */
+void build_linkonce_info(Dwarf_Debug dbg);
+static const char * do_uri_translation(const char *s,
+ const char *context);
+static void reset_overall_CU_error_data();
+
+boolean info_flag = FALSE;
+boolean use_old_dwarf_loclist = FALSE; /* This so both dwarf_loclist()
+ and dwarf_loclist_n() can be
+ tested. Defaults to new
+ dwarf_loclist_n() */
+
+boolean line_flag = FALSE;
+static boolean abbrev_flag = FALSE;
+static boolean frame_flag = FALSE; /* .debug_frame section. */
+static boolean eh_frame_flag = FALSE; /* GNU .eh_frame section. */
+static boolean pubnames_flag = FALSE;
+static boolean macinfo_flag = FALSE;
+static boolean loc_flag = FALSE;
+static boolean aranges_flag = FALSE; /* .debug_aranges section. */
+static boolean ranges_flag = FALSE; /* .debug_ranges section. */
+static boolean string_flag = FALSE;
+static boolean reloc_flag = FALSE;
+static boolean static_func_flag = FALSE;
+static boolean static_var_flag = FALSE;
+static boolean type_flag = FALSE;
+static boolean weakname_flag = FALSE;
+static boolean header_flag = FALSE; /* Control printing of Elf header. */
+boolean producer_children_flag = FALSE; /* List of CUs per compiler */
+
+/* Bitmap for relocations. See globals.h for DW_SECTION_REL_DEBUG_RANGES etc.*/
+static unsigned reloc_map = 0;
+
+/* Start verbose at zero. verbose can
+ be incremented with -v but not decremented. */
+int verbose = 0;
+
+boolean dense = FALSE;
+boolean ellipsis = FALSE;
+boolean show_global_offsets = FALSE; /* Show global and relative offsets */
+boolean show_form_used = FALSE;
+boolean display_offsets = TRUE; /* Emit offsets */
+
+boolean check_abbrev_code = FALSE;
+boolean check_pubname_attr = FALSE;
+boolean check_reloc_offset = FALSE;
+boolean check_attr_tag = FALSE;
+boolean check_tag_tree = FALSE;
+boolean check_type_offset = FALSE;
+boolean check_decl_file = FALSE;
+boolean check_lines = FALSE;
+boolean check_fdes = FALSE;
+boolean check_ranges = FALSE;
+boolean check_aranges = FALSE;
+boolean check_harmless = FALSE;
+boolean check_abbreviations = FALSE;
+boolean check_dwarf_constants = FALSE;
+boolean check_di_gaps = FALSE;
+boolean check_forward_decl = FALSE;
+boolean check_self_references = FALSE;
+boolean generic_1200_regs = FALSE;
+boolean suppress_check_extensions_tables = FALSE;
+
+/* suppress_nested_name_search is a band-aid.
+ A workaround. A real fix for N**2 behavior is needed.
+*/
+boolean suppress_nested_name_search = FALSE;
+static boolean uri_options_translation = TRUE;
+static boolean do_print_uri_in_input = TRUE;
+
+
+/* break_after_n_units is mainly for testing.
+ It enables easy limiting of output size/running time
+ when one wants the output limited.
+ For example,
+ -H 2
+ limits the -i output to 2 compilation units and
+ the -f or -F output to 2 FDEs and 2 CIEs.
+*/
+int break_after_n_units = INT_MAX;
+
+boolean check_names = FALSE;
+boolean check_verbose_mode = TRUE; /* During '-k' mode, display errors */
+boolean check_frames = FALSE;
+boolean check_frames_extended = FALSE; /* Extensive frames check */
+boolean check_locations = FALSE; /* Location list check */
+
+static boolean check_all_compilers = TRUE;
+static boolean check_snc_compiler = FALSE; /* Check SNC compiler */
+static boolean check_gcc_compiler = FALSE;
+static boolean print_summary_all = FALSE;
+
+#define COMPILER_TABLE_MAX 100
+typedef struct anc {
+ struct anc *next;
+ char *item;
+} a_name_chain;
+
+/* Records information about compilers (producers) found in the
+ debug information, including the check results for several
+ categories (see -k option). */
+typedef struct {
+ const char *name;
+ boolean verified;
+ a_name_chain *cu_list;
+ a_name_chain *cu_last;
+ Dwarf_Check_Result results[LAST_CATEGORY];
+} Compiler;
+
+/* Record compilers whose CU names have been seen.
+ Full CU names recorded here, though only a portion
+ of the name may have been checked to cause the
+ compiler data to be entered here.
+ The +1 guarantees we do not overstep the array.
+*/
+static Compiler compilers_detected[COMPILER_TABLE_MAX];
+static int compilers_detected_count = 0;
+
+/* compilers_targeted is a list of indications of compilers
+ on which we wish error checking (and the counts
+ of checks made and errors found). We do substring
+ comparisons, so the compilers_targeted name might be simply a
+ compiler version number or a short substring of a
+ CU producer name.
+ The +1 guarantees we do not overstep the array.
+*/
+static Compiler compilers_targeted[COMPILER_TABLE_MAX];
+static int compilers_targeted_count = 0;
+static int current_compiler = -1;
+
+static void reset_compiler_entry(Compiler *compiler);
+static void PRINT_CHECK_RESULT(char *str,
+ Compiler *pCompiler, Dwarf_Check_Categories category);
+
+
+/* The check and print flags here make it easy to
+ allow check-only or print-only. We no longer support
+ check-and-print in a single run. */
+boolean do_check_dwarf = FALSE;
+boolean do_print_dwarf = FALSE;
+boolean check_show_results = FALSE; /* Display checks results. */
+boolean record_dwarf_error = FALSE; /* A test has failed, this
+ is normally set FALSE shortly after being set TRUE, it is
+ a short-range hint we should print something we might not
+ otherwise print (under the circumstances). */
+
+
+/* These names make diagnostic messages more complete, the
+ fixed length is safe, though ultra long names will get
+ truncated. */
+char PU_name[COMPILE_UNIT_NAME_LEN];
+char CU_name[COMPILE_UNIT_NAME_LEN];
+char CU_producer[COMPILE_UNIT_NAME_LEN];
+
+boolean seen_PU = FALSE; /* Detected a PU */
+boolean seen_CU = FALSE; /* Detected a CU */
+boolean need_CU_name = TRUE; /* Need CU name */
+boolean need_CU_base_address = TRUE; /* Need CU Base address */
+boolean need_CU_high_address = TRUE; /* Need CU High address */
+boolean need_PU_valid_code = TRUE; /* Need PU valid code */
+
+boolean seen_PU_base_address = FALSE; /* Detected a Base address for PU */
+boolean seen_PU_high_address = FALSE; /* Detected a High address for PU */
+Dwarf_Addr PU_base_address = 0; /* PU Base address */
+Dwarf_Addr PU_high_address = 0; /* PU High address */
+
+Dwarf_Off DIE_offset = 0; /* DIE offset in compile unit */
+Dwarf_Off DIE_overall_offset = 0; /* DIE offset in .debug_info */
+
+/* These globals enable better error reporting. */
+Dwarf_Off DIE_CU_offset = 0; /* CU DIE offset in compile unit */
+Dwarf_Off DIE_CU_overall_offset = 0; /* CU DIE offset in .debug_info */
+int current_section_id = 0; /* Section being process */
+
+Dwarf_Addr CU_base_address = 0; /* CU Base address */
+Dwarf_Addr CU_high_address = 0; /* CU High address */
+
+Dwarf_Addr elf_max_address = 0; /* Largest representable address offset */
+Dwarf_Half elf_address_size = 0; /* Target pointer size */
+
+/* Display parent/children when in wide format? */
+boolean display_parent_tree = FALSE;
+boolean display_children_tree = FALSE;
+int stop_indent_level = 0;
+
+/* Print search results in wide format? */
+boolean search_wide_format = FALSE;
+/* -S option: strings for 'any' and 'match' */
+boolean search_is_on = FALSE;
+const char *search_any_text = 0;
+const char *search_match_text = 0;
+const char *search_regex_text = 0;
+#ifdef HAVE_REGEX
+/* -S option: the compiled_regex */
+regex_t search_re;
+#endif
+
+
+/* These configure items are for the
+ frame data. We're pretty flexible in
+ the path to dwarfdump.conf .
+*/
+static const char *config_file_path = 0;
+static const char *config_file_abi = 0;
+static char *config_file_defaults[] = {
+ "dwarfdump.conf",
+ "./dwarfdump.conf",
+ "HOME/.dwarfdump.conf",
+ "HOME/dwarfdump.conf",
+#ifdef CONFPREFIX
+/* See Makefile.in "libdir" and CFLAGS */
+/* We need 2 levels of macro to get the name turned into
+ the string we want. */
+#define STR2(s) # s
+#define STR(s) STR2(s)
+ STR(CONFPREFIX)
+ "/dwarfdump.conf",
+#else
+ "/usr/lib/dwarfdump.conf",
+#endif
+ 0
+};
+static struct dwconf_s config_file_data;
+
+char cu_name[BUFSIZ];
+boolean cu_name_flag = FALSE;
+Dwarf_Unsigned cu_offset = 0;
+
+Dwarf_Error err;
+
+static void suppress_check_dwarf()
+{
+ do_print_dwarf = TRUE;
+ if(do_check_dwarf) {
+ fprintf(stderr,"Warning: check flag turned off, "
+ "checking and printing are separate.\n");
+ }
+ do_check_dwarf = FALSE;
+}
+static void suppress_print_dwarf()
+{
+ do_print_dwarf = FALSE;
+ do_check_dwarf = TRUE;
+}
+
+static int process_one_file(Elf * elf, const char * file_name, int archive,
+ struct dwconf_s *conf);
+static int
+open_a_file(const char * name)
+{
+ /* Set to a file number that cannot be legal. */
+ int f = -1;
+
+#if defined(__CYGWIN__) || defined(WIN32)
+ /* It is not possible to share file handles
+ between applications or DLLs. Each application has its own
+ file-handle table. For two applications to use the same file
+ using a DLL, they must both open the file individually.
+ Let the 'libelf' dll to open and close the file. */
+
+ /* For WIN32 open the file as binary */
+ f = elf_open(name, O_RDONLY | O_BINARY);
+#else
+ f = open(name, O_RDONLY);
+#endif
+ return f;
+
+}
+static void
+close_a_file(int f)
+{
+ close(f);
+}
+
+/*
+ Iterate through dwarf and print all info.
+*/
+int
+main(int argc, char *argv[])
+{
+ const char * file_name = 0;
+ int f = 0;
+ Elf_Cmd cmd = 0;
+ Elf *arf = 0;
+ Elf *elf = 0;
+ int archive = 0;
+
+#ifdef WIN32
+ /* Windows specific. */
+ /* Redirect stderr to stdout. */
+ /* Tried to use SetStdHandle, but it does not work properly. */
+ //BOOL bbb = SetStdHandle(STD_ERROR_HANDLE,GetStdHandle(STD_OUTPUT_HANDLE));
+ //_iob[2]._file = _iob[1]._file;
+ stderr->_file = stdout->_file;
+#endif /* WIN32 */
+
+ print_version_details(argv[0],FALSE);
+
+ (void) elf_version(EV_NONE);
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ (void) fprintf(stderr, "dwarfdump: libelf.a out of date.\n");
+ exit(1);
+ }
+
+ file_name = process_args(argc, argv);
+
+ /* Because LibDwarf now generates some new warnings,
+ allow the user to hide them by using command line options */
+ {
+ Dwarf_Cmdline_Options cmd;
+ cmd.check_verbose_mode = check_verbose_mode;
+ dwarf_record_cmdline_options(cmd);
+ }
+ print_args(argc,argv);
+ f = open_a_file(file_name);
+ if (f == -1) {
+ fprintf(stderr, "%s ERROR: can't open %s\n", program_name,
+ file_name);
+ return (FAILED);
+ }
+
+ cmd = ELF_C_READ;
+ arf = elf_begin(f, cmd, (Elf *) 0);
+ if (elf_kind(arf) == ELF_K_AR) {
+ archive = 1;
+ }
+
+ /* If we are checking .debug_line, .debug_ranges, .debug_aranges,
+ or .debug_loc build the tables containing
+ the pairs LowPC and HighPC. It is safer (and not
+ expensive) to build all
+ of these at once so mistakes in options do not lead
+ to coredumps (like -ka -p did once). */
+ if (check_decl_file || check_ranges || check_locations ||
+ do_check_dwarf || check_self_references) {
+ pRangesInfo = AllocateBucketGroup(KIND_RANGES_INFO);
+ pLinkonceInfo = AllocateBucketGroup(KIND_SECTIONS_INFO);
+ pVisitedInfo = AllocateBucketGroup(KIND_VISITED_INFO);
+ }
+
+ while ((elf = elf_begin(f, cmd, arf)) != 0) {
+ Elf32_Ehdr *eh32;
+
+#ifdef HAVE_ELF64_GETEHDR
+ Elf64_Ehdr *eh64;
+#endif /* HAVE_ELF64_GETEHDR */
+ eh32 = elf32_getehdr(elf);
+ if (!eh32) {
+#ifdef HAVE_ELF64_GETEHDR
+ /* not a 32-bit obj */
+ eh64 = elf64_getehdr(elf);
+ if (!eh64) {
+ /* not a 64-bit obj either! */
+ /* dwarfdump is almost-quiet when not an object */
+ fprintf(stderr, "Can't process %s: unknown format\n",file_name);
+ check_error = 1;
+ } else {
+ process_one_file(elf, file_name, archive,
+ &config_file_data);
+ }
+#endif /* HAVE_ELF64_GETEHDR */
+ } else {
+ process_one_file(elf, file_name, archive,
+ &config_file_data);
+ }
+ cmd = elf_next(elf);
+ elf_end(elf);
+ }
+ elf_end(arf);
+ /* Trivial malloc space cleanup. */
+ clean_up_die_esb();
+ clean_up_syms_malloc_data();
+
+ if(pRangesInfo) {
+ ReleaseBucketGroup(pRangesInfo);
+ pRangesInfo = 0;
+ }
+
+ if(pLinkonceInfo) {
+ ReleaseBucketGroup(pLinkonceInfo);
+ pLinkonceInfo = 0;
+ }
+
+ if(pVisitedInfo) {
+ ReleaseBucketGroup(pVisitedInfo);
+ pVisitedInfo = 0;
+ }
+
+#ifdef HAVE_REGEX
+ if(search_regex_text) {
+ regfree(&search_re);
+ }
+#endif
+ close_a_file(f);
+ if (check_error)
+ return FAILED;
+ else
+ return OKAY;
+}
+
+void
+print_any_harmless_errors(Dwarf_Debug dbg)
+{
+#define LOCAL_PTR_ARY_COUNT 50
+ /* We do not need to initialize the local array,
+ libdwarf does it. */
+ const char *buf[LOCAL_PTR_ARY_COUNT];
+ unsigned totalcount = 0;
+ unsigned i = 0;
+ unsigned printcount = 0;
+ int res = dwarf_get_harmless_error_list(dbg,LOCAL_PTR_ARY_COUNT,buf,
+ &totalcount);
+ if(res == DW_DLV_NO_ENTRY) {
+ return;
+ }
+ if(totalcount > 0) {
+ printf("\n*** HARMLESS ERROR COUNT: %u ***\n",totalcount);
+ }
+ for(i = 0 ; buf[i]; ++i) {
+ ++printcount;
+ DWARF_CHECK_COUNT(harmless_result,1);
+ DWARF_CHECK_ERROR(harmless_result,buf[i]);
+ }
+ if(totalcount > printcount) {
+ //harmless_result.checks += (totalcount - printcount);
+ DWARF_CHECK_COUNT(harmless_result,(totalcount - printcount));
+ //harmless_result.errors += (totalcount - printcount);
+ DWARF_ERROR_COUNT(harmless_result,(totalcount - printcount));
+ }
+}
+
+static void
+print_object_header(Elf *elf,Dwarf_Debug dbg)
+{
+#ifdef WIN32
+ /* Standard libelf has no function generating the names of the
+ encodings, but this libelf apparently does. */
+ Elf_Ehdr_Literal eh_literals;
+ Elf32_Ehdr *eh32;
+#ifdef HAVE_ELF64_GETEHDR
+ Elf64_Ehdr *eh64;
+#endif /* HAVE_ELF64_GETEHDR */
+
+ eh32 = elf32_getehdr(elf);
+ if (eh32) {
+ /* Get literal strings for header fields */
+ elf32_gethdr_literals(eh32,&eh_literals);
+ /* Print 32-bit obj header */
+ printf("\nObject Header:\ne_ident:\n");
+ printf(" File ID = %s\n",eh_literals.e_ident_file_id);
+ printf(" File class = %02x (%s)\n",
+ eh32->e_ident[EI_CLASS], eh_literals.e_ident_file_class);
+ printf(" Data encoding = %02x (%s)\n",
+ eh32->e_ident[EI_DATA], eh_literals.e_ident_data_encoding);
+ printf(" File version = %02x (%s)\n",
+ eh32->e_ident[EI_VERSION], eh_literals.e_ident_file_version);
+ printf(" OS ABI = %02x (%s) (%s)\n", eh32->e_ident[EI_OSABI],
+ eh_literals.e_ident_os_abi_s, eh_literals.e_ident_os_abi_l);
+ //printf(" ABI version = %02x (%s)\n",
+ // eh32->e_ident[EI_ABIVERSION], eh_literals.e_ident_abi_version);
+ printf("e_type : 0x%x (%s)\n",
+ eh32->e_type, eh_literals.e_type);
+ printf("e_machine: 0x%x (%s) (%s)\n", eh32->e_machine,
+ eh_literals.e_machine_s, eh_literals.e_machine_l);
+ printf("e_version: 0x%x\n", eh32->e_version);
+ //printf("e_entry = 0x%I64x\n", eh32->e_entry);
+ printf("e_flags : 0x%x\n", eh32->e_flags);
+ printf("e_phnum : 0x%x\n", eh32->e_phnum);
+ printf("e_shnum : 0x%x\n", eh32->e_shnum);
+ }
+ else {
+#ifdef HAVE_ELF64_GETEHDR
+ /* not a 32-bit obj */
+ eh64 = elf64_getehdr(elf);
+ if (eh64) {
+ /* Get literal strings for header fields */
+ elf64_gethdr_literals(eh64,&eh_literals);
+ /* Print 64-bit obj header */
+ printf("\nObject Header:\ne_ident:\n");
+ printf(" File ID = %s\n",eh_literals.e_ident_file_id);
+ printf(" File class = %02x (%s)\n",
+ eh64->e_ident[EI_CLASS], eh_literals.e_ident_file_class);
+ printf(" Data encoding = %02x (%s)\n",
+ eh64->e_ident[EI_DATA], eh_literals.e_ident_data_encoding);
+ printf(" File version = %02x (%s)\n",
+ eh64->e_ident[EI_VERSION], eh_literals.e_ident_file_version);
+ printf(" OS ABI = %02x (%s) (%s)\n", eh64->e_ident[EI_OSABI],
+ eh_literals.e_ident_os_abi_s, eh_literals.e_ident_os_abi_l);
+ //printf(" ABI version = %02x (%s)\n",
+ // eh64->e_ident[EI_ABIVERSION], eh_literals.e_ident_abi_version);
+ printf("e_type : 0x%x (%s)\n",
+ eh64->e_type, eh_literals.e_type);
+ printf("e_machine: 0x%x (%s) (%s)\n", eh64->e_machine,
+ eh_literals.e_machine_s, eh_literals.e_machine_l);
+ printf("e_version: 0x%x\n", eh64->e_version);
+ //printf("e_entry = 0x%I64x\n", eh64->e_entry);
+ printf("e_flags : 0x%x\n", eh64->e_flags);
+ printf("e_phnum : 0x%x\n", eh64->e_phnum);
+ printf("e_shnum : 0x%x\n", eh64->e_shnum);
+ }
+#endif /* HAVE_ELF64_GETEHDR */
+ }
+#endif /* WIN32 */
+}
+
+/* Print checks and errors for a specific compiler */
+static void
+print_specific_checks_results(Compiler *pCompiler)
+{
+ fprintf(stderr, "\nDWARF CHECK RESULT\n");
+ fprintf(stderr, "<item> <checks> <errors>\n");
+ if (check_pubname_attr) {
+ PRINT_CHECK_RESULT("pubname_attr", pCompiler, pubname_attr_result);
+ }
+ if (check_attr_tag) {
+ PRINT_CHECK_RESULT("attr_tag", pCompiler, attr_tag_result);
+ }
+ if (check_tag_tree) {
+ PRINT_CHECK_RESULT("tag_tree", pCompiler, tag_tree_result);
+ }
+ if (check_type_offset) {
+ PRINT_CHECK_RESULT("type_offset", pCompiler, type_offset_result);
+ }
+ if (check_decl_file) {
+ PRINT_CHECK_RESULT("decl_file", pCompiler, decl_file_result);
+ }
+ if (check_ranges) {
+ PRINT_CHECK_RESULT("ranges", pCompiler, ranges_result);
+ }
+ if (check_lines) {
+ PRINT_CHECK_RESULT("line_table", pCompiler, lines_result);
+ }
+ if (check_fdes) {
+ PRINT_CHECK_RESULT("fde table", pCompiler, fde_duplication);
+ }
+ if (check_aranges) {
+ PRINT_CHECK_RESULT("aranges", pCompiler, aranges_result);
+ }
+
+ if (check_names) {
+ PRINT_CHECK_RESULT("names",pCompiler, names_result);
+ }
+ if (check_frames) {
+ PRINT_CHECK_RESULT("frames",pCompiler, frames_result);
+ }
+ if (check_locations) {
+ PRINT_CHECK_RESULT("locations",pCompiler, locations_result);
+ }
+
+ if(check_harmless) {
+ PRINT_CHECK_RESULT("harmless_errors", pCompiler, harmless_result);
+ }
+
+ if (check_abbreviations) {
+ PRINT_CHECK_RESULT("abbreviations", pCompiler, abbreviations_result);
+ }
+
+ if (check_dwarf_constants) {
+ PRINT_CHECK_RESULT("dwarf_constants",
+ pCompiler, dwarf_constants_result);
+ }
+
+ if (check_di_gaps) {
+ PRINT_CHECK_RESULT("debug_info_gaps", pCompiler, di_gaps_result);
+ }
+
+ if (check_forward_decl) {
+ PRINT_CHECK_RESULT("forward_declarations",
+ pCompiler, forward_decl_result);
+ }
+
+ if (check_self_references) {
+ PRINT_CHECK_RESULT("self_references",
+ pCompiler, self_references_result);
+ }
+
+ PRINT_CHECK_RESULT("** Summarize **",pCompiler, total_check_result);
+}
+
+static int
+qsort_compare_compiler(const void *elem1,const void *elem2)
+{
+ Compiler cmp1 = *(Compiler *)elem1;
+ Compiler cmp2 = *(Compiler *)elem2;
+ int cnt1 = cmp1.results[total_check_result].errors;
+ int cnt2 = cmp2.results[total_check_result].errors;
+ int sc = 0;
+
+ if (cnt1 < cnt2) {
+ return 1;
+ } else if (cnt1 > cnt2) {
+ return -1;
+ }
+ /* When error counts match, sort on name. */
+ sc = strcmp(cmp2.name,cmp1.name);
+ return sc;
+}
+
+/* Print a summary of checks and errors */
+static void
+print_checks_results()
+{
+ int index = 0;
+ Compiler *pCompilers;
+ Compiler *pCompiler;
+
+ fflush(stdout);
+
+ /* Sort based on errors detected; the first entry is reserved */
+ pCompilers = &compilers_detected[1];
+ qsort((void *)pCompilers, compilers_detected_count,
+ sizeof(Compiler),qsort_compare_compiler);
+
+ /* Print list of CUs for each compiler detected */
+ if (producer_children_flag) {
+
+ a_name_chain *nc = 0;
+ a_name_chain *nc_next = 0;
+ int count = 0;
+ int total = 0;
+
+ fprintf(stderr,"\n*** CU NAMES PER COMPILER ***\n");
+ for (index = 1; index <= compilers_detected_count; ++index) {
+ pCompiler = &compilers_detected[index];
+ fprintf(stderr,"\n%02d: %s\n",index,pCompiler->name);
+ count = 0;
+ for (nc = pCompiler->cu_list; nc; nc = nc_next) {
+ fprintf(stderr,"\n %02d: '%s'",++count,nc->item);
+ nc_next = nc->next;
+ free(nc);
+ }
+ total += count;
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"\nDetected %d CU names\n",total);
+ }
+
+ /* Print error report only if errors have been detected */
+ /* Print error report if the -kd option */
+ if ((do_check_dwarf && check_error) || check_show_results) {
+ int count = 0;
+ int compilers_not_detected = 0;
+ int compilers_verified = 0;
+
+ /* Find out how many compilers have been verified. */
+ for (index = 1; index <= compilers_detected_count; ++index) {
+ if (compilers_detected[index].verified) {
+ ++compilers_verified;
+ }
+ }
+ /* Find out how many compilers have been not detected. */
+ for (index = 1; index <= compilers_targeted_count; ++index) {
+ if (!compilers_targeted[index].verified) {
+ ++compilers_not_detected;
+ }
+ }
+
+ /* Print compilers detected list */
+ fprintf(stderr,
+ "\n%d Compilers detected:\n",compilers_detected_count);
+ for (index = 1; index <= compilers_detected_count; ++index) {
+ pCompiler = &compilers_detected[index];
+ fprintf(stderr,"%02d: %s\n",index,pCompiler->name);
+ }
+
+ /* Print compiler list specified by the user with the
+ '-c<str>', that were not detected. */
+ if (compilers_not_detected) {
+ count = 0;
+ fprintf(stderr,
+ "\n%d Compilers not detected:\n",compilers_not_detected);
+ for (index = 1; index <= compilers_targeted_count; ++index) {
+ if (!compilers_targeted[index].verified) {
+ fprintf(stderr,
+ "%02d: '%s'\n",
+ ++count,compilers_targeted[index].name);
+ }
+ }
+ }
+
+ count = 0;
+ fprintf(stderr,"\n%d Compilers verified:\n",compilers_verified);
+ for (index = 1; index <= compilers_detected_count; ++index) {
+ pCompiler = &compilers_detected[index];
+ if (pCompiler->verified) {
+ fprintf(stderr,"%02d: errors = %5d, %s\n",
+ ++count,
+ pCompiler->results[total_check_result].errors,
+ pCompiler->name);
+ }
+ }
+
+ /* Print summary if we have verified compilers or
+ if the -kd option used. */
+ if (compilers_verified || check_show_results) {
+ /* Print compilers detected summary*/
+ if (print_summary_all) {
+ count = 0;
+ fprintf(stderr,"\n*** ERRORS PER COMPILER ***\n");
+ for (index = 1; index <= compilers_detected_count; ++index) {
+ pCompiler = &compilers_detected[index];
+ if (pCompiler->verified) {
+ fprintf(stderr,"%02d: %s\n",
+ ++count,pCompiler->name);
+ print_specific_checks_results(pCompiler);
+ }
+ }
+ }
+
+ /* Print general summary (all compilers checked) */
+ fprintf(stderr,"\n*** TOTAL ERRORS FOR ALL COMPILERS ***\n");
+ print_specific_checks_results(&compilers_detected[0]);
+ }
+ }
+}
+
+/*
+ Given a file which we know is an elf file, process
+ the dwarf data.
+
+*/
+static int
+process_one_file(Elf * elf, const char * file_name, int archive,
+ struct dwconf_s *config_file_data)
+{
+ Dwarf_Debug dbg;
+ int dres;
+
+ dres = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &err);
+ if (dres == DW_DLV_NO_ENTRY) {
+ printf("No DWARF information present in %s\n", file_name);
+ return 0;
+ }
+ if (dres != DW_DLV_OK) {
+ print_error(dbg, "dwarf_elf_init", dres, err);
+ }
+
+ if (archive) {
+ Elf_Arhdr *mem_header = elf_getarhdr(elf);
+
+ printf("\narchive member \t%s\n",
+ mem_header ? mem_header->ar_name : "");
+ }
+ dwarf_set_frame_rule_initial_value(dbg,
+ config_file_data->cf_initial_rule_value);
+ dwarf_set_frame_rule_table_size(dbg,
+ config_file_data->cf_table_entry_count);
+ dwarf_set_frame_cfa_value(dbg,
+ config_file_data->cf_cfa_reg);
+ dwarf_set_frame_same_value(dbg,
+ config_file_data->cf_same_val);
+ dwarf_set_frame_undefined_value(dbg,
+ config_file_data->cf_undefined_val);
+ if(config_file_data->cf_address_size) {
+ dwarf_set_default_address_size(dbg, config_file_data->cf_address_size);
+ }
+ dwarf_set_harmless_error_list_size(dbg,50);
+
+
+ /* Get address size and largest representable address */
+ dres = dwarf_get_address_size(dbg,&elf_address_size,&err);
+ if (dres != DW_DLV_OK) {
+ print_error(dbg, "get_location_list", dres, err);
+ }
+
+ elf_max_address = (elf_address_size == 8 ) ?
+ 0xffffffffffffffffULL : 0xffffffff;
+
+ /* Get .text and .debug_ranges info if in check mode */
+ if (do_check_dwarf) {
+ Dwarf_Addr lower = 0;
+ Dwarf_Addr upper = 0;
+ Dwarf_Unsigned size = 0;
+ int res = 0;
+ res = dwarf_get_section_info_by_name(dbg,".text",&lower,&size,&err);
+ if (DW_DLV_OK == res) {
+ upper = lower + size;
+ }
+
+ /* Set limits for Ranges Information */
+ if (pRangesInfo) {
+ SetLimitsBucketGroup(pRangesInfo,lower,upper);
+ }
+
+ /* Build section information */
+ build_linkonce_info(dbg);
+ }
+
+ if (header_flag) {
+ print_object_header(elf,dbg);
+ }
+ reset_overall_CU_error_data();
+ if (info_flag || line_flag || cu_name_flag || search_is_on ||
+ producer_children_flag) {
+ print_infos(dbg,TRUE);
+ reset_overall_CU_error_data();
+ print_infos(dbg,FALSE);
+ }
+ if (pubnames_flag) {
+ reset_overall_CU_error_data();
+ print_pubnames(dbg);
+ }
+ if (macinfo_flag) {
+ reset_overall_CU_error_data();
+ print_macinfo(dbg);
+ }
+ if (loc_flag) {
+ reset_overall_CU_error_data();
+ print_locs(dbg);
+ }
+ if (abbrev_flag) {
+ reset_overall_CU_error_data();
+ print_abbrevs(dbg);
+ }
+ if (string_flag) {
+ reset_overall_CU_error_data();
+ print_strings(dbg);
+ }
+ if (aranges_flag) {
+ reset_overall_CU_error_data();
+ print_aranges(dbg);
+ }
+ if (ranges_flag) {
+ reset_overall_CU_error_data();
+ print_ranges(dbg);
+ }
+ if (frame_flag || eh_frame_flag) {
+ reset_overall_CU_error_data();
+ current_cu_die_for_print_frames = 0;
+ print_frames(dbg, frame_flag, eh_frame_flag, config_file_data);
+ }
+ if (static_func_flag) {
+ reset_overall_CU_error_data();
+ print_static_funcs(dbg);
+ }
+ if (static_var_flag) {
+ reset_overall_CU_error_data();
+ print_static_vars(dbg);
+ }
+ /* DWARF_PUBTYPES is the standard typenames dwarf section.
+ SGI_TYPENAME is the same concept but is SGI specific ( it was
+ defined 10 years before dwarf pubtypes). */
+
+ if (type_flag) {
+ reset_overall_CU_error_data();
+ print_types(dbg, DWARF_PUBTYPES);
+ reset_overall_CU_error_data();
+ print_types(dbg, SGI_TYPENAME);
+ }
+ if (weakname_flag) {
+ reset_overall_CU_error_data();
+ print_weaknames(dbg);
+ }
+ if (reloc_flag) {
+ reset_overall_CU_error_data();
+ print_relocinfo(dbg, reloc_map);
+ }
+ /* The right time to do this is unclear. But we need to do it. */
+ print_any_harmless_errors(dbg);
+
+ /* Print error report only if errors have been detected */
+ /* Print error report if the -kd option */
+ print_checks_results();
+
+ dres = dwarf_finish(dbg, &err);
+ if (dres != DW_DLV_OK) {
+ print_error(dbg, "dwarf_finish", dres, err);
+ }
+
+ printf("\n");
+ fflush(stderr);
+ return 0;
+
+}
+
+/* Do printing of most sections.
+ Do not do detailed checking.
+*/
+static void
+do_all()
+{
+ info_flag = line_flag = frame_flag = TRUE;
+ pubnames_flag = macinfo_flag = TRUE;
+ aranges_flag = TRUE;
+ /* Do not do
+ loc_flag = TRUE
+ abbrev_flag = TRUE;
+ ranges_flag = TRUE;
+ because nothing in
+ the DWARF spec guarantees the sections are free of random bytes
+ in areas not referenced by .debug_info */
+ string_flag = TRUE;
+ /* Do not do
+ reloc_flag = TRUE;
+ as print_relocs makes no sense for non-elf dwarfdump users. */
+ static_func_flag = static_var_flag = TRUE;
+ type_flag = weakname_flag = TRUE;
+ header_flag = TRUE; /* Dump header info */
+}
+
+
+static const char *usage_text[] = {
+"options:\t-a\tprint all .debug_* sections",
+"\t\t-b\tprint abbrev section",
+"\t\t-c\tprint loc section",
+"\t\t-c<str>\tcheck only specific compiler objects",
+"\t\t \t <str> is described by 'DW_AT_producer'. Examples:",
+"\t\t \t -cg check only GCC compiler objects",
+"\t\t \t -cs check only SNC compiler objects",
+"\t\t \t -c'350.1' check only compiler objects with 350.1 in the CU name",
+"\t\t-C\tactivate printing (with -i) of warnings about",
+"\t\t\tcertain common extensions of DWARF.",
+"\t\t-d\tdense: one line per entry (info section only)",
+"\t\t-D\tdo not show offsets", /* Do not show any offsets */
+"\t\t-e\tellipsis: short names for tags, attrs etc.",
+"\t\t-E\tprint object Header information",
+"\t\t-f\tprint dwarf frame section",
+"\t\t-F\tprint gnu .eh_frame section",
+"\t\t-g\t(use incomplete loclist support)",
+"\t\t-G\tshow global die offsets",
+"\t\t-h\tprint IRIX exception tables (unsupported)",
+"\t\t-H <num>\tlimit output to the first <num> major units",
+"\t\t\t example: to stop after <num> compilation units",
+"\t\t-i\tprint info section",
+"\t\t-k[abcdeEfFgilmMnrRsStx[e]y] check dwarf information",
+"\t\t a\tdo all checks",
+"\t\t b\tcheck abbreviations", /* Check abbreviations */
+"\t\t c\texamine DWARF constants", /* Check for valid DWARF constants */
+"\t\t d\tshow check results", /* Show check results */
+"\t\t e\texamine attributes of pubnames",
+"\t\t E\tignore DWARF extensions", /* Ignore DWARF extensions */
+"\t\t f\texamine frame information (use with -f or -F)",
+"\t\t F\texamine integrity of files-lines attributes", /* Files-Lines integrity */
+"\t\t g\tcheck debug info gaps", /* Check for debug info gaps */
+"\t\t i\tdisplay summary for all compilers", /* Summary all compilers */
+"\t\t l\tcheck location list (.debug_loc)", /* Location list integrity */
+"\t\t m\tcheck ranges list (.debug_ranges)", /* Ranges list integrity */
+"\t\t M\tcheck ranges list (.debug_aranges)",/* Aranges list integrity */
+"\t\t n\texamine names in attributes", /* Check for valid names */
+"\t\t r\texamine tag-attr relation",
+"\t\t R\tcheck forward references to DIEs (declarations)", /* Check DW_AT_specification references */
+"\t\t s\tperform checks in silent mode",
+"\t\t S\tcheck self references to DIEs",
+"\t\t t\texamine tag-tag relations",
+"\t\t x\tbasic frames check (.eh_frame, .debug_frame)",
+"\t\t xe\textensive frames check (.eh_frame, .debug_frame)",
+"\t\t y\texamine type info",
+"\t\t\tUnless -C option given certain common tag-attr and tag-tag",
+"\t\t\textensions are assumed to be ok (not reported).",
+"\t\t-l\tprint line section",
+"\t\t-m\tprint macinfo section",
+"\t\t-M\tprint the form name for each attribute",
+"\t\t-n\tsuppress frame information function name lookup",
+"\t\t \t(when printing frame information from multi-gigabyte",
+"\t\t \tobject files this option may save significant time).",
+"\t\t-N\tprint ranges section",
+"\t\t-o[liaprfoR]\tprint relocation info",
+"\t\t \tl=line,i=info,a=abbrev,p=pubnames,r=aranges,f=frames,o=loc,R=Ranges",
+"\t\t-p\tprint pubnames section",
+"\t\t-P\tprint list of compile units per producer", /* List of CUs per compiler */
+"\t\t-Q\tsuppress printing section data",
+"\t\t-r\tprint aranges section",
+"\t\t-R\tPrint frame register names as r33 etc",
+"\t\t \t and allow up to 1200 registers.",
+"\t\t \t Print using a 'generic' register set.",
+"\t\t-s\tprint string section",
+"\t\t-S <option>=<text>\tsearch for <text> in attributes",
+"\t\t \twith <option>:",
+"\t\t \t-S any=<text>\tany <text>",
+"\t\t \t-S match=<text>\tmatching <text>",
+#ifdef HAVE_REGEX
+"\t\t \t-S regex=<text>\tuse regular expression matching",
+#endif
+"\t\t \t (only one -S option allowed, any= and regex= ",
+"\t\t \t only usable if the functions required are ",
+"\t\t \t found at configure time)",
+"\t\t-t[afv] static: ",
+"\t\t a\tprint both sections",
+"\t\t f\tprint static func section",
+"\t\t v\tprint static var section",
+"\t\t-u<file> print sections only for specified file",
+"\t\t-v\tverbose: show more information",
+"\t\t-vv verbose: show even more information",
+"\t\t-V print version information",
+"\t\t-x name=<path>\tname dwarfdump.conf",
+"\t\t-x abi=<abi>\tname abi in dwarfdump.conf",
+"\t\t-w\tprint weakname section",
+"\t\t-W\tprint parent and children tree (wide format) with the -S option",
+"\t\t-Wp\tprint parent tree (wide format) with the -S option",
+"\t\t-Wc\tprint children tree (wide format) with the -S option",
+"\t\t-y\tprint type section",
+"",
+
+0
+};
+
+
+/* Remove matching leading/trailing quotes.
+ Does not alter the passed in string.
+ If quotes removed does a makename on a modified string. */
+static const char *
+remove_quotes_pair(const char *text)
+{
+ static char single_quote = '\'';
+ static char double_quote = '\"';
+ char quote = 0;
+ const char *p = text;
+ int len = strlen(text);
+
+ if (len < 2) {
+ return p;
+ }
+
+ /* Compare first character with ' or " */
+ if (p[0] == single_quote) {
+ quote = single_quote;
+ } else {
+ if (p[0] == double_quote) {
+ quote = double_quote;
+ }
+ else {
+ return p;
+ }
+ }
+ {
+ if (p[len - 1] == quote) {
+ char *altered = calloc(1,len+1);
+ const char *str2 = 0;
+ strcpy(altered,p+1);
+ altered[len - 2] = '\0';
+ str2 = makename(altered);
+ free(altered);
+ return str2;
+ }
+ }
+ return p;
+}
+
+/* process arguments and return object filename */
+static const char *
+process_args(int argc, char *argv[])
+{
+ extern int optind;
+ int c = 0;
+ boolean usage_error = FALSE;
+ int oarg = 0;
+
+ program_name = argv[0];
+
+ suppress_check_dwarf();
+ if (argv[1] != NULL && argv[1][0] != '-') {
+ do_all();
+ }
+
+ /* j unused */
+ while ((c = getopt(argc, argv,
+ "#:abc::CdDeEfFgGhH:ik:lmMnNo::pPqQrRsS:t:u:UvVwW::x:yz")) != EOF) {
+
+ switch (c) {
+ /* Internal debug level setting. */
+ case '#':
+ {
+ int nTraceLevel = atoi(optarg);
+ if (nTraceLevel > 0 && nTraceLevel <= MAX_TRACE_LEVEL) {
+ nTrace[nTraceLevel] = 1;
+ }
+ break;
+ }
+ case 'M':
+ show_form_used = TRUE;
+ break;
+ case 'x': /* Select abi/path to use */
+ {
+ const char *path = 0;
+ const char *abi = 0;
+ /* -x name=<path> meaning name dwarfdump.conf file -x
+ abi=<abi> meaning select abi from dwarfdump.conf
+ file. Must always select abi to use dwarfdump.conf */
+ if (strncmp(optarg, "name=", 5) == 0) {
+ path = do_uri_translation(&optarg[5],"-x name=");
+ if (strlen(path) < 1) {
+ goto badopt;
+ }
+ config_file_path = path;
+ } else if (strncmp(optarg, "abi=", 4) == 0) {
+ abi = do_uri_translation(&optarg[4],"-x abi=");
+ if (strlen(abi) < 1) {
+ goto badopt;
+ }
+ config_file_abi = abi;
+ break;
+ } else {
+ badopt:
+ fprintf(stderr, "-x name=<path-to-conf> \n");
+ fprintf(stderr, " and \n");
+ fprintf(stderr, "-x abi=<abi-in-conf> \n");
+ fprintf(stderr, "are legal, not -x %s\n", optarg);
+ usage_error = TRUE;
+ break;
+ }
+ }
+ break;
+ case 'C':
+ suppress_check_extensions_tables = TRUE;
+ break;
+ case 'g':
+ use_old_dwarf_loclist = TRUE;
+ info_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'i':
+ info_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'n':
+ suppress_nested_name_search = TRUE;
+ break;
+ case 'l':
+ line_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'f':
+ frame_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'H':
+ {
+ int break_val = atoi(optarg);
+ if(break_val > 0) {
+ break_after_n_units = break_val;
+ }
+ }
+ break;
+ case 'F':
+ eh_frame_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'b':
+ abbrev_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'p':
+ pubnames_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'P':
+ /* List of CUs per compiler */
+ producer_children_flag = TRUE;
+ break;
+ case 'r':
+ aranges_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'N':
+ ranges_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'R':
+ generic_1200_regs = TRUE;
+ break;
+ case 'm':
+ macinfo_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'c':
+ /* Specify compiler name. */
+ if (optarg) {
+ if ('s' == optarg[0]) {
+ /* -cs : Check SNC compiler */
+ check_snc_compiler = TRUE;
+ check_all_compilers = FALSE;
+ }
+ else {
+ if ('g' == optarg[0]) {
+ /* -cg : Check GCC compiler */
+ check_gcc_compiler = TRUE;
+ check_all_compilers = FALSE;
+ }
+ else {
+ /* Assume a compiler version to check,
+ most likely a substring of a compiler name. */
+ if ((compilers_targeted_count+1) < COMPILER_TABLE_MAX) {
+ Compiler *pCompiler = 0;
+ const char *cmp = 0;
+ cmp = do_uri_translation(optarg,"-c<compiler name>");
+ /* First compiler at position [1] */
+ compilers_targeted_count++;
+ pCompiler = &compilers_targeted[compilers_targeted_count];
+ reset_compiler_entry(pCompiler);
+ pCompiler->name = cmp;
+ check_all_compilers = FALSE;
+ } else {
+ fprintf(stderr, "Compiler table max %d exceeded, "
+ "limiting the tracked compilers to %d\n",
+ COMPILER_TABLE_MAX,COMPILER_TABLE_MAX);
+ }
+ }
+ }
+ } else {
+ loc_flag = TRUE;
+ suppress_check_dwarf();
+ }
+ break;
+ case 'Q':
+ /* Q suppresses section data printing. */
+ do_print_dwarf = FALSE;
+ break;
+ case 'q':
+ /* Suppress uri-did-transate notification */
+ do_print_uri_in_input = FALSE;
+ break;
+ case 's':
+ string_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'S':
+ /* -S option: strings for 'any' and 'match' */
+ {
+ boolean err = TRUE;
+ search_is_on = TRUE;
+ const char *tempstr = 0;
+ /* -S text */
+ if (strncmp(optarg,"match=",6) == 0) {
+
+ search_match_text = makename(&optarg[6]);
+ tempstr = remove_quotes_pair(search_match_text);
+ search_match_text = do_uri_translation(tempstr,"-S match=");
+ if (strlen(search_match_text) > 0) {
+ err = FALSE;
+ }
+ }
+ else {
+ if (strncmp(optarg,"any=",4) == 0) {
+ search_any_text = makename(&optarg[4]);
+ tempstr = remove_quotes_pair(search_any_text);
+ search_any_text = do_uri_translation(tempstr,"-S any=");
+ if (strlen(search_any_text) > 0) {
+ err = FALSE;
+ }
+ }
+#ifdef HAVE_REGEX
+ else {
+ if (strncmp(optarg,"regex=",6) == 0) {
+ search_regex_text = makename(&optarg[6]);
+ tempstr = remove_quotes_pair(
+ search_regex_text);
+ search_regex_text = do_uri_translation(tempstr,
+ "-S regex=");
+ if (strlen(search_regex_text) > 0) {
+ if (regcomp(&search_re,search_regex_text,
+ REG_EXTENDED)) {
+ fprintf(stderr,
+ "regcomp: unable to compile %s\n",
+ search_regex_text);
+ }
+ else {
+ err = FALSE;
+ }
+ }
+ }
+ }
+#endif /* HAVE_REGEX */
+ }
+ if (err) {
+ fprintf(stderr,"-S any=<text> or -S match=<text> or -S regex=<text>\n");
+ fprintf(stderr, "is allowed, not -S %s\n",optarg);
+ usage_error = TRUE;
+ }
+ }
+ break;
+
+ case 'a':
+ suppress_check_dwarf();
+ do_all();
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'V':
+ /* Display dwarfdump compilation date and time */
+ print_version_details(argv[0],TRUE);
+ exit(OKAY);
+ break;
+ case 'd':
+ /* This is sort of useless unless printing,
+ but harmless, so we do not insist we
+ are printing with suppress_check_dwarf(). */
+ dense = TRUE;
+ break;
+ case 'D':
+ /* Do not emit offset in output */
+ display_offsets = FALSE;
+ break;
+ case 'e':
+ suppress_check_dwarf();
+ ellipsis = TRUE;
+ break;
+ case 'E':
+ /* Object Header information (but maybe really print) */
+ header_flag = TRUE;
+ break;
+ case 'o':
+ reloc_flag = TRUE;
+ if (optarg) {
+ switch (optarg[0]) {
+ case 'i':
+ reloc_map |= (1 << DW_SECTION_REL_DEBUG_INFO); break;
+ reloc_map |= (1 << DW_SECTION_REL_DEBUG_TYPES); break;
+ case 'l': reloc_map |= (1 << DW_SECTION_REL_DEBUG_LINE); break;
+ case 'p': reloc_map |= (1 << DW_SECTION_REL_DEBUG_PUBNAMES); break;
+ /* Case a has no effect, no relocations can point out
+ of the abbrev section. */
+ case 'a': reloc_map |= (1 << DW_SECTION_REL_DEBUG_ABBREV); break;
+ case 'r': reloc_map |= (1 << DW_SECTION_REL_DEBUG_ARANGES); break;
+ case 'f': reloc_map |= (1 << DW_SECTION_REL_DEBUG_FRAME); break;
+ case 'o': reloc_map |= (1 << DW_SECTION_REL_DEBUG_LOC); break;
+ case 'R': reloc_map |= (1 << DW_SECTION_REL_DEBUG_RANGES); break;
+ default: usage_error = TRUE; break;
+ }
+ } else {
+ /* Display all relocs */
+ reloc_map = 0x00ff;
+ }
+ break;
+ case 'k':
+ suppress_print_dwarf();
+ oarg = optarg[0];
+ switch (oarg) {
+ case 'a':
+ check_pubname_attr = TRUE;
+ check_attr_tag = TRUE;
+ check_tag_tree = check_type_offset = TRUE;
+ check_names = TRUE;
+ pubnames_flag = info_flag = TRUE;
+ check_decl_file = TRUE;
+ check_frames = TRUE;
+ /*check_frames_extended = FALSE; */
+ check_locations = TRUE;
+ frame_flag = eh_frame_flag = TRUE;
+ check_ranges = TRUE;
+ check_lines = TRUE;
+ check_fdes = TRUE;
+ check_harmless = TRUE;
+ check_aranges = TRUE;
+ aranges_flag = TRUE; /* Aranges section */
+ check_abbreviations = TRUE;
+ check_dwarf_constants = TRUE;
+ check_di_gaps = TRUE; /* Check debug info gaps */
+ check_forward_decl = TRUE; /* Check forward declarations */
+ check_self_references = TRUE; /* Check self references */
+ break;
+ /* Abbreviations */
+ case 'b':
+ check_abbreviations = TRUE;
+ info_flag = TRUE;
+ break;
+ /* DWARF constants */
+ case 'c':
+ check_dwarf_constants = TRUE;
+ info_flag = TRUE;
+ break;
+ /* Display check results */
+ case 'd':
+ check_show_results = TRUE;
+ break;
+ case 'e':
+ check_pubname_attr = TRUE;
+ pubnames_flag = TRUE;
+ check_harmless = TRUE;
+ check_fdes = TRUE;
+ break;
+ case 'f':
+ check_harmless = TRUE;
+ check_fdes = TRUE;
+ break;
+ /* files-lines */
+ case 'F':
+ check_decl_file = TRUE;
+ check_lines = TRUE;
+ info_flag = TRUE;
+ break;
+ /* Check debug info gaps */
+ case 'g':
+ check_di_gaps = TRUE;
+ info_flag = TRUE;
+ break;
+ /* Locations list */
+ case 'l':
+ check_locations = TRUE;
+ info_flag = TRUE;
+ loc_flag = TRUE;
+ break;
+ /* Ranges */
+ case 'm':
+ check_ranges = TRUE;
+ info_flag = TRUE;
+ break;
+ /* Aranges */
+ case 'M':
+ check_aranges = TRUE;
+ aranges_flag = TRUE;
+ break;
+ /* invalid names */
+ case 'n':
+ check_names = TRUE;
+ info_flag = TRUE;
+ break;
+ case 'r':
+ check_attr_tag = TRUE;
+ info_flag = TRUE;
+ check_harmless = TRUE;
+ break;
+ /* forward declarations in DW_AT_specification */
+ case 'R':
+ check_forward_decl = TRUE;
+ info_flag = TRUE;
+ break;
+ /* Check verbose mode */
+ case 's':
+ check_verbose_mode = FALSE;
+ break;
+ /* self references in:
+ DW_AT_specification, DW_AT_type, DW_AT_abstract_origin */
+ case 'S':
+ check_self_references = TRUE;
+ info_flag = TRUE;
+ break;
+ case 't':
+ check_tag_tree = TRUE;
+ check_harmless = TRUE;
+ info_flag = TRUE;
+ break;
+ case 'y':
+ check_type_offset = TRUE;
+ check_harmless = TRUE;
+ check_decl_file = TRUE;
+ info_flag = TRUE;
+ check_ranges = TRUE;
+ check_aranges = TRUE;
+ break;
+ /* Summary for each compiler */
+ case 'i':
+ print_summary_all = TRUE;
+ break;
+ /* Frames check */
+ case 'x':
+ check_frames = TRUE;
+ frame_flag = TRUE;
+ eh_frame_flag = TRUE;
+ if (optarg[1]) {
+ if ('e' == optarg[1]) {
+ /* -xe : Extended frames check */
+ check_frames = FALSE;
+ check_frames_extended = TRUE;
+ } else {
+ usage_error = TRUE;
+ }
+ }
+ break;
+ default:
+ usage_error = TRUE;
+ break;
+ }
+ break;
+ case 'u': { /* compile unit */
+ const char *tstr = 0;
+ cu_name_flag = TRUE;
+ tstr = do_uri_translation(optarg,"-u<cu name>");
+ safe_strcpy(cu_name,sizeof(cu_name), tstr,strlen(tstr));
+ }
+ break;
+ case 'U':
+ uri_options_translation = FALSE;
+ break;
+ case 't':
+ oarg = optarg[0];
+ switch (oarg) {
+ case 'a':
+ /* all */
+ static_func_flag = static_var_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'f':
+ /* .debug_static_func */
+ static_func_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'v':
+ /* .debug_static_var */
+ static_var_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ default:
+ usage_error = TRUE;
+ break;
+ }
+ break;
+ case 'y': /* .debug_types */
+ suppress_check_dwarf();
+ type_flag = TRUE;
+ break;
+ case 'w': /* .debug_weaknames */
+ weakname_flag = TRUE;
+ suppress_check_dwarf();
+ break;
+ case 'z':
+ fprintf(stderr, "-z is no longer supported:ignored\n");
+ break;
+ case 'G':
+ show_global_offsets = TRUE;
+ break;
+ case 'W':
+ /* Search results in wide format */
+ search_wide_format = TRUE;
+ if (optarg) {
+ if ('c' == optarg[0]) {
+ /* -Wc : Display children tree */
+ display_children_tree = TRUE;
+ } else {
+ if ('p' == optarg[0]) {
+ /* -Wp : Display parent tree */
+ display_parent_tree = TRUE;
+ } else {
+ usage_error = TRUE;
+ }
+ }
+ }
+ else {
+ /* -W : Display parent and children tree */
+ display_children_tree = TRUE;
+ display_parent_tree = TRUE;
+ }
+ break;
+ default:
+ usage_error = TRUE;
+ break;
+ }
+ }
+
+ init_conf_file_data(&config_file_data);
+ if (config_file_abi && generic_1200_regs) {
+ printf("Specifying both -R and -x abi= is not allowed. Use one "
+ "or the other. -x abi= ignored.\n");
+ config_file_abi = FALSE;
+ }
+ if(generic_1200_regs) {
+ init_generic_config_1200_regs(&config_file_data);
+ }
+ if (config_file_abi && (frame_flag || eh_frame_flag)) {
+ int res = find_conf_file_and_read_config(config_file_path,
+ config_file_abi,
+ config_file_defaults,
+ &config_file_data);
+
+ if (res > 0) {
+ printf
+ ("Frame not configured due to error(s). Giving up.\n");
+ eh_frame_flag = FALSE;
+ frame_flag = FALSE;
+ }
+ }
+ if (usage_error || (optind != (argc - 1))) {
+ print_usage_message(program_name,usage_text);
+ exit(FAILED);
+ }
+
+ if (do_check_dwarf) {
+ /* Reduce verbosity when checking (checking means checking-only). */
+ verbose = 1;
+ }
+ return do_uri_translation(argv[optind],"file-to-process");
+}
+
+
+void
+print_error(Dwarf_Debug dbg, string msg, int dwarf_code,
+ Dwarf_Error err)
+{
+ print_error_and_continue(dbg,msg,dwarf_code,err);
+ dwarf_finish(dbg, &err);
+ exit(FAILED);
+}
+/* ARGSUSED */
+void
+print_error_and_continue(Dwarf_Debug dbg, string msg, int dwarf_code,
+ Dwarf_Error err)
+{
+ fflush(stdout);
+ fflush(stderr);
+
+ fprintf(stderr,"\n");
+
+ if (dwarf_code == DW_DLV_ERROR) {
+ string errmsg = dwarf_errmsg(err);
+ Dwarf_Unsigned myerr = dwarf_errno(err);
+
+ fprintf(stderr, "%s ERROR: %s: %s (%lu)\n",
+ program_name, msg, errmsg, (unsigned long) myerr);
+ } else if (dwarf_code == DW_DLV_NO_ENTRY) {
+ fprintf(stderr, "%s NO ENTRY: %s: \n", program_name, msg);
+ } else if (dwarf_code == DW_DLV_OK) {
+ fprintf(stderr, "%s: %s \n", program_name, msg);
+ } else {
+ fprintf(stderr, "%s InternalError: %s: code %d\n",
+ program_name, msg, dwarf_code);
+ }
+ fflush(stderr);
+
+ /* Display compile unit name */
+ PRINT_CU_INFO();
+}
+
+/* Predicate function. Returns 'true' if the CU should
+ be skipped as the DW_AT_name of the CU
+ does not match the command-line-supplied
+ cu name. Else returns false.*/
+boolean
+should_skip_this_cu(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_Error err)
+{
+ Dwarf_Half tag = 0;
+ Dwarf_Attribute attrib = 0;
+ Dwarf_Half theform = 0;
+ int dares = 0;
+ int tres = 0;
+ int fres = 0;
+
+ tres = dwarf_tag(cu_die, &tag, &err);
+ if (tres != DW_DLV_OK) {
+ print_error(dbg, "dwarf_tag in aranges",
+ tres, err);
+ }
+ dares = dwarf_attr(cu_die, DW_AT_name, &attrib,
+ &err);
+ if (dares != DW_DLV_OK) {
+ print_error(dbg, "dwarf_attr arange"
+ " derived die has no name",
+ dares, err);
+ }
+ fres = dwarf_whatform(attrib, &theform, &err);
+ if (fres == DW_DLV_OK) {
+ if (theform == DW_FORM_string
+ || theform == DW_FORM_strp) {
+ char * temps = 0;
+ int sres = dwarf_formstring(attrib, &temps,
+ &err);
+ if (sres == DW_DLV_OK) {
+ char *p = temps;
+ if (cu_name[0] != '/') {
+ p = strrchr(temps, '/');
+ if (p == NULL) {
+ p = temps;
+ } else {
+ p++;
+ }
+ }
+ /* Ignore case if Windows */
+#if WIN32
+ if (stricmp(cu_name, p)) {
+ // skip this cu.
+ return TRUE;
+ }
+#else
+ if (strcmp(cu_name, p)) {
+ // skip this cu.
+ return TRUE;
+ }
+#endif /* WIN32 */
+
+ } else {
+ print_error(dbg,
+ "arange: string missing",
+ sres, err);
+ }
+ }
+ } else {
+ print_error(dbg,
+ "dwarf_whatform unexpected value",
+ fres, err);
+ }
+ dwarf_dealloc(dbg, attrib, DW_DLA_ATTR);
+ return FALSE;
+}
+
+/* Returns the DW_AT_name of the CU */
+string
+old_get_cu_name(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_Error err)
+{
+ static struct esb_s esb_attr_name;
+ Dwarf_Half tag;
+ Dwarf_Attribute attrib;
+ Dwarf_Half theform;
+ int dares;
+ int tres;
+ int fres;
+
+ /* Initialize flexible string buffer */
+ esb_empty_string(&esb_attr_name);
+
+ tres = dwarf_tag(cu_die, &tag, &err);
+ if (tres != DW_DLV_OK) {
+ print_error(dbg, "dwarf_tag in aranges",
+ tres, err);
+ }
+ dares = dwarf_attr(cu_die, DW_AT_name, &attrib,
+ &err);
+ if (dares != DW_DLV_OK) {
+ print_error(dbg, "dwarf_attr arange"
+ " derived die has no name",
+ dares, err);
+ }
+ fres = dwarf_whatform(attrib, &theform, &err);
+ if (fres == DW_DLV_OK) {
+ if (theform == DW_FORM_string
+ || theform == DW_FORM_strp) {
+ char * temps = 0;
+ int sres = dwarf_formstring(attrib, &temps,
+ &err);
+ if (sres == DW_DLV_OK) {
+ char *p = temps;
+ if (cu_name[0] != '/') {
+ p = strrchr(temps, '/');
+ if (p == NULL) {
+ p = temps;
+ } else {
+ p++;
+ }
+ }
+ esb_append(&esb_attr_name,p);
+ } else {
+ print_error(dbg,
+ "arange: string missing",
+ sres, err);
+ }
+ }
+ } else {
+ print_error(dbg,
+ "dwarf_whatform unexpected value",
+ fres, err);
+ }
+ dwarf_dealloc(dbg, attrib, DW_DLA_ATTR);
+
+ /* Return the esb internal string */
+ return esb_get_string(&esb_attr_name);
+}
+
+/* Returns the cu of the CU */
+int get_cu_name(Dwarf_Debug dbg, Dwarf_Die cu_die,
+ Dwarf_Error err, string *short_name, string *long_name)
+{
+ Dwarf_Attribute name_attr = 0;
+ int ares;
+
+ ares = dwarf_attr(cu_die, DW_AT_name, &name_attr, &err);
+ if (ares == DW_DLV_ERROR) {
+ print_error(dbg, "hassattr on DW_AT_name", ares, err);
+ } else {
+ if (ares == DW_DLV_NO_ENTRY) {
+ *short_name = "<unknown name>";
+ *long_name = "<unknown name>";
+ } else {
+ /* DW_DLV_OK */
+ /* The string return is valid until the next call to this
+ function; so if the caller needs to keep the returned
+ string, the string must be copied (makename()). */
+ static struct esb_s esb_short_name;
+ static struct esb_s esb_long_name;
+ char *filename;
+ esb_empty_string(&esb_long_name);
+ get_attr_value(dbg, DW_TAG_compile_unit,
+ cu_die, name_attr, NULL, 0, &esb_long_name,
+ 0 /*show_form_used*/,0 /* verbose */);
+ *long_name = esb_get_string(&esb_long_name);
+ /* Generate the short name (filename) */
+ filename = strrchr(*long_name,'/');
+ if (!filename) {
+ filename = strrchr(*long_name,'\\');
+ }
+ if (filename) {
+ ++filename;
+ } else {
+ filename = *long_name;
+ }
+ esb_empty_string(&esb_short_name);
+ esb_append(&esb_short_name,filename);
+ *short_name = esb_get_string(&esb_short_name);
+ }
+ }
+
+ dwarf_dealloc(dbg, name_attr, DW_DLA_ATTR);
+ return ares;
+}
+
+/* Returns the producer of the CU */
+int get_producer_name(Dwarf_Debug dbg, Dwarf_Die cu_die,
+ Dwarf_Error err, string *producer_name)
+{
+ Dwarf_Attribute producer_attr = 0;
+ int ares;
+
+ ares = dwarf_attr(cu_die, DW_AT_producer, &producer_attr, &err);
+ if (ares == DW_DLV_ERROR) {
+ print_error(dbg, "hassattr on DW_AT_producer", ares, err);
+ } else {
+ if (ares == DW_DLV_NO_ENTRY) {
+ /* We add extra quotes so it looks more like
+ the names for real producers that get_attr_value
+ produces. */
+ *producer_name = "\"<CU-missing-DW_AT_producer>\"";
+ } else {
+ /* DW_DLV_OK */
+ /* The string return is valid until the next call to this
+ function; so if the caller needs to keep the returned
+ string, the string must be copied (makename()). */
+ static struct esb_s esb_producer;
+ esb_empty_string(&esb_producer);
+ get_attr_value(dbg, DW_TAG_compile_unit,
+ cu_die, producer_attr, NULL, 0, &esb_producer,
+ 0 /*show_form_used*/,0 /* verbose */);
+ *producer_name = esb_get_string(&esb_producer);
+ }
+ }
+
+ dwarf_dealloc(dbg, producer_attr, DW_DLA_ATTR);
+ return ares;
+}
+
+/* GCC linkonce names */
+char *lo_text = ".text."; /*".gnu.linkonce.t.";*/
+char *lo_debug_abbr = ".gnu.linkonce.wa.";
+char *lo_debug_aranges = ".gnu.linkonce.wr.";
+char *lo_debug_frame_1 = ".gnu.linkonce.wf.";
+char *lo_debug_frame_2 = ".gnu.linkonce.wF.";
+char *lo_debug_info = ".gnu.linkonce.wi.";
+char *lo_debug_line = ".gnu.linkonce.wl.";
+char *lo_debug_macinfo = ".gnu.linkonce.wm.";
+char *lo_debug_loc = ".gnu.linkonce.wo.";
+char *lo_debug_pubnames = ".gnu.linkonce.wp.";
+char *lo_debug_ranges = ".gnu.linkonce.wR.";
+char *lo_debug_str = ".gnu.linkonce.ws.";
+
+/* SNC compiler/linker linkonce names */
+char *nlo_text = ".text.";
+char *nlo_debug_abbr = ".debug.wa.";
+char *nlo_debug_aranges = ".debug.wr.";
+char *nlo_debug_frame_1 = ".debug.wf.";
+char *nlo_debug_frame_2 = ".debug.wF.";
+char *nlo_debug_info = ".debug.wi.";
+char *nlo_debug_line = ".debug.wl.";
+char *nlo_debug_macinfo = ".debug.wm.";
+char *nlo_debug_loc = ".debug.wo.";
+char *nlo_debug_pubnames = ".debug.wp.";
+char *nlo_debug_ranges = ".debug.wR.";
+char *nlo_debug_str = ".debug.ws.";
+
+/* Build linkonce section information */
+void
+build_linkonce_info(Dwarf_Debug dbg)
+{
+ int nCount = 0;
+ int section_index = 0;
+ int res = 0;
+
+ static char **linkonce_names[] = {
+ &lo_text, /* .text */
+ &nlo_text, /* .text */
+ &lo_debug_abbr, /* .debug_abbr */
+ &nlo_debug_abbr, /* .debug_abbr */
+ &lo_debug_aranges, /* .debug_aranges */
+ &nlo_debug_aranges, /* .debug_aranges */
+ &lo_debug_frame_1, /* .debug_frame */
+ &nlo_debug_frame_1, /* .debug_frame */
+ &lo_debug_frame_2, /* .debug_frame */
+ &nlo_debug_frame_2, /* .debug_frame */
+ &lo_debug_info, /* .debug_info */
+ &nlo_debug_info, /* .debug_info */
+ &lo_debug_line, /* .debug_line */
+ &nlo_debug_line, /* .debug_line */
+ &lo_debug_macinfo, /* .debug_macinfo */
+ &nlo_debug_macinfo, /* .debug_macinfo */
+ &lo_debug_loc, /* .debug_loc */
+ &nlo_debug_loc, /* .debug_loc */
+ &lo_debug_pubnames, /* .debug_pubnames */
+ &nlo_debug_pubnames, /* .debug_pubnames */
+ &lo_debug_ranges, /* .debug_ranges */
+ &nlo_debug_ranges, /* .debug_ranges */
+ &lo_debug_str, /* .debug_str */
+ &nlo_debug_str, /* .debug_str */
+ NULL
+ };
+
+ const char *section_name = NULL;
+ Dwarf_Addr section_addr = 0;
+ Dwarf_Unsigned section_size = 0;
+ Dwarf_Error error = 0;
+ int nIndex = 0;
+
+ nCount = dwarf_get_section_count(dbg);
+
+ /* Ignore section with index=0 */
+ for (section_index = 1; section_index < nCount; ++section_index) {
+ res = dwarf_get_section_info_by_index(dbg,section_index,
+ &section_name,
+ &section_addr,
+ &section_size,
+ &error);
+
+ if (res == DW_DLV_OK) {
+ for (nIndex = 0; linkonce_names[nIndex]; ++nIndex) {
+ if (section_name == strstr(section_name,
+ *linkonce_names[nIndex])) {
+
+ /* Insert only linkonce sections */
+ AddEntryIntoBucketGroup(pLinkonceInfo,
+ section_index,
+ section_addr,section_addr,
+ section_addr + section_size,
+ section_name,
+ TRUE);
+ break;
+ }
+ }
+ }
+ }
+
+ if (dump_linkonce_info) {
+ PrintBucketGroup(pLinkonceInfo,TRUE);
+ }
+}
+
+/* Check for specific TAGs and initialize some
+ information used by '-k' options */
+void
+tag_specific_checks_setup(Dwarf_Half val,int die_indent_level)
+{
+ switch (val) {
+ case DW_TAG_compile_unit:
+ /* To help getting the compile unit name */
+ seen_CU = TRUE;
+ /* If we are checking line information, build
+ the table containing the pairs LowPC and HighPC */
+ if (check_decl_file || check_ranges || check_locations) {
+ ResetBucketGroup(pRangesInfo);
+ }
+ /* The following flag indicate that only low_pc and high_pc
+ values found in DW_TAG_subprograms are going to be considered when
+ building the address table used to check ranges, lines, etc */
+ need_PU_valid_code = TRUE;
+ break;
+
+ case DW_TAG_subprogram:
+ /* Keep track of a PU */
+ if (die_indent_level == 1) {
+ /* A DW_TAG_subprogram can be nested, when is used to
+ declare a member function for a local class; process the DIE
+ only if we are at level zero in the DIEs tree */
+ seen_PU = TRUE;
+ seen_PU_base_address = FALSE;
+ seen_PU_high_address = FALSE;
+ PU_name[0] = 0;
+ need_PU_valid_code = TRUE;
+ }
+ break;
+ }
+}
+
+/* Indicates if the current CU is a target */
+static boolean current_cu_is_checked_compiler = TRUE;
+
+/* Are we checking for errors from the
+ compiler of the current compilation unit?
+*/
+boolean
+checking_this_compiler()
+{
+ /* This flag has been update by 'update_compiler_target()'
+ and indicates if the current CU is in a targeted compiler
+ specified by the user. Default value is TRUE, which
+ means test all compilers until a CU is detected. */
+ return current_cu_is_checked_compiler || check_all_compilers;
+}
+
+static int
+hasprefix(const char *sample, const char *prefix)
+{
+ unsigned prelen = strlen(prefix);
+ if ( strncmp(sample,prefix,prelen) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Record which compiler was used (or notice we saw
+ it before) and set a couple variables as
+ a side effect (which are used all over):
+ current_cu_is_checked_compiler (used in checking_this_compiler() )
+ current_compiler
+ The compiler name is from DW_AT_producer.
+*/
+void
+update_compiler_target(const char *producer_name)
+{
+ Dwarf_Bool cFound = FALSE;
+ int index = 0;
+
+ safe_strcpy(CU_producer,sizeof(CU_producer),producer_name,
+ strlen(producer_name));
+ current_cu_is_checked_compiler = FALSE;
+
+ /* This list of compilers is just a start:
+ GCC id : "GNU"
+ SNC id : "SN Systems" */
+
+ /* Find a compiler version to check */
+ if (compilers_targeted_count) {
+ for (index = 1; index <= compilers_targeted_count; ++index) {
+ if (is_strstrnocase(CU_producer,compilers_targeted[index].name)) {
+ compilers_targeted[index].verified = TRUE;
+ current_cu_is_checked_compiler = TRUE;
+ break;
+ }
+ }
+ } else {
+ /* Take into account that internally all strings are double quoted */
+ boolean snc_compiler = hasprefix(CU_producer,"\"SN")? TRUE : FALSE;
+ boolean gcc_compiler = hasprefix(CU_producer,"\"GNU")?TRUE : FALSE;
+ current_cu_is_checked_compiler = check_all_compilers ||
+ (snc_compiler && check_snc_compiler) ||
+ (gcc_compiler && check_gcc_compiler) ;
+ }
+
+ /* Check for already detected compiler */
+ for (index = 1; index <= compilers_detected_count; ++index) {
+ if (
+#if WIN32
+ !stricmp(compilers_detected[index].name,CU_producer)
+#else
+ !strcmp(compilers_detected[index].name,CU_producer)
+#endif
+ ) {
+ /* Set current compiler index */
+ current_compiler = index;
+ cFound = TRUE;
+ break;
+ }
+ }
+ if (!cFound) {
+ /* Record a new detected compiler name. */
+ if (compilers_detected_count + 1 < COMPILER_TABLE_MAX) {
+ Compiler *pCompiler = 0;
+ char *cmp = makename(CU_producer);
+ /* Set current compiler index, first compiler at position [1] */
+ current_compiler = ++compilers_detected_count;
+ pCompiler = &compilers_detected[current_compiler];
+ reset_compiler_entry(pCompiler);
+ pCompiler->name = cmp;
+ }
+ }
+}
+
+/* Add a CU name to the current compiler entry, specified by the
+ 'current_compiler'; the name is added to the 'compilers_detected'
+ table and is printed if the '-P' option is specified in the
+ command line. */
+void
+add_cu_name_compiler_target(char *name)
+{
+ a_name_chain *cu_last = 0;
+ a_name_chain *nc = 0;
+ Compiler *pCompiler = 0;
+
+ if (current_compiler < 1) {
+ fprintf(stderr,"Current compiler set to %d, cannot add "
+ "Compilation unit name. Giving up.",current_compiler);
+ exit(1);
+ }
+ pCompiler = &compilers_detected[current_compiler];
+ cu_last = pCompiler->cu_last;
+ /* Record current cu name */
+ nc = (a_name_chain *)malloc(sizeof(a_name_chain));
+ nc->item = makename(name);
+ nc->next = NULL;
+ if (cu_last) {
+ cu_last->next = nc;
+ } else {
+ pCompiler->cu_list = nc;
+ }
+ pCompiler->cu_last = nc;
+}
+
+/* Reset a compiler entry, so all fields are properly set */
+static void
+reset_compiler_entry(Compiler *compiler)
+{
+ memset(compiler,0,sizeof(Compiler));
+}
+
+/* Making this a named string makes it simpler to change
+ what the reset,or 'I do not know' value is for
+ CU name or producer name for PRINT_CU_INFO. */
+static const char * default_cu_producer = "<unknown>";
+static void
+reset_overall_CU_error_data()
+{
+ strcpy(CU_name,default_cu_producer);
+ strcpy(CU_producer,default_cu_producer);
+ DIE_offset = 0;
+ DIE_overall_offset = 0;
+ DIE_CU_offset = 0;
+ DIE_CU_overall_offset = 0;
+ CU_base_address = 0;
+ CU_high_address = 0;
+}
+
+
+static boolean
+cu_data_is_set()
+{
+ if(strcmp(CU_name,default_cu_producer) ||
+ strcmp(CU_producer,default_cu_producer)) {
+ return 1;
+ }
+ if(DIE_offset || DIE_overall_offset) {
+ return 1;
+ }
+ if(CU_base_address || CU_high_address) {
+ return 1;
+ }
+ return 0;
+}
+/* Print CU basic information */
+void PRINT_CU_INFO()
+{
+ if (current_section_id == DEBUG_LINE ||
+ current_section_id == DEBUG_ARANGES) {
+ /* Only in the DEBUG_LINE/ARANGES case is DIE_CU_offset or
+ DIE_CU_overall_offset what we want to print here.
+ In other cases DIE_CU_offset is not really a CU
+ offset at all. */
+ DIE_offset = DIE_CU_offset;
+ DIE_overall_offset = DIE_CU_overall_offset;
+ }
+ if(!cu_data_is_set()) {
+ return;
+ }
+ printf("\n");
+ printf("CU Name = %s\n",CU_name);
+ printf("CU Producer = %s\n",CU_producer);
+ printf("DIE OFF = 0x%08" DW_PR_DUx
+ " GOFF = 0x%08" DW_PR_DUx ,DIE_offset,DIE_overall_offset);
+ printf(", Low PC = 0x%08" DW_PR_DUx ", High PC = 0x%08" DW_PR_DUx ,
+ CU_base_address,CU_high_address);
+ printf("\n");
+ fflush(stdout);
+}
+
+void DWARF_CHECK_COUNT(Dwarf_Check_Categories category, int inc)
+{
+ compilers_detected[0].results[category].checks += inc;
+ compilers_detected[0].results[total_check_result].checks += inc;
+ if(current_compiler > 0 && current_compiler < COMPILER_TABLE_MAX) {
+ compilers_detected[current_compiler].results[category].checks += inc;
+ compilers_detected[current_compiler].results[total_check_result].checks
+ += inc;
+ compilers_detected[current_compiler].verified = TRUE;
+ }
+}
+
+void DWARF_ERROR_COUNT(Dwarf_Check_Categories category, int inc)
+{
+ compilers_detected[0].results[category].errors += inc;
+ compilers_detected[0].results[total_check_result].errors += inc;
+ if(current_compiler > 0 && current_compiler < COMPILER_TABLE_MAX) {
+ compilers_detected[current_compiler].results[category].errors += inc;
+ compilers_detected[current_compiler].results[total_check_result].errors
+ += inc;
+ }
+}
+
+void PRINT_CHECK_RESULT(char *str,
+ Compiler *pCompiler, Dwarf_Check_Categories category)
+{
+ Dwarf_Check_Result result = pCompiler->results[category];
+ fprintf(stderr, "%-24s%10d %10d\n", str, result.checks, result.errors);
+}
+
+void DWARF_CHECK_ERROR_PRINT_CU()
+{
+ if (check_verbose_mode) {
+ PRINT_CU_INFO();
+ }
+ check_error++;
+ record_dwarf_error = TRUE;
+}
+
+void DWARF_CHECK_ERROR(Dwarf_Check_Categories category,
+ const char *str)
+{
+ if (checking_this_compiler()) {
+ DWARF_ERROR_COUNT(category,1);
+ if (check_verbose_mode) {
+ printf("\n*** DWARF CHECK: %s ***\n", str);
+ }
+ DWARF_CHECK_ERROR_PRINT_CU();
+ }
+}
+
+void DWARF_CHECK_ERROR2(Dwarf_Check_Categories category,
+ const char *str1, const char *str2)
+{
+ if (checking_this_compiler()) {
+ DWARF_ERROR_COUNT(category,1);
+ if (check_verbose_mode) {
+ printf("\n*** DWARF CHECK: %s: %s ***\n", str1, str2);
+ }
+ DWARF_CHECK_ERROR_PRINT_CU();
+ }
+}
+
+void DWARF_CHECK_ERROR3(Dwarf_Check_Categories category,
+ const char *str1, const char *str2, const char *strexpl)
+{
+ if (checking_this_compiler()) {
+ DWARF_ERROR_COUNT(category,1);
+ if (check_verbose_mode) {
+ printf("\n*** DWARF CHECK: %s -> %s: %s ***\n",
+ str1, str2,strexpl);
+ }
+ DWARF_CHECK_ERROR_PRINT_CU();
+ }
+}
+
+/* Precondition: 'out' is already constructed and empty. */
+static const char *
+do_uri_translation(const char *s,const char *context)
+{
+ struct esb_s str;
+ char *finalstr = 0;
+ if (!uri_options_translation) {
+ return makename(s);
+ }
+ esb_constructor(&str);
+ translate_from_uri(s,&str);
+ if (do_print_uri_in_input) {
+ if(strcmp(s,esb_get_string(&str))) {
+ printf("Uri Translation on option %s\n",context);
+ printf(" \'%s\'\n",s);
+ printf(" \'%s\'\n",esb_get_string(&str));
+ }
+ }
+ finalstr = makename(esb_get_string(&str));
+ esb_destructor(&str);
+ return finalstr;
+}