diff options
286 files changed, 129178 insertions, 0 deletions
diff --git a/BLDLIBDWARF b/BLDLIBDWARF new file mode 100755 index 0000000..8309961 --- /dev/null +++ b/BLDLIBDWARF @@ -0,0 +1,30 @@ +#!/bin/sh +# +bldone () { + t=$1 + cd $t + # The following distclean will fail on a clean directory + # Ignore the failure + make distclean + ./configure + if [ $? != 0 ] + then + echo build failed + exit + fi + make + if [ $? != 0 ] + then + echo build failed + exit + fi + cd .. +} + +bldone libdwarf +bldone dwarfdump +bldone dwarfdump2 + + + + diff --git a/dwarfdump/CODINGSTYLE b/dwarfdump/CODINGSTYLE new file mode 100644 index 0000000..64bbb48 --- /dev/null +++ b/dwarfdump/CODINGSTYLE @@ -0,0 +1,44 @@ +This document is a brief description of the main +coding style conventions in dwarfdump. Many of them +will be obvious from the code, but over time some +accidental diffences crept in. + + +Code should be indented in multiples of 4 spaces, and +tabs should not be used to indent the source code. +Use the dicheck program to check indenting. + +The struct naming convention is 'struct my_struct_s' for the +struct defined here (meaning the name should end with _s). +It is better to not do struct typedefs of local structs. +Coders should type 'struct mystruct_s'. Readability +is much more important than brevity. + +Any data or function not referenced outside the +defining source file should be declared 'static'. + +Any duplicated code is a candidate for refactoring +into a subprogram. + +Function names should be all lower case with underbars +with the goal that statements and comments 'read well'. + +Variables should be lower-case with +underbars for readability. It's ok for a small loop +with counters to use single letter names like i or k or m. + +Structure members should have a struct-specific +2-character prefix to the name (followed by +an underbar). That makes it much +easier to grep for uses of members. + +Try to keep lines under 80 characters in length. + +Ensure every if() has {} to enclose the actions. + +Use libdwarf.h types for all the data objects you define, +though sometimes an 'unsigned' or 'int' or 'size_t' is +ok in restricted circumstances. Dwarf_Unsigned and +Dwarf_Signed are the preferred integer types for general use. + +------------ diff --git a/dwarfdump/COPYING b/dwarfdump/COPYING new file mode 100644 index 0000000..355bd60 --- /dev/null +++ b/dwarfdump/COPYING @@ -0,0 +1,31 @@ + +David Anderson: December 2006 +The code in the dwarfdump directory is (if you look +in each file) covered by the GPL (not the LGPL). The +DWARFDUMPCOPYRIGHT file, though, said (before December 24, +2006) the copyright is LGPL. There is no doubt in my (David +Anderson) mind that the intent was always that dwarfdump be +GPL and the copyright markings in each file are correct. + +There are three files marked with the LGPL: tag_tree.list +tag_attr.list acconfig.h. These markings are left as is and +these are are therefore LGPL files. + +The DWARFDUMPCOPYRIGHT file now (Dec 24 2006) has both +copyrights and an explanation of where each applies. + + + +------------------------------------------- +The text present for years, thru Dec 23, 2006: +The files: + dwarfdump.c + and all the .h and .c files in this implementation of + dwarfdump are copyrighted according to the file + DWARFDUMPCOPYRIGHT. + + + +$Source: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/COPYING,v $ +$Revision: 1.1 $ +$Date: 2001/01/16 17:47:55 $ diff --git a/dwarfdump/ChangeLog b/dwarfdump/ChangeLog new file mode 100644 index 0000000..03bb4a1 --- /dev/null +++ b/dwarfdump/ChangeLog @@ -0,0 +1,2 @@ +2012-04-10 DavidAnderson <davea42@earthlink.net> + * dwarfdump.c, common.c: Updated version string. diff --git a/dwarfdump/ChangeLog2006 b/dwarfdump/ChangeLog2006 new file mode 100644 index 0000000..dbedb67 --- /dev/null +++ b/dwarfdump/ChangeLog2006 @@ -0,0 +1,332 @@ +2006-12-24 David Anderson <davea@sgi.com> + * DWARFDUMPCOPYRIGHT: Added GPL copyright text with + explanation of the intended content. + * COPYING: added text explaining confusion of GPL vs LGPL. + Thanks to Chris Quenelle for pointing out the disconnect + between DWARFDUMPCOPYRIGHT and the source files in dwarfdump. +2006-12-21 David Anderson <davea@sgi.com> + * tag_tree.list: add tags to make allowed list more complete. + Omission noticed by Marcel Mettes. +2006-06-14 David Anderson <davea@sgi.com> + * print_frames.c: Clean up printing of augmentation data by + eliminating dangling 0x (for eh_frame). +2006-04-28 David Anderson <davea@sgi.com> + * dwarfdump.conf: Now has x86_64 register names. + x86_64 with help from Tom Hughes (verified + from independent sources). + Added m68k register names and refined x86 list + by looking at various information-sources. +2006-04-18 David Anderson <davea@sgi.com> + * *.c: Ran indent so all now follow a standard look. + * dwconf.c: Added fclose(conf_stream). +2006-04-18 David Anderson <davea@sgi.com> + * dwarfdump.c: Forgot to call key new functions for + handling variable-size frame data and different + frame rule initialization value. + * dwconf.c: Add a default print for CFA in case of + an omission in dwarfdump.conf. + * dwarfdump.conf: Move setup and rename the ABIs slightly. +2006-04-17 David Anderson <davea@sgi.com> + * dwarfdump.conf: Correct typos. Remove some register names. + * dwarfdump.c: Fix compiler warnings, fix -x option usage message. + * dwconf.h: Fix compiler warnings by changing types. + * dwconf.c: Change error checking so we check all errors, do + not stop at first error. Ran indent. Added code to check + for extra junk after operand(s). + * print_frames.c: Fix compiler warnings. + * Makefile.in: get <prefix> used in install rule and creating + places to search for dwarfdump.conf +2006-04-16 David Anderson <davea@sgi.com> + * dwarfdump.conf: New dwarfdump configuration file. Makes using frame + information easy to read and correct for any ABI/ISA + without rebuilding dwarfdump. + * Makefile.in: Added new files dwconf.h dwconf.c + * dwconf.h dwconf.c: New files implement reading dwarfdump.conf + and help print_frames.c print frame information correctly + for ABIs specified at runtime. + * dwarfdump.1: document -x commands. + * globals.h: Minor changes to support dwarfdump.conf + * print_frames.c: Major changes to support a run-time description of + the frames info and dwarfdump.conf. + * print_frames.h: Changes to support a run-time description of + the frames info and dwarfdump.conf. + * print_sections.c: Minor tweaks to support a run-time + description of the frames info and dwarfdump.conf. + +2006-03-31 David Anderson <davea@sgi.com> + * Makefile.in globals.h print_sections.c: Refer to new + print_frames.h print_frames.c. + * print_frames.h print_frames.c: Extract cie, fde printing + to separate file, separating loop logic from the printing + of an entry from the loop. +2006-03-31 David Anderson <davea@sgi.com> + * dwarfdump.c global.h print_sections.c: Preparing for + dwarf3 frame interface. + * print_die.c: Corrects handling of DW_AT_encoding (etc) value. +2006-03-29 David Anderson <davea@sgi.com> + * print_sections.c: define DWARFDUMP_TURN_OFF_MIPS_REG_NAMES + at compile time + to turn off the MIPS register names printing. Instead + (aside from cfa) use a name like r4 (where the DWARF + register number follows the letter 'r'). + Indent. Initialize some local variables at declarations. +2006-03-13 David Anderson <davea@sgi.com> + * print_sections.c: Now gets gnu eh_augmentation data by calling + dwarf_get_cie_augmentation_data() or dwarf_get_fde_augmentation_data() + and prints it (use -v to see cie data). + Now prints DWARF3 frame information. +2006-03-08 David Anderson <davea@sgi.com> + * print_sections.c: Add 'break;' at line 710. + Thanks to Richard Stuckey for noticing. +2005-12-01 David Anderson <davea@sgi.com> + * dwarf_names.awk: use snprintf instead of sprintf for safety. +2005-12-01 David Anderson <davea@sgi.com> + * Makefile.in: Build attr/tag trees with + individual commands to catch build errors. + * tag_attr.c,tag_tree.c: Verify that + tables fit in the generated C code and check for + format errors in the *.list files. + * tag_attr.list, tag_tree.list: Added some valid entries. + * globals.h: add DWARF_ERROR3 macro for better diagnostics. + * print_die.c: Show both sides of questionable tag relation + in CHECK -k diagnostic output. + +2005-11-25 David Anderson <davea@sgi.com> + * print_die.c: DW_AT_stride_size changed to DW_AT_bit_stride, + added DW_AT_byte_stride. + * tag_attr.c,tag_tree.c: fixed array size now a #define for + readability. + * tag_attr.list: Added DWARF3 attributes, also new TAGs. + * tag_tree.list: Added DWARF3 TAGs. + +2005-11-08 David Anderson <davea@sgi.com> + * makename.c: remove non-standard malloc.h include, + stdlib.h suffices and is already included. + +2005-10-24 David Anderson <davea@sgi.com> + * tag_attr.c tag_tree.c: added DWARF3 TAGs to string array. + +2005-08-01 David Anderson <davea@sgi.com> + * Makefile.in: Add esb.o and test rule (test code for esb.c). + * dwarfdump.c: Remove old static buffer initialization. + * print_die.c: Use esb now, avoid crash due to long loclist + overrunning static buffer. Uses snprintf now, not sprintf. + snprintf is for safety. + * esb.h esb.c: Adding extensible string buffer (esb) code. + * testesb.c: Test code for esb.c. + * print_reloc.c: size field is now Elf64_Xword for + Elf64 as Elf64_Word is only 32 bits. + +2005-07-15 David Anderson <davea@sgi.com> + * dwarfdump.c: Add print of .debug_pubtypes, remove + erroneous dealloc after dwarf_formstring() call. + * globals.h: Add declarations for .debug_pubtypes print. Add + declaration for full dealloc. + * print_die.c: Remove erroneous dealloc after dwarf_formstring() call. + * print_exception_tables.c: Call dwarf_fde_cie_list_dealloc() + for complete dealloc. + * print_sections.c: Remove incorrect dealloc() call. + Add calls to new dealloc routines. Add support of .debug_pubtypes + print. +2005-07-14 David Anderson <davea@sgi.com> + * print_sections.c (print_line_numbers_this_cu): Use new + dwarf_srclines_dealloc() for deallocation after + dwarf_srclines() called. + +2005-04-13 David Anderson <davea@sgi.com> + * print_sections.c: Factors out common print code into + a new routine. Avoid indexing past end of register names + array. Adds checks and prints so that certain errors + in pubnames-like sections are printed usefully (and dwarfdump + then stops if libdwarf gave an error). + +2005-03-21 David Anderson <davea@sgi.com> + * dwarfdump.c: Add -F flag to + request .eh_frame section print. Changed -f flag meaning + to print .debug_frame only. -a flag no longer + prints .debug_frame by default. + * print_sections.c: avoid printing an eh_frame we don't understand. + Add new information per CU when printing line info: specifically + the line section offset. + * globals.h: Added arguments to print_frames() for -F flag. + +2005-03-18 David Anderson <davea@sgi.com> + * print_sections.c: Correct macro section printing. + +2004-10-28 David Anderson <davea@sgi.com> + * DWARFDUMPCOPYRIGHT config.h defs.h dwarfdump.c globals.h + makename.c makename.h print_die.c print_exception_tables.c + print_reloc.c print_sections.c tag_attr.c tag_attr.list + tag_tree.c tag_tree.list: Copyright update, SGI + corporate address change. + +2004-10-26 David Anderson <davea@sgi.com> + * acconfig.h: removed. Was old style autoconf usage. + * configure.in: Updated AC_DEFINE usage, adding args 2 & 3. + * config.guess: Updated. timestamp='2004-06-11'. + * config.sub: Updated. timestamp='2004-03-12'. + * configure config.h.in: regenerated with autoconf 2.58. + +2004-05-14 David Anderson <davea@sgi.com> + + * print_die.c (print_die_and_children): Change to iteration + on siblings (still recursing on children). + + +2004-03-30 David Anderson <davea@sgi.com> + * dwarfdump.c (main): getopt() string should contain k:g + not kg: Thanks to Peter Seiderer for pointing this out. + +2003-12-31 David Anderson <davea@sgi.com> + * README: Added configure example. + * Makefile.in: Removed bogus LIBS line, updated copyright date. + * acconfig.h: Added LGPL copyright to match libdwarf + Silly, but it matches libdwarf version boilerplate. + * config.guess config.sub: new versions from automake-1.6. + * config.h.in configure: Regenerated. + + +2003-10-06 David Anderson <davea@sgi.com> + * dwarfdump.c print_sections.c: applied indent(1). + * print_die.c: applied indent and added ; after + invocations of macros PUSH_DIE_STACK POP_DIE_STACK SPACE + as these were confusing indent a bit. + The indent control file .indent.pro contained: + -bad -bap -nbbo -br -ce -brs + -l72 -lc72 -hnl -nprs + -fca -i4 -lp -psl -npcs + + + +2003-10-02 David Anderson <davea@sgi.com> + * dwarfdump.c: Add -g to indicate use of older + location entry code in libdwarf. So dwarf_loclist + and dwarf_loclist_n are testable. + * globals.h: Added use_old_dwarf_loclist flag so one + can choose the old dwarf_loclist() interface. + For testing. + * print_die.c: Rearranged to avoid code duplication. + Now supports .debug_loc fully. + * print_sections.c: Prints .debug_loc now. + +2003-09-29 David Anderson <davea@sgi.com> + + * print_die.c: with -v, print 'loclist' start and + end addr and also a hint that DW_FORM_indirect is used. + No change for normal output (for now). + +2003-05-19 David Anderson <davea@sgi.com> + * dwarfdump.c call dwarf_srcfiles() to get file names + per cu and pass down to die print routines. + Removed incorrect tests for when to print ".debug_info", + leaving simpler test. + * print_die.c globals.h: print file name (from line info) + with DW_AT_decl_file, adding data from dwarf_srcfiles + to argument list of a few routines to make that possible. + * print_sections.c: moved "line number info" string print so + it prints for -v as well as normal line ouput. + +2002-10-23 Amaury Le Leyzour amaury@sgi.com + * print_sections.c (print_weaknames): Changed + DW_DLA_TYPENAME to DW_DLA_WEAK at dwarf_dealloc(). + +2002-10-22 Tom Hughes <thh@cyberscience.com> + * print_sections.c: macro printing now supported. + * dwarfdump.c: removed erroneous dwarf_dealloc() + of string returned by dwarf_errmsg(). + +2002-11-22 David Anderson <davea@sgi.com> + * dwarf_names.awk at_list.awk: Allow an name to have two + spellings so the historical name preserved yet the dwarf3 + version is supported. First name seen is used/reported + by dwarfdump. + * dwarf.h: DW_TAG_template_type_param(eter) + DW_TAG_template_value_param(eter) DW_AT_namelist_itm(s) + are the ones with alternate spellings now. + Added Universal Parallel C TAGs/Attributes in + user namespace. + * tag_attr.c tag_attr.list tag_tree.c tag_tree.list: + Use the DW_TAG_template_* dwarf3 spellings. + + +2002-05-08 David Anderson <davea@sgi.com> + * tag_attr.list dwarf.h: DW_AT_namelist_items is + wrong, changed to DW_AT_namelist_item + +2002-04-29 Stephen Clarke <stephen.clarke@superh.com> + * dwarfdump.c (main): #ifdef for __CYGWIN__ on open(). + +2001-06-14 David Anderson <davea@sgi.com> + + * print_sections.c: Calling the new libdwarf function + dwarf_get_arange_cu_header_offset() so we can print + the cu header offset for aranges. + + +2000-07-14 Fred Fish <fnf@ninemoons.com> + + * configure.in (LOCATION_OF_LIBELFHEADER): Fix typo for configure + variable to be tested and enclose libelf/libelf.h in <>. + * configure: Regenerated. + +2000-07-10 Fred Fish <fnf@ninemoons.com> + + * Makefile.in (install): Install dwarfdump.1 from $(srcdir). + +2000 June 12 davea@sgi.com + print_sections.c the DW_CFA_offset_extended print + did not multiply by data-alignment factor in the + -v -v detailed output. + And the offsets used %2d when the values were + unsigned int, so now %2u. + + And not all cfa prints of values had + necessarily a type to match + %llu or %lld where required. Depended on the size of Dwarf_Signed + and Dwarf_Unsigned. + So now explicitly use cast to the + right type to match the % format. +2000 April 13 davea@sgi.com + print_sections.c - 1.56 + - A single byte of zero is a perfectly legitmate null + abbreviation entry (in .debug_abbrev) + now we print those directly and avoid a warning + from dwarfdump + + print_die.c - 1.42 + - Explain what combo checker is doing and make it + more maintainable (and fix bug which would + not be hit, but was real enough (in combo checker), + using too large a number as highest tag number). + + tag_tree.list - 1.2 + - Add valid parent/child relationships so checker + does not report valid entries as bogus. + + + + +2000 Feb 24 + Jason Merrill <jason@cygnus.com> noticed that gcc did + not like gcc -E foo.list, so incorporated his fix so + now the Makefile.in makes a link and does gcc -E _tmp.c + +2000 Jan 26 + elena.demikhovsky@intel.com noticed that 3 statements in + print_sections.c got warnings from the compiler + she was using. Simple casts (provided by her) fixed these. + +1999 July 21 + davea@sgi.com + print_sections changed to allow printing + of dwarf-ish egcs c++ .eh_frame data + + +1999 June 14 + Fred Fish fnf@ninemoons.com contributed + autoconf'ing of the libdwarf and dwarfdump source. + + + +1999 June 10 + ChangeLog started. davea@sgi.com David Anderson diff --git a/dwarfdump/ChangeLog2007 b/dwarfdump/ChangeLog2007 new file mode 100644 index 0000000..d1230b5 --- /dev/null +++ b/dwarfdump/ChangeLog2007 @@ -0,0 +1,108 @@ +2007-12-09 DavidAnderson <davea42@earthlink.net> + * print_sections.c print_frames.c: Forgot to commit yesterday. + yesterday's commit includes renaming _dwarf_fde_section_offset + _dwarf_cie_section_offset, _dwarf_print_lines, _dwarf_ld_sort_lines + to dwarf_* form while retaining support for the now obsolete + _dwarf_* form. +2007-12-08 DavidAnderson <davea42@earthlink.net> + * config.h.in, configure.in: Latest linux libelf.h requires + _GNU_SOURCE to get off64_t defined so dwarfdump compiles. + Only define _GNU_SOURCE if libelf.h defines off64_t. + Regenerated configure. + * config.guess, config.sub: Updated to 2.61 + * acconfig.h: Deleted, removing autoconf complaint. +2007-10-15 DavidAnderson <davea42@earthlink.net> + * print_die.c (clean_up_die_esb): New function + cleans up malloc space. + * print_reloc.c (clean_up_syms_malloc_data): New function + cleans up malloc space. + * dwarfdump.c (main): Call new cleanup functions at end. + * globals.h: Declare new cleanup functions. + +2007-09-04 DavidAnderson <davea42@earthlink.net> + * print_die.c (print_attribute): For DWARF4: DW_AT_high_pc: + add qualifier to value when the value is an offset from + DW_AT_low_pc (thus not itself a address). + Update the address of the FSF. + * print_frames.h DWARFDUMPCOPYRIGHT print_sections.c + print_reloc.c dwarfdump.c tag_tree.c tag_attr.c + esb.c esb.h makename.c acconfig.h dwconf.c makename.h + dwconf.h globals.h print_frames.c: + Update the address of the FSF. + +2007-07-03 DavidAnderson <davea42@earthlink.net> + * print_sections.c (dump_block): Removed superfluous return byte from + printed characters. Removed unused variables. + * print_die.c: A little refactoring for clarity. + * globals.h: dwarfdump_print_one_locdesc() is now a + global-to-dwarfdump function. + * print_frames.c: Now (with -v) prints dwarf expression bytes + in frame expressions readably. +2007-07-02 DavidAnderson <davea42@earthlink.net> + * dwarfdump.c: Add new -R option for 'generic' register sets. + * dwarfdump.1: document -R, add new -x documentation. + * dwconf.c: Set up -R configuration. Slight revision of + register printing code. + * dwconf.h: Interface to register name printing simplified. + * print_frames.c: Use the simpler register name interface. + * dwarfdump.conf: Add new 'generic' abi for up to 1000 registers. + +2007-07-01 DavidAnderson <davea42@earthlink.net> + * print_frames.c: For DW_CFA_def_cfa_sf & DW_CFA_def_cfa_offset_sf + print a computed data alignment factor. +2007-06-29 DavidAnderson <davea42@earthlink.net> + * dwarfdump.1: Corrected spelling error. +2007-05-25 DavidAnderson <davea42@earthlink.net> + * dwconf.h dwconf.c: Changed field name to + cf_named_regs_table_size as old name was less than clear. + * dwarfdump.c: Call frame table setup with + cf_table_entry_count not cf_named_regs_table_size. The newly + renamed field makes it clearer the call was wrong. +2007-05-04 DavidAnderson <davea42@earthlink.net> + * print_die.c: printing of global offset of DIEs + with -G is now more in the style of previous output. +2007-04-18 Chris Quenelle <chris.quenelle@sun.com> + * Makefile.in: + - use $(srcdir) for files in source directory + - support running rules in parallel by + - use different tmp file names in different rules. + - use more accurate target for dwarf_names.{c,h} + * dwarf_names.awk: Enhance script to be able to generate either + #define-style headers or enum-style headers + * dwarfdump.c: dump most everything by default if no arguments + are given to dwarfdump. This seems to be a more useful default + than showing nothing at all. Also add a -G option to show + the (G)lobal section offset for each die within an a.out. If you + think you're seeing data corruption inside a .debug_info + section, this is a useful option to have. + * print_die.c: Support compressed integer blocks. This is an + array (DW_FORM_block) of LEB numbers used as part of a Sun + extension, DW_AT_SUN_func_offsets. Also add support for + a new dwarf enum DW_ATCF_xxxx. This is used in DW_AT_SUN_cf_kind. + Also, fix DW_AT_upper_bound so it can be a constant or a location + list. DW_AT_count and DW_AT_data_member_location should also be + fixed eventually. + * print_sections.c: Changes to support zero-padding in the middle of + section data. Change offset labels to be a little more clear. + Not sure about the get_str failure. + * tag_tree.list: DW_TAG_compile_unit can contain a DW_TAG_namespace +2007-04-10 David Anderson <davea42@earthlink.net> + * print_reloc.c dwarfdump.c print_frames.c: Unified + copyright to the SGI form. No copyright change. + +2007-04-06 David Anderson <davea42@earthlink.net> + * print_die.c (print_die_and_children): Increase static + depth of die stack. Notice if it overflows and + print error. +2007-02-23 David Anderson <davea42@earthlink.net> + * print_reloc.c: 2 lines added (long) cast in printf + and made %3ld instead of %3d to fix compiler warning. + * print_frames.c: newline was missing from the output. + Thanks to Chris Quenelle for noticing. +2007-02-20 David Anderson <davea42@earthlink.net> + * print_frame.c (print_frame_inst_bytes): Fixed + an off by one error (several places) + when printing dwarf expressions and added commentary about it. + Thanks to Julian Seward for pointing out it was off by one. + * dwarfdump.c (print_error): added fflush of stdout, stderr + where we are going to exit right away anyway. diff --git a/dwarfdump/ChangeLog2008 b/dwarfdump/ChangeLog2008 new file mode 100644 index 0000000..24a1ffa --- /dev/null +++ b/dwarfdump/ChangeLog2008 @@ -0,0 +1,96 @@ +2008-12-30 David Anderson <davea42@earthlink.net> + * tag_attr.list: Mark DW_AT_artificial as sensible on + DW_TAG_variable. + * dwarfdump.1: Document -N option to print .debug_ranges. + * Makefile.in: add new source header files + * dwarfdump.c: Implement -N to print .debug_ranges. + * print_sections.c: Allow more flexible printing + of function names for .debug_frame section. + With -N, print .debug_ranges. + * print_die.c: Print .debug_ranges details. + * print_frames.c: Delete useless comment. + * globals.h: Allow re-use of debug_ranges formatting code. + * Makefile.in: Make the header dependency list more complete. + * makename.h: Comment tweaked. +2008-12-08 David Anderson <davea42@earthlink.net> + * print_die.c: the -M option now also prints the form + number (after the form name). And -v prints the DIE + abbreviation code, the index into the relevant abbreviation + table. + * globals.h: Removed unused global variable. + * dwarfdump.c: Removed unused global variable. + * dwarfdump.1: document -M and the new -v features. +2008-12-07 David Anderson <davea42@earthlink.net> + * print_reloc.c (print_relocinfo): Removed unused local variable. +2008-11-19 David Anderson <davea42@earthlink.net> + * globals.h: Added new boolean to support -M. + * dwarfdump.1: Mentioning the -M option. + * dwarfdump.c: Implementing -M, which has each attribute line + show the name of the form. + * print_die.c: Implementing -M option. +2008-10-12 David Anderson <davea42@earthlink.net> + * dwarfdump.conf: Adding power pc register names and table + size for use with -x abi=ppc . +2008-08-13 David Anderson <davea42@earthlink.net> + * dwarfdump.1: When no options (just object files) present + all sections print, now we say that. Renamed fields + in synopsis for readability. +2008-06-23 David Anderson <davea42@earthlink.net> + * print_reloc.c (print_reloc_information_64): Was testing + sym_data_entry_count one place where sym_data_64_entry_count + should have been tested. Thanks to Carlos Alberto Enciso + for noticing. +2008-06-17 David Anderson <davea42@earthlink.net> + * print_die.c: Add to dwarf_formstring failure message. + * README: Correct email: the old sgi.com address is no + longer correct. +2008-06-13 David Anderson <davea42@earthlink.net> + * dwconf.c: Fix an off-by-one condition where + we could index off the end of the cf_regs array in printing + a register name. +2008-04-12 David Anderson <davea42@earthlink.net> + * print_reloc.c: Verify stringtab exists and is + large enough before indexing into it to get a string + in printing relocations. + (Providing default name "<no name>" so it's evident from + the output that we used a default name string). +2008-04-09 David Anderson <davea42@earthlink.net> + * print_sections.c (get_fde_proc_name): Initialize some + local variables at declaration. The function is very slow + and needs a replacement. + * print_die.c: Fixes a typo in a comment. + * dwarfdump.c: Added -n option to suppress function name search + when printing FDEs. Current dwarfdump is n-squared at least + getting those names, this is a bandage-type-workaround when + there are so many FDEs the slowness is painful. + * globals.h: Support for -n option. + * print_frames.c: Support for -n option. +2008-04-08 David Anderson <davea42@earthlink.net> + * dwarfdump.c: Added -H option for testing + (it limits the run length). + And the support for -H in printing DIEs. + * globals.h: Added extern for -H option declaration. + * print_sections.c: Added -H option support to limit frames printing. + +2008-04-04 David Anderson <davea42@earthlink.net> + * print_die.c (tag_tree_combination, tag_attr_combination): + Ensure we do not index off the end of the -k checking arrays. + * print_sections.c: Increase the size of a local variable,. +2008-03-03 David Anderson <davea42@earthlink.net> + * dwarfdump.1: Add description of -ka option. + * print_frames.h print_sections.c testesb.c print_die.c print_reloc.c + dwarfdump.c tag_tree.c tag_attr.c esb.c esb.h makename.c dwconf.c + makename.h dwconf.h globals.h print_frames.c: Change tabs + to spaces with expand(1). +2008-03-03 David Anderson <davea42@earthlink.net> + * print_die.c: Now check that DW_AT_decl_file + and DW_AT_call_file indexes are valid and count instances of the + attribute and errors found in it. + * dwarfdump.c: With -ka and -ky now check that DW_AT_decl_file + and DW_AT_call_file indexes are valid and warn if bad. + Thanks to Carlos Alberto Enciso for the suggestion. + * globals.h: Declare new fields for the DW_AT_decl_file + DW_AT_call_file checks. +2008-02-26 David Anderson <davea42@earthlink.net> + * print_die.c (get_attr_value): Print DW_AT_call_file, + DW_AT_call_line, DW_AT_call_column nicely. diff --git a/dwarfdump/ChangeLog2009 b/dwarfdump/ChangeLog2009 new file mode 100644 index 0000000..9d9a2d5 --- /dev/null +++ b/dwarfdump/ChangeLog2009 @@ -0,0 +1,280 @@ +2009-12-30 DavidAnderson <davea42@earthlink.net> + * configure: Regenerated with autoconf 2.64. + * config.guess, config.sub: Delete these, best not + to have them. +2009-11-24 DavidAnderson <davea42@earthlink.net> + * tag_common.h: Updated 'standard tag table row' and + tag table column maximums now the DWARF4 entries are + in the .list files. Removed dos 'CR' characters at line ends. + * tag_tree.list, tag_attr.list: Added various + DWARF4 entries and added DW_TAG_enumeration_type + under DW_TAG_union_type. +2009-11-17 DavidAnderson <davea42@earthlink.net> + * dwarfdump.1: Document the -u option more fully. + * print_die.c: Check for both info_flag and + cu_name_flag to decide when to print DIEs. +2009-10-12 DavidAnderson <davea42@earthlink.net> + * dwarfdump.c: Updated dwarfdump version string to today. +2009-09-30 DavidAnderson <davea42@earthlink.net> + * dwarfdump.c: Added globals for aranges checking and + to print the resulting error count. + * print_aranges.c: Added checking that all 3 ways + of computing a cu_die_offset from an arange get + the same offset (checked with -r -ka). + * print_frames.c: DW_CFA_cfa_offset_extended_sf + corrected to DW_CFA_offset_extended_sf. +2009-09-01 DavidAnderson <davea42@earthlink.net> + * tag_tree.list: We add + DW_TAG_class_type as a valid child of a DW_TAG_union_type. +2009-08-05 DavidAnderson <davea42@earthlink.net> + * gennames.c: Change include from getopt.h to unistd.h + so the code is more universally compilable. +2009-07-24: David Anderson <davea42@earthlink.net> + * tag_attr.c: Remove duplicate include of naming.h. +2009-06-23: David Anderson <davea42@earthlink.net> + * strstrnocase.c: Corrected typo in TEST code and + added a new test. +2009-06-22: David Anderson <davea42@earthlink.net> + * Makefile.in: switched to personally written + string comparison, strstrnocase.c. + * stristr.c: deleted. + * strstrnocase.c: New code, written by me so no + license issues. + * print_die.c: Call is_strstrnocase(), the new function. + * dwarfdump.1: More fully document -S. + * globals.h: Create extern for is_strstrnocase(). +2009-06-18: David Anderson <davea42@earthlink.net> + * configure: Regenerated. + * Makefile.in: Add stristr.o + * stristr.c: public domain source added to dwarfdump + * print_die.c: Add code and arguments to support -S. + * print_lines.c: print_one_die argument list changed, added + the require argument.. + * dwarfdump.c: Added the -S option. + + * configure.in: Add test to set HAVE_REGEX for the -S option. + * dwarfdump.1: Document the -S options. + * config.h.in: Set the default HAVE_REGEX + * globals.h: Add -S globals, change the print_one_die() + prototype to support -S. + * print_aranges.c: Alter the print_one_die calls added + to support -S. +2009-06-06: David Anderson <davea42@earthlink.net> + * naming.c,naming.h: New files that implement the + ellipsis functionality of dwarfdump and defer to + libdwarf to get the names of the TAGs, attributes, FORMs, etc. + * gennames.c: This file has moved to libdwarf, no longer + present in dwarfdump. + * esb.h, esb.c: Change certain char* arguments to const char* + to avoid compiler warnings. + * print_static_vars.c,print_static_funcs.c, + print_sections.c,print_strings.c, print_locs.c, + print_lines.c, print_pubnames.c,print_ranges.c, + print_macros.c,print_types.c,tag_common.c, + print_weaknames.c, print_aranges.c: Include + changed from dwarf_names.h to naming.h + * tag_common.h: Removed the tag_name array, libdwarf + provides the TAG, ATTR, etc name strings now. + * dwarfdump.c: Updated DWARFDUMP_VERSION string. + * tag_tree.c,tag_attr.c: Include changed from dwarf_names.h to + naming.h. simplified long complicated lines, remove dbg argument + to get_TAG_name. + * print_die.c,print_abbrevs.c: Include changed from dwarf_names.h + to naming.h. + Calls to get_TAG_name (etc) no longer have a dbg argument. + * Makefile.in: We no longer build generated file names.c, + we build naming.c (hand coded, not generated). +2009-05-07: David Anderson <davea42@earthlink.net> + * dwarfdump.cc: updated DWARF_VERSION string. + * Makefile.in: dwarf_names* are now generated by C, + so 'clean' now cleans them out. +2009-05-04: David Anderson <davea42@earthlink.net> + * common.h, common.c: Extracted simple utility routines + into their own files. + * dwarf_names.awk, at_list.awk: deleted. gennames.c replaces these. + * tag_common.c, tag_common.h: Removed the simple utility + routines from these files to simplify dependencies. + * tag_attr.c, tag_tree.c: Include new common.h. + * print_frames.c: Adding address_size argument to call. + * print_frames.h: Adding new address_size argument to + get_string_from_locs() declaration. + * print_locs.c: Gets and uses CU-specific address_size. + * print_ranges.c: Adding commentary. + * print_die.c: adding DIE argument to ensure correct + address size used for the CU in question. + * Makefile.in: Now handles common.* and gennames.c changes. + * gennames.c: New code emitting string 'get name' source. + Replaces awk source. +2009-04-04: David Anderson <davea42@earthlink.net> + * Makefile.in: clean up 'clean' and 'distclean' + so that distributed files are not cleaned out by 'clean' + and all generated files (even those shipped in + distribution) are cleaned out by distclean. + * dwarfdump.c: Now calls the new + libdwarf function dwarf_set_frame_cfa_value() and other + such functions to specify all the values libdwarf needs. + * dwarfdump.conf: Sets the cfa_reg: value to + a new higher value (1436) to avoid conflict with largest + known register count. + * dwconf.h: Corrected commentary on DW_FRAME_CFA_COL3. + * dwconf.c: Now uses DW_FRAME_CFA_COL3 as default for + interface 3, rather than a directly typed number. + Sets undefined-value and same-value pseudo-register numbers. +2009-04-03: David Anderson <davea42@earthlink.net> + * dwarfdump.1: Amplified -R and -x abi= documentation. + * dwarfdump.conf: Added generic500 generic100 abis. +2009-03-29: David Anderson <davea42@earthlink.net> + * print_die.c: Moved print_infos() to here. + * dwarfdump.c: Moved print_infos() out of here. + * globals.h: Declarations changed to allow moving + print_infos(). + * dwarf_names.awk: Eliminate a pointless space before + a newline in the generated code. + * print_locs.c: Add -v section offset output to loclist printing + of the debug_loc section so the entries can be matched to + loclist printing initiated from .debug_info. +2009-03-24: David Anderson <davea42@earthlink.net> + * README: Would be nice if all could use dwarfdump2, + not this C dwarfdump. + * dwconf.c: Initialize new frame regs configure data and + parse it in the .conf file. Fixed old formatting mistakes. + * dwconf.h: Add new fields to frame regs configure struct. Make -R + be 1200 regs so that -R covers all the currently popular ABIs. + * print_die.c, print_lines.c, print_frames.c: Change %# to + 0x% so that zero prints with leading 0x consistently. + * dwarfdump.c: -R is now 1200 registers. So config function + changed and usage message needed update. + * dwarfdump.1: Change -R to 1200 and document -C. + * dwarfdump.conf: Add same_val_reg: and undefined_val_reg: + initial values where needed or interesting. + * print_macros.c: Fix old formatting mistake. +2009-03-23: David Anderson <davea42@earthlink.net> + * print_sections.h: New file for print_*.c + sources. + * dwarfdump.1: Added -C documentation. + * Makefile.in: updated 'mandir' so it works with + current configure (so now make install properly installs + the man page). + * print_sections.c: Moved get_fde_proc_name() and related + code to print_frames.c, where it is referenced. + * dwarfdump.c: No longer turn on info_flag with -f or -F. + Moved the Usage strings into a string table and loop through + to print them. + * globals.h: Removed get_fde_proc_name() declaration. + * print_frames.c: Added get_fde_proc_name() here + and removed the 'inlined:' from the abstract origin + name. +2009-03-20: David Anderson <davea42@earthlink.net> + * print_static_vars.c, print_static_funcs.c, print_strings.c, + print_locs.c, print_pubnames.c, print_lines.c, print_ranges.c, + print_abbrevs.c, print_macros.c, print_types.c, print_weaknames.c, + print_aranges.c: Moved the print_* functions from print_sections.c + into individual sourcefiles. + * Makefile.in: Now lists the new sourcefiles. + * print_sections.c: Deleted code moved to individual sourcefiles. + Added code to try to find the name from a DW_AT_abstract_origin + DIE when a subprogram DIE itself has no DW_AT_name; + * dwarfdump.c: Remove unused local variables. Use DWARFDUMP_VERSION + #define to set version string. + * tag_tree.c: Fix && || problem with parentheses. + * tag_attr.c: Fix && || problem with parentheses. + * print_frames.c: Moved the 'print_frames' function itself from + print_sections.c to here. +2009-03-17: David Anderson <davea42@earthlink.net> + * globals.h: Created predicate function + should_skip_this_cu() predicate function. Eliminating + code duplication. + * print_frames.c: Fix a hex value output to have a leading + 0x as all hex values should (when printed). + * print_sections.c: Call should_skip_this_cu(), which + replaces duplicate code. + Fix the arange print: now the hex value has a leading 0x + as all hex values should. get_proc_name() had local + variable funcnamefound initialized incorrectly, now is + set to 0 as it should be. get_nested_proc_name() + now initializes string buffers. get_fde_proc_name() + now initializes its string buffer. Surprisingly + things worked adequately before in spite of the errors. + * dwarfdump.c: Call should_skip_this_cu(). Implementation + of that new function is in this source file. +2009-03-16: David Anderson <davea42@earthlink.net> + * print_frames.c:DW_CFA_restore output had a spurious newline. + Removed 2 pointless blank lines an initialized 2 local variables. + * print_sections.c: Removed a pointless redeclaration of a function + in libdwarf.h. check_info_offset_sanity() was missing a + return statement in one place, which could lead to spurious + extra (and silly) error text. +2009-03-09: David Anderson <davea42@earthlink.net> + * print_die.c: Make a comment easier to understand. +2009-02-28: David Anderson <davea42@earthlink.net> + * Makefile.in: add tmp-*.tmp to the 'clean' rule. +2009-02-17: David Anderson <davea42@earthlink.net> + * print_sections.c,print_die.c,tag_common.c,print_frames.c: C99 + in-line declarations and // comments are not intended here, + this removes a few that were introduced accidentally. +2009-02-16: David Anderson <davea42@earthlink.net> + * Makefile.in: Removed some use of awk and + simplified some shell scripting here. + renamed temp files, no longer named with + underbars, they uniformly start with 'tmp-'. + * print_sections.c: Added the new argument required + by the updated dwarf_names.c functions argument lists. + * tag_tree_ext.list: List 'common extensions' + of tag->tag relationships. + * tag_attr_ext.list: List 'common extensions' + of tag->attr relationships. + * print_die.c: New 'common extension' tables used + for checking tag->tag and tag->attr relationships + unless turned off with -C. + * dwarf_names.awk: Removed tabs so generated names.c not so + spread out. Added argument to the generated functions so + tag_tree.c, tag_attr.c can use these generated functions nicely. + * dwarfdump.c: Adding -C option, which exposes + some 'common extensions' of dwarf uses as DWARF CHECK + (-ka) warnings. By default these extensions not reported + as warnings. + * tag_tree.c: Now generates base and extensions tables. + Code in common with tag_attr.c is in tag_common* files. + * tag_attr.c: Now generates base and extensions tables. + Code in common with tag_tree.c is in tag_common* files. + * tag_common.c, tag_common.h: New files with the common + data extracted from tag_tree.c and tag_attr.c + * globals.h: global flag added for -C. + +2009-02-14: David Anderson <davea42@earthlink.net> + * configure.in: Define --enable-nonstandardprintf + * config.h.in: new #undef HAVE_NONSTANDARD_PRINTF_64_FORMAT + * configure: Regenerated. + * config.guess, config.sub: Latest version from GNU. + * Makefile.in: Referenced configure variable to avoid + irritating message at configure time. + * README: document --enable-nonstandardprintf + * print_sections.c, print_die.c, print_reloc.c, dwarfdump.c, + dwconf.c, print_frames.c: Use libdwarf.h DW_PR_ printf macros + for for better portability. +2009-02-13: David Anderson <davea42@earthlink.net> + * print_sections.c: Ensure we are checking line table header + correctness whichever line-table-print code is being used. + Allow ARM line header table (which has a bug) to be used. + * dwarfdump.c: Print lines_result total with checking on. + * globals.h: Add lines_result global to count line botches. +2009-02-11: David Anderson <davea42@earthlink.net> + * print_sections.c, print_die.c: DWARF_CHECK_ERROR* + macros now get the count struct passed in. + * tag_tree.c, tag_attr.c: Add a comment in the output + identifying the output as generated code and + with the generation date/time inserted. + * globals.h: Accept the struct in DWARF_CHECK_ERROR* + macros so we can update the error count in the macro. +2009-01-31: David Anderson <davea42@earthlink.net> + * Makefile.in: Remove compilation of _tag_attr_table.c + and _tag_tree_table.c as those are #included in + print_die.c, not separately compiled. + * print_frames.c: A formerly-static function now called + from another file, so declare it here. + * print_sections.c: Improve the printing of the .debug_loc + section. + * print_die.c: A couple of errors were missing their error + count increment. + * tag_attr.list tag_tree.list: Some normal relationships + were left out of the tables: fixed now. diff --git a/dwarfdump/ChangeLog2010 b/dwarfdump/ChangeLog2010 new file mode 100644 index 0000000..e281cae --- /dev/null +++ b/dwarfdump/ChangeLog2010 @@ -0,0 +1,105 @@ +2010-09-30 DavidAnderson <davea42@earthlink.net> + * dwarfdump.c: Now -a no longer implies -c because + the -c option is not guaranteed to work by the DWARF spec, + nor is -c really necessary. + * README: More tweaks on the 'install' issue. +2010-09-29 DavidAnderson <davea42@earthlink.net> + * README, Makefile.in: Amplified make install instructions. +2010-09-20 DavidAnderson <da + * dwarfdump.1: The -c option is not guaranteed to work. + Because .debug_loc can have garbage bytes in areas + not referenced by .debug_info. +2010-06-29 DavidAnderson <davea42@earthlink.net> + * print_die.c: If a location form is wrong report + an error but continue operating. + * dwarfdump.c: Implement print_error_and_continue(). + Fix mistakes in usage message. + * globals.h: Declare print_error_and_continue(). +2010-04-04 DavidAnderson + * dwarfdump.c: New version date. + * configure: regenerated. + * addrmap.c: Added a comment to mention that tdestroy is + GNU only, POSIX does not mention a way to delete the + tsearch tree. Hence the code does #define USE_GNU 1 + to expose the tdestroy function prototype. +2010-04-03 DavidAnderson <davea42@earthlink.net> + * print_frames.h: Added new arguments to a function to get better + function names printing. + * configure.in: Added test for tsearch functions so dwarfdump + will still compile if they are not present. + See HAVE_TSEARCH macro. + * configure: regenerated. + * Makefile.in: Now names object for addrmap.c + * addrmap.c: New file to map pc address to function names + so fde printing gets functions named properly (using tsearch). + * addrmap.h: New file to map pc address to function names + so fde printing gets functions named properly (using tsearch). + * print_lines.c: Correct the calculation of the number + of error checks. + * dwarfdump.c: Added fdes error check print. + * config.h.in: Now handles the HAVE_TSEARCH macro. + * globals.h: Added declarations for the fde error check + globals. + * print_frames.c: Now uses addrmap.h functions to do a + better job of printing function names in the frame output. +2010-03-31 DavidAnderson <davea42@earthlink.net> + * dwarfdump.1: Added some text about 'harmless' + errors. + * dwarfdump.c: Change the size of the harmless error list + to 50. Change harmless error reporting to be associated + with -k flags. + * dwconf.c: Initialize uninitialized fields to satisfy + a compiler warning. + * globals.h: Declarations added for 'harmless' error + reporting. + * print_die.c: Added commentary. + * print_frames.cc: Change harmless error reporting to be + associated with -k flags. + * print_aranges.c: Now calls dwarf_get_arange_info_b() + allowing proper printing of DWARF4 segment-sensitive + aranges. Change harmless error reporting to be + associated with -k flags. +2010-03-28 DavidAnderson <davea42@earthlink.net> + * dwarf_globals.h: Added interface to print_any_harmless_errors(). + * dwarfdump.c: Added print_any_harmless_errors() implementation + and we call it just before closing libdwarf. + * print_frames.c: Call print_any_harmless_errors after + getting cie/fde list. + * dwarfdump.conf: Add abi named 'arm' for Arm users. + * print_die.c: Initialize a local string pointer to NULL at + the point of definition. +2010-02-14 DavidAnderson <davea42@earthlink.net> + * print_die.c: Add newer DW_OP operators, remove + bogus test of DW_OP_nop as the highest valid operator. + Add table of DW_OPs to simplify testing for zero-operand + operators. + Revise so that the FORM of all attributes print with -M. + Move a local variable declaration to the front of a block + to match C 1990 rules. + String searches now also match on attribute name. + * tag_attr.list: Updated copyright. + * dwarfdump.c: Remove a switch FALL THROUGH in the 'g' case. + * tag_tree_ext.list, tag_attr_ext.list: Added GNU template + parameter tags, attributes. Updated copyright. + * tag_tree.list: Added template parameter tags. Added + entry for nested classes. Updated copyright. + * tag_common.h: Increased STD_TAG_TABLE_COLUMNS and + EXT_ATTR_TABLE_COLS. +2010-01-30 DavidAnderson <davea42@earthlink.net> + * print_die.c: Changed the spelling of one + 'DW_AT_type offset does not point to type info' error message so + one can distinguish which check lead to the message. +2010-01-26 DavidAnderson <davea42@earthlink.net> + * dwarfdump.1, dwconf.c, dwconf.h, dwarfdump.conf: The default + frame values in frame + output are now generic registers like r0 to r99 + instead of MIPS register names. + For the MIPS register names use '-x abi=mips'. + * print_frames.c: Added commentary. +2010-01-17 DavidAnderson <davea42@earthlink.net> + * print_die.c: The special case DW_AT_SUN_func_offsets + now prints identically in dwarfdump and dwarfdump2. +2010-01-03 DavidAnderson <davea42@earthlink.net> + * tag_common.c, common.h, common.c: Remove <cr> line + terminator characters. Update copyright year. + * All other files: Update copyright year. diff --git a/dwarfdump/DWARFDUMPCOPYRIGHT b/dwarfdump/DWARFDUMPCOPYRIGHT new file mode 100644 index 0000000..cf465e2 --- /dev/null +++ b/dwarfdump/DWARFDUMPCOPYRIGHT @@ -0,0 +1,85 @@ + +========The dwarfdump copyright======= + +The full text of the GPL version 2 is provided in the file GPL.txt. + +Nearly all the files in this directory have contained a GPL +copyright, not an LGPL copyright, for years. The following +is an example of that copyright as used in the dwarfdump +source, and is what SGI always intended (in David +Anderson's opinion) to have present in +the DWARFDUMPCOPYRIGHT file. (tag_tree.list tag_attr.list +acconfig.h have long been marked LGPL and therefore the LGPL +copyright, not GPL, applies to those three files.) This GPL +copyright text added here to DWARFDUMPCOPYRIGHT Dec 4, 2006 + + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, 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 + + +The following was the entire content of this file before +December 24 2006, Being the LGPL text this is in conflict +with the individual source files and I (David Anderson) +believe the source file copyright was intended for dwarfdump +not the LGPL source directly following this note. However the +3 files tag_tree.list tag_attr.list acconfig.h have long been +marked LGPL and the following copyright applies to those three. + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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 + diff --git a/dwarfdump/GPL.txt b/dwarfdump/GPL.txt new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/dwarfdump/GPL.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/dwarfdump/Makefile.in b/dwarfdump/Makefile.in new file mode 100644 index 0000000..19278f3 --- /dev/null +++ b/dwarfdump/Makefile.in @@ -0,0 +1,191 @@ +# +# Makefile for dwarfdump +# This is made very simple so it should work with +# any 'make'. +# The Makefile does assume that libdwarf is at ../libdwarf +# from the dwarfdump2 source directory. +# + +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +mandir = $(exec_prefix)/share/man +man1dir = $(mandir)/man1 + + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +DATAROOT = @datarootdir@ +SHELL = /bin/sh +CC = @CC@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +RM = rm +RANLIB = @RANLIB@ +DEFS = @DEFS@ +# ../libdwarf gets us to local headers and a libdwarf +# archive, usually, so we assume it. +DIRINC = $(srcdir)/../libdwarf +LIBS = @LIBS@ -L../libdwarf -ldwarf -lelf +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libdwarf +CFLAGS = $(PREINCS) @CFLAGS@ $(INCLUDES) -DCONFPREFIX=${libdir} $(POSTINCS) +LDFLAGS = $(PRELIBS) @LDFLAGS@ $(LIBS) $(POSTLIBS) + + +INSTALL = cp + +binprefix = + +FINALOBJECTS = \ + addrmap.o \ + checkutil.o \ + dwarfdump.o \ + dwconf.o \ + esb.o \ + print_abbrevs.o \ + print_aranges.o \ + print_die.o \ + print_frames.o \ + print_lines.o \ + print_locs.o \ + print_macros.o \ + print_pubnames.o \ + print_ranges.o \ + print_reloc.o \ + print_sections.o \ + print_static_funcs.o \ + print_static_vars.o \ + print_strings.o \ + print_types.o \ + print_weaknames.o \ + strstrnocase.o \ + uri.o +GEN_HFILES = common.o \ + tmp-tt-table.c \ + tmp-ta-table.c \ + tmp-ta-ext-table.c \ + tmp-tt-ext-table.c + +all: dwarfdump + +HEADERS = $(srcdir)/checkutil.h \ + $(srcdir)/common.h \ + $(srcdir)/dwconf.h \ + $(srcdir)/esb.h \ + $(srcdir)/globals.h \ + $(srcdir)/makename.h \ + $(srcdir)/print_frames.h \ + $(srcdir)/uri.h + +$(FINALOBJECTS): $(GEN_HFILES) $(HEADERS) $(srcdir)/naming.c + +default: $(TARGETS) + +dwarfdump: $(FINALOBJECTS) makename.o naming.o common.o + $(CC) $(CFLAGS) -o $@ $(FINALOBJECTS) common.o makename.o naming.o $(LDFLAGS) + +#tag_common.o: $(srcdir)/tag_common.c $(HEADERS) dwarf_names.h +# $(CC) $(CFLAGS) -c $(srcdir)/tag_common.c +makename.o: $(srcdir)/makename.h $(srcdir)/makename.c + $(CC) $(CFLAGS) -c $(srcdir)/makename.c +common.o: $(srcdir)/common.c $(srcdir)/common.h + $(CC) $(CFLAGS) -c $(srcdir)/common.c +gennames: $(srcdir)/gennames.c $(DIRINC)/dwarf.h $(HEADERS) common.o + $(CC) $(CFLAGS) $(srcdir)/gennames.c common.o $(LDFLAGS) -o gennames +naming.o: $(srcdir)/naming.c $(srcdir)/naming.h + $(CC) $(CFLAGS) -c $(srcdir)/naming.c + +# We need this as naming.o has external references we cannot have +# in the tree builds. +trivial_naming.o: $(srcdir)/naming.c + $(CC) $(CFLAGS) -DTRIVIAL_NAMING -c $(srcdir)/naming.c -o trivial_naming.o + +tag_tree_build: $(srcdir)/tag_tree.c $(DIRINC)/dwarf.h $(HEADERS) tag_common.o makename.o common.o trivial_naming.o + $(CC) $(CFLAGS) $(srcdir)/tag_tree.c tag_common.o common.o makename.o trivial_naming.o $(LDFLAGS) -o tag_tree_build + +tag_attr_build: $(srcdir)/tag_attr.c $(DIRINC)/dwarf.h $(HEADERS) tag_common.o makename.o common.o trivial_naming.o + $(CC) $(CFLAGS) $(srcdir)/tag_attr.c tag_common.o common.o makename.o trivial_naming.o $(LDFLAGS) -o tag_attr_build + +tmp-tt-table.c tmp-tt-ext-table.c: $(srcdir)/tag_tree_ext.list $(srcdir)/tag_tree.list tag_tree_build + # gcc -E tag_tree.list does not work, so use a .c name + -rm -f tmp-t1.c + cp $(srcdir)/tag_tree.list tmp-t1.c + $(CC) $(CFLAGS) -E tmp-t1.c > ./tmp-tag-tree-build1.tmp + ./tag_tree_build -s -i tmp-tag-tree-build1.tmp -o tmp-tt-table.c + -rm -f tmp-t4.c + cp $(srcdir)/tag_tree_ext.list tmp-t4.c + $(CC) $(CFLAGS) -E tmp-t4.c > ./tmp-tag-tree-build4.tmp + ./tag_tree_build -e -i tmp-tag-tree-build4.tmp -o tmp-tt-ext-table.c + +tmp-ta-table.c tmp-ta-ext-table.c: $(srcdir)/tag_attr_ext.list $(srcdir)/tag_attr.list tag_attr_build + # gcc -E tag_attr.list does not work, so use a .c name + -rm -f tmp-t2.c + cp $(srcdir)/tag_attr.list tmp-t2.c + $(CC) $(CFLAGS) -E tmp-t2.c > ./tmp-tag-attr-build2.tmp + ./tag_attr_build -s -i tmp-tag-attr-build2.tmp -o tmp-ta-table.c + -rm -f tmp-t3.c + cp $(srcdir)/tag_attr_ext.list tmp-t3.c + $(CC) $(CFLAGS) -E tmp-t3.c > ./tmp-tag-attr-build3.tmp + ./tag_attr_build -e -i tmp-tag-attr-build3.tmp -o tmp-ta-ext-table.c + + +# The file dwarf_names.awk generates BOTH dwarf_names.h and dwarf_names.c +# be careful of the make dependencies here +dwarf_names.h: gennames $(DIRINC)/dwarf.h + rm -f dwarf_names.h dwarf_names.c + ./gennames -s -i ../libdwarf -o . +dwarf_names.c: dwarf_names.h + +test: esb.o $(srcdir)/testesb.c + $(CC) -o test $(srcdir)/testesb.c esb.o + ./test + -rm -f ./test + + +# This simply assumes that a default INSTALL (cp) command +# will work and leave sensible permissions on the resulting files. +# Some adjustment might be required, see README. +install: all + $(INSTALL) dwarfdump $(bindir)/dwarfdump + $(INSTALL) $(srcdir)/dwarfdump.conf $(libdir)/dwarfdump.conf + $(INSTALL) $(srcdir)/dwarfdump.1 $(man1dir)/dwarfdump.1 + +uninstall: + -rm -f $(bindir)/dwarfdump + -rm -f $(man1dir)/dwarfdump.1 + -rm -f $(libdir)/dwarfdump.conf + +clean: + rm -f *.o dwarfdump + rm -f _tag_attr_table.c + rm -f _tag_attr_ext_table.c + rm -f _tag_tree_table.c + rm -f _tag_tree_ext_table.c + -rm -f tag_attr_build*.tmp + -rm -f tag_tree_build*.tmp + rm -f tag_tree_build + rm -f tag_attr_build + -rm -f _*.c _*.h + -rm -f tmp-*.c tmp-*.h tmp-*.tmp + rm -f gennames + rm -f dwarf_names_new.c + rm -f dwarf_names_new.h + rm -f dwarf_names_enum.h + rm -f dwarf_names.h + rm -f dwarf_names.c + + +distclean: clean + rm -f config.log config.h config.cache config.status + rm -rf autom4te.cache + rm -rf Makefile + +shar: + @echo "shar not set up yet" +dist: + @echo "dist not set up yet" diff --git a/dwarfdump/NEWS b/dwarfdump/NEWS new file mode 100644 index 0000000..ed4428b --- /dev/null +++ b/dwarfdump/NEWS @@ -0,0 +1,206 @@ +December 13, 2011 + Now prints missing line table column number as 0 (now + matching the DWARF spec), the previous + practice of printing -1 was always wrong. + And prints the DWARF3/4 new line table fields (when present). +October 29, 2011 + Added support for printing .debug_types (type unit) data. +October 26, 2011 + Added new features to Makefile.in and documented in README + how to build dwarfdump with headers or libraries in + non-standard places. +October 23, 2011 + By default the various places with string option values + and file paths all use URI transformation on input and + if the transformation does anything at all dwarfdump reports + the input and transformed strings. This makes it easy + to deal with strings and expressions and file paths + that are difficult to express in a shell (or that getopt + mangles). Options -q and -U give you control over this process. +October 07, 2011 + The -x abi=mips frame register abi in dwarfdump.conf is now + usable with modern MIPS objects as well as old IRIX objects. + There are other mips-* frame register setups described + in dwarfdump.conf for anyone testing that nothing new has + been added that conflicts with old IRIX/MIPS frame generation. +June 04, 2011 + Error checking is now distinct from section printing, making + error checking (the -k options) much easier to work with on + large objects. + So compiler-created errors can be found, the error reporting + now prints context information. +March 29, 2011 + Added many new correctness tests. Changed the format of + various items (line data prints in a more compact form, numbers + are more uniformly hexadecimal fixed length where that makes sense). + All the source files are uniformly indented to a multiple of 4 + characters and all intent-tabs in the source have been removed. + Major logic changes involved changing error-reporting to be + more detailed and adding new tests for incorrect DWARF. + Now reports error summary by the compiler name, not just overall. +January 26, 2010 + Changed the default frame-data register names from MIPS to + a generic set of registers. + Try '-x abi=mips' to get the traditional old MIPS register + naming. +June 22, 2009 + Added the -S option to dwarfdump. +June 10, 2009 + Moved the gennames.c code to libdwarf. +May 4, 2009 + Replaced awk source-generation of certain functions + with new gennames.c code. + Now we can print an object with an address_size that + varies by compilation unit. +April 4, 2009 + Corrected aspects of the frame-printing by ensuring we pass + all the information libdwarf needs for fully consistent behavior. + Three newly defined libdwarf calls calls made to ensure + that better behavior (specifically having dwarfdump consistently + recognize when registers are the cfa, undefined-value or same-value + pseudo registers). Updated dwarfdump.conf to set these same + things consistently. +Mar 22, 2009 + The -f and -F flags no longer also imply -i (it just + did not make sense to tie them (cannot recall why + it might have been tied before). +Mar 20, 2009 + Moved print_* functions from print_sections.c to individual + source files. Hopefully making the code a bit easier + to read. +Feb 16, 2009 + Added the -C option. It is a sort of 'pedantic' option + as it turns on warnings about certain commonly used + non-standard tag->tag and tag->attr relationships. + Added the tag_attr_ext.list tag_tree_ext.list files which + define the 'common use' extensions. +Feb 14, 2009 + Added configure option --enable-nonstandardprintf + which makes it easy to get printf of Dwarf_Unsigned (etc) + types correct even for non-standard compilers. +December 30, 2008 + Now we print the .debug_ranges section (with -N) + and the data for DW_AT_ranges (with -i). +December 8, 2008 + The -M option now causes printing of FORM details. + And -v adds details about abbreviation 'indexes' into + an abbreviation table (.debug_abbrev) + providing more detail for folks debugging or + improving their understanding of DWARF data. +April 9, 2008 + Added -H <num> to limit the number of compilation-units/FDEs + dwarfdump prints in one run. Added -n to eliminate function-name + printing in .debug_frame output (with a large-enough debug_info + section function-name printing is too slow). The function name + printing will be fixed in another release. +December 8, 2007 + Had to add an ugly configure conditional as libelf has + unconditional use of off64_t in recent libelf.h +July 3, 2007 + Now with -v dwarf expression blocks in frame operations + are printed expanded out. +July 2, 2007 + Added a new abi -x abi=general usable for any cpu with + up to 1000 registers. +May 7, 2007 + Sun Microsystems contributes new dwarf.h extensions and a new -G option + to dwarfdump -i (so one can see the 'global' offset to DIEs). + Thanks to Chris Quenelle of Sun. +April 17, 2006 + New -x name=<conf file> -x abi=<abiname> and configuration file + enable sensible printing of a wide range of .debug_frame eh_frame + correctly without recompiling dwarfdump or touching libdwarf.h or + dwarf.h. +March 29, 2005 + Now handles DWARF3. For non-MIPS objects, the list of register + names in print_sections.c is not appropriate, #define + DWARFDUMP_TURN_OFF_MIPS_REG_NAMES to turn off the MIPS names. +December 1, 2005 + Added new DWARF3 TAGs and ATtributes to the -k lists, + clarified the -k reporting, and made the build more robust + in the face of errors in the *.list relationship-spec-files. + +August 1, 2005 + Now print_die.c deals with long loclists without a coredump. + Added esb.h esb.c (and testesb.c for testing) to encapsulate + getting space for possibly-long strings. + Now print_die.c uses snprintf() not sprintf (hopefully this + will not inconvenience anyone, snprintf() has been available + on most systems for years now). + Altered print of location lists a little bit - for better appearance. + +July 15, 2005 + Now completely frees all allocated memory. Various + routines were not calling dealloc() code and + new libdwarf dealloc routines are now used where those + are needed. + + Now prints DWARF3 .debug_pubtypes section (with -a or -y). + The .debug_pubtypes section and SGI-specific .debug_typenames + are equvalent so they are treated alike. + +Mar 21, 2005 + The -f flag now prints only .debug_frame data. The .eh_frame section + (GNU exceptions data) now prints with -F (not -a). + Printing gcc 3.3 or 3.4 .eh_frame with zR augmentation + does not work at this time, so do not use -F + to print such an object. + The line section print now prints a CU-DIE offset for each such DIEs + line information. This makes it much easier to correctly associate + -l (or -v -l) output with -v -v -l when debugging a faulty + linetable in an executable. + With -v -v -l (two -v) the output of line info continues to be a + completely different format than zero or one -v, the two-v + form showing the detailed line table opcodes. + With g++ 3.3.3 one sees bad line addresses at times as the + DW_LNE_set_address address for header files do not always + get their relocations applied. I am told this is fixed in 3.4.x. + + +Mar 18, 2005 + In correcting printing of macro information the format + of the macro (-m) output has changed substantially. + Much more complete now. Still could use enhancement. + +Oct 28, 2004 + Updated contact address in copyright: SGI moved 1/4 mile + to a new address: 1500 Crittenden Lane. + +Oct 02, 2003 + Now fully supports .debug_loc section. + +June 14, 2001 + Now calling a new function dwarf_get_arange_cu_header_offset() + in libdwarf and printing the returned cu header offset for + aranges entries. Making it easier to track down internal + errors in the dwarf2 data. Also added small other + consistency checks, printing a message and exit()ing on + error. + +April 14, 2000 + The libdwarf copyright has changed to + version 2.1 of the GNU Lesser General Public License. + Anyone holding a version of libdwarf that was published + before this new copyright + is allowed to use + the copyright published in that earlier libdwarf source + on the earlier source + or to use + this new copyright on the earlier source, + at their option. + +July 21, 1999 + Added gnu extensions to the frame information printer + and handling for egcs eh_frame printing. + libdwarf changes mean this now can print little-endian + object dwarf on a big-endian system and vice-versa. + +December, 1998 + added dwarfdump to the dwarf public source distribution. + +June, 1994 + libdwarf consumer interface changed completely so updated to match. + +May, 1993 + Initial version of dwarfdump for dwarf version 2 + written at sgi. diff --git a/dwarfdump/README b/dwarfdump/README new file mode 100644 index 0000000..515e2b6 --- /dev/null +++ b/dwarfdump/README @@ -0,0 +1,82 @@ +I would prefer you try using ../dwarfdump2, not this source. +If you must use this for some reason, could you let me know why? +Thanks. + +To build dwarfdump, first build libdwarf in the neighboring +directory then type + ./configure + make + +Installation is a bit primitive. + sudo make install +may or may not work. +Some or all of the following might be required on Unix or Linux or MacOS: + sudo mkdir -p /usr/local/share/man/man1/ + sudo mkdir -p /usr/local/lib + sudo mkdir -p /usr/local/bin +Then retry the 'sudo make install' and (if necessary) try + sudo chmod a+x /usr/local/bin/dwarfdump + sudo chmod a+r /usr/local/share/man/man1/dwarfdump.1 + sudo chmod a+r /usr/local/lib/dwarfdump.conf +You don't really need the dwarfdump.1 man page, +but you might as well have it. If the man page is not visible +with 'man dwarfdump' try 'man manpath' for hints. + +If you don't need others using dwarfdump on your computer, +just + cp dwarfdump $HOME/bin/dwarfdump +(by convention many people put personal executables in $HOME/bin +and fix up $PATH to refer there) which suffices as 'installation'. +Also + cp dwarfdump.conf $HOME + +To use dwarf or libdwarf, you may want to install dwarf.h +and libdwarf.h somewhere convenient. +You can just copy those two headers to /usr/local/include by hand +(or anywhere, really, that you have permission to copy to) +(you may need to use -I/usr/local/include on compile lines +to reference them there, but see below on configure and make). + +Notice that dwarf_names.c and dwarf_names.h are supplied by +the release though the Makefile can and may rebuild them. +Some users find it difficult to get a reliable awk(1) program, +so for them these prebuilt versions may be useful. + +If your headers or libelf/libdwarf are not in the expected places, +use the make command line to add flags and include directories. +For example + ./configure + PREINCS="-I /usr/local/include" POSTINCS="-I /home/x/include" make +PREINCS content is inserted before CFLAGS as make(1) is running. +POSTINCS content is added after the CFLAGS value. + +To set LDFLAGS, +do so at configure time, for example: + ./configure LDFLAGS="-L /some/dir" +And/or use PRELIBS and/or POSTLIBS at 'make' time similar to the use +of PREINCS and POSTINCS. + +If the libdwarf directory +has both libdwarf.so and libdwarf.a, the libdwarf.so +will be picked up and + "./tag_tree_build: error while loading shared libraries: + libdwarf.so: cannot open shared object file: + No such file or directory" +will probably result. +Either: remove libdwarf.so and rebuild or set +the environment variable LD_LIBRARY_PATH to the directory +containing the .so or use LDFLAGS to set rpath (see just below). +It is perhaps simpler to ensure that the libdwarf directory +only has an archive, not a shared-library. +But sometimes one wants a shared library. +In that case +one can set ld's -rpath on the gcc command line like this: + LDFLAGS="-Wl,-rpath=/some/path/libdir" +so the shared library can be found at run time automatically. + +The same problem may arise with libelf, and the same approach +will solve the problem. + + + +David Anderson. davea42 at earthlink dot net. diff --git a/dwarfdump/addrmap.c b/dwarfdump/addrmap.c new file mode 100644 index 0000000..fb7ba79 --- /dev/null +++ b/dwarfdump/addrmap.c @@ -0,0 +1,149 @@ +/* + Copyright 2010-2011 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. + +*/ + +/* If memory full we do not exit, we just keep going as if + all were well. */ + +#include "globals.h" +#include <stdio.h> +#include "addrmap.h" +#ifndef HAVE_TSEARCH +struct Addr_Map_Entry * addr_map_insert( Dwarf_Unsigned addr, + char *name,void **tree1) +{ return 0; } +struct Addr_Map_Entry * addr_map_find(Dwarf_Unsigned addr,void **tree1) +{ return 0; } +void addr_map_destroy(void *map) +{ return;} + + + +#else /* HAVE_TSEARCH */ +#define __USE_GNU 1 +#include <search.h> + +char firststringcontent[100]; +char *firststring = 0; +struct Addr_Map_Entry *firstaddr = 0; + +static struct Addr_Map_Entry * +addr_map_create_entry(Dwarf_Unsigned k,char *name) +{ + struct Addr_Map_Entry *mp = + (struct Addr_Map_Entry *)malloc(sizeof(struct Addr_Map_Entry)); + if(!mp) { + return 0; + } + mp->mp_key = k; + if(name) { + mp->mp_name = strdup(name); + } else { + mp->mp_name = 0; + } + return mp; +} +static void +addr_map_free_func(void *mx) +{ + struct Addr_Map_Entry *m = mx; + if(!m) { + return; + } + free(m->mp_name); + m->mp_name = 0; + free(m); + return; +} + +static void +DUMPFIRST(int line) +{ + if(!firststring) { + return; + } +} + +static int +addr_map_compare_func(const void *l, const void *r) +{ + const struct Addr_Map_Entry *ml = l; + const struct Addr_Map_Entry *mr = r; + if(ml->mp_key < mr->mp_key) { + return -1; + } + if(ml->mp_key > mr->mp_key) { + return 1; + } + return 0; +} +struct Addr_Map_Entry * +addr_map_insert( Dwarf_Unsigned addr,char *name,void **tree1) +{ + void *retval = 0; + struct Addr_Map_Entry *re = 0; + struct Addr_Map_Entry *e; + e = addr_map_create_entry(addr,name); + DUMPFIRST(__LINE__); + /* tsearch records e's contents unless e + is already present . We must not free it till + destroy time if it got added to tree1. */ + retval = tsearch(e,tree1, addr_map_compare_func); + if(retval) { + re = *(struct Addr_Map_Entry **)retval; + if ( re != e) { + /* We returned an existing record, e not needed. */ + addr_map_free_func(e); + } else { + /* Record e got added to tree1, do not free record e. */ + } + } + return re; +} +struct Addr_Map_Entry * +addr_map_find(Dwarf_Unsigned addr,void **tree1) +{ + void *retval = 0; + struct Addr_Map_Entry *re = 0; + struct Addr_Map_Entry *e = 0; + + e = addr_map_create_entry(addr,NULL); + DUMPFIRST(__LINE__); + retval = tfind(e,tree1, addr_map_compare_func); + if(retval) { + re = *(struct Addr_Map_Entry **)retval; + } + /* The one we created here must be deleted, it is dead. + We look at the returned one instead. */ + addr_map_free_func(e); + return re; +} + +void +addr_map_destroy(void *map) +{ + /* tdestroy is not part of Posix, it is a GNU libc function. */ + tdestroy(map,addr_map_free_func); +} + +#endif /* HAVE_TSEARCH */ diff --git a/dwarfdump/addrmap.h b/dwarfdump/addrmap.h new file mode 100644 index 0000000..a7b26df --- /dev/null +++ b/dwarfdump/addrmap.h @@ -0,0 +1,33 @@ +/* + Copyright 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. + +*/ + +struct Addr_Map_Entry { + Dwarf_Unsigned mp_key; + char * mp_name; +}; + +struct Addr_Map_Entry * addr_map_insert(Dwarf_Unsigned addr, + char *name, void **map); +struct Addr_Map_Entry * addr_map_find(Dwarf_Unsigned addr, void **map); +void addr_map_destroy(void *map); diff --git a/dwarfdump/checkutil.c b/dwarfdump/checkutil.c new file mode 100644 index 0000000..6ba756c --- /dev/null +++ b/dwarfdump/checkutil.c @@ -0,0 +1,565 @@ +/* + Copyright (C) 2011 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2011 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. + +*/ +/* + + These simple list-processing functions are in support + of checking DWARF for compiler-errors of various sorts. + + +*/ + +#include "globals.h" +#include <assert.h> + +/* Private function */ +static void DumpFullBucketGroup(Bucket_Group *pBucketGroup); +static int FindDataIndexInBucket(Bucket_Group *pBucketGroup, + Bucket_Data *pBucketData); +static void PrintBucketData(Bucket_Group *pBucketGroup, + Bucket_Data *pBucketData); +static void ProcessBucketGroup(Bucket_Group *pBucketGroup, + void (*pFunction)(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData)); + +Bucket_Group * +AllocateBucketGroup(int kind) +{ + Bucket_Group *pBucketGroup = (Bucket_Group *)calloc(1,sizeof(Bucket_Group)); + pBucketGroup->kind = kind; + return pBucketGroup; +} + +void +ReleaseBucketGroup(Bucket_Group *pBucketGroup) +{ + Bucket *pBucket = 0; + Bucket *pNext = 0; + + assert(pBucketGroup); + for (pBucket = pBucketGroup->pHead; pBucket; /*pBucket = pBucket->pNext*/) { + pNext = pBucket->pNext; + free(pBucket); + pBucket = pNext; + } + pBucketGroup->pHead = NULL; + pBucketGroup->pTail = NULL; + free(pBucketGroup); +} + +void +ResetBucketGroup(Bucket_Group *pBucketGroup) +{ + Bucket *pBucket = 0; + + assert(pBucketGroup); + for (pBucket = pBucketGroup->pHead; pBucket; pBucket = pBucket->pNext) { + pBucket->nEntries = 0; + } + ResetSentinelBucketGroup(pBucketGroup); +} + +/* Reset sentinels in a Bucket Group. */ +void +ResetSentinelBucketGroup(Bucket_Group *pBucketGroup) +{ + /* Sanity checks */ + assert(pBucketGroup); + pBucketGroup->pFirst = NULL; + pBucketGroup->pLast = NULL; +} + +void PrintBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Bool bFull) +{ + assert(pBucketGroup); + if (bFull) { + DumpFullBucketGroup(pBucketGroup); + } else { + if (pBucketGroup->pFirst && pBucketGroup->pLast) { + printf("\nBegin Traversing, First = 0x%08" DW_PR_DUx + ", Last = 0x%08" DW_PR_DUx "\n", + pBucketGroup->pFirst->key,pBucketGroup->pLast->key); + ProcessBucketGroup(pBucketGroup,PrintBucketData); + } + } +} + +static void +PrintBucketData(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData) +{ + int nCount = 0; + assert(pBucketGroup); + assert(pBucketData); + + nCount = FindDataIndexInBucket(pBucketGroup,pBucketData); + printf("[%06d] Key = 0x%08" DW_PR_DUx ", Base = 0x%08" DW_PR_DUx + ", Low = 0x%08" DW_PR_DUx ", High = 0x%08" DW_PR_DUx + ", Flag = %d, Name = '%s'\n", + ++nCount, + pBucketData->key, + pBucketData->base, + pBucketData->low, + pBucketData->high, + pBucketData->bFlag, + pBucketData->name); +} + +static void +DumpFullBucketGroup(Bucket_Group *pBucketGroup) +{ + int nBucketNo = 1; + int nIndex = 0; + int nCount = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + printf("\nLowPC & HighPC records for bucket %d, at 0x%08lx\n", + nBucketNo++,(unsigned long)pBucket); + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + printf("[%06d] Key = 0x%08" DW_PR_DUx ", Base = 0x%08" DW_PR_DUx + ", Low = 0x%08" DW_PR_DUx ", High = 0x%08" DW_PR_DUx + ", Flag = %d, Name = '%s'\n", + ++nCount, + pBucketData->key, + pBucketData->base, + pBucketData->low, + pBucketData->high, + pBucketData->bFlag, + pBucketData->name); + } + } +} + +/* Insert entry into Bucket Group. + We make no check for duplicate information. */ +void +AddEntryIntoBucketGroup(Bucket_Group *pBucketGroup, + Dwarf_Addr key,Dwarf_Addr base, + Dwarf_Addr low,Dwarf_Addr high, + const char *name, + Dwarf_Bool bFlag) +{ + Bucket *pBucket = 0; + Bucket_Data data; + + data.bFlag = bFlag; + data.name = name; + data.key = key; + data.base = base; + data.low = low; + data.high = high; + + assert(pBucketGroup); + if (!pBucketGroup->pHead) { + /* Allocate first bucket */ + pBucket = (Bucket *)calloc(1,sizeof(Bucket)); + pBucketGroup->pHead = pBucket; + pBucketGroup->pTail = pBucket; + pBucket->nEntries = 1; + pBucket->Entries[0] = data; + return; + } + + pBucket = pBucketGroup->pTail; + + /* Check if we have a previous allocated set of + buckets (have been cleared */ + if (pBucket->nEntries) { + if (pBucket->nEntries < BUCKET_SIZE) { + pBucket->Entries[pBucket->nEntries++] = data; + } else { + /* Allocate new bucket */ + pBucket = (Bucket *)calloc(1,sizeof(Bucket)); + pBucketGroup->pTail->pNext = pBucket; + pBucketGroup->pTail = pBucket; + pBucket->nEntries = 1; + pBucket->Entries[0] = data; + } + } else { + /* We have an allocated bucket with zero entries; search for the + first available bucket to be used as the current + insertion point */ + for (pBucket = pBucketGroup->pHead; pBucket; + pBucket = pBucket->pNext) { + + if (pBucket->nEntries < BUCKET_SIZE) { + pBucket->Entries[pBucket->nEntries++] = data; + break; + } + } + } +} + +/* For Groups where entries are individually deleted, this does + that work. */ +Dwarf_Bool +DeleteKeyInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + /* Sanity checks */ + assert(pBucketGroup); + + /* For now do a linear search */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (pBucketData->key == key) { + Bucket_Data data = {FALSE,NULL,0,0,0,0}; + int nStart; + for (nStart = nIndex + 1; nStart < pBucket->nEntries; + ++nStart) { + + pBucket->Entries[nIndex] = pBucket->Entries[nStart]; + ++nIndex; + } + pBucket->Entries[nIndex] = data; + --pBucket->nEntries; + return TRUE; + } + } + } + return FALSE; +} + +/* Search to see if the address is in the range between + low and high addresses in some Bucked Data record. + This matches == if high is exact match (which usually means + one-past-true-high). */ +Dwarf_Bool +FindAddressInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr address) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + /* For now do a linear search */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (address >= pBucketData->low && + address <= pBucketData->high) { + return TRUE; + } + } + } + return FALSE; +} + +/* Search an entry (Bucket Data) in the Bucket Set */ +Bucket_Data *FindDataInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key) +{ + int mid = 0; + int low = 0; + int high = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + + for (pBucket = pBucketGroup->pHead; pBucket; pBucket = pBucket->pNext) { + /* Get lower and upper references */ + if (pBucket->nEntries) { + low = 0; + high = pBucket->nEntries; + while (low < high) { + mid = low + (high - low) / 2; + if (pBucket->Entries[mid].key < key) { + low = mid + 1; + } else { + high = mid; + } + } + if ((low < pBucket->nEntries) && + (pBucket->Entries[low].key == key)) { + + pBucketData = &pBucket->Entries[low]; + /* Update sentinels to allow traversing the table */ + if (!pBucketGroup->pFirst) { + pBucketGroup->pFirst = pBucketData; + } + pBucketGroup->pLast = pBucketData; + return pBucketData; + } + } + } + return (Bucket_Data *)NULL; +} + +/* Find the Bucket that contains a given Bucket Data + and return its local index. Else return -1. */ +static int +FindDataIndexInBucket(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData) +{ + Bucket *pBucket = 0; + Bucket_Data *pLower = 0; + Bucket_Data *pUpper = 0; + + /* Sanity checks */ + assert(pBucketGroup); + assert(pBucketData); + + /* Use sentinels if any. */ + if (pBucketGroup->pFirst && pBucketGroup->pLast && + pBucketData >= pBucketGroup->pFirst && + pBucketData <= pBucketGroup->pLast) { + + /* Find bucket that contains the first sentinel */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + pLower = &pBucket->Entries[0]; + pUpper = &pBucket->Entries[pBucket->nEntries - 1]; + + /* Check if the first sentinel is in this bucket. */ + if (pBucketGroup->pFirst >= pLower && + pBucketGroup->pFirst <= pUpper) { + /* We have found the bucket, return the index. */ + return pBucketData - pBucketGroup->pFirst; + } + } + } else { + /* Find bucket that contains the entry */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + pLower = &pBucket->Entries[0]; + pUpper = &pBucket->Entries[pBucket->nEntries - 1]; + + /* Check if the first sentinel is in this bucket */ + if (pBucketData >= pLower && pBucketData <= pUpper) { + /* We have found the bucket, return the index */ + return pBucketData - pLower; + } + } + } + /* Invalid data; just return index indicating not-found */ + return -1; +} + +/* Search an entry (Bucket Data) in the Bucket Group. + The key is an offset, a DIE offset + within Visited info. */ +Bucket_Data *FindKeyInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + /* Sanity checks */ + assert(pBucketGroup); + + /* For now do a linear search */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (pBucketData->key == key) { + return pBucketData; + } + } + } + return (Bucket_Data *)NULL; +} + +/* Search an entry (Bucket Data) in the Bucket Set by name. + Used to find link-once section names. */ +Bucket_Data * +FindNameInBucketGroup(Bucket_Group *pBucketGroup,char *name) +{ + int nIndex = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + + assert(pBucketGroup); + /* For now do a linear search. */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (!strcmp(pBucketData->name,name)) { + return pBucketData; + } + } + } + return (Bucket_Data *)NULL; +} + +/* Check if an address valid or not. That is, + check if it is in the lower -> upper range of a bucket. + It checks <= and >= so the lower end + and one-past on the upper end matches. +*/ +Dwarf_Bool +IsValidInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr address) +{ + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + int nIndex = 0; + + assert(pBucketGroup); + /* Check the address is within the allowed limits */ + if (address >= pBucketGroup->lower && address <= pBucketGroup->upper) { + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + for (nIndex = 0; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (address >= pBucketData->low && + address <= pBucketData->high) { + return TRUE; + } + } + } + } + return FALSE; +} + +/* Reset limits for values in the Bucket Set */ +void +ResetLimitsBucketSet(Bucket_Group *pBucketGroup) +{ + assert(pBucketGroup); + pBucketGroup->lower = 0; + pBucketGroup->upper = 0; +} + +/* Limits are set only for ranges, so only in pRangesInfo. */ +void +SetLimitsBucketGroup(Bucket_Group *pBucketGroup, + Dwarf_Addr lower,Dwarf_Addr upper) +{ + assert(pBucketGroup); + if (lower < upper) { + pBucketGroup->lower = lower; + pBucketGroup->upper = upper; + } +} + +/* Traverse Bucket Set and execute a supplied function */ +static void +ProcessBucketGroup(Bucket_Group *pBucketGroup, + void (*pFunction)(Bucket_Group *pBucketGroup,Bucket_Data *pBucketData)) +{ + int nIndex = 0; + int nStart = 0; + Bucket *pBucket = 0; + Bucket_Data *pBucketData = 0; + Bucket_Data *pLower = 0; + Bucket_Data *pUpper = 0; + Dwarf_Bool bFound = FALSE; + + /* Sanity checks */ + assert(pBucketGroup); + + /* No sentinels present; do nothing */ + if (!pBucketGroup->pFirst || !pBucketGroup->pLast) { + return; + } + + /* Find bucket that contains the first sentinel */ + for (pBucket = pBucketGroup->pHead; pBucket && pBucket->nEntries; + pBucket = pBucket->pNext) { + + pLower = &pBucket->Entries[0]; + pUpper = &pBucket->Entries[pBucket->nEntries - 1]; + + /* Check if the first sentinel is in this bucket */ + if (pBucketGroup->pFirst >= pLower && pBucketGroup->pFirst <= pUpper) { + /* Low sentinel is in this bucket */ + bFound = TRUE; + break; + } + } + + /* Invalid sentinel; do nothing */ + if (!bFound) { + return; + } + + /* Calculate index for first sentinel */ + nStart = pBucketGroup->pFirst - pLower; + + /* Start traversing from found bucket */ + for (; pBucket && pBucket->nEntries; pBucket = pBucket->pNext) { + for (nIndex = nStart; nIndex < pBucket->nEntries; ++nIndex) { + pBucketData = &pBucket->Entries[nIndex]; + if (pBucketData > pBucketGroup->pLast) { + return; + } + /* Call the user supplied function */ + if (pFunction) { + pFunction(pBucketGroup,pBucketData); + } + } + /* For next bucket start with first entry */ + nStart = 0; + } +} + +/* Check if a given (lopc,hipc) are valid for a linkonce. + We pass in the linkonce (instead of + referencing the global pLinkonceInfo) as that means + searches for pLinkonceInfo find all the uses, + making understanding of the code a tiny bit easier. + The section name created is supposed to be the appropriate + linkonce section name. +*/ +Dwarf_Bool IsValidInLinkonce(Bucket_Group *pLo, + const char *name,Dwarf_Addr lopc,Dwarf_Addr hipc) +{ +#define SECTION_NAME_LEN 2048 /* Guessing a sensible length */ + static char section_name[SECTION_NAME_LEN]; + Bucket_Data *pBucketData = 0; + /* Since text is quite uniformly just this name, no need to get it + from elsewhere, though it will not work for non-elf. */ + const char *lo_text = ".text"; + + /* Build the name that represents the linkonce section (.text). + This is not defined in DWARF so not correct for all + compilers. */ + snprintf(section_name,sizeof(section_name),"%s%s",lo_text,name); + + pBucketData = FindNameInBucketGroup(pLo,section_name); + if (pBucketData) { + if (lopc >= pBucketData->low && lopc <= pBucketData->high) { + if (hipc >= pBucketData->low && hipc <= pBucketData->high) { + return TRUE; + } + } + } + return FALSE; +} + diff --git a/dwarfdump/checkutil.h b/dwarfdump/checkutil.h new file mode 100644 index 0000000..d922b98 --- /dev/null +++ b/dwarfdump/checkutil.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 2011 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2011 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. + +*/ + +#ifndef CHECKUTIL_H +#define CHECKUTIL_H + +/* Map information. + Depending on the specific functions used various + fields here are either used or ignored. + +*/ +typedef struct { + Dwarf_Bool bFlag; /* General flag */ + const char *name; /* Generic name */ + Dwarf_Addr key; /* Used for binary search, the key + is either a pc address or a DIE offset + depending on which bucket table is in use. */ + Dwarf_Addr base; /* Used for base address */ + Dwarf_Addr low; /* Used for Low PC */ + Dwarf_Addr high; /* Used for High PC */ +} Bucket_Data; + +/* This groups Bucket_Data records into + a 'bucket' so that a single malloc creates + BUCKET_SIZE entries. The intent is to reduce + overhead (as compared to having next/previous + pointers in each Bucket_Data and mallocing + each Bucket_Data individually. +*/ + +#define BUCKET_SIZE 2040 +typedef struct bucket { + int nEntries; + Bucket_Data Entries[BUCKET_SIZE]; + struct bucket *pNext; +} Bucket; + +/* This Forms the head record of a list of Buckets. +*/ +typedef struct { + int kind; /* Kind of bucket */ + Dwarf_Addr lower; /* Lower value for data */ + Dwarf_Addr upper; /* Upper value for data */ + Bucket_Data *pFirst; /* First sentinel */ + Bucket_Data *pLast; /* Last sentinel */ + Bucket *pHead; /* First bucket in set */ + Bucket *pTail; /* Last bucket in set */ +} Bucket_Group; + +Bucket_Group *AllocateBucketGroup(int kind); +void ReleaseBucketGroup(Bucket_Group *pBucketGroup); +void ResetBucketGroup(Bucket_Group *pBucketGroup); +void ResetSentinelBucketGroup(Bucket_Group *pBucketGroup); + +void PrintBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Bool bFull); + +void AddEntryIntoBucketGroup(Bucket_Group *pBucketGroup, + Dwarf_Addr key,Dwarf_Addr base,Dwarf_Addr low,Dwarf_Addr high, + const char *name, Dwarf_Bool bFlag); + +Dwarf_Bool DeleteKeyInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key); + +Dwarf_Bool FindAddressInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr address); +Bucket_Data *FindDataInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key); +Bucket_Data *FindKeyInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr key); +Bucket_Data *FindNameInBucketGroup(Bucket_Group *pBucketGroup,char *name); + +Dwarf_Bool IsValidInBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr pc); + +void ResetLimitsBucketSet(Bucket_Group *pBucketGroup); +void SetLimitsBucketGroup(Bucket_Group *pBucketGroup,Dwarf_Addr lower,Dwarf_Addr upper); +Dwarf_Bool IsValidInLinkonce(Bucket_Group *pLo, + const char *name,Dwarf_Addr lopc,Dwarf_Addr hipc); + + +#endif /* CHECKUTIL_H */ diff --git a/dwarfdump/common.c b/dwarfdump/common.c new file mode 100644 index 0000000..2788578 --- /dev/null +++ b/dwarfdump/common.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2008-2010 SN Systems. All Rights Reserved. + Portions Copyright (C) 2008-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2011 SN Systems Ltd. . 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 + +*/ + +/* These do little except on Windows */ + +#include "common.h" +#include <stdio.h> +#define DWARFDUMP_VERSION " Tue Apr 10 11:43:32 PDT 2012 " + +/* The Linux/Unix version does not want a version string to print + unless -V is on the command line. */ +void +print_version_details(const char * name,int alwaysprint) +{ +#ifdef WIN32 +# ifdef _DEBUG + char *acType = "Debug"; +# else + char *acType = "Release"; +# endif /* _DEBUG */ + static char acVersion[32]; + snprintf(acVersion,sizeof(acVersion), + "[%s %s %s]",__DATE__,__TIME__,acType); + printf("%s %s\n",name,acVersion); +#else /* !WIN32 */ + if(alwaysprint) { + printf("%s\n",DWARFDUMP_VERSION); + } +#endif /* WIN32 */ +} + + +void +print_args(int argc, char *argv[]) +{ +#ifdef WIN32 + int index = 1; + printf("Arguments: "); + for (index = 1; index < argc; ++index) { + printf("%s ",argv[index]); + } + printf("\n"); +#endif /* WIN32 */ +} + +void +print_usage_message(const char *program_name, const char **text) +{ + unsigned i = 0; +#ifndef WIN32 + fprintf(stderr,"Usage: %s <options> <object file>\n", program_name); +#endif + for (i = 0; *text[i]; ++i) { + fprintf(stderr,"%s\n", text[i]); + } +} diff --git a/dwarfdump/common.h b/dwarfdump/common.h new file mode 100644 index 0000000..f1a598e --- /dev/null +++ b/dwarfdump/common.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2009-2010 SN Systems. All Rights Reserved. + Portions Copyright (C) 2009-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 + +*/ + +#ifndef COMMON_INCLUDED_H +#define COMMON_INCLUDED_H + +void print_args(int argc, char *argv[]); +void print_version_details(const char *name, int alwaysprint); +void print_usage_message(const char *program_name, const char **text); + +#endif /* COMMON_INCLUDED_H */ diff --git a/dwarfdump/config.h.in b/dwarfdump/config.h.in new file mode 100644 index 0000000..a1a11db --- /dev/null +++ b/dwarfdump/config.h.in @@ -0,0 +1,100 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the elf64_getehdr function is in libelf.a. */ +#undef HAVE_ELF64_GETEHDR + +/* Define to 1 if the Elf64_Rel structure has r_info field. */ +#undef HAVE_ELF64_R_INFO + +/* Define to 1 if you have the <elf.h> header file. */ +#undef HAVE_ELF_H + +/* Define to 1 if you have the <getopt.h> header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <libelf.h> header file. */ +#undef HAVE_LIBELF_H + +/* Define to 1 if you have the <libelf/libelf.h> header file. */ +#undef HAVE_LIBELF_LIBELF_H + +/* Define 1 if off64 is defined via libelf with GNU_SOURCE. */ +#undef HAVE_LIBELF_OFF64_OK + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define 1 if need nonstandard printf format for 64bit */ +#undef HAVE_NONSTANDARD_PRINTF_64_FORMAT + +/* Define 1 if plain libelf builds. */ +#undef HAVE_RAW_LIBELF_OK + +/* Define 1 if regex seems to be defined */ +#undef HAVE_REGEX + +/* Define to 1 if you have the <sgidefs.h> header file. */ +#undef HAVE_SGIDEFS_H + +/* Define 1 if we have the Windows specific header stdafx.h */ +#undef HAVE_STDAFX_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define 1 if the tsearch functions seem to be defined */ +#undef HAVE_TSEARCH + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* See if __uint32_t is predefined in the compiler. */ +#undef HAVE___UINT32_T + +/* Define 1 if sys/types.h defines __uint32_t. */ +#undef HAVE___UINT32_T_IN_SYS_TYPES_H + +/* See if __uint64_t is predefined in the compiler. */ +#undef HAVE___UINT64_T + +/* Define to header that first defines elf. */ +#undef LOCATION_OF_LIBELFHEADER + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS diff --git a/dwarfdump/configure b/dwarfdump/configure new file mode 100755 index 0000000..67ede72 --- /dev/null +++ b/dwarfdump/configure @@ -0,0 +1,5109 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.68. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="dwarfdump.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +AR +RANLIB +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_nonstandardprintf +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-nonstandardprintf + Use a special printf format for 64bit (default is + NO) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.68 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.68. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if ${ac_cv_prog_gcc_traditional+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgtty.h> +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <termio.h> +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in elf.h getopt.h libelf.h libelf/libelf.h sgidefs.h sys/types.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for elf64_getehdr in -lelf" >&5 +$as_echo_n "checking for elf64_getehdr in -lelf... " >&6; } +if ${ac_cv_lib_elf_elf64_getehdr+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lelf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char elf64_getehdr (); +int +main () +{ +return elf64_getehdr (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_elf_elf64_getehdr=yes +else + ac_cv_lib_elf_elf64_getehdr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_elf_elf64_getehdr" >&5 +$as_echo "$ac_cv_lib_elf_elf64_getehdr" >&6; } +if test "x$ac_cv_lib_elf_elf64_getehdr" = xyes; then : + +$as_echo "#define HAVE_ELF64_GETEHDR 1" >>confdefs.h + +fi + + +if test "$ac_cv_header_elf_h" = yes; then + +$as_echo "#define LOCATION_OF_LIBELFHEADER <elf.h>" >>confdefs.h + +elif test "$ac_cv_header_libelf_h" = yes; then + +$as_echo "#define LOCATION_OF_LIBELFHEADER <libelf.h>" >>confdefs.h + +elif test "$ac_cv_header_libelf_libelf_h" = yes; then + +$as_echo "#define LOCATION_OF_LIBELFHEADER <libelf/libelf.h>" >>confdefs.h + +fi + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include "stdafx.h" +int +main () +{ + int p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_STDAFX_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include LOCATION_OF_LIBELFHEADER +int +main () +{ +Elf64_Rel *p; int i; i = p->r_info; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_ELF64_R_INFO 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__uint32_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__uint64_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> +int +main () +{ + __uint32_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T_IN_SYS_TYPES_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <regex.h> +int +main () +{ + int i; + regex_t r; + int cflags = REG_EXTENDED; + const char *s = "abc"; + i = regcomp(&r,s,cflags); + regfree(&r); + ; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_REGEX 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +#include <stdlib.h> +/* On Ubuntu 10.x, tsearch is in package libc6-dev. */ +/* The tdestroy function is GNU, not POSIX. */ +#define __USE_GNU 1 +#include <search.h> +struct my_tentry { + long mt_key; + char * mt_name; +}; +struct my_tentry * make_my_tentry(long k,char *name) { return 0; } +void mt_free_func(void *mt_data) { return; } +int mt_compare_func(const void *l, const void *r) { return 0; } +int +main () +{ + + long i = 1; + void *tree1 = 0; + char *dbuf = 0; + struct my_tentry *mt = 0; + struct my_tentry *retval = 0; + mt = make_my_tentry(i,dbuf); + retval = tsearch(mt,&tree1, mt_compare_func ); + tdestroy(tree1,mt_free_func); + exit(0); +; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define HAVE_TSEARCH 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + +# Check whether --enable-nonstandardprintf was given. +if test "${enable_nonstandardprintf+set}" = set; then : + enableval=$enable_nonstandardprintf; +$as_echo "#define HAVE_NONSTANDARD_PRINTF_64_FORMAT 1" >>confdefs.h + +fi + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include <libelf.h> + +int +main () +{ + int p; p = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_RAW_LIBELF_OK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _GNU_SOURCE +#include <libelf.h> + +int +main () +{ + off64_t p; p = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_LIBELF_OFF64_OK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.68. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.68, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/dwarfdump/configure.in b/dwarfdump/configure.in new file mode 100644 index 0000000..753a1b4 --- /dev/null +++ b/dwarfdump/configure.in @@ -0,0 +1,98 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(dwarfdump.c) +AC_CONFIG_HEADER(config.h) + +AC_PROG_CC +AC_GCC_TRADITIONAL +AC_PROG_INSTALL +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(AR, ar) +dnl AC_ARFLAGS + +AC_CHECK_HEADERS(elf.h getopt.h libelf.h libelf/libelf.h sgidefs.h sys/types.h) +AC_CHECK_LIB(elf,elf64_getehdr, + AC_DEFINE(HAVE_ELF64_GETEHDR,1, + [Define to 1 if the elf64_getehdr function is in libelf.a.])) + +dnl Find out where the elf header is. +if test "$ac_cv_header_elf_h" = yes; then + AC_DEFINE(LOCATION_OF_LIBELFHEADER,[<elf.h>], [Define to header that first defines elf]) +elif test "$ac_cv_header_libelf_h" = yes; then + AC_DEFINE(LOCATION_OF_LIBELFHEADER, [<libelf.h>], + [Define to header that first defines elf.]) +elif test "$ac_cv_header_libelf_libelf_h" = yes; then + AC_DEFINE(LOCATION_OF_LIBELFHEADER,[<libelf/libelf.h>], + [Define to header that first defines elf.]) +fi + +AC_TRY_COMPILE([#include "stdafx.h"],[ int p; p = 27;] , + AC_DEFINE(HAVE_STDAFX_H,1, + [Define 1 if we have the Windows specific header stdafx.h])) + +AC_TRY_COMPILE([#include LOCATION_OF_LIBELFHEADER], Elf64_Rel *p; int i; i = p->r_info; ,AC_DEFINE(HAVE_ELF64_R_INFO,1, + [Define to 1 if the Elf64_Rel structure has r_info field.])) +AC_TRY_COMPILE([], __uint32_t p; p = 3; ,AC_DEFINE(HAVE___UINT32_T, + 1,[See if __uint32_t is predefined in the compiler. ])) +AC_TRY_COMPILE([], __uint64_t p; p = 3; ,AC_DEFINE(HAVE___UINT64_T, + 1,[See if __uint64_t is predefined in the compiler. ])) +AC_TRY_COMPILE([#include <sys/types.h>],[ __uint32_t p; p = 3]; , + AC_DEFINE(HAVE___UINT32_T_IN_SYS_TYPES_H,1, + [Define 1 if sys/types.h defines __uint32_t.])) +AC_TRY_COMPILE([#include <sys/types.h> + #include <regex.h>],[ int i; + regex_t r; + int cflags = REG_EXTENDED; + const char *s = "abc"; + i = regcomp(&r,s,cflags); + regfree(&r); + ]; , + AC_DEFINE(HAVE_REGEX,1, + [Define 1 if regex seems to be defined])) +AC_TRY_LINK([#include <stdio.h> +#include <stdlib.h> +/* On Ubuntu 10.x, tsearch is in package libc6-dev. */ +/* The tdestroy function is GNU, not POSIX. */ +#define __USE_GNU 1 +#include <search.h> +struct my_tentry { + long mt_key; + char * mt_name; +}; +struct my_tentry * make_my_tentry(long k,char *name) { return 0; } +void mt_free_func(void *mt_data) { return; } +int mt_compare_func(const void *l, const void *r) { return 0; }],[ + long i = 1; + void *tree1 = 0; + char *dbuf = 0; + struct my_tentry *mt = 0; + struct my_tentry *retval = 0; + mt = make_my_tentry(i,dbuf); + retval = tsearch(mt,&tree1, mt_compare_func ); + tdestroy(tree1,mt_free_func); + exit(0); +];, + AC_DEFINE(HAVE_TSEARCH,1, + [Define 1 if the tsearch functions seem to be defined])) + + +AC_ARG_ENABLE(nonstandardprintf,AC_HELP_STRING([--enable-nonstandardprintf], + [Use a special printf format for 64bit (default is NO)]), + [ AC_DEFINE([HAVE_NONSTANDARD_PRINTF_64_FORMAT],[1], + [Define 1 if need nonstandard printf format for 64bit] )], + []) + +AC_TRY_COMPILE([ +#include <libelf.h> +],[ int p; p = 0; ] , + AC_DEFINE(HAVE_RAW_LIBELF_OK,1, + [Define 1 if plain libelf builds.])) +AC_TRY_COMPILE([ +#define _GNU_SOURCE +#include <libelf.h> +],[ off64_t p; p = 0;] , + AC_DEFINE(HAVE_LIBELF_OFF64_OK,1, + [Define 1 if off64 is defined via libelf with GNU_SOURCE.])) + + + +AC_OUTPUT(Makefile) diff --git a/dwarfdump/dwarfdump.1 b/dwarfdump/dwarfdump.1 new file mode 100644 index 0000000..bb7ee37 --- /dev/null +++ b/dwarfdump/dwarfdump.1 @@ -0,0 +1,523 @@ +.TH DWARFDUMP +.SH NAME +dwarfdump \- dumps DWARF debug information of an ELF object +.SH SYNOPSIS +.B dwarfdump [options] \f2objectfilename\fP +.SH DESCRIPTION +The +.B dwarfdump +command prints or checks DWARF sections as requested by specific options. +With no options (but with the required \f2objectfilename\fP ) +all sections print (but some sections cannot be printed independently +safely, so those are only printed at offsets where the .debug_info section +refers to those sections). +.PP +As of June 2011 the printing options and the checking options +are mutually exclusive (if checking options are selected +the section details are not printed). When errors are encountered +dwarfdump does attempt to print sufficient context so that +one can understand exactly where the error is in the DWARF. +This change makes checking really large object files +much easier. +.PP +The format is intended to be human readable. +If a script is to parse the output, the +.B \-d +option is useful. +.PP +Not all sections actually exist in any given object file. +.PP +The format may change from release to release, so it is +unwise to depend too heavily on the format. +.PP +Frame information (.debug_frame and .eh_frame) is heavily +dependent on the ABI/ISA of the object file. +By default we use a generic set of register names +handling up to 100 registers named r0-100. +The '-R' option uses a built-in generic register name set +handling up to 1200 registers named r0-r1199. +The '-x abi=<abi>' +description below shows how to name an abi and use that to guide +the -f or -F processing. +Unless the cpu for the object file being dumped has many registers, +do not use -R or -x abi=generic as those can be needlessly +slow dumping frame sections. Instead, use the correct +abi (if it exists in dwarfdump.conf) or a generic such +as -x abi=generic100 or -x abi=generic500. +To get MIPS/IRIX register names names and call the old version 2 libdwarf +frame interface use the option '-x abi=mips'. +Without '-R' or '-x abi=<abi>' dwarfdump ignores +the dwarfdump.conf file and uses compiled-in generic set of +register names. +If no '-x name=<path>' is given, dwarfdump +looks for "./dwarfdump.conf", "$HOME/.dwarfdump.conf", "<install-prefix>/lib/dwarfdump.conf" and takes the first it finds. +If one or more '-x name=<path>' is given the last of these is +used and all other such files are ignored. +.PP +Some -k (checking) options print so-called harmless errors. +These are compiler errors that do not cause any +known problem and are only detected inside libdwarf itself. +These are difficult to properly report in dwarfdump and +any error strings may not appear close to the time the +error was encountered. +.SH URI STYLE INPUT STRINGS +.PP +The <objectfilename> and the options taking name strings look for URIs and +translate the URI strings to characters by default +(see -x, -c<compiler name>, -S, -u). +So any single % character is treated as if the following two +characters are hex digits representing the underlying true character. +Various characters are meaningful to shells (such as bash or sh) +and to getopt (such as the space character) +If the URI translation does anything it prints the before and after +of the URI translation on standard output, so inspection of the first +lines of output will show if URI did anything. +The actual options themselves are assumed to be non-URI. +So in the option '-cS&T' the -c portion must be non-URI, but the +& character might cause input issues so '-cS%26T' could be used instead. +To actually input a single % character (in a name, for example), +double it to %% on the command line. +.PP +Options -U (turning off URI interpretation) and -q (making finding +URI sequences silent) give finer control of URI interpretation. +PP +As an example, to get a string'a b' make the string 'a%20b' +(here the quote (') is for exposition not part of the string, though +quote is certainly problematic in a name). +Instead of escaping " quotes in the string, type %25, as in + 'a "b' should be typed 'a%20%25b' +Any characters can be typed in URI style, not just characters +which are problematic to the shell or getopt. +We strongly suggest you not type URI-style characters where +such are not needed or use +the % character itself in command line strings unless you must. +.SH PRINTING OPTIONS +.TP +.B \-a +Print each section as independently as possible. Sections that +can safely be printed independently (like .debug_abbrev) +have relevant info printed in the report (sometimes dependent +on -v). + +.TP +.B \-b +Print the .debug_abbrev section. Because the DWARF specfications +do not rule out garbage data areas in .debug_abbrev (if they are not +referenced from .debug_info) any garbage bytes can result in +this print failing. + +.TP +.B \-c +Print locations lists. + +.TP +.B \-f +Print the .debug_frame section. +.TP +.B \-F +Print the .eh_frame section. + +.TP +.B \-i +Print the .debug_info section. + +.TP +.B \-l +Print the .debug_info section and the associated line section data. + +.TP +.B \-m +Print the .debug_macinfo section. + +.TP +.B \-N +Print .debug_ranges section. Because the DWARF specfications +do not rule out garbage data areas in .debug_ranges (if they are not +referenced from .debug_info) any garbage bytes can result in +this print failing. + +.TP +.B \-p +Print the .debug_pubnames section. + +.TP +.B \-r +Print the .debug_aranges section. +.TP +.B \-s +Print .debug_string section. + +.TP +.B \-ta +Print the IRIX only sections .debug_static_funcs and .debug_static_vars. + +.TP +.B \-tf +Print the IRIX only section .debug_static_funcs. +.TP +.B \-tv +Print the IRIX only section .debug_static_vars. + +.TP +.B \-w +Print the IRIX-only .debug_weaknames section. + +.TP +.B \-y +Print the .debug_pubtypes section (and .debug_typenames, +an SGI IRIX-only section). + +.PP +Having dwarfdump print relocations may help establish whether +dwarfdump understands any relocations that might exist. + +.TP +.B \-o +Print all relocation records as well as we can manage. +.TP +.B \-oi +Print .rel*debug_info relocations. +.TP +.B \-ol +Print .rel*debug_line relocation. +.TP +.B \-op +Print .rel*debug_pubnames relocation. +.TP +.B \-oa +Has no effect. +.TP +.B \-or +Print .rel*debug_aranges relocations. +.TP +.B \-of +Print .rel*debug_frame relocations. +.TP +.B \-oo +Print .rel*debug_loc relocations. +.TP +.B \-oR +Print .rel*debug_ranges relocations. + +.TP +.B \-g +Normally used only for testing libdwarf, this tells dwarfdump to +print .debug_info and use an older dwarf_loclist() interface +function (a function that cannot handle all current +location lists). +.TP +.B \-V +Print a dwarfdump date/version string and stop. + +.SH CHECKING OPTIONS +.TP +.B \-cg +Restricts checking to compilers whose +producer string starts with 'GNU' +and turns off -cs . + +.TP +.B \-cs +Restricts checking to compilers whose +producer string starts with 'SN' +and turns off -cg . +.TP +.B \-cname +Restricts checking to compilers whose +producer string contains 'name' (not case sensitive). +The 'name' is read as a URI string. + +.TP +.B \ +-ka : Turns on all checking options except -kxe (-kxe might + be slow enough one mignt not want to use it routinely.) + +.TP +.B \ +-kb : Checks for certain abbreviations section errors when reading + DIEs. +.TP +.B \-kc +Checks for errors in constants in debug_info. +.TP +.B \-kd +Turns on full reporting of error totals per producer. +(the default shows less detail). +.TP +.B \-ke +Turns on reading pubnames and checking for fde errors. +.TP +.B \-kf +Turns on checking for FDE errors. +.TP +.B \-kF +Turns on checking for line table errors. +.TP +.B \-kg +Turns on checking for unused gaps in .debug_info (these +gaps are not an error, just a waste of space). + +.TP +.B \-ki +Causes a summary of checking results per compiler (producer) +to be printed at the end. +.TP +.B \-kl +Turns on locations list checking. +.TP +.B \-km +Turns on checking of ranges. +.TP +.B \-kM +Turns on checking of aranges. +.TP +.B \-kr +Turns on DIE tag-attr combinations checking. +.TP +.B \-kR +Turns on reading DIEs and checking for forward declarations +rom DW_AT_specification attributes. +(which are not an error but can be a source of inefficiency +for debuggers). +.TP +.B \-ks +Turns on extra reporting for some DIE errors checking detects . +.TP +.B \-kS +Turns on checking DIE references for circular references. +.TP +.B \-kt +Turns on tag-tag combinations checking. +.TP +.B \-kx +Turns on check_frames. +.TP +.B \-kxe +Turns off basic check_frames and turns on extended frame checking. +.TP +.B \-ky +Turns on type_offset, decl_file checking, + +.SH OPTION MODIFIERS + +.TP +.B \-C +Normally when checking for tag-tag or tag-attribute combinations +both the standard combinations and some common extensions are allowed. +With -C the extensions are taken out of the allowed class of combinations. + +.TP +.B \-d +When printing DIEs, put all the attributes for each DIE on the same (long) +line as the TAG. This makes searching for DIE information +(as with grep) much simpler as the entire DIE is on one line. + +.TP +.B \-D +Turns off the display of section offsets and attribute values in printed output. +So the .debug_info output isjust TAGs and Attributes. +For pubnames (and the like) it removes offsets from the output. +For locations lists it removes offsets from the output, but that +is useless since the attribute values don't show so neither does +the location data. + +.TP +.B \-e +Turns on truncation of attribute and tag names. For example +DW_TAG_foo becomes foo . Not compatible with +checking, only useful for printing DIEs. + +.TP +.B \-G +When printing, add global offsets to the offsets printed. + +.TP +.B \-H number +When printing or checking .debug_info, this terminates +the search after 'number' compilation units. When printing +frame information this terminates the FDE reporting +after 'number' FDEs and the CIE reporting (which occurs if one adds -v) +after 'number' CIEs. Example '-H 1' + +.TP +.B \-M +When printing, this means one want to have the FORM show for each attribute. +If a -v is also added (or more than one) then details of any form indirection +are also shown. + +.TP +.B \-n +When printing frames, this turns off the search for function names. +In a really large object the search can take more time than +one wants to wait, so this avoids the search. + +.TP +.B \-Q +Suppresses section data printing (set automatically with a checking option). + +.TP +.B \-R +When printing frames for ABIs with lots of registers, this allows +up to 1200 registers to be named (like R999) without choosing an ABI +with, for example '-x abi=ppc' + +.TP +.B \-v +Increases the detail shown when printing. +In some sections, using more -v options +will increase the detail (one to three are useful) or may +change the report to show, for example, the actual +line-data-commands instead of the resultant line-table. + +.SH SELECTIVE ENTRY PRINTING + +.PP +These -S options stand alone and basic print information about the compilation +unit and DIE where the string(s) appear. +At most one of each of the following is effective (so for example +one can only have one 'match', but one can +have a 'match', an 'any', and a 'regex'). +Any -S causes the .debug_info section to be inspected. +No checking options or printing options should be supplied with -S. + +.TP +.B \-S match=string +When printing DIEs +for each tag value or attribute name that matches 'string' exactly +print the compilation unit information and its section offset. +Any CU with no match is not printed. +The 'string' is read as a URI string. +.TP +.B \-S any=string +When printing DIEs +for each tag value or attribute name that contains 'string' +somewhere in the tag or attribute (case insensitive) +print the compilation unit information and its section offset. +Any CU with no match is not printed. +The 'string' is read as a URI string. +.TP +.B \-S regex=string +When printing DIEs +for each tag value or attribute name where the 'string' reqular +expression matches print the compilation unit information +and its section offset. +Any CU with no match is not printed. +The 'string' is read as a URI string. + +.PP +The string cannot have spaces or other characters which are +meaningful to getopt(3) and the shell will strip off quotes and +other characters. +So the string is assumed to be in URI style and is translated. +In other words, to match 'a b' make the -S string 'a%20b' +Instead of escaping " quotes in the string, type %25, as in + 'a "b' should be typed 'a%20%25b' +(the ' are for exposition here, not part of the strings). +Any characters can be typed in URI style, not just characters +which are problematic to the shell or getopt. +.PP +The -S any= and -S regex= options are only usable +if the library functions required are found at configure time. +.PP +The -W option is a modifier to the -S option, and +increases the amount of output -W prints. +Now we show the -W in context with a -S option. + +.TP +.B \-S match=string1 -W +Prints the parent tree and the children tree for the +DIEs that -S matches. + +.TP +.B \-S match=string2 -Wp +Prints the parent tree for the DIEs that -S matches. + +.TP +.B \-S match=string3 -Wc +Prints the parent tree for the DIEs that -S matches. + +.SH OTHER OPTIONS + +.TP +.B \-# number +This option controls internal debugging output, +higher numbers mean more debug actions. See the source code. + + +.TP +.B \-x name=/p/a/t/h.conf +The file path given is the name of a file assumed to be +a dwarfdump.conf-like file. +The file path is read as a URI string. + +.TP +.B \-x abi=ppc +Selects the abi (from a dwarfdump.conf file) to be used in +printing frame information (here using ppc as an example). +The abi is read as a URI string. + +.TP +.B \-P +When checking this adds the list of compilation-unit names +seen for each producer-compiler to the printed checking results. +.TP +.B \-q +When a URI is found and translated while reading +the command line, be quiet about +the URI translation. That is, don't print the +original and translated option strings. + +.TP +.B \-E +Turns on printing object-internal header data for some +systems (for Unix/Linux does nothing). + +.TP +.B \-u cuname +Turns on selective printing of DIEs (printing like -i). +Only the DIEs for a compilation unit that match the +name provided are printed. +If the compilation unit is ./a/b/c.c +the 'cuname' you provide should be c.c as the characters +through the final path-separating / are ignored. +If 'cuname' begins with a / then the entire name string +of a compilation unit must match 'cuname'. +The 'cuname' is read as a URI string. + +.TP +.B \-U +Turn off the URI interpretation of the command line +strings entirely. Must be be on the command line before +any URI strings encountered to be fully effective. + +.TP +.B \-z +No longer suported. + + +.SH FILES +dwarfdump + +dwarfdump.conf + +./dwarfdump.conf + +$(HOME)/.dwarfdump.conf + +$(HOME)/dwarfdump.conf + +<install-prefix>/lib/dwarfdump.conf +.SH NOTES +In some cases compilers use DW_FORM_data1 (for example) +and in such cases the signedness of the value must be taken +from context. Rather than attempt to determine the +context, dwarfdump prints the value with both signednesses +whenever there is ambiguity about the correct interpretation. +For example, +"DW_AT_const_value 176(as signed = -80)". +For normal DWARF consumers that correctly and fully +evaluate all attributes there is no ambiguity of signedness: +the ambiguity for dwarfdump is due to dwarfdump evaluating +DIEs in a simple order and not keeping track of much context. +.SH BUGS +Support for DWARF3 is being completed but may not be complete. 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, + §ion_name, + §ion_addr, + §ion_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; +} diff --git a/dwarfdump/dwarfdump.conf b/dwarfdump/dwarfdump.conf new file mode 100644 index 0000000..d70bab8 --- /dev/null +++ b/dwarfdump/dwarfdump.conf @@ -0,0 +1,810 @@ +# MIPS/IRIX ISA/ABI +# Used to configure dwarfdump printing of .debug_frame and +# .eh_frame. + +# Any number of abi's can be described. Only one can be selected +# in a given dwarfdump run (see dwarfdump options) +# Available commands are +# beginabi: <abiname> +# reg: <regname> <dwarf regnumber> +# frame_interface: <integer value 2 or 3> +# cfa_reg: <number> +# initial_reg_value: <number: often 1034 or 1035 > +# same_val_reg: 1035 +# undefined_val_reg: 1034 +# reg_table_size: <size of table> +# address_size: <4 or 8, Rarely needed, see example below. > +# includeabi: <abiname Inserts the referenced abi as if its text was +# directly inserted at this point.> +# endabi: <abiname> +# +# Symbolic names do not work here, use literal numbers +# where applicable (in C standard decimal, octal (leading 0) or +# hexadecimal <leading 0x>). +# +# Whitespace is required to separate command: from operands and +# operands from each other on a line. +# +# There is no ordering required within a beginabi/endabi pair. +# As many ABIs as required may be listed. +# dwarfdump will choose exactly one abi to dump frame information. +# + + +# MIPS abi,the old IRIX form, not to be used on modern objects. +# Begin with abi name (use here and on dwarfdump command line). +beginabi: mips-irix + +# Instructs dwarfdump to default to the older frame interface. +# Use value 3 to use the newer interface. +# The '2' interface is supported but deprecated (deprecated +# because it cannot work with all popular ABIs: mixing +# the cfa-rule into the table column set was not a good idea +# but it is part of the MIPS/IRIX standard usage). +frame_interface: 2 + +# If (and only if) using frame_interface: 2 tell dwarfdump +# what table colum that DW_FRAME_CFA_COL is. +# If using frame_interface: 3 cfa_reg: should be +# DW_FRAME_CFA_COL3 (1436) +cfa_reg: 0 + +# For MIPS, the same as DW_FRAME_SAME_VAL (1035). +# For other ISA/ABIs 1034 (DW_FRAME_UNDEFINED_VAL) might be better. +# Depends on the ABI convention, if set wrong way too many +# regs will be listed in the frame output. +# This instructs dwarfdump to set libdwarf to this value, +# overriding the libdwarf default. +# If initial_reg_value not set the libdwarf default is used +# (see libdwarf.h DW_FRAME_REG_INITIAL_VALUE). +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +same_val_reg: 1035 +undefined_val_reg: 1034 + +# Built in to frame_interface: 2 as 66. +reg_table_size: 66 + + +# Only name registers for wich a r4 (for example) is not what you +# want to see +# No particular order of the reg: lines required. +reg: cfa 0 # Used with MIPS/IRIX original DWARF2 interface +reg: r1/at 1 +reg: r2/v0 2 +reg: r3/v1 3 +reg: r4/a0 4 +reg: r5/a1 5 +reg: r6/a2 6 +reg: r7/a3 7 +reg: r8/t0 8 +reg: r9/t1 9 +reg: r10/t2 10 +reg: r11/t3 11 +reg: r12/t4 12 +reg: r13/t5 13 +reg: r14/t6 14 +reg: r15/t7 15 +reg: r16/s0 16 +reg: r17/s1 17 +reg: r18/s2 18 +reg: r19/s3 19 +reg: r20/s4 20 +reg: r21/s5 21 +reg: r22/s6 22 +reg: r23/s7 23 +reg: r24/t8 24 +reg: r25/t9 25 +reg: r26/k0 26 +reg: r27/k1 27 +reg: r28/gp 28 +reg: r29/sp 29 +reg: r30/s8 30 +reg: r31 31 + +reg: $f0 32 +reg: $f1 33 +reg: $f2 34 +reg: $f3 35 +reg: $f4 36 +reg: $f5 37 +reg: $f6 38 +reg: $f7 39 +reg: $f8 40 +reg: $f9 41 +reg: $f10 42 +reg: $f11 43 +reg: $f12 44 +reg: $f13 45 +reg: $f14 46 +reg: $f15 47 +reg: $f16 48 +reg: $f17 49 +reg: $f18 50 +reg: $f19 51 +reg: $f20 52 +reg: $f21 53 +reg: $f22 54 +reg: $f23 55 +reg: $f24 56 +reg: $f25 57 +reg: $f26 58 +reg: $f27 59 +reg: $f28 60 +reg: $f29 61 +reg: $f30 62 +reg: $f31 63 +reg: ra 64 +reg: slk 65 + + +# End of abi definition. +endabi: mips-irix + + +# Make 'mips' abi be a modern MIPS, not an old IRIX version. +beginabi: mips +includeabi: mips-simple3 +endabi: mips + + +# MIPS/IRIX ISA/ABI for testing libdwarf. +beginabi: mips-irix2 +frame_interface: 2 +reg_table_size: 66 +cfa_reg: 0 +same_val_reg: 1035 +undefined_val_reg: 1034 +initial_reg_value: 1035 + +reg: cfa 0 # Used with MIPS/IRIX original DWARF2 interface +reg: ra 64 +reg: slk 65 + +# End of abi definition. +endabi: mips-irix2 + +# MIPS/IRIX ISA/ABI for testing the new frame interface +# with libdwarf. +beginabi: mips-simple3 +frame_interface: 3 + +# When using frame_interface: 3 the size of the register table +# is not fixed. It can be as large as needed. +reg_table_size: 66 +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +initial_reg_value: 1035 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# No cfa as a 'normal' register. +# Rule 0 is just register 0, which is not used +# in frame descriptions. +# (so cfa does not have a number here, and dwarfdump gives +# it the name 'cfa' automatically). +reg: ra 64 +reg: slk 65 +# End of abi definition. +endabi: mips-simple3 + + +beginabi: ia64 +frame_interface: 3 +initial_reg_value: 1034 # DW_FRAME_UNDEFINED_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 695 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# The following register names are not necessarily correct... +# Register indexes r32-r127 not used. +reg: f0 128 +# ... +reg: f127 255 +reg: b0 321 +reg: b1 322 +reg: b2 323 +reg: b3 324 +reg: b4 325 +reg: b5 326 +reg: b6 327 +reg: b7 328 +reg: vfp 329 +reg: vrap 330 +reg: pr 331 +reg: ip 332 +reg: psr 333 +reg: cfm 334 +reg: k0 335 +reg: k1 336 +reg: k2 337 +reg: k3 338 +reg: k4 339 +reg: k5 340 +reg: k6 341 +reg: k7 342 +reg: rsc 350 +reg: bsp 351 +reg: bspstore 352 +reg: rnat 353 +reg: fcr 355 +reg: eflag 358 +reg: csd 359 +reg: ssd 360 +reg: cflg 361 +reg: fsr 362 +reg: fir 363 +reg: fdr 364 +reg: pfs 398 +reg: lc 399 +reg: ec 400 + +endabi: ia64 + + +beginabi: x86 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +reg_table_size: 66 # more than large enough, hopefully. +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# The following register names are not necessarily correct... +reg: eax 0 +reg: ecx 1 +reg: edx 2 +reg: ebx 3 +reg: esp 4 +reg: ebp 5 +reg: esi 6 +reg: edi 7 +reg: eip 8 +reg: eflags 9 + +reg: trapno 10 +reg: st0 11 +reg: st1 12 +reg: st2 13 +reg: st3 14 +reg: st4 15 +reg: st5 16 +reg: st6 17 +reg: st7 18 +# 19 is ? 20 is ? +reg: xmm0 21 +reg: xmm1 22 +reg: xmm2 23 +reg: xmm3 24 +reg: xmm4 25 +reg: xmm5 26 +reg: xmm6 27 +reg: xmm7 28 + +reg: mm0 29 +reg: mm1 30 +reg: mm2 31 +reg: mm3 32 +reg: mm4 33 +reg: mm5 34 +reg: mm6 35 +reg: mm7 36 + +reg: fcw 37 +reg: fsw 38 +reg: mxcsr 39 + +reg: es 40 +reg: cs 41 +reg: ss 42 +reg: ds 43 +reg: fs 44 +reg: gs 45 +# 46 47 are ? +reg: tr 48 +reg: ldtr 49 + + +endabi: x86 + + +beginabi: x86_64 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +reg_table_size: 66 # more than large enough, hopefully. +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# The following register names are not necessarily correct... +reg: rax 0 +reg: rdx 1 +reg: rcx 2 +reg: rbx 3 +reg: rsi 4 +reg: rdi 5 +reg: rbp 6 +reg: rsp 7 +reg: r8 8 +reg: r9 9 +reg: r10 10 +reg: r11 11 +reg: r12 12 +reg: r13 13 +reg: r14 14 +reg: r15 15 +reg: rip 16 +reg: xmm0 17 +reg: xmm1 18 +reg: xmm2 19 +reg: xmm3 20 +reg: xmm4 21 +reg: xmm5 22 +reg: xmm6 23 +reg: xmm7 24 +reg: xmm8 25 +reg: xmm9 26 +reg: xmm10 27 +reg: xmm11 28 +reg: xmm12 29 +reg: xmm13 30 +reg: xmm14 31 +reg: xmm15 32 + +reg: st0 33 +reg: st1 34 +reg: st2 35 +reg: st3 36 +reg: st4 37 +reg: st5 38 +reg: st6 39 +reg: st7 40 + +reg: mm0 41 +reg: mm1 42 +reg: mm2 43 +reg: mm3 44 +reg: mm4 45 +reg: mm5 46 +reg: mm6 47 +reg: mm7 48 + +reg: rflags 49 +reg: es 50 +reg: cs 51 +reg: ss 52 +reg: ds 53 +reg: fs 54 +reg: gs 55 +# 56, 57 are ? +reg: fs.base 58 +reg: gs.base 59 +# 60 61 are ? +reg: tr 62 +reg: ldtr 63 + +endabi: x86_64 + +beginabi: m68k +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +reg_table_size: 66 # more than large enough, hopefully. +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1035 +undefined_val_reg: 1034 + +reg: d0 0 +reg: d1 1 +reg: d2 2 +reg: d3 3 +reg: d4 4 +reg: d5 5 +reg: d6 6 +reg: d7 7 + +reg: a0 8 +reg: a1 9 +reg: a2 10 +reg: a3 11 +reg: a4 12 +reg: a5 13 +reg: a6 14 +reg: sp 15 + +reg: fp0 16 +reg: fp1 17 +reg: fp2 18 +reg: fp3 19 +reg: fp4 20 +reg: fp5 21 +reg: fp6 22 +reg: pc 23 + +endabi: m68k + +# Demonstrates use of address_size and includeabi keywords. +# address_size is useful when an Elf64 object has DWARF2 +# 32bit (4 byte) address-size frame data (which has no address_size field) +# and no .debug_info section to provide the 32bit address size. +beginabi: ppc32bitaddress +address_size: 4 +includeabi: ppc +endabi: ppc32bitaddress + +beginabi: ppc +# This abi defined Oct 2008 based on: +# http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html +frame_interface: 3 +# abi dwarf table uses up thru 1155. +# As of Oct 2008, the only ABI requiring a higher +# DW_FRAME_SAME_VAL and DW_FRAME_CFA_COL3. +initial_reg_value: 1235 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1235 +undefined_val_reg: 1234 +reg_table_size: 1200 + +reg: r0 0 +reg: f0 32 +reg: f1 33 +reg: f2 34 +reg: f3 35 +reg: f4 36 +reg: f5 37 +reg: f6 38 +reg: f7 39 +reg: f8 40 +reg: f9 41 +reg: f10 42 +reg: f11 43 +reg: f12 44 +reg: f13 45 +reg: f14 46 +reg: f16 47 +reg: f17 48 +reg: f18 49 +reg: f19 50 +reg: f20 51 +reg: f21 52 +reg: f22 53 +reg: f23 54 +reg: f24 55 +reg: f25 56 +reg: f26 57 +reg: f27 58 +reg: f28 59 +reg: f29 60 +reg: f30 62 +reg: f31 63 +reg: cr 64 +reg: fpcsr 65 +# spr0 is also called MQ +reg: spr0 100 +# spr1 is also called XER +reg: spr1 101 +# spr4 also called rtcu +reg: spr4 104 +# spr5 also called rtcl +reg: spr5 105 +#spr8 also called LR +reg: spr8 108 +# spr9 also called ctr +reg: spr9 109 +reg: msr 66 +reg: sr0 70 +reg: sr1 71 +reg: sr2 72 +reg: sr3 73 +reg: sr4 74 +reg: sr5 75 +reg: sr6 76 +reg: sr7 77 +reg: sr8 78 +reg: sr9 79 + +#dsisr also called spr18 +reg: spr18 118 +# dar also called spr19 +reg: spr19 119 +#dec also called spr22 +reg: spr22 122 +#sdr1 also called spr25 +reg: spr25 125 +#srr0 also called spr26 +reg: spr26 126 +#srr1 also called spr27 +reg: spr27 127 + +#vrsave also called spr256 +reg: spr256 356 +#sprg0 also called spr272 +reg: spr272 372 +#sprg1 also called spr273 +reg: spr273 373 +#sprg2 also called spr274 +reg: spr274 374 +#sprg3 also called spr275 +reg: spr275 375 +#asr also called spr280 +reg: spr280 380 +#ear also called spr282 +reg: spr282 382 +#tb also called spr284 +reg: spr284 384 +#tbu also called spr285 +reg: spr285 385 +#pvr also called spr287 +reg: spr287 387 +#ibat0u also called spr528 +reg: spr528 628 +#ibat0l also called spr529 +reg: spr529 629 +#ibat1u also called spr530 +reg: spr530 630 +#ibat1l also called spr531 +reg: spr531 631 +#ibat2u also called spr532 +reg: spr532 632 +#ibat2l also called spr533 +reg: spr533 633 +#ibat3u also called spr534 +reg: spr534 634 +#ibat3l also called spr535 +reg: spr535 635 +#dbat0u also called spr536 +reg: spr536 636 +#dbat0l also called spr537 +reg: spr537 637 +#dbat1u also called spr538 +reg: spr538 638 +#dbat1l also called spr539 +reg: spr539 639 +#dbat2u also called spr540 +reg: spr540 640 +#dbat2l also called spr541 +reg: spr541 641 +#dbat3u also called spr542 +reg: spr542 642 +#dbat3l also called spr543 +reg: spr543 643 + +#hid0 also called spr1008 +reg: spr1008 1108 +#hid1 also called spr1009 +reg: spr1009 1109 +#hid2 also called iabr or spr1010 +reg: spr1010 1110 +#hid5 also called dabr or spr1013 +reg: spr1013 1113 +#hid15 also called pir or spr1023 +reg: spr1023 1123 + +# vector registers 0-31 +reg: vr0 1124 +reg: vr1 1125 +reg: vr2 1126 +reg: vr3 1127 +reg: vr4 1128 +reg: vr5 1129 +reg: vr6 1130 +reg: vr7 1131 +reg: vr8 1132 +reg: vr9 1133 +reg: vr10 1134 +reg: vr11 1135 +reg: vr12 1136 +reg: vr13 1137 +reg: vr14 1138 +reg: vr15 1130 +reg: vr16 1140 +reg: vr17 1141 +reg: vr18 1142 +reg: vr19 1143 +reg: vr20 1144 +reg: vr21 1145 +reg: vr22 1146 +reg: vr23 1147 +reg: vr24 1148 +reg: vr25 1149 +reg: vr26 1150 +reg: vr27 1151 +reg: vr28 1152 +reg: vr29 1153 +reg: vr30 1154 +reg: vr31 1155 +endabi: ppc + +# 'Generic 1000 register abi'. +# This is useful as a 'general' ABI settings for +# cpus using up to 1000 registers. The register names +# show as a number, like 'r991'. +beginabi: generic +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 1000 +same_val_reg: 1035 +undefined_val_reg: 1034 +reg: r0 0 +endabi: generic + +# 'Generic 500 register abi'. +# This is useful as a 'general' ABI settings for +# cpus using up to 500 registers. The register names +# show as a number, like 'r91'. +beginabi: generic500 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 500 +same_val_reg: 1035 +undefined_val_reg: 1034 +reg: r0 0 +endabi: generic500 + +# 'Generic 100 register abi'. +# This is useful as a 'general' ABI settings for +# cpus using up to 100 registers. The register names +# show as a number, like 'r91'. +beginabi: generic100 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 100 +same_val_reg: 1035 +undefined_val_reg: 1034 +reg: r0 0 +endabi: generic100 + + +beginabi: arm +frame_interface: 3 +# When using frame_interface: 3 the size of the register +# table is not fixed. It can be as large as needed. +reg_table_size: 288 +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +initial_reg_value: 1034 +same_val_reg: 1035 +undefined_val_reg: 1034 +# If the vendor co-processor registers are allowed +# or other numbers above 287 used then +# the reg_table_size must be increased and (possibly) +# the cfa, same_value, undefined_value reg values changed +# here. +# r0-r15 are 0 through 15. +# Numbers 16 through 63 had meaning +# in some ARM DWARF register mappings. +reg: s0 64 +reg: s1 65 +reg: s2 66 +reg: s3 67 +reg: s4 68 +reg: s5 69 +reg: s6 70 +reg: s7 71 +reg: s8 72 +reg: s9 73 +reg: s10 74 +reg: s11 75 +reg: s12 76 +reg: s13 77 +reg: s14 78 +reg: s15 79 +reg: s16 80 +reg: s17 81 +reg: s18 82 +reg: s19 83 +reg: s20 84 +reg: s21 85 +reg: s22 86 +reg: s23 87 +reg: s24 88 +reg: s25 89 +reg: s26 90 +reg: s27 91 +reg: s28 92 +reg: s29 93 +reg: s30 94 +reg: s31 95 +reg: f0 96 +reg: f1 97 +reg: f2 98 +reg: f3 99 +reg: f4 100 +reg: f5 101 +reg: f6 102 +reg: f7 103 +reg: wcgr0 104 +reg: wcgr0 105 +reg: wcgr0 106 +reg: wcgr0 107 +reg: wcgr0 108 +reg: wcgr0 109 +reg: wcgr0 110 +reg: wcgr0 111 +reg: wr0 112 +reg: wr1 113 +reg: wr2 114 +reg: wr3 115 +reg: wr4 116 +reg: wr5 117 +reg: wr6 118 +reg: wr7 119 +reg: wr8 120 +reg: wr9 121 +reg: wr10 122 +reg: wr11 123 +reg: wr12 124 +reg: wr13 125 +reg: wr14 126 +reg: wr15 127 +reg: spsr 128 +reg: spsr_fiq 129 +reg: spsr_irq 130 +reg: spsr_abt 131 +reg: spsr_und 132 +reg: spsr_svc 133 +reg: r8_usr 144 +reg: r9_usr 145 +reg: r10_usr 146 +reg: r11_usr 147 +reg: r12_usr 148 +reg: r13_usr 149 +reg: r14_usr 150 +reg: r8_fiq 151 +reg: r9_fiq 152 +reg: r10_fiq 153 +reg: r11_fiq 154 +reg: r12_fiq 155 +reg: r13_fiq 156 +reg: r14_fiq 157 +reg: r13_riq 158 +reg: r14_riq 159 +reg: r14_abt 160 +reg: r13_abt 161 +reg: r14_und 162 +reg: r13_und 163 +reg: r14_svc 164 +reg: r13_svc 165 +reg: wc0 192 +reg: wc1 193 +reg: wc2 192 +reg: wc3 192 +reg: wc4 192 +reg: wc5 197 +reg: wc6 198 +reg: wc7 199 +reg: d0 256 +reg: d1 257 +reg: d2 258 +reg: d3 259 +reg: d4 260 +reg: d5 261 +reg: d6 262 +reg: d7 263 +reg: d8 264 +reg: d9 265 +reg: d10 266 +reg: d11 267 +reg: d12 268 +reg: d13 269 +reg: d14 270 +reg: d15 271 +reg: d16 272 +reg: d17 273 +reg: d18 274 +reg: d19 275 +reg: d20 266 +reg: d21 277 +reg: d22 278 +reg: d23 279 +reg: d24 280 +reg: d25 281 +reg: d26 282 +reg: d27 283 +reg: d28 284 +reg: d29 285 +reg: d30 286 +reg: d31 287 +# End of abi definition. +endabi: arm + diff --git a/dwarfdump/dwconf.c b/dwarfdump/dwconf.c new file mode 100644 index 0000000..1b59053 --- /dev/null +++ b/dwarfdump/dwconf.c @@ -0,0 +1,1424 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 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/dwconf.c,v 1.4 2006/04/18 18:05:57 davea Exp $ */ + + +/* Windows specific */ +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "globals.h" +#include "dwarf.h" +#include "libdwarf.h" + +#include <ctype.h> +#include "dwconf.h" +#include "makename.h" + +extern int verbose; + +/* The nesting level is arbitrary, 2 should suffice. + But at least this prevents an infinite loop. +*/ +#define MAX_NEST_LEVEL 3 + +struct token_s { + unsigned tk_len; + char *tk_data; +}; +enum linetype_e { + LT_ERROR, + LT_COMMENT, + LT_BLANK, + LT_BEGINABI, + LT_REG, + LT_FRAME_INTERFACE, + LT_CFA_REG, + LT_INITIAL_REG_VALUE, + LT_SAME_VAL_REG, + LT_UNDEFINED_VAL_REG, + LT_REG_TABLE_SIZE, + LT_ADDRESS_SIZE, + LT_INCLUDEABI, + LT_ENDABI +}; + +struct comtable_s { + enum linetype_e type; + char *name; + size_t namelen; +}; + +static int errcount = 0; /* Count errors found in this scan of + the configuration file. */ + +static char name_begin_abi[] = "beginabi:"; +static char name_reg[] = "reg:"; +static char name_frame_interface[] = "frame_interface:"; +static char name_cfa_reg[] = "cfa_reg:"; +static char name_initial_reg_value[] = "initial_reg_value:"; +static char name_same_val_reg[] = "same_val_reg:"; +static char name_undefined_val_reg[] = "undefined_val_reg:"; +static char name_reg_table_size[] = "reg_table_size:"; +static char name_address_size[] = "address_size:"; +static char name_includeabi[] = "includeabi:"; +static char name_endabi[] = "endabi:"; + +static struct comtable_s comtable[] = { + {LT_BEGINABI, name_begin_abi}, + {LT_REG, name_reg}, + {LT_FRAME_INTERFACE, name_frame_interface}, + {LT_CFA_REG, name_cfa_reg}, + {LT_INITIAL_REG_VALUE, name_initial_reg_value}, + {LT_SAME_VAL_REG, name_same_val_reg}, + {LT_UNDEFINED_VAL_REG, name_undefined_val_reg}, + {LT_REG_TABLE_SIZE, name_reg_table_size}, + {LT_ADDRESS_SIZE, name_address_size}, + {LT_INCLUDEABI, name_includeabi}, + {LT_ENDABI, name_endabi}, +}; + +struct conf_internal_s { + unsigned long beginabi_lineno; + unsigned long frame_interface_lineno; + unsigned long initial_reg_value_lineno; + unsigned long reg_table_size_lineno; + unsigned long address_size_lineno; + unsigned long same_val_reg_lineno; + unsigned long undefined_val_reg_lineno; + unsigned long cfa_reg_lineno; + unsigned long regcount; + struct dwconf_s * conf_out; + const char * conf_name_used; + char ** conf_defaults; +}; +static void +init_conf_internal(struct conf_internal_s *s, + struct dwconf_s * conf_out) +{ + s->beginabi_lineno = 0; + s->frame_interface_lineno = 0; + s->initial_reg_value_lineno = 0; + s->reg_table_size_lineno = 0; + s->address_size_lineno = 0; + s->same_val_reg_lineno = 0; + s->undefined_val_reg_lineno = 0; + s->cfa_reg_lineno = 0; + s->cfa_reg_lineno = 0; + s->conf_name_used = 0; + s->conf_defaults = 0; + s->regcount = 0; + s->conf_out = conf_out; +} + +static int size_of_comtable = sizeof(comtable) / sizeof(comtable[0]); + +static FILE *find_a_file(const char *named_file, char **defaults, + const char** name_used); +static int find_abi_start(FILE * stream, const char *abi_name, long *offset, + unsigned long *lineno_out); +static int parse_abi(FILE * stream, const char *fname, const char *abiname, + struct conf_internal_s *out, unsigned long lineno, unsigned nest_level); +static char *get_token(char *cp, struct token_s *outtok); + +/* This finds a dwarfdump.conf file and + then parses it. It updates + conf_out as appropriate. + + This finds the first file (looking in a set of places) + with that name. It then looks for the right ABI entry. + If the first file it finds does not have that ABI entry it + gives up. + + It would also be reasonable to search every 'dwarfdump.conf' + it finds for the abi. But we stop at the first dwarfdump.conf + we find. + This is the internal call to get the conf data to implement + a crude 'includeabi' feature. + + Returns 0 if no errors found, else returns > 0. +*/ +static int +find_conf_file_and_read_config_inner(const char *named_file, + const char *named_abi, + struct conf_internal_s *conf_internal, + unsigned nest_level) +{ + + FILE *conf_stream = 0; + const char *name_used = 0; + long offset = 0; + int res = FALSE; + unsigned long lineno = 0; + + errcount = 0; + + conf_stream = find_a_file(named_file, conf_internal->conf_defaults, + &name_used); + if (!conf_stream) { + ++errcount; + printf("dwarfdump found no file %s!\n", + named_file ? named_file : "readable for configuration. " + "(add options -v -v to see what file names tried)\n"); + return errcount; + } + if (verbose > 1) { + printf("dwarfdump using configuration file %s\n", name_used); + } + conf_internal->conf_name_used = name_used; + + res = find_abi_start(conf_stream, named_abi, &offset, &lineno); + if (errcount > 0) { + ++errcount; + printf("dwarfdump found no ABI %s in file %s.\n", + named_abi, name_used); + return errcount; + } + res = fseek(conf_stream, offset, SEEK_SET); + if (res != 0) { + ++errcount; + printf("dwarfdump seek to %ld offset in %s failed!\n", + offset, name_used); + return errcount; + } + parse_abi(conf_stream, name_used, named_abi, conf_internal, lineno, + nest_level); + fclose(conf_stream); + return errcount; +} + +/* This is the external-facing call to get the conf data. */ +int +find_conf_file_and_read_config(const char *named_file, + const char *named_abi, char **defaults, + struct dwconf_s *conf_out) +{ + int res = 0; + struct conf_internal_s conf_internal; + init_conf_file_data(conf_out); + init_conf_internal(&conf_internal,conf_out); + conf_internal.conf_defaults = defaults; + res = find_conf_file_and_read_config_inner(named_file, + named_abi, + &conf_internal,0); + return res; +} + +/* Given path strings, attempt to make a canonical file name: + that is, avoid superfluous '/' so that no + '//' (or worse) is created in the output. The path components + are to be separated so at least one '/' + is to appear between the two 'input strings' when + creating the output. +*/ +static char * +canonical_append(char *target, unsigned int target_size, + const char *first_string, const char *second_string) +{ + size_t firstlen = strlen(first_string); + + /* +1 +1: Leave room for added "/" and final NUL, though that is + overkill, as we drop a NUL byte too. */ + if ((firstlen + strlen(second_string) + 1 + 1) >= target_size) { + /* Not enough space. */ + return NULL; + } + for (; *second_string == '/'; ++second_string) { + } + for (; firstlen > 0 && first_string[firstlen - 1] == '/'; + --firstlen) { + } + target[0] = 0; + if (firstlen > 0) { + strncpy(target, first_string, firstlen); + target[firstlen + 1] = 0; + } + target[firstlen] = '/'; + firstlen++; + target[firstlen] = 0; + strcat(target, second_string); + return target; +} + +#ifdef BUILD_FOR_TEST +#define CANBUF 25 +struct canap_s { + char *res_exp; + char *first; + char *second; +} canap[] = { + { + "ab/c", "ab", "c"}, { + "ab/c", "ab/", "c"}, { + "ab/c", "ab", "/c"}, { + "ab/c", "ab////", "/////c"}, { + "ab/", "ab", ""}, { + "ab/", "ab////", ""}, { + "ab/", "ab////", ""}, { + "/a", "", "a"}, { + 0, "/abcdefgbijkl", "pqrstuvwxyzabcd"}, { + 0, 0, 0} +}; +static void +test_canonical_append(void) +{ + /* Make buf big, this is test code, so be safe. */ + char lbuf[1000]; + unsigned i; + unsigned failcount = 0; + + printf("Entry test_canonical_append\n"); + for (i = 0;; ++i) { + char *res = 0; + + if (canap[i].first == 0 && canap[i].second == 0) + break; + + res = canonical_append(lbuf, CANBUF, canap[i].first, + canap[i].second); + if (res == 0) { + if (canap[i].res_exp == 0) { + /* GOOD */ + printf("PASS %u\n", i); + } else { + ++failcount; + printf("FAIL: entry %u wrong, expected %s, got NULL\n", + i, canap[i].res_exp); + } + } else { + if (canap[i].res_exp == 0) { + ++failcount; + printf("FAIL: entry %u wrong, got %s expected NULL\n", + i, res); + } else { + if (strcmp(res, canap[i].res_exp) == 0) { + printf("PASS %u\n", i); + /* GOOD */ + } else { + ++failcount; + printf("FAIL: entry %u wrong, expected %s got %s\n", + i, canap[i].res_exp, res); + } + } + } + } + printf("FAIL count %u\n", failcount); + +} +#endif /* BUILD_FOR_TEST */ +/* Try to find a file as named and open for read. + We treat each name as a full name, we are not + combining separate name and path components. + This is an arbitrary choice... + + The defaults are listed in dwarfdump.c in the array + config_file_defaults[]. +*/ +static FILE * +find_a_file(const char *named_file, char **defaults, const char ** name_used) +{ + FILE *fin = 0; + const char *lname = named_file; + const char *type = "rw"; + int i = 0; + +#ifdef BUILD_FOR_TEST + test_canonical_append(); +#endif /* BUILD_FOR_TEST */ + + if (lname) { + /* Name given, just assume it is fully correct, try no other. */ + if (verbose > 1) { + printf("dwarfdump looking for configuration as %s\n", + lname); + } + fin = fopen(lname, type); + if (fin) { + *name_used = lname; + return fin; + } + return 0; + } + /* No name given, find a default, if we can. */ + for (i = 0; defaults[i]; ++i) { + lname = defaults[i]; +#ifdef WIN32 + /* Open the configuration file, located + in the directory where the tool is loaded from */ + { + static char szPath[MAX_PATH]; + if (GetModuleFileName(NULL,szPath,MAX_PATH)) { + char *pDir = strrchr(szPath,'/'); + if (!pDir) { + pDir = strrchr(szPath,'\\'); + if (!pDir) { + /* No file was found */ + return 0; + } + } + /* Add the configuration name to the pathname */ + ++pDir; + strcpy(pDir,"dwarfdump.conf"); + lname = szPath; + } + } +#else /* non-Win */ + if (strncmp(lname, "HOME/", 5) == 0) { + /* arbitrary size */ + char buf[2000]; + char *homedir = getenv("HOME"); + if (homedir) { + char *cp = canonical_append(buf, sizeof(buf), + homedir, lname + 5); + if (!cp) { + /* OOps, ignore this one. */ + continue; + } + lname = makename(buf); + } + } +#endif /* WIN32 */ + if (verbose > 1) { + printf("dwarfdump looking for configuration as %s\n", + lname); + } + fin = fopen(lname, type); + if (fin) { + *name_used = lname; + return fin; + } + } + return 0; +} + +/* Start at a token begin, see how long it is, + return length. */ +unsigned +find_token_len(char *cp) +{ + unsigned len = 0; + + for (; *cp; ++cp) { + if (isspace(*cp)) { + return len; + } + if (*cp == '#') { + return len; /* begins comment */ + } + ++len; + } + return len; +} + +/* + Skip past all whitespace: the only code that even knows + what whitespace is. +*/ +static char * +skipwhite(char *cp) +{ + for (; *cp; ++cp) { + if (!isspace(*cp)) { + return cp; + } + } + return cp; +} + +/* Return TRUE if ok. FALSE if find more tokens. + Emit error message if error. +*/ +static int +ensure_has_no_more_tokens(char *cp, const char *fname, unsigned long lineno) +{ + struct token_s tok; + + cp = get_token(cp, &tok); + if (tok.tk_len > 0) { + printf("dwarfdump.conf error: " + "extra characters after command operands, found " + "\"%s\" in %s line %lu\n", tok.tk_data, fname, lineno); + ++errcount; + return FALSE; + } + return TRUE; +} + + +/* There may be many beginabi: lines in a dwarfdump.conf file, + find the one we want and return its file offset. +*/ +static int +find_abi_start(FILE * stream, const char *abi_name, + long *offset, unsigned long *lineno_out) +{ + char buf[100]; + unsigned long lineno = 0; + + for (; !feof(stream);) { + + struct token_s tok; + char *line = 0; + long loffset = ftell(stream); + + line = fgets(buf, sizeof(buf), stream); + ++lineno; + if (!line) { + ++errcount; + return FALSE; + } + + line = get_token(buf, &tok); + + if (strcmp(tok.tk_data, name_begin_abi) != 0) { + continue; + } + get_token(line, &tok); + if (strcmp(tok.tk_data, abi_name) != 0) { + continue; + } + + *offset = loffset; + *lineno_out = lineno; + return TRUE; + } + + ++errcount; + return FALSE; +} + +static char *tempstr = 0; +static unsigned tempstr_len = 0; + +/* Use a global buffer (tempstr) to turn a non-delimited + input char array into a NUL-terminated C string + (with the help of makename() to get a permanent + address for the result ing string). +*/ +static char * +build_string(unsigned tlen, char *cp) +{ + if (tlen >= tempstr_len) { + free(tempstr); + tempstr = malloc(tlen + 100); + } + strncpy(tempstr, cp, tlen); + tempstr[tlen] = 0; + return makename(tempstr); +} + +/* The tokenizer for our simple parser. +*/ +static char * +get_token(char *cp, struct token_s *outtok) +{ + char *lcp = skipwhite(cp); + unsigned tlen = find_token_len(lcp); + + outtok->tk_len = tlen; + if (tlen > 0) { + outtok->tk_data = build_string(tlen, lcp); + } else { + outtok->tk_data = ""; + } + return lcp + tlen; + +} + +/* + We can't get all the field set up statically very easily, + so we get the command string length set here. +*/ +static void +finish_comtable_setup(void) +{ + unsigned i; + + for (i = 0; i < size_of_comtable; ++i) { + comtable[i].namelen = strlen(comtable[i].name); + } +} + +/* + Given a line of the table, determine if it is a command + or not, and if a command, which one is it. + Return LT_ERROR if it's not recognized. +*/ +static enum linetype_e +which_command(char *cp, struct comtable_s **tableentry) +{ + int i; + struct token_s tok; + + if (*cp == '#') + return LT_COMMENT; + if (!*cp) + return LT_BLANK; + + get_token(cp, &tok); + + for (i = 0; i < size_of_comtable; ++i) { + if (tok.tk_len == comtable[i].namelen && + strcmp(comtable[i].name, tok.tk_data) == 0) { + + *tableentry = &comtable[i]; + return comtable[i].type; + } + } + + return LT_ERROR; +} + +/* We are promised it's an abiname: command + find the name on the line. +*/ +static int +parsebeginabi(char *cp, const char *fname, const char *abiname, + unsigned long lineno, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + size_t abinamelen = strlen(abiname); + struct token_s tok; + + + cp = cp + clen + 1; + cp = skipwhite(cp); + get_token(cp, &tok); + if (tok.tk_len != abinamelen || + strncmp(cp, abiname, abinamelen) != 0) { + printf("dwarfdump internal error: " + "mismatch %s with %s %s line %lu\n", + cp, tok.tk_data, fname, lineno); + ++errcount; + return FALSE; + } + ensure_has_no_more_tokens(cp + tok.tk_len, fname, lineno); + return TRUE; +} + +/* This expands register names as required, but does not + ensure no names duplicated. +*/ +#define CONF_TABLE_OVERSIZE 100 +static void +add_to_reg_table(struct dwconf_s *conf, + char *rname, unsigned long rval, const char *fname, + unsigned long lineno) +{ + if (conf->cf_regs_malloced == 0) { + conf->cf_regs = 0; + conf->cf_named_regs_table_size = 0; + } + if (rval >= conf->cf_named_regs_table_size) { + char **newregs = 0; + unsigned long newtablen = rval + CONF_TABLE_OVERSIZE; + unsigned long newtabsize = newtablen * sizeof(char *); + unsigned long oldtabsize = + conf->cf_named_regs_table_size * sizeof(char *); + newregs = realloc(conf->cf_regs, newtabsize); + if (!newregs) { + printf("dwarfdump: unable to malloc table %lu bytes. " + " %s line %lu\n", newtabsize, fname, lineno); + exit(1); + } + /* Zero out the new entries. */ + memset((char *) newregs + (oldtabsize), 0, + (newtabsize - oldtabsize)); + conf->cf_named_regs_table_size = (unsigned long) newtablen; + conf->cf_regs = newregs; + conf->cf_regs_malloced = 1; + } + conf->cf_regs[rval] = rname; + return; +} + +/* Our input is supposed to be a number. + Determine the value (and return it) or generate an error message. +*/ +static int +make_a_number(char *cmd, const char *filename, unsigned long + lineno, struct token_s *tok, unsigned long *val_out) +{ + char *endnum = 0; + unsigned long val = 0; + + val = strtoul(tok->tk_data, &endnum, 0); + if (val == 0 && endnum == (tok->tk_data)) { + printf("dwarfdump.conf error: " + "%s missing register number (\"%s\" not valid) %s line %lu\n", + cmd, tok->tk_data, filename, lineno); + ++errcount; + return FALSE; + } + if (endnum != (tok->tk_data + tok->tk_len)) { + printf("dwarfdump.conf error: " + "%s Missing register number (\"%s\" not valid) %s line %lu\n", + cmd, tok->tk_data, filename, lineno); + ++errcount; + return FALSE; + } + *val_out = val; + return TRUE; + + + +} + +/* We are guaranteed it's a reg: command, so parse that command + and record the interesting data. +*/ +static int +parsereg(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s regnum; + struct token_s tokreg; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tokreg); + cp = get_token(cp, ®num); + if (tokreg.tk_len == 0) { + printf("dwarfdump.conf error: " + "reg: missing register name %s line %lu", + fname, lineno); + ++errcount; + return FALSE; + + } + if (regnum.tk_len == 0) { + printf("dwarfdump.conf error: " + "reg: missing register number %s line %lu", + fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, ®num, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + + add_to_reg_table(conf->conf_out, tokreg.tk_data, val, fname, lineno); + + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +/* + We are guaranteed it's an frame_interface: command. + Parse it and record the value data. +*/ +static int +parseframe_interface(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing interface number %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + if (val != 2 && val != 3) { + printf("dwarfdump.conf error: " + "%s only interface numbers 2 or 3 are allowed, " + " not %lu. %s line %lu", + comtab->name, val, fname, lineno); + ++errcount; + return FALSE; + } + + conf->conf_out->cf_interface_number = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +/* + We are guaranteed it's a cfa_reg: command. Parse it + and record the important data. +*/ +static int +parsecfa_reg(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing cfa_reg number %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + conf->conf_out->cf_cfa_reg = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + +/* We are guaranteed it's an initial_reg_value: command, + parse it and put the reg value where it will be remembered. +*/ +static int +parseinitial_reg_value(char *cp, const char *fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing initial reg value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + + ++errcount; + return FALSE; + } + conf->conf_out->cf_initial_rule_value = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +static int +parsesame_val_reg(char *cp, const char *fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing same_reg value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + + ++errcount; + return FALSE; + } + conf->conf_out->cf_same_val = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +static int +parseundefined_val_reg(char *cp, const char *fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing undefined_reg value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + + ++errcount; + return FALSE; + } + conf->conf_out->cf_undefined_val = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + + +/* We are guaranteed it's a table size command, parse it + and record the table size. +*/ +static int +parsereg_table_size(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing reg table size value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + conf->conf_out->cf_table_entry_count = (unsigned long) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +/* We are guaranteed it's a table size command, parse it + and record the table size. +*/ +static int +parseaddress_size(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing address size value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + conf->conf_out->cf_address_size = (unsigned long) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + +/* We are guaranteed it's an endabi: command, parse it and + check we have the right abi. +*/ +static int +parseendabi(char *cp, const char *fname, + const char *abiname, unsigned long lineno, + struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + int res = 0; + + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (strcmp(abiname, tok.tk_data) != 0) { + printf("%s error: " + "mismatch abi name %s (here) vs. %s (beginabi:) %s line %lu\n", + comtab->name, tok.tk_data, abiname, fname, lineno); + ++errcount; + return FALSE; + } + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} +static int +parseincludeabi(char *cp, const char *fname, unsigned long lineno, + char **abiname_out, + struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + char *name = 0; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + name = makename(tok.tk_data); + + *abiname_out = name; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + + + +/* Return TRUE if we succeeded and filed in *out. + Return FALSE if we failed (and fill in nothing). + beginabi: <abiname> + reg: <regname> <dwarf regnumber> + frame_interface: <integer value 2 or 3> + cfa_reg: <number> + initial_reg_value: <number: normally 1034 or 1035 > + reg_table_size: <size of table> + endabi: <abiname> + + We are positioned at the start of a beginabi: line when + called. + +*/ +static int +parse_abi(FILE * stream, const char *fname, const char *abiname, + struct conf_internal_s *conf_internal, + unsigned long lineno, + unsigned int nest_level) +{ + struct dwconf_s *localconf = conf_internal->conf_out; + char buf[1000]; + int comtype = 0; + + static int first_time_done = 0; + struct comtable_s *comtabp = 0; + + if( nest_level > MAX_NEST_LEVEL) { + ++errcount; + printf("dwarfdump.conf: includeabi nest too deep in %s at line %lu\n", + fname, lineno); + return FALSE; + } + + + if (first_time_done == 0) { + finish_comtable_setup(); + first_time_done = 1; + } + + for (; !feof(stream);) { + char *line = 0; + + /* long loffset = ftell(stream); */ + line = fgets(buf, sizeof(buf), stream); + if (!line) { + ++errcount; + printf + ("dwarfdump: end of file or error before endabi: in %s, line %lu\n", + fname, lineno); + return FALSE; + } + ++lineno; + line = skipwhite(line); + comtype = which_command(line, &comtabp); + switch (comtype) { + case LT_ERROR: + ++errcount; + printf + ("dwarfdump: Unknown text in %s is \"%s\" at line %lu\n", + fname, line, lineno); + break; + case LT_COMMENT: + break; + case LT_BLANK: + break; + case LT_BEGINABI: + if (conf_internal->beginabi_lineno > 0) { + ++errcount; + printf + ("dwarfdump: Encountered beginabi: when not expected. " + "%s line %lu previous beginabi line %lu\n", fname, + lineno, conf_internal->beginabi_lineno); + } + conf_internal->beginabi_lineno = lineno; + parsebeginabi(line, fname, abiname, lineno, comtabp); + break; + + case LT_REG: + parsereg(line, fname, lineno, conf_internal, comtabp); + conf_internal->regcount++; + break; + case LT_FRAME_INTERFACE: + if (conf_internal->frame_interface_lineno > 0) { + ++errcount; + printf + ("dwarfdump: Encountered duplicate frame_interface: " + "%s line %lu previous frame_interface: line %lu\n", + fname, lineno, conf_internal->frame_interface_lineno); + } + conf_internal->frame_interface_lineno = lineno; + parseframe_interface(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_CFA_REG: + if (conf_internal->cfa_reg_lineno > 0) { + printf("dwarfdump: Encountered duplicate cfa_reg: " + "%s line %lu previous cfa_reg line %lu\n", + fname, lineno, conf_internal->cfa_reg_lineno); + ++errcount; + } + conf_internal->cfa_reg_lineno = lineno; + parsecfa_reg(line, fname, lineno, conf_internal, comtabp); + break; + case LT_INITIAL_REG_VALUE: + if (conf_internal->initial_reg_value_lineno > 0) { + printf + ("dwarfdump: Encountered duplicate initial_reg_value: " + "%s line %lu previous initial_reg_value: line %lu\n", + fname, lineno, conf_internal->initial_reg_value_lineno); + ++errcount; + } + conf_internal->initial_reg_value_lineno = lineno; + parseinitial_reg_value(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_SAME_VAL_REG: + if (conf_internal->same_val_reg_lineno > 0) { + ++errcount; + printf + ("dwarfdump: Encountered duplicate same_val_reg: " + "%s line %lu previous initial_reg_value: line %lu\n", + fname, lineno, conf_internal->initial_reg_value_lineno); + } + conf_internal->same_val_reg_lineno = lineno; + parsesame_val_reg(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_UNDEFINED_VAL_REG: + if (conf_internal->undefined_val_reg_lineno > 0) { + ++errcount; + printf + ("dwarfdump: Encountered duplicate undefined_val_reg: " + "%s line %lu previous initial_reg_value: line %lu\n", + fname, lineno, conf_internal->initial_reg_value_lineno); + } + conf_internal->undefined_val_reg_lineno = lineno; + parseundefined_val_reg(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_REG_TABLE_SIZE: + if (conf_internal->reg_table_size_lineno > 0) { + printf("dwarfdump: duplicate reg_table_size: " + "%s line %lu previous reg_table_size: line %lu\n", + fname, lineno, conf_internal->reg_table_size_lineno); + ++errcount; + } + conf_internal->reg_table_size_lineno = lineno; + parsereg_table_size(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_ENDABI: + parseendabi(line, fname, abiname, lineno, comtabp); + + if (conf_internal->regcount > localconf->cf_table_entry_count) { + printf("dwarfdump: more registers named than " + " in %s ( %lu named vs %s %lu) %s line %lu\n", + abiname, (unsigned long) conf_internal->regcount, + name_reg_table_size, + (unsigned long) localconf->cf_table_entry_count, + fname, (unsigned long) lineno); + ++errcount; + } + return TRUE; + case LT_ADDRESS_SIZE: + if (conf_internal->address_size_lineno > 0) { + printf("dwarfdump: duplicate address_size: " + "%s line %lu previous address_size: line %lu\n", + fname, lineno, conf_internal->address_size_lineno); + ++errcount; + } + conf_internal->address_size_lineno = lineno; + parseaddress_size(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_INCLUDEABI: { + char *abiname_inner = 0; + unsigned long abilno = conf_internal->beginabi_lineno; + int ires = 0; + ires = parseincludeabi(line,fname,lineno, &abiname_inner,comtabp); + if(ires == FALSE) { + return FALSE; + } + /* For the nested abi read, the abi line number must be + set as if not-yet-read, and then restored. */ + conf_internal->beginabi_lineno = 0; + find_conf_file_and_read_config_inner( + conf_internal->conf_name_used, + abiname_inner, conf_internal,nest_level+1); + conf_internal->beginabi_lineno = abilno; + } + break; + default: + printf + ("dwarfdump internal error, impossible line type %d %s %lu \n", + (int) comtype, fname, lineno); + exit(1); + + } + } + ++errcount; + printf("End of file, no endabi: found. %s, line %lu\n", + fname, lineno); + return FALSE; +} + +/* MIPS/IRIX frame register names. + For alternate name sets, use dwarfdump.conf or + revise dwarf.h and libdwarf.h and this table. +*/ +static char *regnames[] = { + "cfa", + "r1/at", "r2/v0", "r3/v1", + "r4/a0", "r5/a1", "r6/a2", "r7/a3", + "r8/t0", "r9/t1", "r10/t2", "r11/t3", + "r12/t4", "r13/t5", "r14/t6", "r15/t7", + "r16/s0", "r17/s1", "r18/s2", "r19/s3", + "r20/s4", "r21/s5", "r22/s6", "r23/s7", + "r24/t8", "r25/t9", "r26/k0", "r27/k1", + "r28/gp", "r29/sp", "r30/s8", "r31", + + "$f0", "$f1", + "$f2", "$f3", + "$f4", "$f5", + "$f6", "$f7", + "$f8", "$f9", + "$f10", "$f11", + "$f12", "$f13", + "$f14", "$f15", + "$f16", "$f17", + "$f18", "$f19", + "$f20", "$f21", + "$f22", "$f23", + "$f24", "$f25", + "$f26", "$f27", + "$f28", "$f29", + "$f30", "$f31", + "ra", "slk", +}; + + +/* Naming a few registers makes printing these just + a little bit faster. +*/ +static char *genericregnames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20" +}; + +/* This is a simple generic set of registers. The + table entry count is pretty arbitrary. +*/ +void +init_conf_file_data(struct dwconf_s *config_file_data) +{ + unsigned generic_table_count; + config_file_data->cf_abi_name = ""; + config_file_data->cf_config_file_path = ""; + config_file_data->cf_interface_number = 3; + config_file_data->cf_table_entry_count = 100; + config_file_data->cf_initial_rule_value = DW_FRAME_UNDEFINED_VAL; + config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL3; + config_file_data->cf_address_size = 0; + config_file_data->cf_same_val = DW_FRAME_SAME_VAL; + config_file_data->cf_undefined_val = DW_FRAME_UNDEFINED_VAL; + config_file_data->cf_regs = genericregnames; + generic_table_count = + sizeof(genericregnames) / sizeof(genericregnames[0]); + config_file_data->cf_named_regs_table_size = generic_table_count; + config_file_data->cf_regs_malloced = 0; +} + +/* These defaults match MIPS/IRIX ABI defaults, but this + function is not actually used. + For a 'generic' ABI, see -R or init_conf_file_data(). + To really get the old MIPS, use '-x abi=mips'. + For other ABIs, see -x abi=<whatever> + to configure dwarfdump (and libdwarf) frame + data reporting at runtime. +*/ +void +init_mips_conf_file_data(struct dwconf_s *config_file_data) +{ + unsigned long base_table_count = + sizeof(regnames) / sizeof(regnames[0]); + + memset(config_file_data, 0, sizeof(*config_file_data)); + /* Interface 2 is deprecated, but for testing purposes + is acceptable. */ + config_file_data->cf_interface_number = 2; + config_file_data->cf_table_entry_count = DW_REG_TABLE_SIZE; + config_file_data->cf_initial_rule_value = + DW_FRAME_REG_INITIAL_VALUE; + config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL; + config_file_data->cf_address_size = 0; + config_file_data->cf_same_val = DW_FRAME_SAME_VAL; + config_file_data->cf_undefined_val = DW_FRAME_UNDEFINED_VAL; + config_file_data->cf_regs = regnames; + config_file_data->cf_named_regs_table_size = base_table_count; + config_file_data->cf_regs_malloced = 0; + if (config_file_data->cf_table_entry_count != base_table_count) { + printf("dwarfdump: improper base table initization, " + "header files wrong: " + "DW_REG_TABLE_SIZE %u != string table size %lu\n", + (unsigned) DW_REG_TABLE_SIZE, + (unsigned long) base_table_count); + exit(1); + } + return; +} + +/* A 'generic' ABI. For up to 1200 registers. + Perhaps cf_initial_rule_value should be d + UNDEFINED VALUE (1034) instead, but for the purposes of + getting the dwarfdump output correct + either will work. +*/ +void +init_generic_config_1200_regs(struct dwconf_s *config_file_data) +{ + unsigned long generic_table_count = + sizeof(genericregnames) / sizeof(genericregnames[0]); + config_file_data->cf_interface_number = 3; + config_file_data->cf_table_entry_count = 1200; + /* There is no defined name for cf_initial_rule_value, + cf_same_val, or cf_undefined_val in libdwarf.h, + these must just be high enough to be higher than + any real register number. + DW_FRAME_CFA_COL3 must also be higher than any + real register number. */ + config_file_data->cf_initial_rule_value = 1235; /* SAME VALUE */ + config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL3; + config_file_data->cf_address_size = 0; + config_file_data->cf_same_val = 1235; + config_file_data->cf_undefined_val = 1234; + config_file_data->cf_regs = genericregnames; + config_file_data->cf_named_regs_table_size = generic_table_count; + config_file_data->cf_regs_malloced = 0; +} + +/* Print the 'right' string for the register we are given. + Deal sensibly with the special regs as well as numbers + we know and those we have not been told about. + +*/ +void +print_reg_from_config_data(Dwarf_Signed reg, + struct dwconf_s *config_data) +{ + char *name = 0; + + if (reg == config_data->cf_cfa_reg) { + fputs("cfa",stdout); + return; + } + if (reg == config_data->cf_undefined_val) { + fputs("u",stdout); + return; + } + if (reg == config_data->cf_same_val) { + fputs("s",stdout); + return; + } + + if (config_data->cf_regs == 0 || + reg < 0 || + reg >= config_data->cf_named_regs_table_size) { + printf("r%" DW_PR_DSd "", (Dwarf_Signed) reg); + return; + } + name = config_data->cf_regs[reg]; + if (!name) { + /* Can happen, the reg names table can be sparse. */ + printf("r%" DW_PR_DSd "", (Dwarf_Signed) reg); + return; + } + fputs(name,stdout); + return; +} diff --git a/dwarfdump/dwconf.h b/dwarfdump/dwconf.h new file mode 100644 index 0000000..471a3d4 --- /dev/null +++ b/dwarfdump/dwconf.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 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/dwconf.h,v 1.2 2006/04/18 04:29:39 davea Exp $ */ + + +/* declarations helping configure the frame reader. */ +struct dwconf_s { + char *cf_config_file_path; + char *cf_abi_name; + + /* 2 for old, 3 for frame interface 3. 2 means use the old + mips-abi-oriented frame interface. 3 means use the new + DWARF3-capable and configureable-abi interface. + + Now, anyone who revises dwarf.h and libdwarf.h to match their + abi-of-interest will still be able to use cf_interface_number 2 + as before. But most folks don't update those header files and + instead of making *them* configurable we make dwarfdump (and + libdwarf) configurable sufficiently to print frame information + sensibly. */ + int cf_interface_number; + + /* The number of table rules , aka columns. For MIPS/IRIX is 66. */ + unsigned long cf_table_entry_count; + + /* Array of cf_table_entry_count reg names. Names not filled in + from dwarfdump.conf have NULL (0) pointer value. + cf_named_regs_table_size must match size of cf_regs array. + Set cf_regs_malloced 1 if table was malloced. Set 0 + if static. + */ + char **cf_regs; + unsigned long cf_named_regs_table_size; + int cf_regs_malloced; + + /* The 'default initial value' when intializing a table. for MIPS + is DW_FRAME_SAME_VAL(1035). For other ISA/ABIs may be + DW_FRAME_UNDEFINED_VAL(1034). */ + int cf_initial_rule_value; + int cf_same_val; + int cf_undefined_val; + + /* The number of the cfa 'register'. For cf_interface_number 2 of + MIPS this is 0. For other architectures (and anytime using + cf_interface_number 3) this should be outside the table, a + special value such as 1436, not a table column at all). */ + int cf_cfa_reg; + + /* If non-zero it is the number of bytes in an address + for the frame data. Normally it will be zero because + there are usually other sources for the correct address size. + However, with DWARF2 frame data there is no explicit address + size in the frame data and the object file might not have + other .debug_ sections to work with. + If zero, no address size was supplied, and that is normal and + the already-set (or defaulted) address size is to be used. + Only an exceptional frame configure will specify address + size here. This won't work at all if the object needing + this setting has different address size in different CUs. */ + int cf_address_size; +}; + + +/* Returns DW_DLV_OK if works. DW_DLV_ERROR if cannot do what is asked. */ +int find_conf_file_and_read_config(const char *named_file, + const char *named_abi, char **defaults, + struct dwconf_s *conf_out); +void init_conf_file_data(struct dwconf_s *config_file_data); +void init_mips_conf_file_data(struct dwconf_s *config_file_data); + +void print_reg_from_config_data(Dwarf_Signed reg, + struct dwconf_s *config_data); + + +void init_generic_config_1200_regs(struct dwconf_s *conf); diff --git a/dwarfdump/esb.c b/dwarfdump/esb.c new file mode 100644 index 0000000..8c806c8 --- /dev/null +++ b/dwarfdump/esb.c @@ -0,0 +1,242 @@ +/* + Copyright (C) 2005 Silicon Graphics, 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/esb.c,v 1.1 2005/08/04 05:09:37 davea Exp $ */ + +/* esb.c + extensible string buffer. + + A simple means (vaguely like a C++ class) that + enables safely saving strings of arbitrary length built up + in small pieces. + +*/ + +#include "globals.h" +#include <stdarg.h> /* For va_start etc. */ +#include "esb.h" + +#define INITIAL_ALLOC 1024 +static size_t alloc_size = INITIAL_ALLOC; + + +static void +init_esb_string(struct esb_s *data, size_t min_len) +{ + string d; + + if (data->esb_allocated_size > 0) { + return; + } + if (min_len < alloc_size) { + min_len = alloc_size; + } + d = malloc(min_len); + if (!d) { + fprintf(stderr, + "dwarfdump is out of memory allocating %lu bytes\n", + (unsigned long) min_len); + exit(5); + } + data->esb_string = d; + data->esb_allocated_size = min_len; + data->esb_string[0] = 0; + data->esb_used_bytes = 0; +} + +/* Make more room. Leaving contents unchanged, effectively. +*/ +static void +allocate_more(struct esb_s *data, size_t len) +{ + size_t new_size = data->esb_allocated_size + len; + string newd = 0; + + if (new_size < alloc_size) + new_size = alloc_size; + newd = realloc(data->esb_string, new_size); + if (!newd) { + fprintf(stderr, "dwarfdump is out of memory re-allocating " + "%lu bytes\n", (unsigned long) new_size); + exit(5); + } + data->esb_string = newd; + data->esb_allocated_size = new_size; +} + +static void +esb_appendn_internal(struct esb_s *data, const char * in_string, size_t len); + +void +esb_appendn(struct esb_s *data, const char * in_string, size_t len) +{ + size_t full_len = strlen(in_string); + + if (full_len < len) { + fprintf(stderr, "dwarfdump internal error, bad string length " + " %lu < %lu \n", + (unsigned long) full_len, (unsigned long) len); + len = full_len; + } + + esb_appendn_internal(data, in_string, len); +} + +/* The length is gotten from the in_string itself. */ +void +esb_append(struct esb_s *data, const char * in_string) +{ + size_t len = strlen(in_string); + + esb_appendn_internal(data, in_string, len); +} + +/* The 'len' is believed. Do not pass in strings < len bytes long. */ +static void +esb_appendn_internal(struct esb_s *data, const char * in_string, size_t len) +{ + size_t remaining = 0; + size_t needed = len + 1; + + if (data->esb_allocated_size == 0) { + size_t maxlen = (len > alloc_size) ? len : alloc_size; + + init_esb_string(data, maxlen); + } + remaining = data->esb_allocated_size - data->esb_used_bytes; + if (remaining < needed) { + allocate_more(data, needed); + } + strncpy(&data->esb_string[data->esb_used_bytes], in_string, len); + data->esb_used_bytes += len; + /* Insist on explicit NUL terminator */ + data->esb_string[data->esb_used_bytes] = 0; +} + +/* Always returns an empty string or a non-empty string. Never 0. */ +string +esb_get_string(struct esb_s *data) +{ + if (data->esb_allocated_size == 0) { + init_esb_string(data, alloc_size); + } + return data->esb_string; +} + + +/* Sets esb_used_bytes to zero. The string is not freed and + esb_allocated_size is unchanged. */ +void +esb_empty_string(struct esb_s *data) +{ + if (data->esb_allocated_size == 0) { + init_esb_string(data, alloc_size); + } + data->esb_used_bytes = 0; + data->esb_string[0] = 0; + +} + + +/* Return esb_used_bytes. */ +size_t +esb_string_len(struct esb_s *data) +{ + return data->esb_used_bytes; +} + + +/* The following are for testing esb, not use by dwarfdump. */ + +/* *data is presumed to contain garbage, not values, and + is properly initialized. */ +void +esb_constructor(struct esb_s *data) +{ + memset(data, 0, sizeof(*data)); +} + +/* The string is freed, contents of *data set to zeroes. */ +void +esb_destructor(struct esb_s *data) +{ + if (data->esb_string) { + free(data->esb_string); + } + esb_constructor(data); +} + + +/* To get all paths in the code tested, this sets the + allocation/reallocation to the given value, which can be quite small + but must not be zero. */ +void +esb_alloc_size(size_t size) +{ + alloc_size = size; +} + +size_t +esb_get_allocated_size(struct esb_s *data) +{ + return data->esb_allocated_size; +} + +/* Append a formatted string */ +void +esb_append_printf(struct esb_s *data,const char *in_string, ...) +{ +#if WIN32 + #define NULL_DEVICE_FILE "NUL" +#else + #define NULL_DEVICE_FILE "/dev/null" +#endif /* WIN32 */ + + static FILE *null_file = NULL; + + int needed_size = 0; + int length = 0; + va_list ap; + va_start(ap,in_string); + if (null_file == NULL) { + null_file = fopen(NULL_DEVICE_FILE,"w"); + } + length = vfprintf(null_file,in_string,ap); + + /* Check if we require allocate more space */ + needed_size = data->esb_used_bytes + length; + if (needed_size > data->esb_allocated_size) { + allocate_more(data,length); + } + vsprintf(&data->esb_string[data->esb_used_bytes],in_string,ap); + data->esb_used_bytes += length; + va_end(ap); +} diff --git a/dwarfdump/esb.h b/dwarfdump/esb.h new file mode 100644 index 0000000..260db07 --- /dev/null +++ b/dwarfdump/esb.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 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/esb.h,v 1.1 2005/08/04 05:09:37 davea Exp $ */ + + +/* esb.h + Extensible string buffer. + A simple vaguely object oriented extensible string buffer. + + The struct could be opaque here, but it seems ok to expose + the contents: simplifies debugging. +*/ + + +struct esb_s { + string esb_string; /* pointer to the data itself, or NULL. */ + size_t esb_allocated_size; /* Size of allocated data or 0 */ + size_t esb_used_bytes; /* Amount of space used or 0 */ +}; + +/* string length taken from string itself. */ +void esb_append(struct esb_s *data, const char * in_string); + +/* The 'len' is believed. Do not pass in strings < len bytes long. */ +void esb_appendn(struct esb_s *data, const char * in_string, size_t len); + +/* Always returns an empty string or a non-empty string. Never 0. */ +string esb_get_string(struct esb_s *data); + + +/* Sets esb_used_bytes to zero. The string is not freed and + esb_allocated_size is unchanged. */ +void esb_empty_string(struct esb_s *data); + + +/* Return esb_used_bytes. */ +size_t esb_string_len(struct esb_s *data); + +/* The following are for testing esb, not use by dwarfdump. */ + +/* *data is presumed to contain garbage, not values, and + is properly initialized. */ +void esb_constructor(struct esb_s *data); + +/* The string is freed, contents of *data set to zeroes. */ +void esb_destructor(struct esb_s *data); + + +/* To get all paths in the code tested, this sets the + allocation/reallocation to the given value, which can be quite small + but must not be zero. */ +void esb_alloc_size(size_t size); +size_t esb_get_allocated_size(struct esb_s *data); + +/* Append a formatted string */ +void esb_append_printf(struct esb_s *data,const char *in_string, ...); diff --git a/dwarfdump/globals.h b/dwarfdump/globals.h new file mode 100644 index 0000000..46cbc11 --- /dev/null +++ b/dwarfdump/globals.h @@ -0,0 +1,459 @@ +/* + Copyright (C) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 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/globals.h,v 1.25 2006/04/17 00:09:56 davea Exp $ */ + +#ifndef globals_INCLUDED +#define globals_INCLUDED + +#include "config.h" +#if (!defined(HAVE_RAW_LIBELF_OK) && defined(HAVE_LIBELF_OFF64_OK) ) +/* At a certain point libelf.h requires _GNU_SOURCE. + here we assume the criteria in configure determine that + usefully. +*/ +#define _GNU_SOURCE 1 +#endif + +/* We want __uint32_t and __uint64_t and __int32_t __int64_t + properly defined but not duplicated, since duplicate typedefs + are not legal C. + HAVE___UINT32_T + HAVE___UINT64_T will be set by configure if + our 4 types are predefined in compiler +*/ + + +#if (!defined(HAVE___UINT32_T)) && defined(HAVE_SGIDEFS_H) +#include <sgidefs.h> /* sgidefs.h defines them */ +#define HAVE___UINT32_T 1 +#define HAVE___UINT64_T 1 +#endif + + + +#if (!defined(HAVE___UINT32_T)) && defined(HAVE_SYS_TYPES_H) && defined(HAVE___UINT32_T_IN_SYS_TYPES_H) +# include <sys/types.h> +/* we assume __[u]int32_t and __[u]int64_t defined + since __uint32_t defined in the sys/types.h in use */ +#define HAVE___UINT32_T 1 +#define HAVE___UINT64_T 1 +#endif + +#ifndef HAVE___UINT32_T +typedef int __int32_t; +typedef unsigned __uint32_t; +#define HAVE___UINT32_T 1 +#endif +#ifndef HAVE___UINT64_T +typedef long long __int64_t; +typedef unsigned long long __uint64_t; +#define HAVE___UINT64_T 1 +#endif + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* Windows specific */ +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_ELF_H +#include <elf.h> +#endif +#ifdef HAVE_LIBELF_H +#include <libelf.h> +#else +#ifdef HAVE_LIBELF_LIBELF_H +#include <libelf/libelf.h> +#endif +#endif +#include <dwarf.h> +#include <libdwarf.h> +#ifdef HAVE_REGEX +#include <regex.h> +#endif +typedef char * string; + +#include "checkutil.h" +#ifndef BOOLEAN_TYPEDEFED +#define BOOLEAN_TYPEDEFED +typedef int boolean; +#endif /* BOOLEAN_TYPEDEFED */ +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FAILED +#define FAILED 1 +#endif + +/* size of attrib_buffer, defined in print_die.c */ +#define ATTRIB_BUFSIZ 999 + +typedef struct { + int checks; + int errors; +} Dwarf_Check_Result; + +extern boolean do_check_dwarf; +extern boolean do_print_dwarf; + +extern boolean record_dwarf_error; /* 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). */ + +/* Compilation Unit information for improved error messages. + If the strings are too short we just truncate so fixed length + here is fine. */ +#define COMPILE_UNIT_NAME_LEN 512 +extern char PU_name[COMPILE_UNIT_NAME_LEN]; /* PU Name */ +extern char CU_name[COMPILE_UNIT_NAME_LEN]; /* CU Name */ +extern char CU_producer[COMPILE_UNIT_NAME_LEN]; /* CU Producer Name */ + +extern boolean seen_PU; /* Detected a PU. */ +extern boolean seen_CU; /* Detected a CU. */ +extern boolean need_CU_name; /* Need CU name. */ +extern boolean need_CU_base_address; /* Need CU Base address. */ +extern boolean need_CU_high_address; /* Need CU High address. */ +extern boolean need_PU_valid_code; /* Need PU valid code. */ + +extern boolean seen_PU_base_address; /* Detected a Base address for PU */ +extern boolean seen_PU_high_address; /* Detected a High address for PU */ +extern Dwarf_Addr PU_base_address; /* PU Base address */ +extern Dwarf_Addr PU_high_address; /* PU High address */ + +extern Dwarf_Off DIE_offset; /* DIE offset in compile unit. */ +extern Dwarf_Off DIE_overall_offset; /* DIE offset in .debug_info. */ + +/* Current CU information for better error reporting. */ +extern Dwarf_Off DIE_CU_offset; /* CU DIE offset in compile unit */ +extern Dwarf_Off DIE_CU_overall_offset; /* CU DIE offset in .debug_info */ +extern int current_section_id; /* Section being process. */ + +extern Dwarf_Addr CU_base_address; /* CU Base address. */ +extern Dwarf_Addr CU_high_address; /* CU High address. */ + +extern Dwarf_Addr elf_max_address; /* Largest representable + address offset. */ +extern Dwarf_Half elf_address_size; /* Target pointer size. */ + +/* Ranges and Location tables for better error checking: see + dwarfdump.c comments for more information. */ +extern Bucket_Group *pRangesInfo; +extern Bucket_Group *pLinkonceInfo; +extern Bucket_Group *pVisitedInfo; + +/* Display parent/children when in wide format. */ +extern boolean display_parent_tree; +extern boolean display_children_tree; +extern int stop_indent_level; + +/* Print search results when in wide format. */ +extern boolean search_wide_format; +extern boolean search_is_on; + +const extern char *search_any_text; +const extern char *search_match_text; +const extern char *search_regex_text; +#ifdef HAVE_REGEX +extern regex_t search_re; +#endif +extern boolean is_strstrnocase(const char *data, const char *pattern); + +/* Options to enable debug tracing. */ +#define MAX_TRACE_LEVEL 10 +extern int nTrace[MAX_TRACE_LEVEL + 1]; + +#define DUMP_RANGES_INFO 1 /* Dump RangesInfo Table. */ +#define DUMP_LOCATION_SECTION_INFO 2 /* Dump Location (.debug_loc) Info. */ +#define DUMP_RANGES_SECTION_INFO 3 /* Dump Ranges (.debug_ranges) Info. */ +#define DUMP_LINKONCE_INFO 4 /* Dump Linkonce Table. */ +#define DUMP_VISITED_INFO 5 /* Dump Visited Info. */ + +#define dump_ranges_info nTrace[DUMP_RANGES_INFO] +#define dump_location_section_info nTrace[DUMP_LOCATION_SECTION_INFO] +#define dump_ranges_section_info nTrace[DUMP_RANGES_SECTION_INFO] +#define dump_linkonce_info nTrace[DUMP_LINKONCE_INFO] +#define dump_visited_info nTrace[DUMP_VISITED_INFO] + +/* Section IDs */ +#define DEBUG_ABBREV 1 +#define DEBUG_ARANGES 2 +#define DEBUG_FRAME 3 +#define DEBUG_INFO 4 +#define DEBUG_LINE 5 +#define DEBUG_LOC 6 +#define DEBUG_MACINFO 7 +#define DEBUG_PUBNAMES 8 +#define DEBUG_RANGES 9 +#define DEBUG_STATIC_VARS 10 +#define DEBUG_STATIC_FUNC 11 +#define DEBUG_STR 12 +#define DEBUG_WEAKNAMES 13 +#define DEBUG_TYPES 14 + +extern int verbose; +extern boolean dense; +extern boolean ellipsis; +extern boolean use_mips_regnames; +extern boolean show_global_offsets; +extern boolean show_form_used; +extern boolean display_offsets; + +extern boolean check_pubname_attr; +extern boolean check_attr_tag; +extern boolean check_tag_tree; +extern boolean check_type_offset; +extern boolean check_decl_file; +extern boolean check_lines; +extern boolean check_ranges; /* Ranges (aranges & ranges) check */ +extern boolean check_fdes; +extern boolean check_aranges; +extern boolean check_harmless; +extern boolean check_abbreviations; +extern boolean check_dwarf_constants; +extern boolean check_di_gaps; +extern boolean check_forward_decl; +extern boolean check_self_references; +extern boolean suppress_nested_name_search; +extern boolean suppress_check_extensions_tables; + +extern int break_after_n_units; + +extern boolean check_names; /* Check for invalid names */ +extern boolean check_verbose_mode; /* During '-k' mode, display errors */ +extern boolean check_frames; /* Frames check */ +extern boolean check_frames_extended;/* Extensive frames check */ +extern boolean check_locations; /* Location list check */ + +/* Check categories corresponding to the -k option */ +typedef enum /* Dwarf_Check_Categories */ { + abbrev_code_result, + pubname_attr_result, + reloc_offset_result, + attr_tag_result, + tag_tree_result, + type_offset_result, + decl_file_result, + ranges_result, + lines_result, + aranges_result, + /* Harmless errors are errors detected inside libdwarf but + not reported via DW_DLE_ERROR returns because the errors + won't really affect client code. The 'harmless' errors + are reported and otherwise ignored. It is difficult to report + the error when the error is noticed by libdwarf, the error + is reported at a later time. + The other errors dwarfdump reports are also generally harmless + but are detected by dwarfdump so it's possble to report the + error as soon as the error is discovered. */ + harmless_result, + fde_duplication, + frames_result, + locations_result, + names_result, + abbreviations_result, + dwarf_constants_result, + di_gaps_result, + forward_decl_result, + self_references_result, + total_check_result, + LAST_CATEGORY /* Must be last */ +} Dwarf_Check_Categories; + +extern boolean info_flag; +extern boolean line_flag; +extern boolean use_old_dwarf_loclist; +extern boolean producer_children_flag; /* List of CUs per compiler */ + +extern char cu_name[ ]; +extern boolean cu_name_flag; +extern Dwarf_Unsigned cu_offset; +extern Dwarf_Off fde_offset_for_cu_low; +extern Dwarf_Off fde_offset_for_cu_high; + +/* Process TAGs for checking mode and reset pRangesInfo table + if appropriate. */ +extern void tag_specific_checks_setup(Dwarf_Half val,int die_indent_level); + +extern char *program_name; +extern Dwarf_Error err; +extern void print_error_and_continue (Dwarf_Debug dbg, string msg,int res, Dwarf_Error err); +extern void print_error (Dwarf_Debug dbg, string msg,int res, Dwarf_Error err); + +extern void print_line_numbers_this_cu (Dwarf_Debug dbg, Dwarf_Die in_die); + +struct dwconf_s; +extern void print_frames (Dwarf_Debug dbg, int print_debug_frame, + int print_eh_frame,struct dwconf_s *); +extern void print_ranges (Dwarf_Debug dbg); +extern void print_pubnames (Dwarf_Debug dbg); +extern void print_macinfo (Dwarf_Debug dbg); +extern void print_infos (Dwarf_Debug dbg,Dwarf_Bool is_info); +extern void print_locs (Dwarf_Debug dbg); +extern void print_abbrevs (Dwarf_Debug dbg); +extern void print_strings (Dwarf_Debug dbg); +extern void print_aranges (Dwarf_Debug dbg); +extern void print_relocinfo (Dwarf_Debug dbg,unsigned reloc_map); +extern void print_static_funcs(Dwarf_Debug dbg); +extern void print_static_vars(Dwarf_Debug dbg); +enum type_type_e {SGI_TYPENAME, DWARF_PUBTYPES} ; +extern void print_types(Dwarf_Debug dbg,enum type_type_e type_type); +extern void print_weaknames(Dwarf_Debug dbg); +extern void print_exception_tables(Dwarf_Debug dbg); + +struct esb_s; +extern void print_ranges_list_to_extra(Dwarf_Debug dbg, + Dwarf_Unsigned off, + Dwarf_Ranges *rangeset, + Dwarf_Signed rangecount, + Dwarf_Unsigned bytecount, + struct esb_s *stringbuf); +boolean should_skip_this_cu(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_Error err); + +/* Returns the DW_AT_name of the CU */ +string old_get_cu_name(Dwarf_Debug dbg,Dwarf_Die cu_die,Dwarf_Error err); + +/* Returns the producer of the CU */ +int get_cu_name(Dwarf_Debug dbg,Dwarf_Die cu_die, + Dwarf_Error err,char **short_name,char **long_name); +int get_producer_name(Dwarf_Debug dbg,Dwarf_Die cu_die, + Dwarf_Error err,char **producer_name); + +/* Get number of abbreviations for a CU */ +extern void get_abbrev_array_info(Dwarf_Debug dbg,Dwarf_Unsigned offset); +/* Validate an abbreviation */ +extern void validate_abbrev_code(Dwarf_Debug dbg,Dwarf_Unsigned abbrev_code); + +extern void print_die_and_children( + Dwarf_Debug dbg, + Dwarf_Die in_die, + Dwarf_Bool is_info, + char **srcfiles, + Dwarf_Signed cnt); +extern boolean print_one_die( + Dwarf_Debug dbg, + Dwarf_Die die, + boolean print_information, + int die_indent_level, + char **srcfiles, + Dwarf_Signed cnt, + boolean ignore_die_stack); + +/* Check for specific compiler */ +extern boolean checking_this_compiler(); +extern void update_compiler_target(const char *producer_name); +extern void add_cu_name_compiler_target(char *name); + +/* General error reporting routines. These were + macros for a short time and when changed into functions + they kept (for now) their capitalization. + The capitalization will likely change. */ +extern void PRINT_CU_INFO(); +extern void DWARF_CHECK_COUNT(Dwarf_Check_Categories category, int inc); +extern void DWARF_ERROR_COUNT(Dwarf_Check_Categories category, int inc); +extern void DWARF_CHECK_ERROR_PRINT_CU(); +extern void DWARF_CHECK_ERROR(Dwarf_Check_Categories category, + const char *str); +extern void DWARF_CHECK_ERROR2(Dwarf_Check_Categories category, + const char *str1, const char *str2); +extern void DWARF_CHECK_ERROR3(Dwarf_Check_Categories category, + const char *str1, const char *str2, const char *strexpl); + +struct esb_s; + +extern Dwarf_Die current_cu_die_for_print_frames; /* This is + an awful hack, making current_cu_die_for_print_frames public. + But it enables cleaning up (doing all dealloc needed). */ + +extern void printreg(Dwarf_Signed reg,struct dwconf_s *config_data); +extern void print_frame_inst_bytes(Dwarf_Debug dbg, + Dwarf_Ptr cie_init_inst, Dwarf_Signed len, + Dwarf_Signed data_alignment_factor, + int code_alignment_factor, Dwarf_Half addr_size, + struct dwconf_s *config_data); + +int +get_proc_name(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr low_pc, + char *proc_name_buf, int proc_name_buf_len, void **pcMap); + +void get_attr_value(Dwarf_Debug dbg, Dwarf_Half tag, + Dwarf_Die die, + Dwarf_Attribute attrib, + char **srcfiles, + Dwarf_Signed cnt, struct esb_s *esbp, + int show_form,int local_verbose); + + +extern Dwarf_Unsigned local_dwarf_decode_u_leb128(unsigned char *leb128, + unsigned int *leb128_length); + +extern Dwarf_Signed local_dwarf_decode_s_leb128(unsigned char *leb128, + unsigned int *leb128_length); + +extern void dump_block(char *prefix, char *data, Dwarf_Signed len); + +extern void format_sig8_string(Dwarf_Sig8 *data,struct esb_s *out); + +int +dwarfdump_print_one_locdesc(Dwarf_Debug dbg, + Dwarf_Locdesc * llbuf, + int skip_locdesc_header, + struct esb_s *string_out); +void clean_up_die_esb(); +void clean_up_syms_malloc_data(); +void safe_strcpy(char *out, long outlen, const char *in, long inlen); + + +void print_any_harmless_errors(Dwarf_Debug dbg); + +/* Definitions for printing relocations. */ +#define DW_SECTION_REL_DEBUG_INFO 0 +#define DW_SECTION_REL_DEBUG_LINE 1 +#define DW_SECTION_REL_DEBUG_PUBNAMES 2 +#define DW_SECTION_REL_DEBUG_ABBREV 3 +#define DW_SECTION_REL_DEBUG_ARANGES 4 +#define DW_SECTION_REL_DEBUG_FRAME 5 +#define DW_SECTION_REL_DEBUG_LOC 6 +#define DW_SECTION_REL_DEBUG_RANGES 7 +#define DW_SECTION_REL_DEBUG_TYPES 8 + +#endif /* globals_INCLUDED */ diff --git a/dwarfdump/install.sh b/dwarfdump/install.sh new file mode 100755 index 0000000..0ff4b6a --- /dev/null +++ b/dwarfdump/install.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/dwarfdump/makename.c b/dwarfdump/makename.c new file mode 100644 index 0000000..e97e1d0 --- /dev/null +++ b/dwarfdump/makename.c @@ -0,0 +1,68 @@ + +/* + Copyright (C) 2000,2004 Silicon Graphics, 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 + + makename.c + $Revision: 1.4 $ + $Date: 2005/11/08 21:48:42 $ + + This used to be elaborate stuff. + Now it is trivial, as duplicating names is + unimportant in dwarfdump (in general). + + And in fact, this is only called for attributes and + tags etc whose true name is unknown. Not for + any normal case. + +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "makename.h" + +char * +makename(const char *s) +{ + char *newstr; + + if (!s) { + return ""; + } + + newstr = strdup(s); + if (newstr == 0) { + fprintf(stderr, "Out of memory mallocing %d bytes\n", + (int) strlen(s)); + exit(1); + } + return newstr; +} diff --git a/dwarfdump/makename.h b/dwarfdump/makename.h new file mode 100644 index 0000000..da1f798 --- /dev/null +++ b/dwarfdump/makename.h @@ -0,0 +1,53 @@ +#ifndef names_h +#define names_h +/* + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 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 +*/ + +/* makename.h + $Revision: 1.3 $ + $Date: 2004/10/28 22:26:58 $ + + This is for putting strings into stable storage. + + Effectively an strdup() wrapper. + + Rarely called. + + It leaks memory, (the memory + is never freed) but that seems unimportant since + use of this is very rare. +*/ + +char * makename(const char *); /* Makes a copy of the string in + a malloc area. Can never return 0. */ +#endif diff --git a/dwarfdump/naming.c b/dwarfdump/naming.c new file mode 100644 index 0000000..115fd09 --- /dev/null +++ b/dwarfdump/naming.c @@ -0,0 +1,261 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2011 SN Systems Ltd. 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 + +*/ + +/* 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. +*/ + + + +/* naming.c */ +#include "globals.h" +#include "dwarf.h" +#include "libdwarf.h" +#include "makename.h" + +static const char * +skipunder(const char *v) +{ + const char *cp = v; + int undercount = 0; + for( ; *cp ; ++cp) { + if( *cp == '_') { + ++undercount; + if(undercount == 2) { + return cp+1; + } + } + } + return ""; +} + +static const char * +ellipname(int res, int val_in, const char *v,const char *ty,int printonerr) +{ +#ifndef TRIVIAL_NAMING + if (check_dwarf_constants && checking_this_compiler()) { + DWARF_CHECK_COUNT(dwarf_constants_result,1); + } +#endif + if(res != DW_DLV_OK) { + char buf[100]; + char *n; + snprintf(buf,sizeof(buf),"<Unknown %s value 0x%x>",ty,val_in); + /* Capture any name error in DWARF constants */ +#ifndef TRIVIAL_NAMING + if(printonerr && check_dwarf_constants && checking_this_compiler()) { + if (check_verbose_mode) { + fprintf(stderr,"%s of %d (0x%x) is unknown to dwarfdump. " + "Continuing. \n",ty,val_in,val_in ); + } + DWARF_ERROR_COUNT(dwarf_constants_result,1); + DWARF_CHECK_ERROR_PRINT_CU(); + } +#else + /* This is for the tree-generation, not dwarfdump itself. */ + if(printonerr) { + fprintf(stderr,"%s of %d (0x%x) is unknown to dwarfdump. " + "Continuing. \n",ty,val_in,val_in ); + } +#endif + n = makename(buf); + return n; + } + if(ellipsis) { + return skipunder(v); + } + return v; +} + +const char * get_TAG_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_TAG_name(val_in,&v); + return ellipname(res,val_in,v,"TAG",printonerr); +} +const char * get_children_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_children_name(val_in,&v); + return ellipname(res,val_in,v,"children",printonerr); +} +const char * get_FORM_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_FORM_name(val_in,&v); + return ellipname(res,val_in,v,"FORM",printonerr); +} +const char * get_AT_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_AT_name(val_in,&v); + return ellipname(res,val_in,v,"AT",printonerr); +} +const char * get_OP_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_OP_name(val_in,&v); + return ellipname(res,val_in,v,"OP",printonerr); +} +const char * get_ATE_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_ATE_name(val_in,&v); + return ellipname(res,val_in,v,"ATE",printonerr); +} +const char * get_DS_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_DS_name(val_in,&v); + return ellipname(res,val_in,v,"DS",printonerr); +} +const char * get_END_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_END_name(val_in,&v); + return ellipname(res,val_in,v,"END",printonerr); +} +const char * get_ATCF_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_ATCF_name(val_in,&v); + return ellipname(res,val_in,v,"ATCF",printonerr); +} +const char * get_ACCESS_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_ACCESS_name(val_in,&v); + return ellipname(res,val_in,v,"ACCESS",printonerr); +} +const char * get_VIS_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_VIS_name(val_in,&v); + return ellipname(res,val_in,v,"VIS",printonerr); +} +const char * get_VIRTUALITY_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_VIRTUALITY_name(val_in,&v); + return ellipname(res,val_in,v,"VIRTUALITY",printonerr); +} +const char * get_LANG_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_LANG_name(val_in,&v); + return ellipname(res,val_in,v,"LANG",printonerr); +} +const char * get_ID_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_ID_name(val_in,&v); + return ellipname(res,val_in,v,"ID",printonerr); +} +const char * get_CC_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_CC_name(val_in,&v); + return ellipname(res,val_in,v,"CC",printonerr); +} +const char * get_INL_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_INL_name(val_in,&v); + return ellipname(res,val_in,v,"INL",printonerr); +} +const char * get_ORD_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_ORD_name(val_in,&v); + return ellipname(res,val_in,v,"ORD",printonerr); +} +const char * get_DSC_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_DSC_name(val_in,&v); + return ellipname(res,val_in,v,"DSC",printonerr); +} +const char * get_LNS_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_LNS_name(val_in,&v); + return ellipname(res,val_in,v,"LNS",printonerr); +} +const char * get_LNE_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_LNE_name(val_in,&v); + return ellipname(res,val_in,v,"LNE",printonerr); +} +const char * get_MACINFO_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_MACINFO_name(val_in,&v); + return ellipname(res,val_in,v,"MACINFO",printonerr); +} +const char * get_CFA_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_CFA_name(val_in,&v); + return ellipname(res,val_in,v,"CFA",printonerr); +} +const char * get_EH_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_EH_name(val_in,&v); + return ellipname(res,val_in,v,"EH",printonerr); +} +const char * get_FRAME_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_FRAME_name(val_in,&v); + return ellipname(res,val_in,v,"FRAME",printonerr); +} +const char * get_CHILDREN_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_CHILDREN_name(val_in,&v); + return ellipname(res,val_in,v,"CHILDREN",printonerr); +} +const char * get_ADDR_name(unsigned int val_in,int printonerr) +{ + const char *v = 0; + int res = dwarf_get_ADDR_name(val_in,&v); + return ellipname(res,val_in,v,"ADDR",printonerr); +} + + diff --git a/dwarfdump/naming.h b/dwarfdump/naming.h new file mode 100644 index 0000000..89a1594 --- /dev/null +++ b/dwarfdump/naming.h @@ -0,0 +1,73 @@ + +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 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 + +*/ + +/* 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. +*/ + + +/* naming.h */ + +extern const char * get_TAG_name(unsigned int val_in,int printonerr); +extern const char * get_children_name(unsigned int val_in,int printonerr); +extern const char * get_FORM_name(unsigned int val_in,int printonerr); +extern const char * get_AT_name(unsigned int val_in,int printonerr); +extern const char * get_OP_name(unsigned int val_in,int printonerr); +extern const char * get_ATE_name(unsigned int val_in,int printonerr); +extern const char * get_DS_name(unsigned int val_in,int printonerr); +extern const char * get_END_name(unsigned int val_in,int printonerr); +extern const char * get_ATCF_name(unsigned int val_in,int printonerr); +extern const char * get_ACCESS_name(unsigned int val_in,int printonerr); +extern const char * get_VIS_name(unsigned int val_in,int printonerr); +extern const char * get_VIRTUALITY_name(unsigned int val_in,int printonerr); +extern const char * get_LANG_name(unsigned int val_in,int printonerr); +extern const char * get_ID_name(unsigned int val_in,int printonerr); +extern const char * get_CC_name(unsigned int val_in,int printonerr); +extern const char * get_INL_name(unsigned int val_in,int printonerr); +extern const char * get_ORD_name(unsigned int val_in,int printonerr); +extern const char * get_DSC_name(unsigned int val_in,int printonerr); +extern const char * get_LNS_name(unsigned int val_in,int printonerr); +extern const char * get_LNE_name(unsigned int val_in,int printonerr); +extern const char * get_MACINFO_name(unsigned int val_in,int printonerr); +extern const char * get_CFA_name(unsigned int val_in,int printonerr); +extern const char * get_EH_name(unsigned int val_in,int printonerr); +extern const char * get_FRAME_name(unsigned int val_in,int printonerr); +extern const char * get_CHILDREN_name(unsigned int val_in,int printonerr); +extern const char * get_ADDR_name(unsigned int val_in,int printonerr); + + diff --git a/dwarfdump/print_abbrevs.c b/dwarfdump/print_abbrevs.c new file mode 100644 index 0000000..76a08f5 --- /dev/null +++ b/dwarfdump/print_abbrevs.c @@ -0,0 +1,304 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" + + +/* The following relevent for one specific Linker. */ +#define SNLINKER_MAX_ATTRIB_COUNT 16 + +/* Print data in .debug_abbrev + This is inherently unsafe as it assumes there + are no byte sequences in .debug_abbrev other than + legal abbrev sequences. But the Dwarf spec + does not promise that. The spec only promises + that any bytes at an offset referred to from + .debug_info are legal sequences. +*/ +extern void +print_abbrevs(Dwarf_Debug dbg) +{ + Dwarf_Abbrev ab; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned abbrev_entry_count = 0; + /* Maximum defined tag is 0xffff, DW_TAG_hi_user. */ + Dwarf_Half tag = 0; + Dwarf_Half attr = 0; + Dwarf_Signed form = 0; + Dwarf_Off off = 0; + Dwarf_Unsigned i = 0; + const char * child_name = 0; + Dwarf_Unsigned abbrev_num = 1; + Dwarf_Signed child_flag = 0; + int abres = 0; + int tres = 0; + int acres = 0; + Dwarf_Unsigned abbrev_code = 0; + + current_section_id = DEBUG_ABBREV; + + if (do_print_dwarf) { + printf("\n.debug_abbrev\n"); + } + while ((abres = dwarf_get_abbrev(dbg, offset, &ab, + &length, &abbrev_entry_count, + &err)) == DW_DLV_OK) { + + if (abbrev_entry_count == 0) { + /* Simple innocuous zero : null abbrev entry */ + if (dense) { + printf("<%" DW_PR_DUu "><0x%" DW_PR_XZEROS DW_PR_DUx "><%" + DW_PR_DSd "><%s>\n", + abbrev_num, + offset, + (Dwarf_Signed) /* abbrev_code */ 0, + "null .debug_abbrev entry"); + } else { + printf("<%5" DW_PR_DUu "><0x%" DW_PR_XZEROS DW_PR_DUx + "><code: %3" DW_PR_DSd "> %-20s\n", + abbrev_num, + offset, + (Dwarf_Signed) /* abbrev_code */ 0, + "null .debug_abbrev entry"); + } + + offset += length; + ++abbrev_num; + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + continue; + } + tres = dwarf_get_abbrev_tag(ab, &tag, &err); + if (tres != DW_DLV_OK) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_tag", tres, err); + } + tres = dwarf_get_abbrev_code(ab, &abbrev_code, &err); + if (tres != DW_DLV_OK) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_code", tres, err); + } + if (dense) { + printf("<%" DW_PR_DUu "><0x%" DW_PR_XZEROS DW_PR_DUx + "><%" DW_PR_DSd "><%s>", + abbrev_num, + offset, abbrev_code, + get_TAG_name(tag,dwarf_names_print_on_error)); + } + else { + printf("<%5" DW_PR_DUu "><0x%" DW_PR_XZEROS DW_PR_DUx "><code: %3" + DW_PR_DSd "> %-20s", + abbrev_num, + offset, abbrev_code, + get_TAG_name(tag,dwarf_names_print_on_error)); + } + /* Process specific TAGs specially. */ + tag_specific_checks_setup(tag,0); + ++abbrev_num; + acres = dwarf_get_abbrev_children_flag(ab, &child_flag, &err); + if (acres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_children_flag", acres, + err); + } + if (acres == DW_DLV_NO_ENTRY) { + child_flag = 0; + } + child_name = get_children_name(child_flag, + dwarf_names_print_on_error); + if (dense) + printf(" %s", child_name); + else + printf(" %s\n", child_name); + /* Abbrev just contains the format of a die, which debug_info + then points to with the real data. So here we just print the + given format. */ + for (i = 0; i < abbrev_entry_count; i++) { + int aeres = 0; + + aeres = + dwarf_get_abbrev_entry(ab, i, &attr, &form, &off, &err); + if (aeres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_entry", aeres, err); + } + if (aeres == DW_DLV_NO_ENTRY) { + attr = -1LL; + form = -1LL; + } + if (dense) { + printf(" <%ld>%s<%s>", (unsigned long) off, + get_AT_name(attr,dwarf_names_print_on_error), + get_FORM_name((Dwarf_Half) form, + dwarf_names_print_on_error)); + } else { + printf(" <0x%08lx> %-28s%s\n", + (unsigned long) off, + get_AT_name(attr, + dwarf_names_print_on_error), + get_FORM_name((Dwarf_Half) form, + dwarf_names_print_on_error)); + } + } + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + offset += length; + if (dense) { + printf("\n"); + } + } + if (abres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_abbrev", abres, err); + } +} + +/* Number of abbreviations for current CU */ +static Dwarf_Unsigned CU_abbrev_count = 0; + +/* Abbreviations array info for checking abbrev tags. + The [zero] entry is not used. + We never shrink the array, but it never grows beyond + the largest abbreviation count of all the CUs. +*/ + +static Dwarf_Signed *abbrev_array = NULL; +/* Size of the array, the same as the abbrev tag + count of the CU with the most of them. */ +static Dwarf_Unsigned abbrev_array_size = 0; +#define ABBREV_ARRAY_INITIAL_SIZE 64 + +/* Calculate the number of abbreviations for the + current CU and set up a basic abbreviations array info, + storing the number of attributes per abbreviation. +*/ +void +get_abbrev_array_info(Dwarf_Debug dbg, Dwarf_Unsigned offset_in) +{ + Dwarf_Unsigned offset = offset_in; + if (check_abbreviations) { + Dwarf_Abbrev ab; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned abbrev_entry_count = 0; + Dwarf_Unsigned abbrev_code; + int abres = DW_DLV_OK; + Dwarf_Error err; + + Dwarf_Bool bMore = TRUE; + CU_abbrev_count = 0; + + if (abbrev_array == NULL) { + /* Allocate initial abbreviation array info */ + abbrev_array = (Dwarf_Signed *) + calloc(ABBREV_ARRAY_INITIAL_SIZE+1,sizeof(Dwarf_Signed)); + abbrev_array_size = ABBREV_ARRAY_INITIAL_SIZE; + } else { + /* Clear out values from previous CU */ + memset((void *)abbrev_array,0, + (abbrev_array_size+1) * sizeof(Dwarf_Signed)); + } + + while (bMore && (abres = dwarf_get_abbrev(dbg, offset, &ab, + &length, &abbrev_entry_count, + &err)) == DW_DLV_OK) { + dwarf_get_abbrev_code(ab,&abbrev_code,&err); + if (abbrev_code == 0) { + /* End of abbreviation table for this CU */ + ++offset; /* Skip abbreviation code */ + bMore = FALSE; + } else { + /* Valid abbreviation code */ + if (abbrev_code > 0) { + if (abbrev_code > abbrev_array_size) { + /* Resize abbreviation array */ + abbrev_array_size *= 2; + abbrev_array = (Dwarf_Signed *) + realloc(abbrev_array, + (abbrev_array_size+1) * sizeof(Dwarf_Signed)); + } + abbrev_array[abbrev_code] = abbrev_entry_count; + ++CU_abbrev_count; + offset += length; + } else { + /* Invalid abbreviation code */ + print_error(dbg, "get_abbrev_array_info", abres, err); + } + } + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + } + } +} + +/* Validate an abbreviation for the current CU. */ +void +validate_abbrev_code(Dwarf_Debug dbg,Dwarf_Unsigned abbrev_code) +{ + char buf[128]; + + DWARF_CHECK_COUNT(abbreviations_result,1); + if (abbrev_code < 0 || (abbrev_code && abbrev_code > CU_abbrev_count)) { + snprintf(buf, sizeof(buf), + "Abbrev code %" DW_PR_DUu + " outside valid range of [0-%" DW_PR_DUu "]", + abbrev_code,CU_abbrev_count); + DWARF_CHECK_ERROR2(abbreviations_result,buf, + "Invalid abbreviation code."); + } else { + Dwarf_Signed abbrev_entry_count = + abbrev_array[abbrev_code]; + if (abbrev_entry_count < 0 || + abbrev_entry_count > SNLINKER_MAX_ATTRIB_COUNT) { + snprintf(buf, sizeof(buf), + "Abbrev code %" DW_PR_DUu + ", with %" DW_PR_DUu " attributes: " + "outside valid range.", + abbrev_code, + abbrev_entry_count); + DWARF_CHECK_ERROR2(abbreviations_result,buf, + "Invalid number of attributes."); + } + } +} diff --git a/dwarfdump/print_aranges.c b/dwarfdump/print_aranges.c new file mode 100644 index 0000000..f3e076c --- /dev/null +++ b/dwarfdump/print_aranges.c @@ -0,0 +1,267 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" + + +static void +do_checking(Dwarf_Debug dbg, Dwarf_Arange *arange_buf,Dwarf_Signed i, + Dwarf_Off cu_die_offset,Dwarf_Bool first_cu, + Dwarf_Off cu_die_offset_prev, Dwarf_Die cu_die ) +{ + int dres = 0; + Dwarf_Off cuhdroff = 0; + Dwarf_Off cudieoff3 = 0; + dres = dwarf_get_arange_cu_header_offset( + arange_buf[i],&cuhdroff,&err); + if(dres == DW_DLV_OK) { + Dwarf_Off cudieoff2 = 0; + + /* Get the CU offset for easy error reporting */ + if (first_cu || cu_die_offset != cu_die_offset_prev) { + cu_die_offset_prev = cu_die_offset; + dres = dwarf_die_offsets(cu_die,&DIE_overall_offset,&DIE_offset,&err); + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_die_offsets", dres, err); + } + } + dres = dwarf_get_cu_die_offset_given_cu_header_offset( + dbg,cuhdroff,&cudieoff2,&err); + if(dres == DW_DLV_OK) { + /* Get the CU offset for easy error reporting */ + dwarf_die_offsets(cu_die,&DIE_overall_offset,&DIE_offset,&err); + DWARF_CHECK_COUNT(aranges_result,1); + if(cudieoff2 != cu_die_offset) { + printf("Error, cu_die offsets mismatch, 0x%" + DW_PR_DUx + " != 0x%" DW_PR_DUx " from arange data", + cu_die_offset,cudieoff2); + DWARF_CHECK_ERROR(aranges_result, + " dwarf_get_cu_die_offset_given_cu..." + " gets wrong offset"); + } + } else { + print_error(dbg, "dwarf_get_cu_die_offset_given...", dres, err); + } + } else { + print_error(dbg, "dwarf_get_arange_cu_header_offset", dres, err); + } + dres = dwarf_get_cu_die_offset(arange_buf[i],&cudieoff3, + &err); + if(dres == DW_DLV_OK) { + DWARF_CHECK_COUNT(aranges_result,1); + if(cudieoff3 != cu_die_offset) { + printf( + "Error, cu_die offsets (b) mismatch , 0x%" + DW_PR_DUx + " != 0x%" DW_PR_DUx " from arange data", + cu_die_offset,cudieoff3); + DWARF_CHECK_ERROR(aranges_result, + " dwarf_get_cu_die_offset " + " gets wrong offset"); + } + } else { + print_error(dbg, "dwarf_get_cu_die_offset failed ", + dres,err); + } +} + +/* get all the data in .debug_aranges */ +extern void +print_aranges(Dwarf_Debug dbg) +{ + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Arange *arange_buf = NULL; + int ares = 0; + int aires = 0; + Dwarf_Off prev_off = 0; /* Holds previous CU offset */ + Dwarf_Bool first_cu = TRUE; + Dwarf_Off cu_die_offset_prev = 0; + + /* Reset the global state, so we can traverse the debug_info */ + seen_CU = FALSE; + need_CU_name = TRUE; + need_CU_base_address = TRUE; + need_CU_high_address = TRUE; + + current_section_id = DEBUG_ARANGES; + if (do_print_dwarf) { + printf("\n.debug_aranges\n"); + } + ares = dwarf_get_aranges(dbg, &arange_buf, &count, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_aranges", ares, err); + } else if (ares == DW_DLV_NO_ENTRY) { + /* no arange is included */ + } else { + for (i = 0; i < count; i++) { + Dwarf_Unsigned segment = 0; + Dwarf_Unsigned segment_entry_size = 0; + Dwarf_Addr start = 0; + Dwarf_Unsigned length = 0; + Dwarf_Off cu_die_offset = 0; + Dwarf_Die cu_die = NULL; + aires = dwarf_get_arange_info_b(arange_buf[i], + &segment, + &segment_entry_size, + &start, &length, + &cu_die_offset, &err); + if (aires != DW_DLV_OK) { + print_error(dbg, "dwarf_get_arange_info", aires, err); + } else { + int dres; + char *producer_name = 0; + + /* Get basic locations for error reporting */ + dres = dwarf_offdie(dbg, cu_die_offset, &cu_die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_offdie", dres, err); + } + + if (cu_name_flag) { + if(should_skip_this_cu(dbg,cu_die,err)) { + continue; + } + } + /* Get producer name for this CU and update compiler list */ + get_producer_name(dbg,cu_die,err,&producer_name); + update_compiler_target(producer_name); + if (!checking_this_compiler()) { + continue; + } + + if (check_aranges) { + do_checking(dbg,arange_buf,i,cu_die_offset,first_cu, + cu_die_offset_prev,cu_die); + } + /* Get the offset of the cu header itself in the + section, but not for end-entries. */ + if(start || length) { + Dwarf_Off off = 0; + int cures3 = dwarf_get_arange_cu_header_offset( + arange_buf[i], &off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_get_cu_hdr_offset", + cures3, err); + } + + /* Print the CU information if different. */ + if (prev_off != off || first_cu) { + first_cu = FALSE; + prev_off = off; + /* We are faking the indent level. We do not know + what level it is, really. + + If do_check_dwarf we do not want to do + the die print call as it will do + check/print we may not have asked for. + And if we did ask for debug_info checks + this will do the checks a second time! + So only call print_one_die if printing. + */ + if(do_print_dwarf){ + /* There is no die if its a set-end entry */ + print_one_die(dbg, cu_die, + /* print_information= */ (boolean) TRUE, + /* indent_level = */0, + /* srcfiles= */ 0, + /* cnt= */ 0, + /* ignore_die_stack= */TRUE); + } + /* Reset the state, so we can traverse the debug_info */ + seen_CU = FALSE; + need_CU_name = TRUE; + if (do_print_dwarf) { + printf("\n"); + } + } + + if (do_print_dwarf) { + /* Print current aranges record */ + if(segment_entry_size) { + printf( + "\narange starts at seg,off 0x%" + DW_PR_XZEROS DW_PR_DUx + ",0x%" DW_PR_XZEROS DW_PR_DUx + ", ", + segment, + (Dwarf_Unsigned)start); + } else { + printf("\narange starts at 0x%" + DW_PR_XZEROS DW_PR_DUx ", ", + (Dwarf_Unsigned)start); + } + printf("length of 0x%" DW_PR_XZEROS DW_PR_DUx + ", cu_die_offset = 0x%" DW_PR_XZEROS DW_PR_DUx, + length, + (Dwarf_Unsigned)cu_die_offset); + + } + if (verbose && do_print_dwarf) { + printf(" cuhdr 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Unsigned)off); + } + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + cu_die = 0; + } else { + /* Must be a range end. We really do want to print + this as there is a real record here, an + 'arange end' record. */ + if (do_print_dwarf) { + printf("\narange end"); + } + }/* end start||length test */ + } /* end aires DW_DLV_OK test */ + + /* print associated die too? */ + dwarf_dealloc(dbg, arange_buf[i], DW_DLA_ARANGE); + } + dwarf_dealloc(dbg, arange_buf, DW_DLA_LIST); + } +} diff --git a/dwarfdump/print_die.c b/dwarfdump/print_die.c new file mode 100644 index 0000000..5951385 --- /dev/null +++ b/dwarfdump/print_die.c @@ -0,0 +1,3540 @@ +/* + + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2007-2011 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 "esb.h" /* For flexible string buffer. */ +#include "makename.h" /* Non-duplicating string table. */ +#include "print_frames.h" /* for get_string_from_locs() . */ +#include "tag_common.h" + +/* Traverse a DIE and attributes to check self references */ +static boolean traverse_one_die(Dwarf_Debug dbg, Dwarf_Attribute attrib, + Dwarf_Die die, char **srcfiles, + Dwarf_Signed cnt, int die_indent_level); +static boolean traverse_attribute(Dwarf_Debug dbg, Dwarf_Die die, + Dwarf_Half attr, Dwarf_Attribute attr_in, + boolean print_information, + char **srcfiles, Dwarf_Signed cnt, + int die_indent_level); +static void print_die_and_children_internal(Dwarf_Debug dbg, + Dwarf_Die in_die_in, + Dwarf_Bool is_info, + char **srcfiles, Dwarf_Signed cnt); +static int print_one_die_section(Dwarf_Debug dbg,Dwarf_Bool is_info); + +/* Is this a PU has been invalidated by the SN Systems linker? */ +#define IsInvalidCode(low,high) ((low == 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(int show_form,int verbose, + int theform, int directform, struct esb_s * str_out); +static void print_exprloc_content(Dwarf_Debug dbg,Dwarf_Die die, Dwarf_Attribute attrib, + int showhextoo, struct esb_s *esbp); +static boolean print_attribute(Dwarf_Debug dbg, Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Attribute actual_addr, + boolean print_information, + int die_indent_level, char **srcfiles, + Dwarf_Signed cnt); +static void get_location_list(Dwarf_Debug dbg, Dwarf_Die die, + Dwarf_Attribute attr, struct esb_s *esbp); +static int legal_tag_attr_combination(Dwarf_Half tag, Dwarf_Half attr); +static int 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, struct esb_s *string_out); +static int formxdata_print_value(Dwarf_Debug dbg,Dwarf_Attribute attrib, + struct esb_s *esbp, Dwarf_Error * err, Dwarf_Bool hex_format); + +/* esb_base is static so gets initialized to zeros. + It is not thread-safe or + safe for multiple open producer instances for + but that does not matter here in dwarfdump. + + The memory used by esb_base and esb_extra is never freed. +*/ +static struct esb_s esb_base; +static struct esb_s esb_extra; + +static int dwarf_names_print_on_error = 1; + +static int die_stack_indent_level = 0; +static boolean local_symbols_already_began = FALSE; + +typedef const char *(*encoding_type_func) (unsigned,int 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 Dwarf_Bool bSawLow = FALSE; +static Dwarf_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; + const char * 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,""} +}; + +struct die_stack_data_s { + Dwarf_Die die_; + boolean already_printed_; +}; +struct die_stack_data_s empty_stack_entry; + +#define DIE_STACK_SIZE 800 +static struct die_stack_data_s die_stack[DIE_STACK_SIZE]; + +#define SET_DIE_STACK_ENTRY(i,x) { die_stack[i].die_ = x; \ + die_stack[die_stack_indent_level].already_printed_ = FALSE; } +#define EMPTY_DIE_STACK_ENTRY(i) { die_stack[i] = empty_stack_entry; } + +static int +print_as_info_or_cu() +{ + return (info_flag || cu_name_flag); +} + + +/* process each compilation unit in .debug_info */ +void +print_infos(Dwarf_Debug dbg,Dwarf_Bool is_info) +{ + int nres = 0; + if(is_info) { + nres = print_one_die_section(dbg,TRUE); + if (nres == DW_DLV_ERROR) { + char * errmsg = dwarf_errmsg(err); + Dwarf_Unsigned myerr = dwarf_errno(err); + + fprintf(stderr, "%s ERROR: %s: %s (%lu)\n", + program_name, "attempting to print .debug_info", + errmsg, (unsigned long) myerr); + fprintf(stderr, "attempting to continue.\n"); + } + return; + } + nres = print_one_die_section(dbg,FALSE); + if (nres == DW_DLV_ERROR) { + char * errmsg = dwarf_errmsg(err); + Dwarf_Unsigned myerr = dwarf_errno(err); + + fprintf(stderr, "%s ERROR: %s: %s (%lu)\n", + program_name, "attempting to print .debug_types", + errmsg, (unsigned long) myerr); + fprintf(stderr, "attempting to continue.\n"); + } +} +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) { + printf(" %s<0x%" DW_PR_XZEROS DW_PR_DUx + ">", "cu_header_length", + cu_header_length); + printf(" %s<0x%04x>", "version_stamp", + version_stamp); + printf(" %s<0x%" DW_PR_XZEROS DW_PR_DUx + ">", "abbrev_offset", abbrev_offset); + printf(" %s<0x%02x>", "address_size", + address_size); + } else { + printf(" %-16s = 0x%" DW_PR_XZEROS DW_PR_DUx + " %" DW_PR_DUu + "\n", "cu_header_length", + cu_header_length, + cu_header_length); + printf(" %-16s = 0x%04x %u\n", "version_stamp", + version_stamp,version_stamp); + printf(" %-16s = 0x%" DW_PR_XZEROS DW_PR_DUx + " %" DW_PR_DUu + "\n", "abbrev_offset", + abbrev_offset, + abbrev_offset); + printf(" %-16s = 0x%02x %u\n", "address_size", + address_size,address_size); + } +} +static void +print_std_cu_signature(Dwarf_Sig8 *signature,Dwarf_Unsigned typeoffset) +{ + if(dense) { + struct esb_s sig8str; + esb_constructor(&sig8str); + format_sig8_string(signature,&sig8str); + printf(" %s<%s>", "signature",esb_get_string(&sig8str)); + printf(" %s<0x%" DW_PR_XZEROS DW_PR_DUx ">", + "typeoffset", typeoffset); + esb_destructor(&sig8str); + } else { + struct esb_s sig8str; + esb_constructor(&sig8str); + format_sig8_string(signature,&sig8str); + printf(" %-16s = %s\n", "signature",esb_get_string(&sig8str)); + printf(" %-16s = 0x%" DW_PR_XZEROS DW_PR_DUx " %" DW_PR_DUu "\n", + "typeoffset", + typeoffset,typeoffset); + esb_destructor(&sig8str); + } +} + +static int +print_one_die_section(Dwarf_Debug dbg,Dwarf_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; + unsigned loop_count = 0; + int nres = DW_DLV_OK; + int cu_count = 0; + char * cu_short_name = NULL; + char * cu_long_name = NULL; + char * producer_name = NULL; + + current_section_id = DEBUG_INFO; + + if (print_as_info_or_cu() && do_print_dwarf) { + if(is_info) { + printf("\n.debug_info\n"); + } + } + + /* Loop until it fails. */ + for(;;++loop_count) { + int sres = DW_DLV_OK; + Dwarf_Die cu_die = 0; + + 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 && + print_as_info_or_cu() && do_print_dwarf) { + printf("\n.debug_types\n"); + } + if (nres != DW_DLV_OK) { + return nres; + } + if(cu_count >= break_after_n_units) { + printf("Break at %d\n",cu_count); + break; + } + /* Regardless of any options used, get basic + information about the current CU: producer, name */ + 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,&DIE_overall_offset,&DIE_offset,&err); + + if (cu_name_flag) { + if(should_skip_this_cu(dbg,cu_die,err)) { + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + cu_die = 0; + ++cu_count; + cu_offset = next_cu_offset; + continue; + } + } + + /* Get producer name for this CU and update compiler list */ + get_producer_name(dbg,cu_die,err,&producer_name); + update_compiler_target(producer_name); + + /* Once the compiler table has been updated, see + if we need to generate the list of CU compiled + by all the producers contained in the elf file */ + if (producer_children_flag) { + get_cu_name(dbg,cu_die,err,&cu_short_name,&cu_long_name); + /* Add CU name to current compiler entry */ + add_cu_name_compiler_target(cu_long_name); + } + + /* If the current compiler is not requested by the + user, then move to the next CU */ + if (!checking_this_compiler()) { + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + ++cu_count; + cu_offset = next_cu_offset; + cu_die = 0; + continue; + } + + /* We have not seen the compile unit yet, reset these + error-reporting globals. */ + seen_CU = FALSE; + need_CU_name = TRUE; + need_CU_base_address = TRUE; + need_CU_high_address = TRUE; + seen_PU_base_address = FALSE; + seen_PU_high_address = FALSE; + + /* Release the 'cu_die' created by the call + to 'dwarf_siblingof' at the top of the main loop. */ + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + cu_die = 0; /* For debugging, stale die should be NULL. */ + + if (info_flag && do_print_dwarf) { + if(verbose) { + if (dense) { + printf("<%s>", "cu_header"); + } else { + printf("\nCU_HEADER:\n"); + } + print_std_cu_hdr(cu_header_length,abbrev_offset, + version_stamp,address_size); + if(!is_info) { + print_std_cu_signature(&signature,typeoffset); + } + if(dense) { + printf("\n"); + } + } else { + if(!is_info) { + if(dense) { + printf("<%s>", "cu_header"); + } else { + printf("\nCU_HEADER:\n"); + } + print_std_cu_signature(&signature,typeoffset); + if(dense) { + printf("\n"); + } + } + } + } + + /* Get abbreviation info for this CU */ + get_abbrev_array_info(dbg,abbrev_offset); + + /* process a single compilation unit in .debug_info. */ + sres = dwarf_siblingof_b(dbg, NULL,is_info, &cu_die, &err); + if (sres == DW_DLV_OK) { + if (print_as_info_or_cu() || search_is_on) { + Dwarf_Signed cnt = 0; + char **srcfiles = 0; + int srcf = dwarf_srcfiles(cu_die, + &srcfiles, &cnt, &err); + if (srcf != DW_DLV_OK) { + srcfiles = 0; + cnt = 0; + } + + /* Get the CU offset for easy error reporting */ + dwarf_die_offsets(cu_die,&DIE_CU_overall_offset, + &DIE_CU_offset,&err); + print_die_and_children(dbg, cu_die,is_info, srcfiles, cnt); + if (srcf == DW_DLV_OK) { + int si = 0; + for (si = 0; si < cnt; ++si) { + dwarf_dealloc(dbg, srcfiles[si], DW_DLA_STRING); + } + dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST); + } + } + + /* Dump Ranges Information */ + if (dump_ranges_info) { + PrintBucketGroup(pRangesInfo,TRUE); + } + + /* Traverse the line section if in check mode */ + if (line_flag || check_decl_file) { + print_line_numbers_this_cu(dbg, cu_die); + } + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + cu_die = 0; + } 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,char **srcfiles,Dwarf_Signed cnt,int lev) +{ + boolean print_information = TRUE; + boolean ignore_die_stack = FALSE; + print_one_die(dbg,die_stack[lev].die_,print_information,lev,srcfiles,cnt, + ignore_die_stack); +} +extern void +print_die_and_children(Dwarf_Debug dbg, + Dwarf_Die in_die_in, + Dwarf_Bool is_info, + char **srcfiles, Dwarf_Signed cnt) +{ + print_die_and_children_internal(dbg, + in_die_in,is_info,srcfiles,cnt); +} + +static void +print_die_stack(Dwarf_Debug dbg,char **srcfiles,Dwarf_Signed cnt) +{ + int lev = 0; + boolean print_information = TRUE; + boolean ignore_die_stack = FALSE; + + for(lev = 0; lev <= die_stack_indent_level; ++lev) + { + print_one_die(dbg,die_stack[lev].die_,print_information, + lev,srcfiles,cnt, + ignore_die_stack); + } +} + +/* recursively follow the die tree */ +static void +print_die_and_children_internal(Dwarf_Debug dbg, + Dwarf_Die in_die_in, + Dwarf_Bool is_info, + char **srcfiles, Dwarf_Signed cnt) +{ + Dwarf_Die child = 0; + Dwarf_Die sibling = 0; + Dwarf_Error err = 0; + int tres = 0; + int cdres = 0; + Dwarf_Die in_die = in_die_in; + + for (;;) { + SET_DIE_STACK_ENTRY(die_stack_indent_level,in_die); + + /* Get the CU offset for easy error reporting */ + dwarf_die_offsets(in_die,&DIE_overall_offset,&DIE_offset,&err); + + if (check_tag_tree) { + DWARF_CHECK_COUNT(tag_tree_result,1); + if (die_stack_indent_level == 0) { + Dwarf_Half tag = 0; + + 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; + int pres = 0; + int cres = 0; + const char *ctagname = "<child tag invalid>"; + const char *ptagname = "<parent tag invalid>"; + + pres = dwarf_tag(die_stack[die_stack_indent_level - 1].die_, + &tag_parent, &err); + 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,die_stack_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 do pre-descent processing of the die. */ + { + boolean retry_print_on_match = FALSE; + boolean ignore_die_stack = FALSE; + retry_print_on_match = print_one_die(dbg, in_die, + print_as_info_or_cu(), + die_stack_indent_level, srcfiles, cnt,ignore_die_stack); + if(!print_as_info_or_cu() && retry_print_on_match) { + if (display_parent_tree) { + print_die_stack(dbg,srcfiles,cnt); + } else { + if (display_children_tree) { + print_a_die_stack(dbg,srcfiles,cnt,die_stack_indent_level); + } + } + if (display_children_tree) { + stop_indent_level = die_stack_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; + Dwarf_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) { + die_stack_indent_level++; + SET_DIE_STACK_ENTRY(die_stack_indent_level,0); + if(die_stack_indent_level >= DIE_STACK_SIZE ) { + print_error(dbg, + "compiled in DIE_STACK_SIZE limit exceeded", + DW_DLV_OK,err); + } + print_die_and_children_internal(dbg, child,is_info, srcfiles, cnt); + EMPTY_DIE_STACK_ENTRY(die_stack_indent_level); + die_stack_indent_level--; + if (die_stack_indent_level == 0) + local_symbols_already_began = FALSE; + dwarf_dealloc(dbg, child, DW_DLA_DIE); + child = 0; + } 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 == die_stack_indent_level) { + + info_flag = FALSE; + } + + cdres = dwarf_siblingof_b(dbg, in_die,is_info, &sibling, &err); + if (cdres == DW_DLV_OK) { + /* print_die_and_children(dbg, sibling, srcfiles, cnt); 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); + } + + /* 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. */ + + EMPTY_DIE_STACK_ENTRY(die_stack_indent_level); + if (in_die != in_die_in) { + /* Dealloc our in_die, but not the argument die, it belongs + to our caller. Whether the siblingof call worked or not. */ + dwarf_dealloc(dbg, in_die, DW_DLA_DIE); + in_die = 0; + } + if (cdres == DW_DLV_OK) { + /* Set to process the sibling, loop again. */ + in_die = sibling; + } 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)) + +/* If print_information is FALSE, check the TAG and if it is a CU die + print the information anyway. */ +boolean +print_one_die(Dwarf_Debug dbg, Dwarf_Die die, + boolean print_information, + int die_indent_level, + char **srcfiles, Dwarf_Signed cnt, + boolean ignore_die_stack) +{ + Dwarf_Signed i = 0; + Dwarf_Off offset = 0; + Dwarf_Off overall_offset = 0; + const char * tagname = 0; + Dwarf_Half tag = 0; + Dwarf_Signed atcnt = 0; + Dwarf_Attribute *atlist = 0; + int tres = 0; + int ores = 0; + int atres = 0; + int abbrev_code = dwarf_die_abbrev_code(die); + boolean 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_stack && die_stack[die_indent_level].already_printed_) { + /* FALSE seems like a safe return. */ + return FALSE; + } + + /* Reset indentation column if no offsets */ + if (!display_offsets) { + nColumn = 2; + } + + tres = dwarf_tag(die, &tag, &err); + if (tres != DW_DLV_OK) { + print_error(dbg, "accessing tag of die!", tres, err); + } + tagname = get_TAG_name(tag,dwarf_names_print_on_error); + + tag_specific_checks_setup(tag,die_indent_level); + ores = dwarf_dieoffset(die, &overall_offset, &err); + if (ores != DW_DLV_OK) { + print_error(dbg, "dwarf_dieoffset", ores, err); + } + 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) { + printf("<%2d><0x%" DW_PR_XZEROS DW_PR_DUx + " GOFF=0x%" DW_PR_XZEROS DW_PR_DUx "> ", + die_indent_level, (Dwarf_Unsigned)offset, + (Dwarf_Unsigned)overall_offset); + printf("%*s%s\n",die_indent_level * 2 + 2," ",tagname); + } + + /* Print the die */ + if (PRINTING_DIES && print_information) { + if (!ignore_die_stack) { + die_stack[die_indent_level].already_printed_ = TRUE; + } + if (die_indent_level == 0) { + if (dense) { + printf("\n"); + } else { + printf("\nCOMPILE_UNIT<header overall offset = 0x%" + DW_PR_XZEROS DW_PR_DUx ">:\n", + (Dwarf_Unsigned)(overall_offset - offset)); + } + } else if (local_symbols_already_began == FALSE && + die_indent_level == 1 && !dense) { + + printf("\nLOCAL_SYMBOLS:\n"); + local_symbols_already_began = TRUE; + } + + /* Print just the Tags and Attributes */ + if (!display_offsets) { + /* Print using indentation */ + printf("%*s%s\n",die_stack_indent_level * 2 + 2," ",tagname); + } else { + if (dense) { + if (show_global_offsets) { + if (die_indent_level == 0) { + printf("<%d><0x%" DW_PR_DUx "+0x%" DW_PR_DUx " GOFF=0x%" + DW_PR_DUx ">", die_indent_level, + (Dwarf_Unsigned)(overall_offset - offset), + (Dwarf_Unsigned)offset, + (Dwarf_Unsigned)overall_offset); + } else { + printf("<%d><0x%" DW_PR_DUx " GOFF=0x%" DW_PR_DUx ">", + die_indent_level, + (Dwarf_Unsigned)offset, + (Dwarf_Unsigned)overall_offset); + } + } else { + if (die_indent_level == 0) { + printf("<%d><0x%" DW_PR_DUx "+0x%" DW_PR_DUx ">", + die_indent_level, + (Dwarf_Unsigned)(overall_offset - offset), + (Dwarf_Unsigned)offset); + } else { + printf("<%d><0x%" DW_PR_DUx ">", die_indent_level, + (Dwarf_Unsigned)offset); + } + } + printf("<%s>",tagname); + if(verbose) { + printf(" <abbrev %d>",abbrev_code); + } + } else { + if (show_global_offsets) { + printf("<%2d><0x%" DW_PR_XZEROS DW_PR_DUx + " GOFF=0x%" DW_PR_XZEROS DW_PR_DUx ">", + die_indent_level, (Dwarf_Unsigned)offset, + (Dwarf_Unsigned)overall_offset); + } else { + printf("<%2d><0x%" DW_PR_XZEROS DW_PR_DUx ">", + die_indent_level, + (Dwarf_Unsigned)offset); + } + + /* Print using indentation */ + printf("%*s%s",die_indent_level * 2 + 2," ",tagname); + if(verbose) { + printf(" <abbrev %d>",abbrev_code); + } + fputs("\n",stdout); + } + } + } + + 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(die,&DIE_CU_overall_offset,&DIE_CU_offset,&err); + + for (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) { + printf("%*s",die_indent_level * 2 + 2 + nColumn," "); + } + + { + boolean attr_match = print_attribute(dbg, die, attr, + atlist[i], + print_information, die_indent_level, srcfiles, cnt); + 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 (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) { + printf("\n"); + } + return attribute_matched; +} + +/* Encodings have undefined signedness. Accept either + signedness. The values are integer-like (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. + + The numbers need not be small (in spite of the + function name), but the result should be an integer. + + 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 + + The known_signed bool is set true(nonzero) or false (zero) + and *both* uval_out and sval_out are set to the value, + though of course uval_out cannot represent a signed + value properly and sval_out cannot represent all unsigned + values properly. + + 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, + char *attr_name, + const char ** string_out, + encoding_type_func val_as_string, + Dwarf_Error * err, + int show_form) +{ + Dwarf_Unsigned uval = 0; + char buf[100]; /* The strings are small. */ + 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) { + snprintf(buf, sizeof(buf), + "%s has a bad form.", attr_name); + *string_out = makename(buf); + } + return vres; + } + *uval_out = uval; + } else { + uval = (Dwarf_Unsigned) sval; + *uval_out = uval; + } + } else { + *uval_out = uval; + } + if (string_out) { + Dwarf_Half theform = 0; + Dwarf_Half directform = 0; + get_form_values(attrib,&theform,&directform); + esb_empty_string(&esb_base); + esb_append(&esb_base, val_as_string((Dwarf_Half) uval, + dwarf_names_print_on_error)); + show_form_itself(show_form, verbose, theform, directform,&esb_base); + *string_out = makename(esb_get_string(&esb_base)); + } + 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 void +get_FLAG_BLOCK_string(Dwarf_Debug dbg, Dwarf_Attribute attrib, + struct esb_s*esbp) +{ + 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; + char linebuf[100]; + + /* first get compressed block data */ + fres = dwarf_formblock (attrib,&tempb, &err); + if (fres != DW_DLV_OK) { + print_error(dbg,"DW_FORM_blockn cannot get block\n",fres,err); + return; + } + + /* uncompress block into int array */ + array = dwarf_uncompress_integer_block(dbg, + 1, /* 'true' (meaning signed ints)*/ + 32, /* bits per unit */ + tempb->bl_data, + tempb->bl_len, + &array_len, /* len of out array */ + &err); + if (array == (void*) DW_DLV_BADOFFSET) { + print_error(dbg,"DW_AT_SUN_func_offsets cannot uncompress data\n",0,err); + return; + } + if (array_len == 0) { + print_error(dbg,"DW_AT_SUN_func_offsets has no data\n",0,err); + return; + } + + /* fill in string buffer */ + array_remain = array_len; + array_ptr = array; + while (array_remain > 8) { + /* Print a full line */ + /* If you touch this string, update the magic number 8 in + the += and -= below! */ + snprintf(linebuf, sizeof(linebuf), + "\n 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", + array_ptr[0], array_ptr[1], + array_ptr[2], array_ptr[3], + array_ptr[4], array_ptr[5], + array_ptr[6], array_ptr[7]); + array_ptr += 8; + array_remain -= 8; + esb_append(&esb_base, linebuf); + } + + /* now do the last line */ + if (array_remain > 0) { + esb_append(&esb_base, "\n "); + while (array_remain > 0) { + snprintf(linebuf, sizeof(linebuf), " 0x%08x", *array_ptr); + array_remain--; + array_ptr++; + esb_append(&esb_base, linebuf); + } + } + + /* free array buffer */ + dwarf_dealloc_uncompressed_block(dbg, array); + +} + +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"; +} + + +void +print_ranges_list_to_extra(Dwarf_Debug dbg, + Dwarf_Unsigned off, + Dwarf_Ranges *rangeset, + Dwarf_Signed rangecount, + Dwarf_Unsigned bytecount, + struct esb_s *stringbuf) +{ + char tmp[200]; + Dwarf_Signed i; + if(dense) { + snprintf(tmp,sizeof(tmp), + "< ranges: %" DW_PR_DSd " ranges at .debug_ranges offset %" + DW_PR_DUu " (0x%" DW_PR_XZEROS DW_PR_DUx ") " + "(%" DW_PR_DUu " bytes)>", + rangecount, + off, + off, + bytecount); + esb_append(stringbuf,tmp); + } else { + snprintf(tmp,sizeof(tmp), + "\t\tranges: %" DW_PR_DSd " at .debug_ranges offset %" + DW_PR_DUu " (0x%" DW_PR_XZEROS DW_PR_DUx ") " + "(%" DW_PR_DUu " bytes)\n", + rangecount, + off, + off, + bytecount); + esb_append(stringbuf,tmp); + } + for(i = 0; i < rangecount; ++i) { + Dwarf_Ranges * r = rangeset +i; + const char *type = get_rangelist_type_descr(r); + if(dense) { + snprintf(tmp,sizeof(tmp), + "<[%2" DW_PR_DSd + "] %s 0x%" DW_PR_XZEROS DW_PR_DUx + " 0x%" DW_PR_XZEROS DW_PR_DUx ">", + (Dwarf_Signed)i, + type, + (Dwarf_Unsigned)r->dwr_addr1, + (Dwarf_Unsigned)r->dwr_addr2); + } else { + snprintf(tmp,sizeof(tmp), + "\t\t\t[%2" DW_PR_DSd + "] %-14s 0x%" DW_PR_XZEROS DW_PR_DUx + " 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Signed)i, + type, + (Dwarf_Unsigned)r->dwr_addr1, + (Dwarf_Unsigned)r->dwr_addr2); + } + esb_append(stringbuf,tmp); + } +} + + +static boolean +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,struct esb_s *out) +{ + const char *n = 0; + int res; + char buf[30]; + esb_append(out,"ERROR: Attribute "); + snprintf(buf,sizeof(buf),"%u",attr); + esb_append(out,buf); + esb_append(out," ("); + res = dwarf_get_AT_name(attr,&n); + if(res != DW_DLV_OK) { + n = "UknownAttribute"; + } + esb_append(out,n); + esb_append(out,") "); + esb_append(out," has form "); + snprintf(buf,sizeof(buf),"%u",form); + esb_append(out,buf); + esb_append(out," ("); + res = dwarf_get_FORM_name(form,&n); + if(res != DW_DLV_OK) { + n = "UknownForm"; + } + esb_append(out,n); + esb_append(out,"), a form which is not appropriate"); + print_error_and_continue(dbg,esb_get_string(out), DW_DLV_OK,err); +} + +/* Traverse an attribute and following any reference + in order to detect self references to DIES (loop). */ +static boolean +traverse_attribute(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attr, + Dwarf_Attribute attr_in, + boolean print_information, + char **srcfiles, Dwarf_Signed cnt, + int die_indent_level) +{ + Dwarf_Attribute attrib = 0; + const char * atname = 0; + const char * valname = 0; + int tres = 0; + Dwarf_Half tag = 0; + boolean 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; + esb_empty_string(&esb_base); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &esb_base, show_form_used,verbose); + valname = esb_get_string(&esb_base); + + /* 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) { + ++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 */ + + printf("<%2d><0x%" DW_PR_XZEROS DW_PR_DUx + " GOFF=0x%" DW_PR_XZEROS DW_PR_DUx "> ", + die_indent_level, (Dwarf_Unsigned)off, + (Dwarf_Unsigned)die_off); + printf("%*s%s -> %s\n",die_indent_level * 2 + 2, + " ",atname,valname); + } + circular_reference = traverse_one_die(dbg,attrib,ref_die, + srcfiles,cnt,die_indent_level); + DeleteKeyInBucketGroup(pVisitedInfo,ref_off); + dwarf_dealloc(dbg,ref_die,DW_DLA_DIE); + --die_indent_level; + ref_die = 0; + } + } + break; + } /* End switch. */ + return circular_reference; +} + +/* Traverse one DIE in order to detect self references to DIES. */ +static boolean +traverse_one_die(Dwarf_Debug dbg, Dwarf_Attribute attrib, Dwarf_Die die, + char **srcfiles, Dwarf_Signed cnt, int die_indent_level) +{ + Dwarf_Half tag = 0; + Dwarf_Off overall_offset = 0; + Dwarf_Signed atcnt = 0; + int res = 0; + boolean circular_reference = FALSE; + boolean print_information = FALSE; + + 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; + const char * tagname = 0; + 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); + printf("<%2d><0x%" DW_PR_XZEROS DW_PR_DUx + " GOFF=0x%" DW_PR_XZEROS DW_PR_DUx "> ", + die_indent_level, (Dwarf_Unsigned)offset, + (Dwarf_Unsigned)overall_offset); + printf("%*s%s\n",die_indent_level * 2 + 2," ",tagname); + } + + DWARF_CHECK_COUNT(self_references_result,1); + if (FindKeyInBucketGroup(pVisitedInfo,overall_offset)) { + char * valname = NULL; + Dwarf_Half attr = 0; + const char *atname = NULL; + esb_empty_string(&esb_base); + get_attr_value(dbg, tag, die, attrib, srcfiles, + cnt, &esb_base, show_form_used,verbose); + valname = esb_get_string(&esb_base); + 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_Signed i = 0; + Dwarf_Attribute *atlist = 0; + + /* Add current DIE */ + AddEntryIntoBucketGroup(pVisitedInfo,overall_offset, + 0,0,0,NULL,FALSE); + + 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 (i = 0; i < atcnt; i++) { + Dwarf_Half attr; + int ares; + + ares = dwarf_whatattr(atlist[i], &attr, &err); + if (ares == DW_DLV_OK) { + circular_reference = traverse_attribute(dbg, die, attr, + atlist[i], + print_information, srcfiles, cnt, + die_indent_level); + } else { + print_error(dbg, "dwarf_whatattr entry missing", + ares, err); + } + } + + for (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 */ + DeleteKeyInBucketGroup(pVisitedInfo,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, + boolean print_information, + int *append_extra_string) +{ + 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 = CU_base_address; + Dwarf_Addr lopc = 0; + Dwarf_Addr hipc = 0; + Dwarf_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 == 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 (IsValidInBucketGroup(pRangesInfo,lopc) && + IsValidInBucketGroup(pRangesInfo,hipc)) { + /* Valid values; do nothing */ + } else { + /* At this point may be we + are dealing with a + linkonce symbol */ + if (IsValidInLinkonce(pLinkonceInfo, + 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) { + printf( + "Offset = 0x%" DW_PR_XZEROS DW_PR_DUx + ", Base = 0x%" DW_PR_XZEROS DW_PR_DUx + ", " + "Low = 0x%" DW_PR_XZEROS DW_PR_DUx + " (0x%" DW_PR_XZEROS DW_PR_DUx + "), High = 0x%" + DW_PR_XZEROS DW_PR_DUx + " (0x%" DW_PR_XZEROS DW_PR_DUx + ")\n", + off,base_address,lopc, + r->dwr_addr1,hipc, + r->dwr_addr2); + } + } + } + } + /* Each entry holds 2 addresses (offsets) */ + off += elf_address_size * 2; + } + if (bError && check_verbose_mode) { + printf("\n"); + } + } + if(print_information) { + *append_extra_string = 1; + esb_empty_string(&esb_extra); + print_ranges_list_to_extra(dbg,original_off, + rangeset,rangecount,bytecount, + &esb_extra); + } + 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) { + printf("\ndwarf_get_ranges() " + "finds no 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), + " fails to find DW_AT_ranges at offset"); + } + } + } else { + if (do_print_dwarf) { + struct esb_s local; + char tmp[100]; + + snprintf(tmp,sizeof(tmp)," attr 0x%x form 0x%x ", + (unsigned)attr,(unsigned)theform); + esb_constructor(&local); + esb_append(&local, + " fails to find DW_AT_ranges offset"); + esb_append(&local,tmp); + printf(" %s ",esb_get_string(&local)); + esb_destructor(&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 char *val) +{ + if (strncmp(val,"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 void +trim_quotes(const char *val,struct esb_s *es) +{ + if(val[0] == '"') { + size_t l = strlen(val); + if(l > 2 && val[l-1] == '"') { + esb_appendn(es,val+1,l-2); + return; + } + } + esb_append(es,val); +} + +static int +have_a_search_match(const char *valname,const char *atname) +{ + /* valname may have had quotes inserted, but search_match_text + will not. So we need to use a new copy, not valname here. + */ + struct esb_s esb_match; + char *s2; + esb_constructor(&esb_match); + + trim_quotes(valname,&esb_match); + s2 = esb_get_string(&esb_match); + if (search_match_text ) { + if(!strcmp(s2,search_match_text) || + !strcmp(atname,search_match_text)) { + + esb_destructor(&esb_match); + return TRUE; + } + } + if (search_any_text) { + if(is_strstrnocase(s2,search_any_text) || + is_strstrnocase(atname,search_any_text)) { + + esb_destructor(&esb_match); + return TRUE; + } + } +#ifdef HAVE_REGEX + if (search_regex_text) { + if(!regexec(&search_re,s2,0,NULL,0) || + !regexec(&search_re,atname,0,NULL,0)) { + + esb_destructor(&esb_match); + return TRUE; + } + } +#endif + esb_destructor(&esb_match); + return FALSE; +} + + +static boolean +print_attribute(Dwarf_Debug dbg, Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Attribute attr_in, + boolean print_information, + int die_indent_level, + char **srcfiles, Dwarf_Signed cnt) +{ + Dwarf_Attribute attrib = 0; + Dwarf_Unsigned uval = 0; + const char * atname = 0; + const char * valname = 0; + int tres = 0; + Dwarf_Half tag = 0; + int append_extra_string = 0; + boolean found_search_attr = FALSE; + boolean bTextFound = FALSE; + Dwarf_Bool is_info = FALSE; + + is_info = dwarf_get_die_infotypes_flag(die); + esb_empty_string(&esb_extra); + 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 */ + } + if (check_attr_tag && checking_this_compiler()) { + const char *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_stack_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} */ + enum Dwarf_Form_Class fc = DW_FORM_CLASS_UNKNOWN; + Dwarf_Half theform = 0; + Dwarf_Half directform = 0; + Dwarf_Half version = 0; + Dwarf_Half offset_size = 0; + int wres = 0; + + get_form_values(attrib,&theform,&directform); + 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; + } + fc = dwarf_get_form_class(version,attr,offset_size,theform); + if(fc == DW_FORM_CLASS_CONSTANT) { + esb_empty_string(&esb_base); + wres = formxdata_print_value(dbg,attrib,&esb_base, + &err, FALSE); + show_form_itself(show_form_used,verbose, theform, + directform,&esb_base); + valname = esb_get_string(&esb_base); + 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: + { + /* The value is a location description + or location list. */ + + Dwarf_Half theform = 0; + Dwarf_Half directform = 0; + get_form_values(attrib,&theform,&directform); + esb_empty_string(&esb_base); + if(is_location_form(theform)) { + get_location_list(dbg, die, attrib, &esb_base); + show_form_itself(show_form_used,verbose, + theform, directform,&esb_base); + } else if (theform == DW_FORM_exprloc) { + int showhextoo = 1; + print_exprloc_content(dbg,die,attrib,showhextoo,&esb_base); + } else { + show_attr_form_error(dbg,attr,theform,&esb_base); + } + valname = esb_get_string(&esb_base); + } + break; + case DW_AT_SUN_func_offsets: + { + /* value is a location description or location list */ + Dwarf_Half theform = 0; + Dwarf_Half directform = 0; + get_form_values(attrib,&theform,&directform); + esb_empty_string(&esb_base); + get_FLAG_BLOCK_string(dbg, attrib,&esb_base); + show_form_itself(show_form_used,verbose, theform, + directform,&esb_base); + valname = esb_get_string(&esb_base); + } + break; + case DW_AT_SUN_cf_kind: + { + Dwarf_Half kind = 0; + Dwarf_Unsigned tempud = 0; + Dwarf_Error err = 0; + int wres = 0; + Dwarf_Half theform = 0; + Dwarf_Half directform = 0; + get_form_values(attrib,&theform,&directform); + wres = dwarf_formudata (attrib,&tempud, &err); + esb_empty_string(&esb_base); + if(wres == DW_DLV_OK) { + kind = tempud; + esb_append(&esb_base, + get_ATCF_name(kind,dwarf_names_print_on_error)); + } else if (wres == DW_DLV_NO_ENTRY) { + esb_append(&esb_base, "?"); + } else { + print_error(dbg,"Cannot get formudata....",wres,err); + esb_append(&esb_base, "??"); + } + show_form_itself(show_form_used,verbose, theform, + directform,&esb_base); + valname = esb_get_string(&esb_base); + } + 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; + } + + esb_empty_string(&esb_base); + 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, &esb_base); + show_form_itself(show_form_used,verbose, theform, + directform,&esb_base); + valname = esb_get_string(&esb_base); + } + break; + default: + get_attr_value(dbg, tag, die, + attrib, srcfiles, cnt, &esb_base, show_form_used,verbose); + valname = esb_get_string(&esb_base); + 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; + } + esb_empty_string(&esb_base); + 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. */ + esb_append(&esb_base,"<offset-from-lowpc>"); + } + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &esb_base,show_form_used,verbose); + valname = esb_get_string(&esb_base); + + /* Update base and high addresses for CU */ + if (seen_CU && (need_CU_base_address || + need_CU_high_address)) { + + /* Update base address for CU */ + if (need_CU_base_address && attr == DW_AT_low_pc) { + dwarf_formaddr(attrib, &CU_base_address, &err); + need_CU_base_address = FALSE; + } + + /* Update high address for CU */ + if (need_CU_high_address && attr == DW_AT_high_pc) { + dwarf_formaddr(attrib, &CU_high_address, &err); + 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 (seen_PU && !seen_PU_base_address) { + seen_PU_base_address = TRUE; + 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 (seen_PU && !seen_PU_high_address) { + seen_PU_high_address = TRUE; + 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 (need_PU_valid_code) { + 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 != elf_max_address && + lowAddr > highAddr) { + DWARF_CHECK_ERROR(ranges_result, + ".debug_info: Incorrect values " + "for low_pc/high_pc"); + if (check_verbose_mode) { + printf("Low = 0x%" DW_PR_XZEROS DW_PR_DUx + ", High = 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + lowAddr,highAddr); + } + } + if (check_decl_file || check_ranges || + check_locations) { + AddEntryIntoBucketGroup(pRangesInfo,0,lowAddr, + lowAddr,highAddr,NULL,FALSE); + } + } + 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; + } + + esb_empty_string(&esb_base); + get_attr_value(dbg, tag,die, attrib, srcfiles, cnt, &esb_base, + show_form_used,verbose); + print_range_attribute(dbg, die, attr,attr_in, theform, + dwarf_names_print_on_error,print_information, + &append_extra_string); + valname = esb_get_string(&esb_base); + } + break; + case DW_AT_MIPS_linkage_name: + esb_empty_string(&esb_base); + get_attr_value(dbg, tag, die, attrib, srcfiles, + cnt, &esb_base, show_form_used,verbose); + valname = esb_get_string(&esb_base); + + if (check_locations || check_ranges) { + int local_show_form = 0; + int local_verbose = 0; + struct esb_s lesb; + const char *name = 0; + esb_constructor(&lesb); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &lesb, local_show_form,local_verbose); + /* Look for specific name forms, attempting to + notice and report 'odd' identifiers. */ + name = esb_get_string(&lesb); + safe_strcpy(PU_name,sizeof(PU_name),name,strlen(name)); + } + break; + case DW_AT_name: + case DW_AT_GNU_template_name: + esb_empty_string(&esb_base); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &esb_base, show_form_used,verbose); + valname = esb_get_string(&esb_base); + + if (check_names && checking_this_compiler()) { + int local_show_form = FALSE; + int local_verbose = 0; + struct esb_s lesb; + const char *name = 0; + esb_constructor(&lesb); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &lesb, local_show_form,local_verbose); + /* Look for specific name forms, attempting to + notice and report 'odd' identifiers. */ + name = esb_get_string(&lesb); + DWARF_CHECK_COUNT(names_result,1); + if (!strcmp("\"(null)\"",name)) { + DWARF_CHECK_ERROR(names_result, + "string attribute is \"(null)\"."); + } else { + if (!dot_ok_in_identifier(tag,die,name) + && !need_CU_name && strchr(name,'.')) { + /* 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."); + } + } + esb_destructor(&lesb); + } + + /* If we are in checking mode and we do not have a PU name */ + if ((check_locations || check_ranges) && seen_PU && !PU_name[0]) { + int local_show_form = FALSE; + int local_verbose = 0; + const char *name = 0; + struct esb_s lesb; + esb_constructor(&lesb); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &lesb, local_show_form,local_verbose); + name = esb_get_string(&lesb); + + safe_strcpy(PU_name,sizeof(PU_name),name,strlen(name)); + esb_destructor(&lesb); + } + + /* If we are processing the compile unit, record the name */ + if (seen_CU && need_CU_name) { + /* Lets not get the form name included. */ + struct esb_s lesb; + int local_show_form_used = FALSE; + int local_verbose = 0; + char *localname = 0; + esb_constructor(&lesb); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &lesb, local_show_form_used,local_verbose); + localname = esb_get_string(&lesb); + safe_strcpy(CU_name,sizeof(CU_name),localname,strlen(localname)); + need_CU_name = FALSE; + esb_destructor(&lesb); + } + break; + + case DW_AT_producer: + esb_empty_string(&esb_base); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &esb_base, show_form_used,verbose); + valname = esb_get_string(&esb_base); + /* If we are in checking mode, identify the compiler */ + if (do_check_dwarf || search_is_on) { + /* Do not use show-form here! We just want the producer name, not + the form name. */ + int show_form_local = FALSE; + int local_verbose = 0; + struct esb_s local_e; + esb_constructor(&local_e); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, + &local_e, show_form_local,local_verbose); + /* Check if this compiler version is a target */ + update_compiler_target(esb_get_string(&local_e)); + esb_destructor(&local_e); + } + 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: + esb_empty_string(&esb_base); + get_attr_value(dbg, tag, die, attrib, srcfiles, cnt, &esb_base, + show_form_used,verbose); + valname = esb_get_string(&esb_base); + 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; + + ResetBucketGroup(pVisitedInfo); + AddEntryIntoBucketGroup(pVisitedInfo,die_off,0,0,0,NULL,FALSE); + + /* Follow reference chain, looking for self references */ + res = dwarf_offdie_b(dbg,ref_off,is_info,&ref_die,&err); + if (res == DW_DLV_OK) { + ++die_indent_level; + struct esb_s copy_base; + if (dump_visited_info) { + Dwarf_Off off; + dwarf_die_CU_offset(die, &off, &err); + printf("<%2d><0x%" DW_PR_XZEROS DW_PR_DUx + " GOFF=0x%" DW_PR_XZEROS DW_PR_DUx "> ", + die_indent_level, (Dwarf_Unsigned)off, + (Dwarf_Unsigned)die_off); + printf("%*s%s -> %s\n",die_indent_level * 2 + 2, + " ",atname,valname); + } + /* Because esb_base is global, lets not + let the traversal trash what we have here. */ + esb_constructor(©_base); + esb_append(©_base,esb_get_string(&esb_base)); + esb_empty_string(&esb_base); + traverse_one_die(dbg,attrib,ref_die,srcfiles,cnt,die_indent_level); + esb_empty_string(&esb_base); + esb_append(&esb_base,esb_get_string(©_base)); + esb_destructor(©_base); + dwarf_dealloc(dbg,ref_die,DW_DLA_DIE); + ref_die = 0; + --die_indent_level; + } + DeleteKeyInBucketGroup(pVisitedInfo,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) && seen_PU && !PU_name[0]) { + if (tag == DW_TAG_subprogram) { + /* This gets the DW_AT_name if this DIE has one. */ + Dwarf_Addr low_pc = 0; + static char proc_name[BUFSIZ]; + proc_name[0] = 0; + get_proc_name(dbg,die,low_pc,proc_name,BUFSIZ,/*pcMap=*/0); + if (proc_name[0]) { + safe_strcpy(PU_name,sizeof(PU_name),proc_name, + strlen(proc_name)); + } + } + } + break; + default: + esb_empty_string(&esb_base); + get_attr_value(dbg, tag,die, attrib, srcfiles, cnt, &esb_base, + show_form_used,verbose); + valname = esb_get_string(&esb_base); + 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) { + /* Print just the Tags and Attributes */ + if (!display_offsets) { + printf("%-28s\n",atname); + } else { + if (dense) { + printf(" %s<%s>", atname, valname); + if(append_extra_string) { + char *v = esb_get_string(&esb_extra); + printf("%s", v); + } + } else { + printf("%-28s%s\n", atname, valname); + if( append_extra_string) { + char *v = esb_get_string(&esb_extra); + printf("%s", v); + } + } + } + /* Due to redirection of stderr */ + fflush(stdout); + bTextFound = FALSE; + } + return found_search_attr; +} + + +int +dwarfdump_print_one_locdesc(Dwarf_Debug dbg, + Dwarf_Locdesc * llbuf, + int skip_locdesc_header, + struct esb_s *string_out) +{ + + Dwarf_Locdesc *locd = 0; + Dwarf_Half no_of_ops = 0; + int i = 0; + char small_buf[100]; + + if (!skip_locdesc_header && (verbose || llbuf->ld_from_loclist)) { + snprintf(small_buf, sizeof(small_buf), + "<lowpc=0x%" DW_PR_XZEROS DW_PR_DUx ">", + (Dwarf_Unsigned) llbuf->ld_lopc); + esb_append(string_out, small_buf); + + + snprintf(small_buf, sizeof(small_buf), + "<highpc=0x%" DW_PR_XZEROS DW_PR_DUx ">", + (Dwarf_Unsigned) llbuf->ld_hipc); + esb_append(string_out, small_buf); + if (display_offsets && verbose) { + snprintf(small_buf, sizeof(small_buf), + "<from %s offset 0x%" DW_PR_XZEROS DW_PR_DUx ">", + llbuf->ld_from_loclist ? ".debug_loc" : ".debug_info", + llbuf->ld_section_offset); + esb_append(string_out, small_buf); + } + } + + locd = llbuf; + no_of_ops = llbuf->ld_cents; + for (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 int +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, + struct esb_s *string_out) +{ + /* local_space_needed is intended to be 'more than big enough' + for a short group of loclist entries. */ + char small_buf[100]; + Dwarf_Small op; + Dwarf_Unsigned opd1; + Dwarf_Unsigned opd2; + const char * op_name; + + if (index > 0) { + esb_append(string_out, " "); + } + + op = expr->lr_atom; + + /* We have valid operands whose values are bigger than the + DW_OP_nop = 0x96; for example: DW_OP_GNU_push_tls_address = 0xe0 + Also, the function 'get_OP_name' handles this case, generating a + name 'Unknown OP value'. */ + if (op > DW_OP_hi_user) { + print_error(dbg, "dwarf_op unexpected value!", DW_DLV_OK, + err); + return DW_DLV_ERROR; + } + op_name = get_OP_name(op,dwarf_names_print_on_error); + esb_append(string_out, op_name); + + opd1 = expr->lr_number; + if(op_has_no_operands(op)) { + /* Nothing to add. */ + } else if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { + snprintf(small_buf, sizeof(small_buf), + "%+" DW_PR_DSd , (Dwarf_Signed) opd1); + esb_append(string_out, small_buf); + } else { + switch (op) { + case DW_OP_addr: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + 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: + snprintf(small_buf, sizeof(small_buf), + " %" DW_PR_DSd, (Dwarf_Signed) opd1); + esb_append(string_out, small_buf); + 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: + snprintf(small_buf, sizeof(small_buf), + " %" DW_PR_DUu , opd1); + esb_append(string_out, small_buf); + break; + case DW_OP_bregx: + snprintf(small_buf, sizeof(small_buf), + "0x%08" DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + opd2 = expr->lr_number2; + snprintf(small_buf, sizeof(small_buf), + "+%" DW_PR_DSd , (Dwarf_Signed) opd2); + esb_append(string_out, small_buf); + break; + case DW_OP_call2: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + break; + case DW_OP_call4: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + break; + case DW_OP_call_ref: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + break; + case DW_OP_bit_piece: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + opd2 = expr->lr_number2; + snprintf(small_buf, sizeof(small_buf), + " offset 0x%" DW_PR_DUx , (Dwarf_Signed) opd2); + esb_append(string_out, small_buf); + break; + case DW_OP_implicit_value: + { +#define IMPLICIT_VALUE_PRINT_MAX 12 + unsigned int print_len = 0; + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + /* The other operand is a block of opd1 bytes. */ + /* FIXME */ + 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) { + const unsigned char *bp = 0; + unsigned int i = 0; + opd2 = expr->lr_number2; + /* This is a really ugly cast, a way + to implement DW_OP_implicit value in + this libdwarf context. */ + bp = (const unsigned char *) opd2; + esb_append(string_out," contents 0x"); + for( ; i < print_len; ++i,++bp) { + /* Do not use DW_PR_DUx here, + the value *bp is a const unsigned char. */ + snprintf(small_buf, sizeof(small_buf), + "%02x", *bp); + esb_append(string_out,small_buf); + } + } + } + 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; + case DW_OP_stack_value: /* DWARF4 */ + break; + case DW_OP_GNU_uninit: /* DW_OP_APPLE_uninit */ + /* No operands. */ + break; + case DW_OP_GNU_encoded_addr: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + break; + case DW_OP_GNU_implicit_pointer: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + break; + case DW_OP_GNU_entry_value: + snprintf(small_buf, sizeof(small_buf), + " 0x%" DW_PR_XZEROS DW_PR_DUx , opd1); + esb_append(string_out, small_buf); + break; + default: + { + snprintf(small_buf, sizeof(small_buf), + " dwarf_op unknown 0x%x", (unsigned)op); + esb_append(string_out,small_buf); + } + break; + } + } + return DW_DLV_OK; +} + +/* Fill buffer with location lists + Buffer esbp expands as needed. +*/ +/*ARGSUSED*/ static void +get_location_list(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Attribute attr, + struct esb_s *esbp) +{ + 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; + + /* Base address used to update entries in .debug_loc */ + Dwarf_Addr base_address = CU_base_address; + Dwarf_Addr lopc = 0; + Dwarf_Addr hipc = 0; + Dwarf_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,esbp); + 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) { + char small_buf[100]; + Dwarf_Off offset = 0; + + llbuf = llbufarray[llent]; + /* 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 * elf_address_size; + + if (llbuf->ld_lopc == 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 (IsValidInBucketGroup(pRangesInfo,lopc) && + IsValidInBucketGroup(pRangesInfo,hipc)) { + /* Valid values; do nothing */ + } else { + /* At this point may be we are dealing with + a linkonce symbol */ + if (IsValidInLinkonce(pLinkonceInfo,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) { + printf( + "Offset = 0x%" DW_PR_XZEROS DW_PR_DUx + ", Base = 0x%" DW_PR_XZEROS DW_PR_DUx ", " + "Low = 0x%" DW_PR_XZEROS DW_PR_DUx + " (0x%" DW_PR_XZEROS DW_PR_DUx + "), High = 0x%" DW_PR_XZEROS DW_PR_DUx + " (0x%" DW_PR_XZEROS DW_PR_DUx ")\n", + offset,base_address,lopc, + llbuf->ld_lopc, + hipc, + llbuf->ld_hipc); + } + } + } + } + } + + if (!dense && llbuf->ld_from_loclist) { + if (llent == 0) { + snprintf(small_buf, sizeof(small_buf), + "<loclist with %ld entries follows>", + (long) no_of_elements); + esb_append(esbp, small_buf); + } + esb_append(esbp, "\n\t\t\t"); + snprintf(small_buf, sizeof(small_buf), "[%2d]", llent); + esb_append(esbp, small_buf); + } + lres = dwarfdump_print_one_locdesc(dbg, + llbuf, + skip_locdesc_header, + esbp); + 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) { + printf("\n"); + } + + 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); +} + +static void +formx_unsigned(Dwarf_Unsigned u, struct esb_s *esbp, Dwarf_Bool hex_format) +{ + char small_buf[40]; + if (hex_format) { + snprintf(small_buf, sizeof(small_buf),"0x%" DW_PR_XZEROS DW_PR_DUx , u); + } else { + snprintf(small_buf, sizeof(small_buf), + "%" DW_PR_DUu , u); + } + esb_append(esbp, small_buf); +} +static void +formx_signed(Dwarf_Signed u, struct esb_s *esbp) +{ + char small_buf[40]; + snprintf(small_buf, sizeof(small_buf), + "%" DW_PR_DSd , u); + esb_append(esbp, small_buf); +} +/* 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, + struct esb_s *esbp, + Dwarf_Error * err, Dwarf_Bool hex_format) +{ + Dwarf_Signed tempsd = 0; + Dwarf_Unsigned tempud = 0; + int sres = 0; + int ures = 0; + Dwarf_Error serr = 0; + + ures = dwarf_formudata(attrib, &tempud, err); + sres = dwarf_formsdata(attrib, &tempsd, &serr); + if(ures == DW_DLV_OK) { + if(sres == DW_DLV_OK) { + if(tempud == tempsd && tempsd >= 0) { + /* Data is the same value and not negative, + so makes no difference which + we print. */ + formx_unsigned(tempud,esbp,hex_format); + } else { + formx_unsigned(tempud,esbp,hex_format); + esb_append(esbp,"(as signed = "); + formx_signed(tempsd,esbp); + esb_append(esbp,")"); + } + } else if (sres == DW_DLV_NO_ENTRY) { + formx_unsigned(tempud,esbp,hex_format); + } else /* DW_DLV_ERROR */{ + formx_unsigned(tempud,esbp,hex_format); + } + goto cleanup; + } else { + /* ures == DW_DLV_ERROR or DW_DLV_NO_ENTRY*/ + if(sres == DW_DLV_OK) { + formx_signed(tempsd,esbp); + } else { + /* Neither worked. */ + } + } + /* Clean up any unused Dwarf_Error data. + DW_DLV_NO_ENTRY cannot really happen, + so a complete cleanup for that is + not necessary. */ + 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 char * +get_form_number_as_string(int form, char *buf, unsigned bufsize) +{ + snprintf(buf,bufsize," %d",form); + return buf; +} + +static void +print_exprloc_content(Dwarf_Debug dbg,Dwarf_Die die, Dwarf_Attribute attrib, + int showhextoo, struct esb_s *esbp) +{ + 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 { + Dwarf_Half address_size = 0; + int ares = 0; + unsigned u = 0; + snprintf(small_buf, sizeof(small_buf), + "len 0x%04" DW_PR_DUx ": ",tempud); + esb_append(esbp, small_buf); + if(showhextoo) { + for (u = 0; u < tempud; u++) { + snprintf(small_buf, sizeof(small_buf), "%02x", + *(u + (unsigned char *) x)); + esb_append(esbp, small_buf); + } + esb_append(esbp,": "); + } + 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 { + get_string_from_locs(dbg,x,tempud,address_size, esbp); + } + } +} + + + + +/* 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 esbp's buffer. +*/ +void +get_attr_value(Dwarf_Debug dbg, Dwarf_Half tag, + Dwarf_Die die, Dwarf_Attribute attrib, + char **srcfiles, Dwarf_Signed cnt, struct esb_s *esbp, + int show_form, + int local_verbose) +{ + Dwarf_Half theform = 0; + char * temps = 0; + Dwarf_Block *tempb = 0; + Dwarf_Signed tempsd = 0; + Dwarf_Unsigned tempud = 0; + int i = 0; + Dwarf_Half attr = 0; + Dwarf_Off off = 0; + Dwarf_Off goff = 0; /* Global offset */ + Dwarf_Die die_for_check = 0; + Dwarf_Half tag_for_check = 0; + Dwarf_Bool tempbool = 0; + Dwarf_Addr addr = 0; + int fres = 0; + int bres = 0; + int wres = 0; + int dres = 0; + Dwarf_Half direct_form = 0; + char small_buf[COMPILE_UNIT_NAME_LEN]; /* Size to hold a filename */ + Dwarf_Bool is_info = TRUE; + + + is_info = dwarf_get_die_infotypes_flag(die); + /* Dwarf_whatform gets the real form, DW_FORM_indir is + never returned: instead the real form following + DW_FORM_indir is returned. */ + fres = dwarf_whatform(attrib, &theform, &err); + /* Depending on the form and the attribute, process the 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; + } + + /* dwarf_whatform_direct gets the 'direct' form, so if + the form is DW_FORM_indir that is what is returned. */ + dwarf_whatform_direct(attrib, &direct_form, &err); + /* Ignore errors in dwarf_whatform_direct() */ + + + switch (theform) { + case DW_FORM_addr: + bres = dwarf_formaddr(attrib, &addr, &err); + if (bres == DW_DLV_OK) { + snprintf(small_buf, sizeof(small_buf), + "0x%" DW_PR_XZEROS DW_PR_DUx , + (Dwarf_Unsigned) addr); + esb_append(esbp, small_buf); + } 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) { + snprintf(small_buf, sizeof(small_buf), + "<global die offset 0x%" DW_PR_XZEROS DW_PR_DUx + ">", + (Dwarf_Unsigned) off); + esb_append(esbp, small_buf); + } 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; + int res = dwarf_die_CU_offset_range(die,&cuoff, + &culen,&err); + DWARF_CHECK_COUNT(tag_tree_result,1); + 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 */ + snprintf(small_buf,sizeof(small_buf), + "%s, offset=<0x%" DW_PR_XZEROS DW_PR_DUx + ">","reference form with no valid local ref?!",off); + print_error(dbg, small_buf, 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 */ + snprintf(small_buf,sizeof(small_buf), + "%s, global die offset=<0x%" DW_PR_XZEROS DW_PR_DUx + ">","invalid offset",goff); + print_error(dbg, small_buf, 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) { + snprintf(small_buf, sizeof(small_buf), + "<0x%" DW_PR_XZEROS DW_PR_DUx " GOFF=0x%" DW_PR_XZEROS DW_PR_DUx ">", + (Dwarf_Unsigned)off, goff); + } else { + snprintf(small_buf, sizeof(small_buf), + "<0x%" DW_PR_XZEROS DW_PR_DUx ">", off); + } + + esb_append(esbp, small_buf); + if (check_type_offset) { + attr = 0; + 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) { + snprintf(small_buf,sizeof(small_buf), + "DW_AT_type offset does not point to a DIE for global offset 0x%" DW_PR_DUx " cu off 0x%" DW_PR_DUx " local offset 0x%" DW_PR_DUx, + cu_offset + off,cu_offset,off); + DWARF_CHECK_ERROR(type_offset_result,small_buf); + } else { + int 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: + { + snprintf(small_buf,sizeof(small_buf), + "DW_AT_type offset does not point to Type info we got tag 0x%x %s", + tag_for_check, + get_TAG_name(tag_for_check, + dwarf_names_print_on_error)); + DWARF_CHECK_ERROR(type_offset_result,small_buf); + } + break; + } + dwarf_dealloc(dbg, die_for_check, DW_DLA_DIE); + die_for_check = 0; + } 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: + fres = dwarf_formblock(attrib, &tempb, &err); + if (fres == DW_DLV_OK) { + for (i = 0; i < tempb->bl_len; i++) { + snprintf(small_buf, sizeof(small_buf), "%02x", + *(i + (unsigned char *) tempb->bl_data)); + esb_append(esbp, small_buf); + } + dwarf_dealloc(dbg, tempb, DW_DLA_BLOCK); + tempb = 0; + } 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: + { int show_form_here = 0; + wres = get_small_encoding_integer_and_name(dbg, + attrib, + &tempud, + /* attrname */ (char *) NULL, + /* err_string */ (const char **) NULL, + (encoding_type_func) 0, + &err,show_form_here); + + if (wres == DW_DLV_OK) { + snprintf(small_buf, sizeof(small_buf), + "0x%08" DW_PR_DUx , + tempud); + esb_append(esbp, small_buf); + if (attr == DW_AT_decl_file || attr == DW_AT_call_file) { + if (srcfiles && tempud > 0 && tempud <= cnt) { + /* 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. */ + char *fname = srcfiles[tempud - 1]; + + esb_append(esbp, " "); + esb_append(esbp, 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 > cnt) { + if(!srcfiles) { + snprintf(small_buf,sizeof(small_buf), + "There is a file number=%" DW_PR_DUu + " but no source files " + " are known.",tempud); + } else { + snprintf(small_buf, sizeof(small_buf), + "Does not point to valid file info " + " filenum=%" DW_PR_DUu + " filecount=%" DW_PR_DUu ".", + tempud,cnt); + } + DWARF_CHECK_ERROR2(decl_file_result, + get_AT_name(attr, + dwarf_names_print_on_error), + small_buf); + } + } + } + } else { + print_error(dbg, "Cannot get encoding attribute ..", + wres, err); + } + } + break; + case DW_AT_const_value: + /* Do not use hexadecimal format */ + wres = formxdata_print_value(dbg,attrib,esbp, &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: + /* Do not use hexadecimal format except for + DW_AT_ranges. */ + wres = formxdata_print_value(dbg,attrib,esbp, &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) { + snprintf(small_buf, sizeof(small_buf), + "0x%" DW_PR_XZEROS DW_PR_DUx , tempsd); + esb_append(esbp, small_buf); + } 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) { + snprintf(small_buf, sizeof(small_buf), "0x%" DW_PR_XZEROS DW_PR_DUx , + tempud); + esb_append(esbp, small_buf); + } 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: + wres = dwarf_formstring(attrib, &temps, &err); + if (wres == DW_DLV_OK) { + /* Print as quoted string for clarity. */ + esb_append(esbp, "\""); + esb_append(esbp, temps); + esb_append(esbp, "\""); + } 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: + wres = dwarf_formflag(attrib, &tempbool, &err); + if (wres == DW_DLV_OK) { + if (tempbool) { + snprintf(small_buf, sizeof(small_buf), "yes(%d)", + tempbool); + esb_append(esbp, small_buf); + } else { + snprintf(small_buf, sizeof(small_buf), "no"); + esb_append(esbp, small_buf); + } + } 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. */ + esb_append(esbp, get_FORM_name(theform, + dwarf_names_print_on_error)); + break; + case DW_FORM_exprloc: { /* DWARF4 */ + int showhextoo = 1; + print_exprloc_content(dbg,die,attrib,showhextoo,esbp); + } + break; + case DW_FORM_sec_offset: { /* DWARF4 */ + string emptyattrname = 0; + int show_form_here = 0; + 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 { + snprintf(small_buf, sizeof(small_buf), + "0x%" DW_PR_XZEROS DW_PR_DUx, + tempud); + esb_append(esbp,small_buf); + } + } + + break; + case DW_FORM_flag_present: /* DWARF4 */ + esb_append(esbp,"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 { + struct esb_s sig8str; + esb_constructor(&sig8str); + format_sig8_string(&sig8data,&sig8str); + esb_append(esbp,esb_get_string(&sig8str)); + esb_destructor(&sig8str); + } + } + break; + + default: + print_error(dbg, "dwarf_whatform unexpected value", DW_DLV_OK, + err); + } + show_form_itself(show_form,local_verbose,theform, direct_form,esbp); +} + +void +format_sig8_string(Dwarf_Sig8*data, struct esb_s *out) +{ + unsigned i = 0; + char small_buf[40]; + esb_append(out,"0x"); + for( ; i < sizeof(data->signature); ++i) { + if (i == 4) { + esb_append(out," 0x"); + } + snprintf(small_buf,sizeof(small_buf), "%02x", + (unsigned char)(data->signature[i])); + esb_append(out,small_buf); + } +} + + +/* A cleanup so that when using a memory checker + we don't show irrelevant leftovers. +*/ +void +clean_up_die_esb() +{ + esb_destructor(&esb_base); +} + +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(int local_show_form, + int local_verbose, + int theform, + int directform, struct esb_s *esbp) +{ + char small_buf[100]; + if (local_show_form + && directform && directform == DW_FORM_indirect) { + char *form_indir = " (used DW_FORM_indirect"; + char *form_indir2 = ") "; + esb_append(esbp, form_indir); + if(local_verbose) { + esb_append(esbp, get_form_number_as_string(DW_FORM_indirect, + small_buf,sizeof(small_buf))); + } + esb_append(esbp, form_indir2); + } + if(local_show_form) { + esb_append(esbp," <form "); + esb_append(esbp,get_FORM_name(theform, + dwarf_names_print_on_error)); + if(local_verbose) { + esb_append(esbp, get_form_number_as_string(theform, + small_buf, sizeof(small_buf))); + } + esb_append(esbp,">"); + } +} + + +#include "tmp-ta-table.c" +#include "tmp-ta-ext-table.c" + +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.c" +#include "tmp-tt-ext-table.c" + +/* Look only at valid table entries + The check here must match the building-logic in + tag_tree.c + And must match the tags defined in dwarf.h + The tag_tree_combination_table is a table of bit flags. */ +static int +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); +} + diff --git a/dwarfdump/print_frames.c b/dwarfdump/print_frames.c new file mode 100644 index 0000000..01e4130 --- /dev/null +++ b/dwarfdump/print_frames.c @@ -0,0 +1,1823 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2011 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2007-2011 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_frames.c,v 1.5 2006/06/14 20:34:02 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. +*/ + +/* From 199x through 2010 print_frames relied on + the order of the fdes matching the order of the functions + in the CUs when it came to printing a function name with + an FDE. This sometimes worked for SGI/IRIX because of + the way the compiler often emitted things. It always worked poorly + for gcc and other compilers. + + As of 2010 the addrmap.h addrmap.h code provides help + in doing a better job when the tsearch functions (part of + POSIX) are available. */ + +#include "globals.h" + +#include "print_frames.h" +#include "dwconf.h" +#include "esb.h" +#include "addrmap.h" + +static void +print_one_frame_reg_col(Dwarf_Debug dbg, + Dwarf_Unsigned rule_id, + Dwarf_Small value_type, + Dwarf_Unsigned reg_used, + Dwarf_Half addr_size, + struct dwconf_s *config_data, + Dwarf_Signed offset_relevant, + Dwarf_Signed offset, Dwarf_Ptr block_ptr); + +/* A strcpy which ensures NUL terminated string + and never overruns the output. +*/ +void +safe_strcpy(char *out, long outlen, const char *in, long inlen) +{ + if (inlen >= (outlen - 1)) { + strncpy(out, in, outlen - 1); + out[outlen - 1] = 0; + } else { + strcpy(out, in); + } +} + +/* For inlined functions, try to find name */ +static int +get_abstract_origin_funcname(Dwarf_Debug dbg,Dwarf_Attribute attr, + char *name_out, unsigned maxlen) +{ + Dwarf_Off off = 0; + Dwarf_Die origin_die = 0; + Dwarf_Attribute *atlist = NULL; + Dwarf_Signed atcnt = 0; + Dwarf_Signed i = 0; + int dres = 0; + int atres; + int name_found = 0; + int res = dwarf_global_formref(attr,&off,&err); + if(res != DW_DLV_OK) { + return DW_DLV_NO_ENTRY; + } + dres = dwarf_offdie(dbg,off,&origin_die,&err); + if(dres != DW_DLV_OK) { + return DW_DLV_NO_ENTRY; + } + atres = dwarf_attrlist(origin_die, &atlist, &atcnt, &err); + if (atres != DW_DLV_OK) { + dwarf_dealloc(dbg,origin_die,DW_DLA_DIE); + return DW_DLV_NO_ENTRY; + } + for (i = 0; i < atcnt; i++) { + Dwarf_Half lattr; + int ares; + ares = dwarf_whatattr(atlist[i], &lattr, &err); + if (ares == DW_DLV_ERROR) { + break; + } else if (ares == DW_DLV_OK) { + if(lattr == DW_AT_name) { + int sres = 0; + char* temps = 0; + sres = dwarf_formstring(atlist[i], &temps, &err); + if (sres == DW_DLV_OK) { + long len = (long) strlen(temps); + safe_strcpy(name_out, maxlen, temps, len); + name_found = 1; + break; + } + } + } + } + for (i = 0; i < atcnt; i++) { + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); + dwarf_dealloc(dbg,origin_die,DW_DLA_DIE); + if(!name_found) { + return DW_DLV_NO_ENTRY; + } + return DW_DLV_OK; +} +/* + Returns 1 if a proc with this low_pc found. + Else returns 0. + + From print_die.c this has no pcMap passed in, + we do not really have a sensible context, so this + really just looks at the current attributes for a name. +*/ +int +get_proc_name(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr low_pc, + char *proc_name_buf, int proc_name_buf_len, void **pcMap) +{ + Dwarf_Signed atcnt = 0; + Dwarf_Signed i = 0; + Dwarf_Attribute *atlist = NULL; + Dwarf_Addr low_pc_die = 0; + int atres = 0; + int funcres = 1; + int funcpcfound = 0; + int funcnamefound = 0; + + proc_name_buf[0] = 0; /* always set to something */ + if(pcMap) { + struct Addr_Map_Entry *ame = 0; + ame = addr_map_find(low_pc,pcMap); + if(ame && ame->mp_name) { + /* mp_name is NULL only if we ran out of heap space. */ + safe_strcpy(proc_name_buf, proc_name_buf_len, + ame->mp_name,(long) strlen(ame->mp_name)); + return 1; + } + } + + atres = dwarf_attrlist(die, &atlist, &atcnt, &err); + if (atres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_attrlist", atres, err); + return 0; + } + if (atres == DW_DLV_NO_ENTRY) { + return 0; + } + for (i = 0; i < atcnt; i++) { + Dwarf_Half attr = 0; + int ares = 0; + string temps = 0; + int sres = 0; + int dres = 0; + + if (funcnamefound == 1 && funcpcfound == 1) { + /* stop as soon as both found */ + break; + } + ares = dwarf_whatattr(atlist[i], &attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "get_proc_name whatattr error", ares, err); + } else if (ares == DW_DLV_OK) { + switch (attr) { + case DW_AT_specification: + case DW_AT_abstract_origin: + { + if(!funcnamefound) { + /* Only use this if we have not seen DW_AT_name + yet .*/ + int aores = get_abstract_origin_funcname(dbg, + atlist[i], proc_name_buf,proc_name_buf_len); + if(aores == DW_DLV_OK) { + /* FOUND THE NAME */ + funcnamefound = 1; + } + } + } + break; + case DW_AT_name: + /* Even if we saw DW_AT_abstract_origin, go ahead + and take DW_AT_name. */ + sres = dwarf_formstring(atlist[i], &temps, &err); + if (sres == DW_DLV_ERROR) { + print_error(dbg, + "formstring in get_proc_name failed", + sres, err); + /* 50 is safe wrong length since is bigger than the + actual string */ + safe_strcpy(proc_name_buf, proc_name_buf_len, + "ERROR in dwarf_formstring!", 50); + } else if (sres == DW_DLV_NO_ENTRY) { + /* 50 is safe wrong length since is bigger than the + actual string */ + safe_strcpy(proc_name_buf, proc_name_buf_len, + "NO ENTRY on dwarf_formstring?!", 50); + } else { + long len = (long) strlen(temps); + + safe_strcpy(proc_name_buf, proc_name_buf_len, temps, + len); + } + funcnamefound = 1; /* FOUND THE NAME */ + break; + case DW_AT_low_pc: + dres = dwarf_formaddr(atlist[i], &low_pc_die, &err); + if (dres == DW_DLV_ERROR) { + print_error(dbg, "formaddr in get_proc_name failed", + dres, err); + low_pc_die = ~low_pc; + /* ensure no match */ + } + funcpcfound = 1; + + break; + default: + break; + } + } + } + for (i = 0; i < atcnt; i++) { + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); + if(funcnamefound && funcpcfound && pcMap ) { + /* Insert every name to map, not just the one + we are looking for. + This version does extra work in that + early symbols in a CU will be inserted + multiple times (the extra times have no + effect), the dwarfdump2 + version of this does less work. */ + addr_map_insert(low_pc_die,proc_name_buf,pcMap); + } + if (funcnamefound == 0 || funcpcfound == 0 || low_pc != low_pc_die) { + funcres = 0; + } + return (funcres); +} + +/* Modified Depth First Search looking for the procedure: + a) only looks for children of subprogram. + b) With subprogram looks at current die *before* looking + for a child. + + Needed since some languages, including SGI MP Fortran, + have nested functions. + Return 0 on failure, 1 on success. +*/ +static int +load_nested_proc_name(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr low_pc, + char *ret_name_buf, int ret_name_buf_len, + void **pcMap) +{ + char name_buf[BUFSIZ]; + Dwarf_Die curdie = die; + int die_locally_gotten = 0; + Dwarf_Die prev_child = 0; + Dwarf_Die newchild = 0; + Dwarf_Die newsibling = 0; + Dwarf_Half tag; + Dwarf_Error err = 0; + int chres = DW_DLV_OK; + + ret_name_buf[0] = 0; + name_buf[0] = 0; + while (chres == DW_DLV_OK) { + int tres; + + tres = dwarf_tag(curdie, &tag, &err); + newchild = 0; + err = 0; + if (tres == DW_DLV_OK) { + int lchres; + + if (tag == DW_TAG_subprogram) { + int proc_name_v = get_proc_name(dbg, curdie, low_pc, + name_buf, BUFSIZ,pcMap); + if (proc_name_v) { + safe_strcpy(ret_name_buf, ret_name_buf_len, + name_buf, (long) strlen(name_buf)); + if (die_locally_gotten) { + /* If we got this die from the parent, we do + not want to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 1; + } + /* Check children of subprograms recursively should + this really be check children of anything, + or just children of subprograms? */ + + lchres = dwarf_child(curdie, &newchild, &err); + if (lchres == DW_DLV_OK) { + /* look for inner subprogram */ + int newprog = + load_nested_proc_name(dbg, newchild, low_pc, + name_buf, BUFSIZ, + pcMap); + + dwarf_dealloc(dbg, newchild, DW_DLA_DIE); + if (newprog) { + /* Found it. We could just take this name or + we could concatenate names together For now, + just take name */ + if (die_locally_gotten) { + /* If we got this die from the parent, we + do not want to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + safe_strcpy(ret_name_buf, ret_name_buf_len, + name_buf, (long) strlen(name_buf)); + return 1; + } + } else if (lchres == DW_DLV_NO_ENTRY) { + /* nothing to do */ + } else { + print_error(dbg, + "load_nested_proc_name dwarf_child() failed ", + chres, err); + if (die_locally_gotten) { + /* If we got this die from the parent, we do + not want to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; + } + } /* end if TAG_subprogram */ + } else { + print_error(dbg, "no tag on child read ", tres, err); + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; + } + /* try next sibling */ + prev_child = curdie; + chres = dwarf_siblingof(dbg, curdie, &newsibling, &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_cu_header On Child read ", chres, + err); + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; + } else if (chres == DW_DLV_NO_ENTRY) { + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, prev_child, DW_DLA_DIE); + } + return 0;/* proc name not at this level */ + } else { + /* DW_DLV_OK */ + curdie = newsibling; + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, prev_child, DW_DLA_DIE); + } + prev_child = 0; + die_locally_gotten = 1; + } + + } + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want to + dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; +} + +/* For SGI MP Fortran and other languages, functions + nest! As a result, we must dig thru all functions, + not just the top level. + This remembers the CU die and restarts each search at the start + of the current cu. +*/ +static string +get_fde_proc_name(Dwarf_Debug dbg, Dwarf_Addr low_pc, + void **pcMap, + int *all_cus_seen) +{ + static char proc_name[BUFSIZ]; + Dwarf_Unsigned cu_header_length = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half version_stamp = 0; + Dwarf_Half address_size = 0; + Dwarf_Unsigned next_cu_offset = 0; + int cures = DW_DLV_OK; + int dres = DW_DLV_OK; + int chres = DW_DLV_OK; + int looping = 0; + + proc_name[0] = 0; + { + struct Addr_Map_Entry *ame = 0; + ame = addr_map_find(low_pc,pcMap); + if(ame && ame->mp_name) { + /* mp_name is only NULL here if we just ran out of heap memory! */ + safe_strcpy(proc_name, sizeof(proc_name), + ame->mp_name,(long) strlen(ame->mp_name)); + return proc_name; + } + if (*all_cus_seen) { + return ""; + } + } + if (current_cu_die_for_print_frames == NULL) { + /* Call depends on dbg->cu_context to know what to do. */ + cures = dwarf_next_cu_header(dbg, &cu_header_length, + &version_stamp, &abbrev_offset, + &address_size, &next_cu_offset, + &err); + if (cures == DW_DLV_ERROR) { + return NULL; + } else if (cures == DW_DLV_NO_ENTRY) { + /* loop thru the list again */ + current_cu_die_for_print_frames = 0; + ++looping; + } else { /* DW_DLV_OK */ + dres = dwarf_siblingof(dbg, NULL, + ¤t_cu_die_for_print_frames, + &err); + if (dres == DW_DLV_ERROR) { + return NULL; + } + } + } + if (dres == DW_DLV_OK) { + Dwarf_Die child = 0; + + if (current_cu_die_for_print_frames == 0) { + /* no information. Possibly a stripped file */ + return NULL; + } + chres = + dwarf_child(current_cu_die_for_print_frames, &child, &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_cu_header on child read ", chres, + err); + } else if (chres == DW_DLV_NO_ENTRY) { + } else { /* DW_DLV_OK */ + int gotname = + load_nested_proc_name(dbg, child, low_pc, proc_name, + BUFSIZ,pcMap); + + dwarf_dealloc(dbg, child, DW_DLA_DIE); + if (gotname) { + return (proc_name); + } + child = 0; + } + } + for (;;) { + Dwarf_Die ldie = 0; + + cures = dwarf_next_cu_header(dbg, &cu_header_length, + &version_stamp, &abbrev_offset, + &address_size, &next_cu_offset, + &err); + if (cures != DW_DLV_OK) { + *all_cus_seen = 1; + break; + } + + dres = dwarf_siblingof(dbg, NULL, &ldie, &err); + if (current_cu_die_for_print_frames) { + dwarf_dealloc(dbg, current_cu_die_for_print_frames, + DW_DLA_DIE); + } + current_cu_die_for_print_frames = 0; + if (dres == DW_DLV_ERROR) { + print_error(dbg, + "dwarf_cu_header Child Read finding proc name for .debug_frame", + chres, err); + continue; + } else if (dres == DW_DLV_NO_ENTRY) { + ++looping; + if (looping > 1) { + print_error(dbg, "looping on cu headers!", dres, err); + return NULL; + } + continue; + } + /* DW_DLV_OK */ + current_cu_die_for_print_frames = ldie; + { + int chres = 0; + Dwarf_Die child = 0; + + chres = + dwarf_child(current_cu_die_for_print_frames, &child, + &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf Child Read ", chres, err); + } else if (chres == DW_DLV_NO_ENTRY) { + + ;/* do nothing, loop on cu */ + } else { + /* DW_DLV_OK) */ + + int gotname = + load_nested_proc_name(dbg, child, low_pc, proc_name, + BUFSIZ,pcMap); + + dwarf_dealloc(dbg, child, DW_DLA_DIE); + if (gotname) { + return (proc_name); + } + } + } + } + return (NULL); +} + +/* Gather the fde print logic here so the control logic + determining what FDE to print is clearer. */ +static int +print_one_fde(Dwarf_Debug dbg, Dwarf_Fde fde, + Dwarf_Unsigned fde_index, + Dwarf_Cie * cie_data, + Dwarf_Signed cie_element_count, + Dwarf_Half address_size, int is_eh, + struct dwconf_s *config_data, + void **pcMap, + void **lowpcSet, + int * all_cus_seen) +{ + Dwarf_Addr j = 0; + Dwarf_Addr low_pc = 0; + Dwarf_Unsigned func_length = 0; + Dwarf_Ptr fde_bytes = NULL; + Dwarf_Unsigned fde_bytes_length = 0; + Dwarf_Off cie_offset = 0; + Dwarf_Signed cie_index = 0; + Dwarf_Off fde_offset = 0; + Dwarf_Signed eh_table_offset = 0; + int fres = 0; + int offres = 0; + string temps = 0; + Dwarf_Error err = 0; + int printed_intro_addr = 0; + + fres = dwarf_get_fde_range(fde, + &low_pc, &func_length, + &fde_bytes, + &fde_bytes_length, + &cie_offset, &cie_index, + &fde_offset, &err); + if (fres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_fde_range", fres, err); + } + if (fres == DW_DLV_NO_ENTRY) { + return DW_DLV_NO_ENTRY; + } + if (cu_name_flag && + fde_offset_for_cu_low != DW_DLV_BADOFFSET && + (fde_offset < fde_offset_for_cu_low || + fde_offset > fde_offset_for_cu_high)) { + return DW_DLV_NO_ENTRY; + } + /* eh_table_offset is IRIX ONLY. */ + fres = dwarf_get_fde_exception_info(fde, &eh_table_offset, &err); + if (fres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_fde_exception_info", fres, err); + } + if(suppress_nested_name_search) { + temps = 0; + } else { +#ifdef HAVE_TSEARCH + struct Addr_Map_Entry *mp = 0; + temps = get_fde_proc_name(dbg, low_pc,pcMap,all_cus_seen); + mp = addr_map_find(low_pc,lowpcSet); + if (check_frames || check_frames_extended) { + DWARF_CHECK_COUNT(fde_duplication,1); + } + if (mp) { + if (check_frames || check_frames_extended) { + char msg[400]; + if(temps && (strlen(temps) > 0)) { + snprintf(msg,sizeof(msg),"An fde low pc of 0x%" + DW_PR_DUx + " is not the first fde with that pc. " + "The first is named \"%s\"", + (Dwarf_Unsigned)low_pc, + temps); + } else { + snprintf(msg,sizeof(msg),"An fde low pc of 0x%" + DW_PR_DUx + " is not the first fde with that pc. " + "The first is not named.", + (Dwarf_Unsigned)low_pc); + + } + DWARF_CHECK_ERROR(fde_duplication,msg); + } + } else { + addr_map_insert(low_pc,0,lowpcSet); + } +#endif + } + + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("<%5" DW_PR_DSd "><0x%" DW_PR_XZEROS DW_PR_DUx + ":0x%" DW_PR_XZEROS DW_PR_DUx + "><%s><fde offset 0x%" DW_PR_XZEROS DW_PR_DUx + " length: 0x%" DW_PR_XZEROS DW_PR_DUx ">", + cie_index, (Dwarf_Unsigned)low_pc, + (Dwarf_Unsigned)(low_pc + func_length), + temps ? temps : "", (Dwarf_Unsigned)fde_offset, fde_bytes_length); + } + + + + if (!is_eh) { + /* IRIX uses eh_table_offset. */ + /* Do not print if in check mode */ + if (!check_frames_extended) { + if (eh_table_offset == DW_DLX_NO_EH_OFFSET) { + printf("<eh offset %s>\n", "none"); + } else if (eh_table_offset == DW_DLX_EH_OFFSET_UNAVAILABLE) { + printf("<eh offset %s>\n", "unknown"); + } else { + printf("<eh offset 0x%" DW_PR_XZEROS DW_PR_DUx + ">\n", eh_table_offset); + } + } + } else { + int ares = 0; + Dwarf_Small *data = 0; + Dwarf_Unsigned len = 0; + + ares = dwarf_get_fde_augmentation_data(fde, &data, &len, &err); + if (ares == DW_DLV_NO_ENTRY) { + /* do nothing. */ + } else if (ares == DW_DLV_OK) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + int k2 = 0; + + printf("<eh aug data len 0x%" DW_PR_DUx , len); + for (k2 = 0; k2 < len; ++k2) { + if (k2 == 0) { + printf(" bytes 0x"); + } + printf("%02x ", (unsigned char) data[k2]); + } + printf(">"); + } + } /* else DW_DLV_ERROR, do nothing */ + + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\n"); + + } + } + + for (j = low_pc; j < low_pc + func_length; j++) { + Dwarf_Half k = 0; + + if (config_data->cf_interface_number == 3) { + Dwarf_Signed reg = 0; + Dwarf_Signed offset_relevant = 0; + Dwarf_Small value_type = 0; + Dwarf_Signed offset_or_block_len = 0; + Dwarf_Signed offset = 0; + Dwarf_Ptr block_ptr = 0; + Dwarf_Addr row_pc = 0; + + int fires = dwarf_get_fde_info_for_cfa_reg3(fde, + j, + &value_type, + &offset_relevant, + ®, + &offset_or_block_len, + &block_ptr, + &row_pc, + &err); + offset = offset_or_block_len; + if (fires == DW_DLV_ERROR) { + print_error(dbg, + "dwarf_get_fde_info_for_reg", fires, err); + } + if (fires == DW_DLV_NO_ENTRY) { + continue; + } + if (row_pc != j) { + /* duplicate row */ + continue; + } + + /* Do not print if in check mode */ + if (!printed_intro_addr && !check_frames_extended) { + printf(" 0x%" DW_PR_XZEROS DW_PR_DUx + ": ", (Dwarf_Unsigned)j); + printed_intro_addr = 1; + } + print_one_frame_reg_col(dbg, config_data->cf_cfa_reg, + value_type, + reg, + address_size, + config_data, + offset_relevant, offset, block_ptr); + } + for (k = 0; k < config_data->cf_table_entry_count; k++) { + Dwarf_Signed reg = 0; + Dwarf_Signed offset_relevant = 0; + int fires = 0; + Dwarf_Small value_type = 0; + Dwarf_Ptr block_ptr = 0; + Dwarf_Signed offset_or_block_len = 0; + Dwarf_Signed offset = 0; + Dwarf_Addr row_pc = 0; + + if (config_data->cf_interface_number == 3) { + fires = dwarf_get_fde_info_for_reg3(fde, + k, + j, + &value_type, + &offset_relevant, + ®, + &offset_or_block_len, + &block_ptr, + &row_pc, &err); + offset = offset_or_block_len; + } else { + /* This interface is deprecated. Is the old + MIPS/DWARF2 interface. */ + /* ASSERT: config_data->cf_interface_number == 2 */ + value_type = DW_EXPR_OFFSET; + fires = dwarf_get_fde_info_for_reg(fde, + k, + j, + &offset_relevant, + ®, + &offset, &row_pc, + &err); + } + if (fires == DW_DLV_ERROR) { + printf("\n"); + print_error(dbg, + "dwarf_get_fde_info_for_reg", fires, err); + } + if (fires == DW_DLV_NO_ENTRY) { + continue; + } + if (row_pc != j) { + /* duplicate row */ + break; + } + + /* Do not print if in check mode */ + if (!printed_intro_addr && !check_frames_extended) { + printf(" 0x%" DW_PR_XZEROS DW_PR_DUx ": ", + (Dwarf_Unsigned)j); + printed_intro_addr = 1; + } + print_one_frame_reg_col(dbg,k, + value_type, + reg, + address_size, + config_data, + offset_relevant, offset, block_ptr); + } + if (printed_intro_addr) { + printf("\n"); + printed_intro_addr = 0; + } + } + if (verbose > 1) { + Dwarf_Off fde_off = 0; + Dwarf_Off cie_off = 0; + + /* Get the fde instructions and print them in raw form, just + like cie instructions */ + Dwarf_Ptr instrs = 0; + Dwarf_Unsigned ilen = 0; + int res = 0; + + res = dwarf_get_fde_instr_bytes(fde, &instrs, &ilen, &err); + offres = + dwarf_fde_section_offset(dbg, fde, &fde_off, &cie_off, + &err); + if (offres == DW_DLV_OK) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf(" fde section offset %" DW_PR_DUu + " 0x%" DW_PR_XZEROS DW_PR_DUx + " cie offset for fde: %" DW_PR_DUu + " 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Unsigned) fde_off, + (Dwarf_Unsigned) fde_off, + (Dwarf_Unsigned) cie_off, + (Dwarf_Unsigned) cie_off); + } + } + + + if (res == DW_DLV_OK) { + int cires = 0; + Dwarf_Unsigned cie_length = 0; + Dwarf_Small version = 0; + string augmenter = 0; + Dwarf_Unsigned code_alignment_factor = 0; + Dwarf_Signed data_alignment_factor = 0; + Dwarf_Half return_address_register_rule = 0; + Dwarf_Ptr initial_instructions = 0; + Dwarf_Unsigned initial_instructions_length = 0; + + if (cie_index >= cie_element_count) { + printf("Bad cie index %" DW_PR_DSd + " with fde index %" DW_PR_DUu "! " + "(table entry max %" DW_PR_DSd ")\n", + cie_index, fde_index, + cie_element_count); + exit(1); + } + cires = dwarf_get_cie_info(cie_data[cie_index], + &cie_length, + &version, + &augmenter, + &code_alignment_factor, + &data_alignment_factor, + &return_address_register_rule, + &initial_instructions, + &initial_instructions_length, + &err); + if (cires == DW_DLV_ERROR) { + printf + ("Bad cie index %" DW_PR_DSd + " with fde index %" DW_PR_DUu "!\n", + cie_index, fde_index); + print_error(dbg, "dwarf_get_cie_info", cires, err); + } + if (cires == DW_DLV_NO_ENTRY) { + ; /* ? */ + } else { + /* Do not print if in check mode */ + if (!check_frames_extended) { + print_frame_inst_bytes(dbg, instrs, + (Dwarf_Signed) ilen, + data_alignment_factor, + (int) code_alignment_factor, + address_size, config_data); + } + } + } else if (res == DW_DLV_NO_ENTRY) { + printf("Impossible: no instr bytes for fde index %" + DW_PR_DUu "?\n", + fde_index); + } else { + /* DW_DLV_ERROR */ + printf("Error: on gettinginstr bytes for fde index %" + DW_PR_DUu "?\n", + fde_index); + print_error(dbg, "dwarf_get_fde_instr_bytes", res, err); + } + + } + return DW_DLV_OK; +} + + +/* Print a cie. Gather the print logic here so the + control logic deciding what to print + is clearer. +*/ +int +print_one_cie(Dwarf_Debug dbg, Dwarf_Cie cie, + Dwarf_Unsigned cie_index, Dwarf_Half address_size, + struct dwconf_s *config_data) +{ + + int cires = 0; + Dwarf_Unsigned cie_length = 0; + Dwarf_Small version = 0; + string augmenter = ""; + Dwarf_Unsigned code_alignment_factor = 0; + Dwarf_Signed data_alignment_factor = 0; + Dwarf_Half return_address_register_rule = 0; + Dwarf_Ptr initial_instructions = 0; + Dwarf_Unsigned initial_instructions_length = 0; + Dwarf_Off cie_off = 0; + Dwarf_Error err = 0; + + cires = dwarf_get_cie_info(cie, + &cie_length, + &version, + &augmenter, + &code_alignment_factor, + &data_alignment_factor, + &return_address_register_rule, + &initial_instructions, + &initial_instructions_length, &err); + if (cires == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_cie_info", cires, err); + } + if (cires == DW_DLV_NO_ENTRY) { + printf("Impossible DW_DLV_NO_ENTRY on cie %" DW_PR_DUu "\n", + cie_index); + return DW_DLV_NO_ENTRY; + } + { + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("<%5" DW_PR_DUu ">\tversion\t\t\t\t%d\n", + cie_index, version); + cires = dwarf_cie_section_offset(dbg, cie, &cie_off, &err); + if (cires == DW_DLV_OK) { + printf("\tcie section offset\t\t%" DW_PR_DUu + " 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Unsigned) cie_off, + (Dwarf_Unsigned) cie_off); + } + printf("\taugmentation\t\t\t%s\n", augmenter); + printf("\tcode_alignment_factor\t\t%" DW_PR_DUu "\n", + code_alignment_factor); + printf("\tdata_alignment_factor\t\t%" DW_PR_DSd "\n", + data_alignment_factor); + printf("\treturn_address_register\t\t%d\n", + return_address_register_rule); + } + + { + int ares = 0; + Dwarf_Small *data = 0; + Dwarf_Unsigned len = 0; + + ares = + dwarf_get_cie_augmentation_data(cie, &data, &len, &err); + if (ares == DW_DLV_NO_ENTRY) { + /* do nothing. */ + } else if (ares == DW_DLV_OK && len > 0) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + int k2 = 0; + + printf(" eh aug data len 0x%" DW_PR_DUx , len); + for (k2 = 0; data && k2 < len; ++k2) { + if (k2 == 0) { + printf(" bytes 0x"); + } + printf("%02x ", (unsigned char) data[k2]); + } + printf("\n"); + } + } /* else DW_DLV_ERROR or no data, do nothing */ + } + + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\tbytes of initial instructions\t%" DW_PR_DUu "\n", + initial_instructions_length); + printf("\tcie length\t\t\t%" DW_PR_DUu "\n", cie_length); + /* For better layout */ + printf("\tinitial instructions\n"); + print_frame_inst_bytes(dbg, initial_instructions, + (Dwarf_Signed) initial_instructions_length, + data_alignment_factor, + (int) code_alignment_factor, + address_size, config_data); + } + } + return DW_DLV_OK; +} + +void +get_string_from_locs(Dwarf_Debug dbg, + Dwarf_Ptr bytes_in, + Dwarf_Unsigned block_len, + Dwarf_Half addr_size, + struct esb_s *out_string) +{ + + Dwarf_Locdesc *locdescarray = 0; + Dwarf_Signed listlen = 0; + Dwarf_Error err2 =0; + int skip_locdesc_header=1; + int res = 0; + int res2 = dwarf_loclist_from_expr_a(dbg, + bytes_in,block_len, + addr_size, + &locdescarray, + &listlen,&err2); + if (res2 == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_loclist_from_expr_a", + res2, err2); + } + if(res2==DW_DLV_NO_ENTRY) { + return; + } + /* lcnt is always 1 */ + + /* Use locdescarray here.*/ + res = dwarfdump_print_one_locdesc(dbg, + locdescarray, + skip_locdesc_header, + out_string); + if(res != DW_DLV_OK) { + printf("Bad status from _dwarf_print_one_locdesc %d\n",res); + exit(1); + } + + dwarf_dealloc(dbg, locdescarray->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(dbg, locdescarray, DW_DLA_LOCDESC); + return ; +} + +/* Print the frame instructions in detail for a glob of instructions. +*/ + +/*ARGSUSED*/ void +print_frame_inst_bytes(Dwarf_Debug dbg, + Dwarf_Ptr cie_init_inst, Dwarf_Signed len, + Dwarf_Signed data_alignment_factor, + int code_alignment_factor, Dwarf_Half addr_size, + struct dwconf_s *config_data) +{ + unsigned char *instp = (unsigned char *) cie_init_inst; + Dwarf_Unsigned uval = 0; + Dwarf_Unsigned uval2 = 0; + unsigned int uleblen = 0; + unsigned int off = 0; + unsigned int loff = 0; + unsigned short u16 = 0; + unsigned int u32 = 0; + unsigned long long u64; + + for (; len > 0;) { + unsigned char ibyte = *instp; + int top = ibyte & 0xc0; + int bottom = ibyte & 0x3f; + int delta = 0; + int reg = 0; + + switch (top) { + case DW_CFA_advance_loc: + delta = ibyte & 0x3f; + printf("\t%2u DW_CFA_advance_loc %d", off, + (int) (delta * code_alignment_factor)); + if (verbose) { + printf(" (%d * %d)", (int) delta, + (int) code_alignment_factor); + } + printf("\n"); + break; + case DW_CFA_offset: + loff = off; + reg = ibyte & 0x3f; + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_offset ", loff); + printreg((Dwarf_Signed) reg, config_data); + printf(" %" DW_PR_DSd , (Dwarf_Signed) + (((Dwarf_Signed) uval) * data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DUu " * %" DW_PR_DSd ")", uval, + data_alignment_factor); + } + printf("\n"); + break; + + case DW_CFA_restore: + reg = ibyte & 0x3f; + printf("\t%2u DW_CFA_restore ", off); + printreg((Dwarf_Signed) reg, config_data); + printf("\n"); + break; + + default: + loff = off; + switch (bottom) { + case DW_CFA_set_loc: + /* operand is address, so need address size */ + /* which will be 4 or 8. */ + switch (addr_size) { + case 4: + { + __uint32_t v32 = 0; + memcpy(&v32, instp + 1, addr_size); + uval = v32; + } + break; + case 8: + { + __uint64_t v64 = 0; + memcpy(&v64, instp + 1, addr_size); + uval = v64; + } + break; + default: + printf + ("Error: Unexpected address size %d in DW_CFA_set_loc!\n", + addr_size); + uval = 0; + } + + instp += addr_size; + len -= (Dwarf_Signed) addr_size; + off += addr_size; + printf("\t%2u DW_CFA_set_loc %" DW_PR_DUu "\n", + loff, uval); + break; + case DW_CFA_advance_loc1: + delta = (unsigned char) *(instp + 1); + uval2 = delta; + instp += 1; + len -= 1; + off += 1; + printf("\t%2u DW_CFA_advance_loc1 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_advance_loc2: + memcpy(&u16, instp + 1, 2); + uval2 = u16; + instp += 2; + len -= 2; + off += 2; + printf("\t%2u DW_CFA_advance_loc2 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_advance_loc4: + memcpy(&u32, instp + 1, 4); + uval2 = u32; + instp += 4; + len -= 4; + off += 4; + printf("\t%2u DW_CFA_advance_loc4 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_MIPS_advance_loc8: + memcpy(&u64, instp + 1, 8); + uval2 = u64; + instp += 8; + len -= 8; + off += 8; + printf("\t%2u DW_CFA_MIPS_advance_loc8 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_offset_extended: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_offset_extended ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , + (Dwarf_Signed) (((Dwarf_Signed) uval2) * + data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DUu " * %d)", uval2, + (int) data_alignment_factor); + } + printf("\n"); + break; + + case DW_CFA_restore_extended: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_restore_extended ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_undefined: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_undefined ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_same_value: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_same_value ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_register: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_register ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" = "); + printreg((Dwarf_Signed) uval2, config_data); + printf("\n"); + break; + case DW_CFA_remember_state: + printf("\t%2u DW_CFA_remember_state\n", loff); + break; + case DW_CFA_restore_state: + printf("\t%2u DW_CFA_restore_state\n", loff); + break; + case DW_CFA_def_cfa: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DUu , (unsigned long long) uval2); + printf("\n"); + break; + case DW_CFA_def_cfa_register: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_register ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_def_cfa_offset: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_offset %" DW_PR_DUu "\n", + loff, uval); + break; + + case DW_CFA_nop: + printf("\t%2u DW_CFA_nop\n", loff); + break; + + case DW_CFA_def_cfa_expression: /* DWARF3 */ + { + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf + ("\t%2u DW_CFA_def_cfa_expression expr block len %" + DW_PR_DUu "\n", + loff, + block_len); + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + printf("\n"); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + instp+1,block_len,addr_size,&exprstring); + printf("\t\t%s\n",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + instp += block_len; + len -= block_len; + off += block_len; + } + break; + case DW_CFA_expression: /* DWARF3 */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf + ("\t%2u DW_CFA_expression %" DW_PR_DUu + " expr block len %" DW_PR_DUu "\n", + loff, uval, + block_len); + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + printf("\n"); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + instp+1,block_len,addr_size,&exprstring); + printf("\t\t%s\n",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + instp += block_len; + len -= block_len; + off += block_len; + } + break; + case DW_CFA_offset_extended_sf: /* DWARF3 */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_offset_extended_sf ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , (Dwarf_Signed) + ((sval2) * data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DSd " * %d)", sval2, + (int) data_alignment_factor); + } + } + printf("\n"); + break; + case DW_CFA_def_cfa_sf: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_sf ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , (long long) sval2); + printf(" (*data alignment factor=>%" DW_PR_DSd ")", + (Dwarf_Signed)(sval2*data_alignment_factor)); + } + printf("\n"); + break; + case DW_CFA_def_cfa_offset_sf: /* DWARF3 */ + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Signed sval = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_offset_sf %" + DW_PR_DSd " (*data alignment factor=> %" + DW_PR_DSd ")\n", + loff, sval, + (Dwarf_Signed)(data_alignment_factor*sval)); + + } + break; + case DW_CFA_val_offset: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_val_offset ", loff); + printreg((Dwarf_Signed)uval, config_data); + printf(" %" DW_PR_DSd , + (Dwarf_Signed) (sval2 * + data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DSd " * %d)", + (Dwarf_Signed) sval2, + (int) data_alignment_factor); + } + } + printf("\n"); + + break; + case DW_CFA_val_offset_sf: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_val_offset_sf ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , (signed long long) + ((sval2) * data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DSd " * %d)", sval2, + (int) data_alignment_factor); + } + } + printf("\n"); + + break; + case DW_CFA_val_expression: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf + ("\t%2u DW_CFA_val_expression %" DW_PR_DUu + " expr block len %" DW_PR_DUu "\n", + loff, uval, + block_len); + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + printf("\n"); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + instp+1,block_len,addr_size,&exprstring); + printf("\t\t%s\n",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + instp += block_len; + len -= block_len; + off += block_len; + } + + + break; + + +#ifdef DW_CFA_GNU_window_save + case DW_CFA_GNU_window_save:{ + /* no information: this just tells unwinder to + restore the window registers from the previous + frame's window save area */ + printf("\t%2u DW_CFA_GNU_window_save \n", loff); + } + break; +#endif +#ifdef DW_CFA_GNU_negative_offset_extended + case DW_CFA_GNU_negative_offset_extended:{ + printf("\t%2u DW_CFA_GNU_negative_offset_extended \n", + loff); + } + break; +#endif +#ifdef DW_CFA_GNU_args_size + /* single uleb128 is the current arg area size in + bytes. no register exists yet to save this in */ + case DW_CFA_GNU_args_size:{ + Dwarf_Unsigned lreg = 0; + + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + lreg = local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + printf("\t%2u DW_CFA_GNU_args_size arg size: %" + DW_PR_DUu "\n", + loff, lreg); + instp += uleblen; + len -= uleblen; + off += uleblen; + } + break; +#endif + + default: + printf(" %u Unexpected op 0x%x: \n", + loff, (unsigned int) bottom); + len = 0; + break; + } + } + instp++; + len--; + off++; + } +} + +/* Print our register names for the cases we have a name. + Delegate to the configure code to actually do the print. +*/ +void +printreg(Dwarf_Signed reg, struct dwconf_s *config_data) +{ + print_reg_from_config_data(reg, config_data); +} + +/* Actually does the printing of a rule in the table. + This may print something or may print nothing! */ +static void +print_one_frame_reg_col(Dwarf_Debug dbg, + Dwarf_Unsigned rule_id, + Dwarf_Small value_type, + Dwarf_Unsigned reg_used, + Dwarf_Half addr_size, + struct dwconf_s *config_data, + Dwarf_Signed offset_relevant, + Dwarf_Signed offset, + Dwarf_Ptr block_ptr) +{ + char *type_title = ""; + int print_type_title = 1; + + if (check_frames_extended) { + return; + } + + if (config_data->cf_interface_number == 2) + print_type_title = 0; + + switch (value_type) { + case DW_EXPR_OFFSET: + type_title = "off"; + goto preg2; + case DW_EXPR_VAL_OFFSET: + type_title = "valoff"; + + preg2: + if (reg_used == config_data->cf_initial_rule_value) { + break; + } + if (print_type_title) + printf("<%s ", type_title); + printreg((Dwarf_Signed) rule_id, config_data); + printf("="); + if (offset_relevant == 0) { + printreg((Dwarf_Signed) reg_used, config_data); + printf(" "); + } else { + printf("%02" DW_PR_DSd , offset); + printf("("); + printreg((Dwarf_Signed) reg_used, config_data); + printf(") "); + } + if (print_type_title) + printf("%s", "> "); + break; + case DW_EXPR_EXPRESSION: + type_title = "expr"; + goto pexp2; + case DW_EXPR_VAL_EXPRESSION: + type_title = "valexpr"; + + pexp2: + if (print_type_title) + printf("<%s ", type_title); + printreg((Dwarf_Signed) rule_id, config_data); + printf("="); + printf("expr-block-len=%" DW_PR_DSd , offset); + if (print_type_title) + printf("%s", "> "); + if (verbose) { + char pref[40]; + + strcpy(pref, "<"); + strcat(pref, type_title); + strcat(pref, "bytes:"); + dump_block(pref, block_ptr, offset); + printf("%s", "> "); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + block_ptr,offset,addr_size,&exprstring); + printf("<expr:%s>",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + } + break; + default: + printf("Internal error in libdwarf, value type %d\n", + value_type); + exit(1); + } + return; +} + + +/* get all the data in .debug_frame (or .eh_frame). + The '3' versions mean print using the dwarf3 new interfaces. + The non-3 mean use the old interfaces. + All combinations of requests are possible. */ +extern void +print_frames(Dwarf_Debug dbg, int print_debug_frame, int print_eh_frame, + struct dwconf_s *config_data) +{ + Dwarf_Signed i; + int fres = 0; + Dwarf_Half address_size = 0; + int framed = 0; + void * map_lowpc_to_name = 0; + + current_section_id = DEBUG_FRAME; + + /* The address size here will not be right for all frames. + Only in DWARF4 is there a real address size known + in the frame data itself. If any DIE + is known then a real address size can be gotten from + dwarf_get_die_address_size(). */ + fres = dwarf_get_address_size(dbg, &address_size, &err); + if (fres != DW_DLV_OK) { + print_error(dbg, "dwarf_get_address_size", fres, err); + } + for (framed = 0; framed < 2; ++framed) { + Dwarf_Cie *cie_data = NULL; + Dwarf_Signed cie_element_count = 0; + Dwarf_Fde *fde_data = NULL; + Dwarf_Signed fde_element_count = 0; + int frame_count = 0; + int cie_count = 0; + int all_cus_seen = 0; + void * lowpcSet = 0; + char *framename = 0; + int silent_if_missing = 0; + int is_eh = 0; + + if (framed == 0) { + if (!print_debug_frame) { + continue; + } + framename = ".debug_frame"; + /* Big question here is how to print all the info? + Can print the logical matrix, but that is huge, + though could skip lines that don't change. + Either that, or print the instruction statement program + that describes the changes. */ + fres = dwarf_get_fde_list(dbg, &cie_data, &cie_element_count, + &fde_data, &fde_element_count, &err); + if(check_harmless) { + print_any_harmless_errors(dbg); + } + } else { + if (!print_eh_frame) { + continue; + } + is_eh = 1; + /* This is gnu g++ exceptions in a .eh_frame section. Which + is just like .debug_frame except that the empty, or + 'special' CIE_id is 0, not -1 (to distinguish fde from + cie). And the augmentation is "eh". As of egcs-1.1.2 + anyway. A non-zero cie_id is in a fde and is the + difference between the fde address and the beginning of + the cie it belongs to. This makes sense as this is + intended to be referenced at run time, and is part of + the running image. For more on augmentation strings, see + libdwarf/dwarf_frame.c. */ + + /* Big question here is how to print all the info? + Can print the logical matrix, but that is huge, + though could skip lines that don't change. + Either that, or print the instruction statement program + that describes the changes. */ + silent_if_missing = 1; + framename = ".eh_frame"; + fres = dwarf_get_fde_list_eh(dbg, &cie_data, + &cie_element_count, &fde_data, + &fde_element_count, &err); + if(check_harmless) { + print_any_harmless_errors(dbg); + } + } + + /* Do not print any frame info if in check mode */ + if (check_frames) { + addr_map_destroy(lowpcSet); + lowpcSet = 0; + continue; + } + + if (fres == DW_DLV_ERROR) { + printf("\n%s\n", framename); + print_error(dbg, "dwarf_get_fde_list", fres, err); + } else if (fres == DW_DLV_NO_ENTRY) { + if (!silent_if_missing) { + printf("\n%s\n", framename); + } + /* no frame information */ + } else { /* DW_DLV_OK */ + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\n%s\n", framename); + printf("\nfde:\n"); + } + + for (i = 0; i < fde_element_count; i++) { + print_one_fde(dbg, fde_data[i], + i, cie_data, cie_element_count, + address_size, is_eh, config_data, + &map_lowpc_to_name, + &lowpcSet, + &all_cus_seen); + ++frame_count; + if(frame_count >= break_after_n_units) { + break; + } + } + /* Print the cie set. */ + if (verbose) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\ncie:\n"); + } + for (i = 0; i < cie_element_count; i++) { + print_one_cie(dbg, cie_data[i], i, address_size, + config_data); + ++cie_count; + if(cie_count >= break_after_n_units) { + break; + } + } + } + dwarf_fde_cie_list_dealloc(dbg, cie_data, cie_element_count, + fde_data, fde_element_count); + } + addr_map_destroy(lowpcSet); + lowpcSet = 0; + } + if (current_cu_die_for_print_frames) { + dwarf_dealloc(dbg, current_cu_die_for_print_frames, DW_DLA_DIE); + current_cu_die_for_print_frames = 0; + } + addr_map_destroy(map_lowpc_to_name); +} + diff --git a/dwarfdump/print_frames.h b/dwarfdump/print_frames.h new file mode 100644 index 0000000..2a133d8 --- /dev/null +++ b/dwarfdump/print_frames.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 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_frames.h,v 1.2 2006/04/17 00:09:56 davea Exp $ */ + +int print_one_cie(Dwarf_Debug dbg, Dwarf_Cie cie, + Dwarf_Unsigned cie_index, + Dwarf_Half address_size, + struct dwconf_s * config_data); + +void get_string_from_locs(Dwarf_Debug dbg, + Dwarf_Ptr bytes_in, + Dwarf_Unsigned block_len, + Dwarf_Half addr_size, + struct esb_s *out_string); + diff --git a/dwarfdump/print_lines.c b/dwarfdump/print_lines.c new file mode 100644 index 0000000..4b33994 --- /dev/null +++ b/dwarfdump/print_lines.c @@ -0,0 +1,433 @@ + +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" +#include "uri.h" +#include <ctype.h> + +#include "print_sections.h" + +/* + Print line number information: + [line] [address] <new statement> + new basic-block + filename +*/ + + +static void +print_source_intro(Dwarf_Die cu_die) +{ + Dwarf_Off off = 0; + int ores = dwarf_dieoffset(cu_die, &off, &err); + + if (ores == DW_DLV_OK) { + printf("Source lines (from CU-DIE at .debug_info offset 0x%" + DW_PR_XZEROS DW_PR_DUx "):\n", + (Dwarf_Unsigned) off); + } else { + printf("Source lines (for the CU-DIE at unknown location):\n"); + } +} + +static void +record_line_error(const char *where, Dwarf_Error err) +{ + char tmp_buff[500]; + if(check_lines && checking_this_compiler()) { + snprintf(tmp_buff, sizeof(tmp_buff), + "Error getting line details calling %s dwarf error is %s", + where,dwarf_errmsg(err)); + DWARF_CHECK_ERROR(lines_result,tmp_buff); + } +} + +extern void +print_line_numbers_this_cu(Dwarf_Debug dbg, Dwarf_Die cu_die) +{ + Dwarf_Signed linecount = 0; + Dwarf_Line *linebuf = NULL; + Dwarf_Signed i = 0; + Dwarf_Addr pc = 0; + Dwarf_Unsigned lineno = 0; + Dwarf_Unsigned column = 0; + + Dwarf_Bool newstatement = 0; + Dwarf_Bool lineendsequence = 0; + Dwarf_Bool new_basic_block = 0; + int lres = 0; + int sres = 0; + int ares = 0; + int lires = 0; + int cores = 0; + int line_errs = 0; + + Dwarf_Bool SkipRecord = FALSE; + + current_section_id = DEBUG_LINE; + + /* line_flag is TRUE */ + + if (do_print_dwarf) { + printf("\n.debug_line: line number info for a single cu\n"); + } + if (verbose > 1) { + int errcount = 0; + print_source_intro(cu_die); + print_one_die(dbg, cu_die, + /* print_information= */ 1, + /* indent level */0, + /* srcfiles= */ 0, /* cnt= */ 0, + /* ignore_die_stack= */TRUE); + DWARF_CHECK_COUNT(lines_result,1); + lres = dwarf_print_lines(cu_die, &err,&errcount); + if(errcount > 0) { + DWARF_ERROR_COUNT(lines_result,errcount); + DWARF_CHECK_COUNT(lines_result,(errcount-1)); + } + if (lres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_srclines details", lres, err); + } + return; + } + + if(check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + dwarf_check_lineheader(cu_die,&line_errs); + if(line_errs > 0) { + DWARF_CHECK_ERROR_PRINT_CU(); + DWARF_ERROR_COUNT(lines_result,line_errs); + DWARF_CHECK_COUNT(lines_result,(line_errs-1)); + } + } + lres = dwarf_srclines(cu_die, &linebuf, &linecount, &err); + if (lres == DW_DLV_ERROR) { + /* Do not terminate processing */ + if (check_decl_file) { + DWARF_CHECK_COUNT(decl_file_result,1); + DWARF_CHECK_ERROR2(decl_file_result,"dwarf_srclines", + dwarf_errmsg(err)); + record_dwarf_error = FALSE; /* Clear error condition */ + } else { + print_error(dbg, "dwarf_srclines", lres, err); + } + } else if (lres == DW_DLV_NO_ENTRY) { + /* no line information is included */ + } else { + struct esb_s lastsrc;; + esb_constructor(&lastsrc); + if (do_print_dwarf) { + print_source_intro(cu_die); + if (verbose) { + print_one_die(dbg, cu_die, + /* print_information= */ TRUE, + /* indent_level= */ 0, + /* srcfiles= */ 0, /* cnt= */ 0, + /* ignore_die_stack= */TRUE); + } + printf("\n<pc> [row,col] " + "NS BB ET PE EB IS= DI= uri: \"filepath\"\n"); + printf("NS new statement, BB new basic block, " + "ET end of text sequence\n"); + printf("PE prologue end, EB epilogue begin\n"); + printf("IA=val ISA number, DI=val discriminator value\n"); + } + for (i = 0; i < linecount; i++) { + Dwarf_Line line = linebuf[i]; + string filename = 0; + int nsres = 0; + Dwarf_Bool found_line_error = FALSE; + Dwarf_Bool has_is_addr_set = FALSE; + char *where = NULL; + + if (check_decl_file && checking_this_compiler()) { + /* A line record with addr=0 was detected */ + if (SkipRecord) { + /* Skip records that do not have ís_addr_set' */ + ares = dwarf_line_is_addr_set(line, &has_is_addr_set, &err); + if (ares == DW_DLV_OK && has_is_addr_set) { + SkipRecord = FALSE; + } + else { + /* Keep ignoring records until we have + one with 'is_addr_set' */ + continue; + } + } + } + + if(check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + } + filename = "<unknown>"; + sres = dwarf_linesrc(line, &filename, &err); + if (sres == DW_DLV_ERROR) { + /* Do not terminate processing */ + where = "dwarf_linesrc()"; + record_line_error(where,err); + found_line_error = TRUE; + } + + ares = dwarf_lineaddr(line, &pc, &err); + + if (ares == DW_DLV_ERROR) { + /* Do not terminate processing */ + where = "dwarf_lineaddr()"; + record_line_error(where,err); + found_line_error = TRUE; + } + if (ares == DW_DLV_NO_ENTRY) { + pc = 0; + } + lires = dwarf_lineno(line, &lineno, &err); + if (lires == DW_DLV_ERROR) { + /* Do not terminate processing */ + where = "dwarf_lineno()"; + record_line_error(where,err); + found_line_error = TRUE; + } + if (lires == DW_DLV_NO_ENTRY) { + lineno = -1LL; + } + cores = dwarf_lineoff_b(line, &column, &err); + if (cores == DW_DLV_ERROR) { + /* Do not terminate processing */ + where = "dwarf_lineoff()"; + record_line_error(where,err); + found_line_error = TRUE; + } + if (cores == DW_DLV_NO_ENTRY) { + /* Zero was always the correct default, meaning + the left edge. DWARF2/3/4 spec sec 6.2.2 */ + column = 0; + } + + /* Process any possible error condition, though + we won't be at the first such error. */ + if (check_decl_file && checking_this_compiler()) { + DWARF_CHECK_COUNT(decl_file_result,1); + if (found_line_error) { + DWARF_CHECK_ERROR2(decl_file_result,where,dwarf_errmsg(err)); + } else if (do_check_dwarf) { + /* Check the address lies with a valid [lowPC:highPC] + in the .text section*/ + if (IsValidInBucketGroup(pRangesInfo,pc)) { + /* Valid values; do nothing */ + } else { + /* At this point may be we are dealing with + a linkonce symbol. The problem we have here + is we have consumed the deug_info section + and we are dealing just with the records + from the .debug_line, so no PU_name is + available and no high_pc. Traverse the linkonce + table if try to match the pc value with + one of those ranges. + */ + if(check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + } + if (FindAddressInBucketGroup(pLinkonceInfo,pc)){ + /* Valid values; do nothing */ + } else { + /* The SN Systems Linker generates + line records + with addr=0, when dealing with linkonce + symbols and no stripping */ + if (pc) { + char addr_tmp[100]; + if(check_lines && checking_this_compiler()) { + snprintf(addr_tmp,sizeof(addr_tmp), + ".debug_line: Address" + " 0x%" DW_PR_XZEROS DW_PR_DUx + " outside a valid .text range",pc); + DWARF_CHECK_ERROR(lines_result, + addr_tmp); + } + } else { + SkipRecord = TRUE; + } + } + } + /* Check the last record for the .debug_line, + the one created by DW_LNE_end_sequence, + is the same as the high_pc + address for the last known user program + unit (PU) */ + if ((i + 1 == linecount) && + seen_PU_high_address) { + /* Ignore those PU that have been stripped + by the linker; their low_pc values are + set to -1 (snc linker only) */ + /* It is perfectly sensible for a compiler + to leave a few bytes of NOP or other stuff + after the last instruction in a subprogram, + for cache-alignment or other purposes, so + a mismatch here is not necessarily + an error. */ + + if (check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + if ((pc != PU_high_address) && + (PU_base_address != elf_max_address)) { + char addr_tmp[100]; + snprintf(addr_tmp,sizeof(addr_tmp), + ".debug_line: Address" + " 0x%" DW_PR_XZEROS DW_PR_DUx + " may be incorrect" + " as DW_LNE_end_sequence address",pc); + DWARF_CHECK_ERROR(lines_result, + addr_tmp); + } + } + } + } + } + + /* Display the error information */ + if (found_line_error || record_dwarf_error) { + if (check_verbose_mode) { + /* Print the record number for better error description */ + printf("Record = %" DW_PR_DUu + " Addr = 0x%" DW_PR_XZEROS DW_PR_DUx + " [%4" DW_PR_DUu ",%2" DW_PR_DUu "] '%s'\n", + i, pc,lineno,column,filename); + /* Flush due to the redirection of stderr */ + fflush(stdout); + /* The compilation unit was already printed */ + if (!check_decl_file) { + PRINT_CU_INFO(); + } + } + record_dwarf_error = FALSE; + /* Due to a fatal error, skip current record */ + if (found_line_error) { + continue; + } + } + if (do_print_dwarf) { + printf("0x%08" DW_PR_DUx + " [%4" DW_PR_DUu ",%2" DW_PR_DUu "]", pc, lineno, + column); + } + + nsres = dwarf_linebeginstatement(line, &newstatement, &err); + if (nsres == DW_DLV_OK) { + if (newstatement && do_print_dwarf) { + printf(" %s","NS"); + } + } else if (nsres == DW_DLV_ERROR) { + print_error(dbg, "linebeginstatment failed", nsres, err); + } + nsres = dwarf_lineblock(line, &new_basic_block, &err); + if (nsres == DW_DLV_OK) { + if (new_basic_block && do_print_dwarf) { + printf(" %s","BB"); + } + } else if (nsres == DW_DLV_ERROR) { + print_error(dbg, "lineblock failed", nsres, err); + } + nsres = dwarf_lineendsequence(line, &lineendsequence, &err); + if (nsres == DW_DLV_OK) { + if (lineendsequence && do_print_dwarf) { + printf(" %s", "ET"); + } + } else if (nsres == DW_DLV_ERROR) { + print_error(dbg, "lineblock failed", nsres, err); + } + if(do_print_dwarf) { + Dwarf_Bool prologue_end = 0; + Dwarf_Bool epilogue_begin = 0; + Dwarf_Unsigned isa = 0; + Dwarf_Unsigned discriminator = 0; + int disres = dwarf_prologue_end_etc(line, + &prologue_end,&epilogue_begin, + &isa,&discriminator,&err); + if (disres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_prologue_end_etc() failed", + disres, err); + } + if(prologue_end) { + printf(" PE"); + } + if(epilogue_begin) { + printf(" EB"); + } + if(isa) { + printf(" IS=0x%" DW_PR_DUx, isa); + } + if(discriminator) { + printf(" DI=0x%" DW_PR_DUx, discriminator); + } + } + + + if (i > 0 && verbose < 3 && + strcmp(filename,esb_get_string(&lastsrc)) == 0) { + /* Do not print name. */ + } else { + struct esb_s urs; + esb_constructor(&urs); + esb_append(&urs, " uri: \""); + translate_to_uri(filename,&urs); + esb_append(&urs,"\""); + if(do_print_dwarf) { + printf("%s",esb_get_string(&urs)); + } + esb_destructor(&urs); + esb_empty_string(&lastsrc); + esb_append(&lastsrc,filename); + } + if (sres == DW_DLV_OK) { + dwarf_dealloc(dbg, filename, DW_DLA_STRING); + } + if (do_print_dwarf) { + printf("\n"); + } + } + esb_destructor(&lastsrc); + dwarf_srclines_dealloc(dbg, linebuf, linecount); + } +} diff --git a/dwarfdump/print_locs.c b/dwarfdump/print_locs.c new file mode 100644 index 0000000..c7cf99f --- /dev/null +++ b/dwarfdump/print_locs.c @@ -0,0 +1,128 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" +#include "print_frames.h" + +/* print data in .debug_loc + There is no guarantee this will work because we are assuming + that all bytes are valid loclist data, that there are no + odd padding or garbage bytes. In normal use one gets + into here via an offset from .debug_info, so it could be + that bytes not referenced from .debug_info are garbage + or even zero padding. So this can fail (error off) as such bytes + can lead dwarf_get_loclist_entry() astray. + + It's also wrong because we don't know what CU or frame each + loclist is from, so we don't know the address_size for sure. +*/ +extern void +print_locs(Dwarf_Debug dbg) +{ + Dwarf_Unsigned offset = 0; + Dwarf_Addr hipc_offset = 0; + Dwarf_Addr lopc_offset = 0; + Dwarf_Ptr data = 0; + Dwarf_Unsigned entry_len = 0; + Dwarf_Unsigned next_entry = 0; + struct esb_s exprstring; + int index = 0; + int lres = 0; + int fres = 0; + + /* This is sometimes wrong, we need a frame-specific size. */ + Dwarf_Half address_size = 0; + + current_section_id = DEBUG_LOC; + + /* Do nothing if not printing. */ + if (!do_print_dwarf) { + return; + } + + fres = dwarf_get_address_size(dbg, &address_size, &err); + if (fres != DW_DLV_OK) { + print_error(dbg, "dwarf_get_address_size", fres, err); + } + + printf("\n.debug_loc"); + + printf("\nFormat <i o b e l>: " + "index section-offset begin-addr end-addr length-of-block-entry\n"); + esb_constructor(&exprstring); + while ((lres = dwarf_get_loclist_entry(dbg, offset, + &hipc_offset, &lopc_offset, + &data, &entry_len, + &next_entry, + &err)) == DW_DLV_OK) { + get_string_from_locs(dbg,data,entry_len,address_size, + &exprstring); + /* Display offsets */ + if (display_offsets) { + ++index; + printf(" <iobel> [%8d] 0x%" DW_PR_XZEROS DW_PR_DUx, + index, offset); + if(verbose) { + printf(" <expr-off 0x%" DW_PR_XZEROS DW_PR_DUx ">", + next_entry - entry_len); + } + } + printf(" 0x%" DW_PR_XZEROS DW_PR_DUx + " 0x%" DW_PR_XZEROS DW_PR_DUx + " %8" DW_PR_DUu " %s\n", + (Dwarf_Unsigned) lopc_offset, + (Dwarf_Unsigned) hipc_offset, entry_len, + esb_get_string(&exprstring)); + esb_empty_string(&exprstring); + offset = next_entry; + } + esb_destructor(&exprstring); + if (lres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_loclist_entry", lres, err); + } +} diff --git a/dwarfdump/print_macros.c b/dwarfdump/print_macros.c new file mode 100644 index 0000000..0a36fc9 --- /dev/null +++ b/dwarfdump/print_macros.c @@ -0,0 +1,216 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" +#include "print_frames.h" + + +struct macro_counts_s { + long mc_start_file; + long mc_end_file; + long mc_define; + long mc_undef; + long mc_extension; + long mc_code_zero; + long mc_unknown; +}; + +static void +print_one_macro_entry_detail(long i, + char *type, + struct Dwarf_Macro_Details_s *mdp) +{ + /* "DW_MACINFO_*: section-offset file-index [line] string\n" */ + if (mdp->dmd_macro) { + printf("%3ld %s: %6" DW_PR_DUu " %2" DW_PR_DSd " [%4" + DW_PR_DSd "] \"%s\" \n", + i, + type, + (Dwarf_Unsigned)mdp->dmd_offset, + mdp->dmd_fileindex, mdp->dmd_lineno, mdp->dmd_macro); + } else { + printf("%3ld %s: %6" DW_PR_DUu " %2" DW_PR_DSd " [%4" + DW_PR_DSd "] 0\n", + i, + type, + (Dwarf_Unsigned)mdp->dmd_offset, + mdp->dmd_fileindex, mdp->dmd_lineno); + } + +} + +static void +print_one_macro_entry(long i, + struct Dwarf_Macro_Details_s *mdp, + struct macro_counts_s *counts) +{ + + switch (mdp->dmd_type) { + case 0: + counts->mc_code_zero++; + print_one_macro_entry_detail(i, "DW_MACINFO_type-code-0", mdp); + break; + + case DW_MACINFO_start_file: + counts->mc_start_file++; + print_one_macro_entry_detail(i, "DW_MACINFO_start_file", mdp); + break; + + case DW_MACINFO_end_file: + counts->mc_end_file++; + print_one_macro_entry_detail(i, "DW_MACINFO_end_file ", mdp); + break; + + case DW_MACINFO_vendor_ext: + counts->mc_extension++; + print_one_macro_entry_detail(i, "DW_MACINFO_vendor_ext", mdp); + break; + + case DW_MACINFO_define: + counts->mc_define++; + print_one_macro_entry_detail(i, "DW_MACINFO_define ", mdp); + break; + + case DW_MACINFO_undef: + counts->mc_undef++; + print_one_macro_entry_detail(i, "DW_MACINFO_undef ", mdp); + break; + + default: + { + char create_type[50]; /* More than large enough. */ + + counts->mc_unknown++; + snprintf(create_type, sizeof(create_type), + "DW_MACINFO_0x%x", mdp->dmd_type); + print_one_macro_entry_detail(i, create_type, mdp); + } + break; + } +} + +/* print data in .debug_macinfo */ +/* FIXME: should print name of file whose index is in macro data + here -- somewhere. */ +/*ARGSUSED*/ extern void +print_macinfo(Dwarf_Debug dbg) +{ + Dwarf_Off offset = 0; + Dwarf_Unsigned max = 0; + Dwarf_Signed count = 0; + long group = 0; + Dwarf_Macro_Details *maclist = NULL; + int lres = 0; + + current_section_id = DEBUG_MACINFO; + if (!do_print_dwarf) { + return; + } + + printf("\n.debug_macinfo\n"); + + while ((lres = dwarf_get_macro_details(dbg, offset, + max, &count, &maclist, + &err)) == DW_DLV_OK) { + long i = 0; + struct macro_counts_s counts; + + + memset(&counts, 0, sizeof(counts)); + + printf("\n"); + printf("compilation-unit .debug_macinfo # %ld\n", group); + printf + ("num name section-offset file-index [line] \"string\"\n"); + for (i = 0; i < count; i++) { + struct Dwarf_Macro_Details_s *mdp = &maclist[i]; + + print_one_macro_entry(i, mdp, &counts); + } + + if (counts.mc_start_file == 0) { + printf + ("DW_MACINFO file count of zero is invalid DWARF2/3\n"); + } + if (counts.mc_start_file != counts.mc_end_file) { + printf("Counts of DW_MACINFO file (%ld) end_file (%ld) " + "do not match!.\n", + counts.mc_start_file, counts.mc_end_file); + } + if (counts.mc_code_zero < 1) { + printf("Count of zeros in macro group should be non-zero " + "(1 preferred), count is %ld\n", + counts.mc_code_zero); + } + printf("Macro counts: start file %ld, " + "end file %ld, " + "define %ld, " + "undef %ld, " + "ext %ld, " + "code-zero %ld, " + "unknown %ld\n", + counts.mc_start_file, + counts.mc_end_file, + counts.mc_define, + counts.mc_undef, + counts.mc_extension, + counts.mc_code_zero, counts.mc_unknown); + + + /* int type= maclist[count - 1].dmd_type; */ + /* ASSERT: type is zero */ + + offset = maclist[count - 1].dmd_offset + 1; + dwarf_dealloc(dbg, maclist, DW_DLA_STRING); + ++group; + } + if (lres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_macro_details", lres, err); + } +} + diff --git a/dwarfdump/print_pubnames.c b/dwarfdump/print_pubnames.c new file mode 100644 index 0000000..8018152 --- /dev/null +++ b/dwarfdump/print_pubnames.c @@ -0,0 +1,300 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. +v Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" +#include "print_sections.h" + +/* This unifies the code for some error checks to + avoid code duplication. +*/ +static void +check_info_offset_sanity(char *sec, + char *field, + char *global, + Dwarf_Unsigned offset, Dwarf_Unsigned maxoff) +{ + if (maxoff == 0) { + /* Lets make a heuristic check. */ + if (offset > 0xffffffff) { + printf("Warning: section %s %s %s offset 0x%" + DW_PR_XZEROS DW_PR_DUx " " + "exceptionally large \n", + sec, field, global, offset); + } + return; + } + if (offset >= maxoff) { + printf("Warning: section %s %s %s offset 0x%" + DW_PR_XZEROS DW_PR_DUx " " + "larger than max of 0x%" DW_PR_DUx "\n", + sec, field, global, offset, maxoff); + } +} + +/* Unified pubnames style output. + The error checking here against maxoff may be useless + (in that libdwarf may return an error if the offset is bad + and we will not get called here). + But we leave it in nonetheless as it looks sensible. + In at least one gigantic executable such offsets turned out wrong. +*/ +void +print_pubname_style_entry(Dwarf_Debug dbg, + char *line_title, + char *name, + Dwarf_Unsigned die_off, + Dwarf_Unsigned cu_off, + Dwarf_Unsigned global_cu_offset, + Dwarf_Unsigned maxoff) +{ + Dwarf_Die die = NULL; + Dwarf_Off die_CU_off = 0; + int dres = 0; + int ddres = 0; + int cudres = 0; + char tmp_buf[100]; + + /* get die at die_off */ + dres = dwarf_offdie(dbg, die_off, &die, &err); + if (dres != DW_DLV_OK) { + struct esb_s details; + esb_constructor(&details); + esb_append(&details,line_title); + esb_append(&details," dwarf_offdie : " + "die offset does not reference valid DIE. "); + snprintf(tmp_buf,sizeof(tmp_buf),"0x%" DW_PR_DUx, die_off); + esb_append(&details,tmp_buf); + esb_append(&details,"."); + print_error(dbg, esb_get_string(&details), dres, err); + esb_destructor(&details); + } + + /* get offset of die from its cu-header */ + ddres = dwarf_die_CU_offset(die, &die_CU_off, &err); + if (ddres != DW_DLV_OK) { + struct esb_s details; + esb_constructor(&details); + esb_append(&details,line_title); + esb_append(&details," cannot get CU die offset"); + print_error(dbg, esb_get_string(&details), dres, err); + esb_destructor(&details); + die_CU_off = 0; + } + + /* Get die at offset cu_off to check its existence. */ + { + Dwarf_Die cu_die = NULL; + cudres = dwarf_offdie(dbg, cu_off, &cu_die, &err); + if (cudres != DW_DLV_OK) { + struct esb_s details; + esb_constructor(&details); + esb_append(&details,line_title); + esb_append(&details," dwarf_offdie: " + "cu die offset does not reference valid CU DIE. "); + snprintf(tmp_buf,sizeof(tmp_buf),"0x%" DW_PR_DUx, cu_off); + esb_append(&details,tmp_buf); + esb_append(&details,"."); + print_error(dbg, esb_get_string(&details), dres, err); + esb_destructor(&details); + } else { + /* It exists, all is well. */ + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + } + } + /* Display offsets */ + if (display_offsets) { + /* Print 'name'at the end for better layout */ + printf("%s die-in-sect 0x%" DW_PR_XZEROS DW_PR_DUx + ", cu-in-sect 0x%" DW_PR_XZEROS DW_PR_DUx "," + " die-in-cu 0x%" DW_PR_XZEROS DW_PR_DUx + ", cu-header-in-sect 0x%" DW_PR_XZEROS DW_PR_DUx , + line_title, + die_off, cu_off, + (Dwarf_Unsigned) die_CU_off, + /* Following is absolute offset of the ** beginning of the + cu */ + (Dwarf_Signed) (die_off - die_CU_off)); + } + + if ((die_off - die_CU_off) != global_cu_offset) { + printf(" error: real cuhdr 0x%" DW_PR_XZEROS DW_PR_DUx, + global_cu_offset); + exit(1); + } + + /* Display offsets */ + if (display_offsets && verbose) { + printf(" cuhdr 0x%" DW_PR_XZEROS DW_PR_DUx , global_cu_offset); + } + + /* Print 'name'at the end for better layout */ + printf(" '%s'\n",name); + + dwarf_dealloc(dbg, die, DW_DLA_DIE); + + check_info_offset_sanity(line_title, + "die offset", name, die_off, maxoff); + check_info_offset_sanity(line_title, + "die cu offset", name, die_CU_off, maxoff); + check_info_offset_sanity(line_title, + "cu offset", name, + (die_off - die_CU_off), maxoff); + +} + +/* Get all the data in .debug_pubnames */ +void +print_pubnames(Dwarf_Debug dbg) +{ + Dwarf_Global *globbuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + + /* Offset to previous CU */ + Dwarf_Off prev_cu_off = elf_max_address; + + char *name = 0; + int res = 0; + + current_section_id = DEBUG_PUBNAMES; + if (do_print_dwarf) { + printf("\n.debug_pubnames\n"); + } + res = dwarf_get_globals(dbg, &globbuf, &count, &err); + if (res == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_globals", res, err); + } else if (res == DW_DLV_NO_ENTRY) { + /* (err == 0 && count == DW_DLV_NOCOUNT) means there are no + pubnames. */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (i = 0; i < count; i++) { + int nres = 0; + int cures3 = 0; + Dwarf_Off global_cu_off = 0; + + nres = dwarf_global_name_offsets(globbuf[i], + &name, &die_off, &cu_off, + &err); + deal_with_name_offset_err(dbg, "dwarf_global_name_offsets", + name, die_off, nres, err); + cures3 = dwarf_global_cu_offset(globbuf[i], + &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_global_cu_offset", cures3, err); + } + + if (check_pubname_attr) { + Dwarf_Bool has_attr; + int ares; + int dres; + Dwarf_Die die; + + /* We are processing a new set of pubnames + for a different CU; get the producer ID, at 'cu_off' + to see if we need to skip these pubnames */ + if (cu_off != prev_cu_off) { + char *producer_name = 0; + + /* Record offset for previous CU */ + prev_cu_off = cu_off; + + dres = dwarf_offdie(dbg, cu_off, &die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "print pubnames: dwarf_offdie a", dres,err); + } + + /* Get producer name for this CU and update compiler list */ + get_producer_name(dbg,die,err,&producer_name); + update_compiler_target(producer_name); + + dwarf_dealloc(dbg, die, DW_DLA_DIE); + } + + /* get die at die_off */ + dres = dwarf_offdie(dbg, die_off, &die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "print pubnames: dwarf_offdie b", dres, err); + } + + + ares = + dwarf_hasattr(die, DW_AT_external, &has_attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "hassattr on DW_AT_external", ares, + err); + } + + /* Check for specific compiler */ + if (checking_this_compiler()) { + DWARF_CHECK_COUNT(pubname_attr_result,1); + if (ares == DW_DLV_OK && has_attr) { + /* Should the value of flag be examined? */ + } else { + DWARF_CHECK_ERROR2(pubname_attr_result,name, + "pubname does not have DW_AT_external"); + } + } + dwarf_dealloc(dbg, die, DW_DLA_DIE); + } + + /* Now print pubname, after the test */ + if (do_print_dwarf || (record_dwarf_error && check_verbose_mode)) { + print_pubname_style_entry(dbg, + "global", + name, die_off, cu_off, + global_cu_off, maxoff); + record_dwarf_error = FALSE; /* Clear error condition */ + } + + } + dwarf_globals_dealloc(dbg, globbuf, count); + } +} /* print_pubnames() */ + diff --git a/dwarfdump/print_ranges.c b/dwarfdump/print_ranges.c new file mode 100644 index 0000000..aee55e0 --- /dev/null +++ b/dwarfdump/print_ranges.c @@ -0,0 +1,106 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" +#include "print_sections.h" + +static struct esb_s esb_string; + +/* Because we do not know what DIE is involved, if the + object being printed has different address sizes + in different compilation units this will not work + properly: anything could happen. */ +extern void +print_ranges(Dwarf_Debug dbg) +{ + Dwarf_Unsigned off = 0; + int group_number = 0; + int wasdense = 0; + + current_section_id = DEBUG_RANGES; + if (!do_print_dwarf) { + return; + } + printf("\n.debug_ranges\n"); + + /* Turn off dense, we do not want print_ranges_list_to_extra + to use dense form here. */ + wasdense = dense; + dense = 0; + for(;;) { + Dwarf_Ranges *rangeset = 0; + Dwarf_Signed rangecount = 0; + Dwarf_Unsigned bytecount = 0; + + /* We do not know what DIE is involved, we use + the older call here. */ + int rres = dwarf_get_ranges(dbg,off,&rangeset, + &rangecount,&bytecount,&err); + if(rres == DW_DLV_OK) { + char *val = 0; + printf(" Ranges group %d:\n",group_number); + esb_empty_string(&esb_string); + print_ranges_list_to_extra(dbg,off, + rangeset,rangecount,bytecount, + &esb_string); + dwarf_ranges_dealloc(dbg,rangeset,rangecount); + val = esb_get_string(&esb_string); + printf("%s",val); + ++group_number; + } else if (rres == DW_DLV_NO_ENTRY) { + printf("End of .debug_ranges.\n"); + break; + } else { + /* ERROR, which does not quite mean a real error, + as we might just be misaligned reading things without + a DW_AT_ranges offset.*/ + printf("End of .debug_ranges..\n"); + break; + } + off += bytecount; + } + dense = wasdense; +} diff --git a/dwarfdump/print_reloc.c b/dwarfdump/print_reloc.c new file mode 100644 index 0000000..35a1574 --- /dev/null +++ b/dwarfdump/print_reloc.c @@ -0,0 +1,1150 @@ +/* + Copyright (C) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2011 SN Systems Ltd. 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_reloc.c,v 1.11 2005/08/04 05:09:37 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 "print_reloc.h" + +#define DW_SECTION_REL_DEBUG_NUM 9 /* Number of sections */ +/* .debug_abbrev should never have a relocation applied to it as it + never refers to another section! (other sections refer to + .debug_abbrev) */ + +#define DW_SECTNAME_RELA_DEBUG ".rela.debug_" +#define DW_SECTNAME_RELA_DEBUG_INFO ".rela.debug_info" +#define DW_SECTNAME_RELA_DEBUG_LINE ".rela.debug_line" +#define DW_SECTNAME_RELA_DEBUG_PUBNAMES ".rela.debug_pubnames" +#define DW_SECTNAME_RELA_DEBUG_ABBREV ".rela.debug_abbrev" +#define DW_SECTNAME_RELA_DEBUG_ARANGES ".rela.debug_aranges" +#define DW_SECTNAME_RELA_DEBUG_FRAME ".rela.debug_frame" +#define DW_SECTNAME_RELA_DEBUG_LOC ".rela.debug_loc" +#define DW_SECTNAME_RELA_DEBUG_RANGES ".rela.debug_ranges" +#define DW_SECTNAME_RELA_DEBUG_TYPES ".rela.debug_types" + +#define DW_SECTNAME_REL_DEBUG ".rel.debug_" +#define DW_SECTNAME_REL_DEBUG_INFO ".rel.debug_info" +#define DW_SECTNAME_REL_DEBUG_LINE ".rel.debug_line" +#define DW_SECTNAME_REL_DEBUG_PUBNAMES ".rel.debug_pubnames" +#define DW_SECTNAME_REL_DEBUG_ABBREV ".rel.debug_abbrev" +#define DW_SECTNAME_REL_DEBUG_ARANGES ".rel.debug_aranges" +#define DW_SECTNAME_REL_DEBUG_FRAME ".rel.debug_frame" +#define DW_SECTNAME_REL_DEBUG_LOC ".rel.debug_loc" +#define DW_SECTNAME_REL_DEBUG_RANGES ".rel.debug_ranges" +#define DW_SECTNAME_REL_DEBUG_TYPES ".rel.debug_types" + + +#define STRING_FOR_DUPLICATE " duplicate" +#define STRING_FOR_NULL " null" + +static char *sectnames[] = { + DW_SECTNAME_REL_DEBUG_INFO, + DW_SECTNAME_REL_DEBUG_LINE, + DW_SECTNAME_REL_DEBUG_PUBNAMES, + DW_SECTNAME_REL_DEBUG_ABBREV, + DW_SECTNAME_REL_DEBUG_ARANGES, + DW_SECTNAME_REL_DEBUG_FRAME, + DW_SECTNAME_REL_DEBUG_LOC, + DW_SECTNAME_REL_DEBUG_RANGES, + DW_SECTNAME_REL_DEBUG_TYPES, +}; +static char *sectnamesa[] = { + DW_SECTNAME_RELA_DEBUG_INFO, + DW_SECTNAME_RELA_DEBUG_LINE, + DW_SECTNAME_RELA_DEBUG_PUBNAMES, + DW_SECTNAME_RELA_DEBUG_ABBREV, + DW_SECTNAME_RELA_DEBUG_ARANGES, + DW_SECTNAME_RELA_DEBUG_FRAME, + DW_SECTNAME_RELA_DEBUG_LOC, + DW_SECTNAME_RELA_DEBUG_RANGES, + DW_SECTNAME_RELA_DEBUG_TYPES, +}; + +static char *error_msg_duplicate[] = { + DW_SECTNAME_REL_DEBUG_INFO STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_LINE STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_PUBNAMES STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_ABBREV STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_ARANGES STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_FRAME STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_LOC STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_RANGES STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_TYPES STRING_FOR_DUPLICATE, +}; + +static char *error_msg_null[] = { + DW_SECTNAME_REL_DEBUG_INFO STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_LINE STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_PUBNAMES STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_ABBREV STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_ARANGES STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_FRAME STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_LOC STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_RANGES STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_TYPES STRING_FOR_NULL, +}; + +/* Include Section type, to be able to deal with all the + Elf32_Rel, Elf32_Rela, Elf64_Rel, Elf64_Rela relocation types */ +#define SECT_DATA_SET(x,t,n) { \ + if (sect_data[(x)].buf != NULL) { \ + print_error(dbg, error_msg_duplicate[(x)], DW_DLV_OK, err); \ + } \ + if ((data = elf_getdata(scn, 0)) == NULL || data->d_size == 0) {\ + print_error(dbg, error_msg_null[(x)],DW_DLV_OK, err); \ + } \ + sect_data[(x)].buf = data -> d_buf; \ + sect_data[(x)].size = data -> d_size; \ + sect_data[(x)].type = t; \ + sect_data[(x)].name = n; \ + } + +/* PowerPC relocations defined by the ABIs */ +static char *reloc_type_names_PPC[] = { + "R_PPC_NONE", /* 00 */ + "R_PPC_ADDR32", /* 01 */ + "R_PPC_ADDR24", /* 02 */ + "R_PPC_ADDR16", /* 03 */ + "R_PPC_ADDR16_LO", /* 04 */ + "R_PPC_ADDR16_HI", /* 05 */ + "R_PPC_ADDR16_HA", /* 06 */ + "R_PPC_ADDR14", /* 07 */ + "R_PPC_ADDR14_BRTAKEN", /* 08 */ + "R_PPC_ADDR14_BRNTAKEN", /* 09 */ + "R_PPC_REL24", /* 10 */ + "R_PPC_REL14", /* 11 */ + "R_PPC_REL14_BRTAKEN", /* 12 */ + "R_PPC_REL14_BRNTAKEN", /* 13 */ + "R_PPC_GOT16", /* 14 */ + "R_PPC_GOT16_LO", /* 15 */ + "R_PPC_GOT16_HI", /* 16 */ + "R_PPC_GOT16_HA", /* 17 */ + "R_PPC_PLTREL24", /* 18 */ + "R_PPC_COPY", /* 19 */ + "R_PPC_GLOB_DAT", /* 20 */ + "R_PPC_JMP_SLOT", /* 21 */ + "R_PPC_RELATIVE", /* 22 */ + "R_PPC_LOCAL24PC", /* 23 */ + "R_PPC_UADDR32", /* 24 */ + "R_PPC_UADDR16", /* 25 */ + "R_PPC_REL32", /* 26 */ + "R_PPC_PLT32", /* 27 */ + "R_PPC_PLTREL32", /* 28 */ + "R_PPC_PLT16_LO", /* 29 */ + "R_PPC_PLT16_HI", /* 30 */ + "R_PPC_PLT16_HA", /* 31 */ + "R_PPC_SDAREL16", /* 32 */ + "R_PPC_SECTOFF", /* 33 */ + "R_PPC_SECTOFF_LO", /* 34 */ + "R_PPC_SECTOFF_HI", /* 35 */ + "R_PPC_SECTOFF_HA", /* 36 */ + "R_PPC_37", /* 37 */ + "R_PPC_38", /* 38 */ + "R_PPC_39", /* 39 */ + "R_PPC_40", /* 40 */ + "R_PPC_41", /* 41 */ + "R_PPC_42", /* 42 */ + "R_PPC_43", /* 43 */ + "R_PPC_44", /* 44 */ + "R_PPC_45", /* 45 */ + "R_PPC_46", /* 46 */ + "R_PPC_47", /* 47 */ + "R_PPC_48", /* 48 */ + "R_PPC_49", /* 49 */ + "R_PPC_50", /* 50 */ + "R_PPC_51", /* 51 */ + "R_PPC_52", /* 52 */ + "R_PPC_53", /* 53 */ + "R_PPC_54", /* 54 */ + "R_PPC_55", /* 55 */ + "R_PPC_56", /* 56 */ + "R_PPC_57", /* 57 */ + "R_PPC_58", /* 58 */ + "R_PPC_59", /* 59 */ + "R_PPC_60", /* 60 */ + "R_PPC_61", /* 61 */ + "R_PPC_62", /* 62 */ + "R_PPC_63", /* 63 */ + "R_PPC_64", /* 64 */ + "R_PPC_65", /* 65 */ + "R_PPC_66", /* 66 */ + "R_PPC_TLS", /* 67 */ + "R_PPC_DTPMOD32", /* 68 */ + "R_PPC_TPREL16", /* 69 */ + "R_PPC_TPREL16_LO", /* 70 */ + "R_PPC_TPREL16_HI", /* 71 */ + "R_PPC_TPREL16_HA", /* 72 */ + "R_PPC_TPREL32", /* 73 */ + "R_PPC_DTPREL16", /* 74 */ + "R_PPC_DTPREL16_LO", /* 75 */ + "R_PPC_DTPREL16_HI", /* 76 */ + "R_PPC_DTPREL16_HA", /* 77 */ + "R_PPC_DTPREL64", /* 78 */ + "R_PPC_GOT_TLSGD16", /* 79 */ + "R_PPC_GOT_TLSGD16_LO", /* 80 */ + "R_PPC_GOT_TLSGD16_HI", /* 81 */ + "R_PPC_GOT_TLSGD16_HA", /* 82 */ + "R_PPC_GOT_TLSLD16", /* 83 */ + "R_PPC_GOT_TLSLD16_LO", /* 84 */ + "R_PPC_GOT_TLSLD16_HI", /* 85 */ + "R_PPC_GOT_TLSLD16_HA", /* 86 */ + "R_PPC_GOT_TPREL16_DS", /* 87 */ + "R_PPC_GOT_TPREL16_LO", /* 88 */ + "R_PPC_GOT_TPREL16_HI", /* 89 */ + "R_PPC_GOT_TPREL16_HA", /* 90 */ + "R_PPC_GOT_DTPREL16", /* 91 */ + "R_PPC_GOT_DTPREL16_LO", /* 92 */ + "R_PPC_GOT_DTPREL16_HI", /* 93 */ + "R_PPC_GOT_DTPREL16_HA", /* 94 */ +}; + +/* PowerPC64 relocations defined by the ABIs */ +static char *reloc_type_names_PPC64[] = { + "R_PPC64_NONE", /* 00 */ + "R_PPC64_ADDR32", /* 01 */ + "R_PPC64_ADDR24", /* 02 */ + "R_PPC64_ADDR16", /* 03 */ + "R_PPC64_ADDR16_LO", /* 04 */ + "R_PPC64_ADDR16_HI", /* 05 */ + "R_PPC64_ADDR16_HA", /* 06 */ + "R_PPC64_ADDR14", /* 07 */ + "R_PPC64_ADDR14_BRTAKEN", /* 08 */ + "R_PPC64_ADDR14_BRNTAKEN", /* 09 */ + "R_PPC64_REL24", /* 10 */ + "R_PPC64_REL14", /* 11 */ + "R_PPC64_REL14_BRTAKEN", /* 12 */ + "R_PPC64_REL14_BRNTAKEN", /* 13 */ + "R_PPC64_GOT16", /* 14 */ + "R_PPC64_GOT16_LO", /* 15 */ + "R_PPC64_GOT16_HI", /* 16 */ + "R_PPC64_GOT16_HA", /* 17 */ + "R_PPC64_PLTREL24", /* 18 */ + "R_PPC64_COPY", /* 19 */ + "R_PPC64_GLOB_DAT", /* 20 */ + "R_PPC64_JMP_SLOT", /* 21 */ + "R_PPC64_RELATIVE", /* 22 */ + "R_PPC64_LOCAL24PC", /* 23 */ + "R_PPC64_UADDR32", /* 24 */ + "R_PPC64_UADDR16", /* 25 */ + "R_PPC64_REL32", /* 26 */ + "R_PPC64_PLT32", /* 27 */ + "R_PPC64_PLTREL32", /* 28 */ + "R_PPC64_PLT16_LO", /* 29 */ + "R_PPC64_PLT16_HI", /* 30 */ + "R_PPC64_PLT16_HA", /* 31 */ + "R_PPC64_SDAREL16", /* 32 */ + "R_PPC64_SECTOFF", /* 33 */ + "R_PPC64_SECTOFF_LO", /* 34 */ + "R_PPC64_SECTOFF_HI", /* 35 */ + "R_PPC64_SECTOFF_HA", /* 36 */ + "R_PPC64_REL30", /* 37 */ + "R_PPC64_ADDR64", /* 38 */ + "R_PPC64_ADDR16_HIGHER", /* 39 */ + "R_PPC64_ADDR16_HIGHERA", /* 40 */ + "R_PPC64_ADDR16_HIGHEST", /* 41 */ + "R_PPC64_ADDR16_HIGHESTA", /* 42 */ + "R_PPC64_UADDR64", /* 43 */ + "R_PPC64_REL64", /* 44 */ + "R_PPC64_PLT64", /* 45 */ + "R_PPC64_PLTREL64", /* 46 */ + "R_PPC64_TOC16", /* 47 */ + "R_PPC64_TOC16_LO", /* 48 */ + "R_PPC64_TOC16_HI", /* 49 */ + "R_PPC64_TOC16_HA", /* 50 */ + "R_PPC64_TOC", /* 51 */ + "R_PPC64_PLTGOT16", /* 52 */ + "R_PPC64_PLTGOT16_LO", /* 53 */ + "R_PPC64_PLTGOT16_HI", /* 54 */ + "R_PPC64_PLTGOT16_HA", /* 55 */ + "R_PPC64_ADDR16_DS", /* 56 */ + "R_PPC64_ADDR16_LO_DS", /* 57 */ + "R_PPC64_GOT16_DS", /* 58 */ + "R_PPC64_GOT16_LO_DS", /* 59 */ + "R_PPC64_PLT16_LO_DS", /* 60 */ + "R_PPC64_SECTOFF_DS", /* 61 */ + "R_PPC64_SECTOFF_LO_DS", /* 62 */ + "R_PPC64_TOC16_DS", /* 63 */ + "R_PPC64_TOC16_LO_DS", /* 64 */ + "R_PPC64_PLTGOT16_DS", /* 65 */ + "R_PPC64_PLTGOT16_LO_DS", /* 66 */ + "R_PPC64_TLS", /* 67 */ + "R_PPC64_DTPMOD32", /* 68 */ + "R_PPC64_TPREL16", /* 69 */ + "R_PPC64_TPREL16_LO", /* 70 */ + "R_PPC64_TPREL16_HI", /* 71 */ + "R_PPC64_TPREL16_HA", /* 72 */ + "R_PPC64_TPREL32", /* 73 */ + "R_PPC64_DTPREL16", /* 74 */ + "R_PPC64_DTPREL16_LO", /* 75 */ + "R_PPC64_DTPREL16_HI", /* 76 */ + "R_PPC64_DTPREL16_HA", /* 77 */ + "R_PPC64_DTPREL64", /* 78 */ + "R_PPC64_GOT_TLSGD16", /* 79 */ + "R_PPC64_GOT_TLSGD16_LO", /* 80 */ + "R_PPC64_GOT_TLSGD16_HI", /* 81 */ + "R_PPC64_GOT_TLSGD16_HA", /* 82 */ + "R_PPC64_GOT_TLSLD16", /* 83 */ + "R_PPC64_GOT_TLSLD16_LO", /* 84 */ + "R_PPC64_GOT_TLSLD16_HI", /* 85 */ + "R_PPC64_GOT_TLSLD16_HA", /* 86 */ + "R_PPC64_GOT_TPREL16_DS", /* 87 */ + "R_PPC64_GOT_TPREL16_LO", /* 88 */ + "R_PPC64_GOT_TPREL16_HI", /* 89 */ + "R_PPC64_GOT_TPREL16_HA", /* 90 */ + "R_PPC64_GOT_DTPREL16", /* 91 */ + "R_PPC64_GOT_DTPREL16_LO", /* 92 */ + "R_PPC64_GOT_DTPREL16_HI", /* 93 */ + "R_PPC64_GOT_DTPREL16_HA", /* 94 */ + "R_PPC64_TPREL16_DS", /* 95 */ + "R_PPC64_TPREL16_LO_DS", /* 96 */ + "R_PPC64_TPREL16_HIGHER", /* 97 */ + "R_PPC64_TPREL16_HIGHERA", /* 98 */ + "R_PPC64_TPREL16_HIGHEST", /* 99 */ + "R_PPC64_TPREL16_HIGHESTA", /* 100 */ + "R_PPC64_DTPREL16_DS", /* 101 */ + "R_PPC64_DTPREL16_LO_DS", /* 102 */ + "R_PPC64_DTPREL16_HIGHER", /* 103 */ + "R_PPC64_DTPREL16_HIGHERA", /* 104 */ + "R_PPC64_DTPREL16_HIGHEST", /* 105 */ + "R_PPC64_DTPREL16_HIGHESTA", /* 106 */ + "R_PPC64_TOC32", /* 107 */ + "R_PPC64_DTPMOD32", /* 108 */ + "R_PPC64_TPREL32", /* 109 */ + "R_PPC64_DTPREL32", /* 110 */ +}; + +/* Relocation types for MIPS */ +static char *reloc_type_names_MIPS[] = { + "R_MIPS_NONE", "R_MIPS_16", "R_MIPS_32", "R_MIPS_REL32", + "R_MIPS_26", "R_MIPS_HI16", "R_MIPS_LO16", "R_MIPS_GPREL16", + "R_MIPS_LITERAL", "R_MIPS_GOT16", "R_MIPS_PC16", "R_MIPS_CALL16", + "R_MIPS_GPREL32", /* 12 */ + "reloc type 13?", "reloc type 14?", "reloc type 15?", + "R_MIPS_SHIFT5", /* 16 */ + "R_MIPS_SHIFT6", /* 17 */ + "R_MIPS_64", /* 18 */ + "R_MIPS_GOT_DISP", /* 19 */ + "R_MIPS_GOT_PAGE", /* 20 */ + "R_MIPS_GOT_OFST", /* 21 */ + "R_MIPS_GOT_HI16", /* 22 */ + "R_MIPS_GOT_LO16", /* 23 */ + "R_MIPS_SUB", /* 24 */ + "R_MIPS_INSERT_A", /* 25 */ + "R_MIPS_INSERT_B", /* 26 */ + "R_MIPS_DELETE", /* 27 */ + "R_MIPS_HIGHER", /* 28 */ + "R_MIPS_HIGHEST", /* 29 */ + "R_MIPS_CALL_HI16", /* 30 */ + "R_MIPS_CALL_LO16", /* 31 */ + "R_MIPS_SCN_DISP", /* 32 */ + "R_MIPS_REL16", /* 33 */ + "R_MIPS_ADD_IMMEDIATE", /* 34 */ +}; + +/* ARM relocations defined by the ABIs */ +static char *reloc_type_names_ARM[] = { + "R_ARM_NONE", /* 00 */ + "R_ARM_PC24", /* 01 */ + "R_ARM_ABS32", /* 02 */ + "R_ARM_REL32", /* 03 */ + "R_ARM_LDR_PC_G0", /* 04 */ + "R_ARM_ABS16", /* 05 */ + "R_ARM_ABS12", /* 06 */ + "R_ARM_THM_ABS5", /* 07 */ + "R_ARM_ABS8", /* 08 */ + "R_ARM_SBREL32", /* 09 */ + "R_ARM_THM_CALL", /* 10 */ + "R_ARM_THM_PC8", /* 11 */ + "R_ARM_BREL_ADJ", /* 12 */ + "R_ARM_TLS_DESC", /* 13 */ + "R_ARM_THM_SWI8", /* 14 */ + "R_ARM_XPC25", /* 15 */ + "R_ARM_THM_XPC22", /* 16 */ + "R_ARM_TLS_DTPMOD32", /* 17 */ + "R_ARM_TLS_DTPOFF32", /* 18 */ + "R_ARM_TLS_TPOFF32", /* 19 */ + "R_ARM_COPY", /* 20 */ + "R_ARM_GLOB_DAT", /* 21 */ + "R_ARM_JUMP_SLOT", /* 22 */ + "R_ARM_RELATIVE", /* 23 */ + "R_ARM_GOTOFF32", /* 24 */ + "R_ARM_BASE_PREL", /* 25 */ + "R_ARM_GOT_BREL", /* 26 */ + "R_ARM_PLT32", /* 27 */ + "R_ARM_CALL", /* 28 */ + "R_ARM_JUMP24", /* 29 */ + "R_ARM_THM_JUMP24", /* 30 */ + "R_ARM_BASE_ABS", /* 31 */ + "R_ARM_ALU_PCREL_7_0", /* 32 */ + "R_ARM_ALU_PCREL_15_8", /* 33 */ + "R_ARM_ALU_PCREL_23_15", /* 34 */ + "R_ARM_LDR_SBREL_11_0_NC", /* 35 */ + "R_ARM_ALU_SBREL_19_12_NC", /* 36 */ + "R_ARM_ALU_SBREL_27_20_CK", /* 37 */ + "R_ARM_TARGET1", /* 38 */ + "R_ARM_SBREL31", /* 39 */ + "R_ARM_V4BX", /* 40 */ + "R_ARM_TARGET2", /* 41 */ + "R_ARM_PREL31", /* 42 */ + "R_ARM_MOVW_ABS_NC", /* 43 */ + "R_ARM_MOVT_ABS", /* 44 */ + "R_ARM_MOVW_PREL_NC", /* 45 */ + "R_ARM_MOVT_PREL", /* 46 */ + "R_ARM_THM_MOVW_ABS_NC", /* 47 */ + "R_ARM_THM_MOVT_ABS", /* 48 */ + "R_ARM_THM_MOVW_PREL_NC", /* 49 */ + "R_ARM_THM_MOVT_PREL", /* 50 */ + "R_ARM_THM_JUMP19", /* 51 */ + "R_ARM_THM_JUMP6", /* 52 */ + "R_ARM_THM_ALU_PREL_11_0", /* 53 */ + "R_ARM_THM_PC12", /* 54 */ + "R_ARM_ABS32_NOI", /* 55 */ + "R_ARM_REL32_NOI", /* 56 */ + "R_ARM_ALU_PC_G0_NC", /* 57 */ + "R_ARM_ALU_PC_G0", /* 58 */ + "R_ARM_ALU_PC_G1_NC", /* 59 */ + "R_ARM_ALU_PC_G1", /* 60 */ + "R_ARM_ALU_PC_G2", /* 61 */ + "R_ARM_LDR_PC_G1", /* 62 */ + "R_ARM_LDR_PC_G2", /* 63 */ + "R_ARM_LDRS_PC_G0", /* 64 */ + "R_ARM_LDRS_PC_G1", /* 65 */ + "R_ARM_LDRS_PC_G2", /* 66 */ + "R_ARM_LDC_PC_G0", /* 67 */ + "R_ARM_LDC_PC_G1", /* 68 */ + "R_ARM_LDC_PC_G2", /* 69 */ + "R_ARM_ALU_SB_G0_NC", /* 70 */ + "R_ARM_ALU_SB_G0", /* 71 */ + "R_ARM_ALU_SB_G1_NC", /* 72 */ + "R_ARM_ALU_SB_G1", /* 73 */ + "R_ARM_ALU_SB_G2", /* 74 */ + "R_ARM_LDR_SB_G0", /* 75 */ + "R_ARM_LDR_SB_G1", /* 76 */ + "R_ARM_LDR_SB_G2", /* 77 */ + "R_ARM_LDRS_SB_G0", /* 78 */ + "R_ARM_LDRS_SB_G1", /* 79 */ + "R_ARM_LDRS_SB_G2", /* 80 */ + "R_ARM_LDC_SB_G0", /* 81 */ + "R_ARM_LDC_SB_G1", /* 82 */ + "R_ARM_LDC_SB_G2", /* 83 */ + "R_ARM_MOVW_BREL_NC", /* 84 */ + "R_ARM_MOVT_BREL", /* 85 */ + "R_ARM_MOVW_BREL", /* 86 */ + "R_ARM_THM_MOVW_BREL_NC", /* 87 */ + "R_ARM_THM_MOVT_BREL", /* 88 */ + "R_ARM_THM_MOVW_BREL", /* 89 */ + "R_ARM_TLS_GOTDESC", /* 90 */ + "R_ARM_TLS_CALL", /* 91 */ + "R_ARM_TLS_DESCSEQ", /* 92 */ + "R_ARM_THM_TLS_CALL", /* 93 */ + "R_ARM_PLT32_ABS", /* 94 */ + "R_ARM_GOT_ABS", /* 95 */ + "R_ARM_GOT_PREL", /* 96 */ + "R_ARM_GOT_BREL12", /* 97 */ + "R_ARM_GOTOFF12", /* 98 */ + "R_ARM_GOTRELAX", /* 99 */ + "R_ARM_GNU_VTENTRY", /* 100 */ + "R_ARM_GNU_VTINHERIT", /* 101 */ + "R_ARM_THM_JUMP11", /* 102 */ + "R_ARM_THM_JUMP8", /* 103 */ + "R_ARM_TLS_GD32", /* 104 */ + "R_ARM_TLS_LDM32", /* 105 */ + "R_ARM_TLS_LDO32", /* 106 */ + "R_ARM_TLS_IE32", /* 107 */ + "R_ARM_TLS_LE32", /* 108 */ + "R_ARM_TLS_LDO12", /* 109 */ + "R_ARM_TLS_LE12", /* 110 */ + "R_ARM_TLS_IE12GP", /* 111 */ + "R_ARM_TLS_MOVT_TPOFF32", /* 112 */ /* "R_ARM_PRIVATE_0" */ + "R_ARM_TLS_MOVW_TPOFF32", /* 113 */ /* "R_ARM_PRIVATE_1" */ + "R_ARM_THM_TLS_MOVT_TPOFF32", /* 114 */ /* "R_ARM_PRIVATE_2" */ + "R_ARM_THM_TLS_MOVT_TPOFF32", /* 115 */ /* "R_ARM_PRIVATE_3" */ + "R_ARM_PRIVATE_4", /* 116 */ + "R_ARM_PRIVATE_5", /* 117 */ + "R_ARM_PRIVATE_6", /* 118 */ + "R_ARM_PRIVATE_7", /* 119 */ + "R_ARM_PRIVATE_8", /* 120 */ + "R_ARM_PRIVATE_9", /* 121 */ + "R_ARM_PRIVATE_10", /* 122 */ + "R_ARM_PRIVATE_11", /* 123 */ + "R_ARM_PRIVATE_12", /* 124 */ + "R_ARM_PRIVATE_13", /* 125 */ + "R_ARM_PRIVATE_14", /* 126 */ + "R_ARM_PRIVATE_15", /* 127 */ + "R_ARM_ME_TOO", /* 128 */ + "R_ARM_THM_TLS_DESCSEQ16", /* 129 */ + "R_ARM_THM_TLS_DESCSEQ32", /* 130 */ +}; + +/* Record the relocation table name information */ +static char **reloc_type_names = NULL; +static Dwarf_Small number_of_reloc_type_names = 0; + +/* Set the relocation names based on the machine type */ +static void +set_relocation_table_names(Dwarf_Small machine_type) +{ + switch (machine_type) { + case EM_MIPS: + reloc_type_names = reloc_type_names_MIPS; + number_of_reloc_type_names = + sizeof(reloc_type_names_MIPS) / sizeof(char *); + break; + case EM_PPC: + reloc_type_names = reloc_type_names_PPC; + number_of_reloc_type_names = + sizeof(reloc_type_names_PPC) / sizeof(char *); + break; + case EM_PPC64: + reloc_type_names = reloc_type_names_PPC64; + number_of_reloc_type_names = + sizeof(reloc_type_names_PPC64) / sizeof(char *); + break; + case EM_ARM: + reloc_type_names = reloc_type_names_ARM; + number_of_reloc_type_names = + sizeof(reloc_type_names_ARM) / sizeof(char *); + break; + default: + /* We don't have others covered. */ + reloc_type_names = 0; + number_of_reloc_type_names = 0; + break; + } +} + +/* + Return valid reloc type names. + If buf is used, it is static, so beware: it + will be overwritten by the next call. +*/ +static char * +get_reloc_type_names(int index) +{ + static char buf[100]; + char *retval = 0; + + if (index < 0 || index >= number_of_reloc_type_names) { + sprintf(buf, "reloc type %d unknown", (int) index); + retval = buf; + } else { + retval = reloc_type_names[index]; + } + return retval; +} + +#ifndef HAVE_ELF64_GETEHDR +#define Elf64_Addr long +#define Elf64_Word unsigned long +#define Elf64_Xword unsigned long +#define Elf64_Sym long +#endif + +static struct { + Dwarf_Small *buf; + Dwarf_Unsigned size; + Dwarf_Bool display; /* Display reloc if TRUE */ + const char *name; /* Section name */ + Elf64_Xword type; /* To cover 32 and 64 records types */ +} sect_data[DW_SECTION_REL_DEBUG_NUM]; + + +typedef size_t indx_type; + +typedef struct { + indx_type indx; + char *name; + Elf32_Addr value; + Elf32_Word size; + int type; + int bind; + unsigned char other; + Elf32_Half shndx; +} SYM; + + +typedef struct { + indx_type indx; + char *name; + Elf64_Addr value; + Elf64_Xword size; + int type; + int bind; + unsigned char other; + unsigned short shndx; +} SYM64; + +static void print_reloc_information_64(int section_no, + Dwarf_Small * buf, + Dwarf_Unsigned size, + Elf64_Xword type, + char **scn_names,int scn_names_count); +static void print_reloc_information_32(int section_no, + Dwarf_Small * buf, + Dwarf_Unsigned size, + Elf64_Xword type, + char **scn_names,int scn_names_count); +static SYM *readsyms(Elf32_Sym * data, size_t num, Elf * elf, + Elf32_Word link); +static SYM64 *read_64_syms(Elf64_Sym * data, size_t num, Elf * elf, + Elf64_Word link); +static void *get_scndata(Elf_Scn * fd_scn, size_t * scn_size); +static void print_relocinfo_64(Dwarf_Debug dbg, Elf * elf); +static void print_relocinfo_32(Dwarf_Debug dbg, Elf * elf); + +static SYM *sym_data; +static SYM64 *sym_data_64; +static long sym_data_entry_count; +static long sym_data_64_entry_count; + +typedef struct { + indx_type index; + char *name_rel; /* .rel.debug_* names */ + char *name_rela; /* .rela.debug_* names */ +} REL_INFO; + +/* If the incoming scn_name is known, record the name + in our reloc section names table. + For a given (debug) section there can be a .rel or a .rela, + not both. + The name-to-index in this table is fixed, invariant. + It has to match other tables like +*/ +static int +get_reloc_section(Dwarf_Debug dbg, + Elf_Scn *scn, + char *scn_name, + Elf64_Word sh_type) +{ + static REL_INFO rel_info[DW_SECTION_REL_DEBUG_NUM] = { + {/*0*/ DW_SECTION_REL_DEBUG_INFO, + DW_SECTNAME_REL_DEBUG_INFO, + DW_SECTNAME_RELA_DEBUG_INFO}, + + {/*1*/ DW_SECTION_REL_DEBUG_LINE, + DW_SECTNAME_REL_DEBUG_LINE, + DW_SECTNAME_RELA_DEBUG_LINE}, + + {/*2*/ DW_SECTION_REL_DEBUG_PUBNAMES, + DW_SECTNAME_REL_DEBUG_PUBNAMES, + DW_SECTNAME_RELA_DEBUG_PUBNAMES}, + + {/*3*/ DW_SECTION_REL_DEBUG_ABBREV, + DW_SECTNAME_REL_DEBUG_ABBREV, + DW_SECTNAME_RELA_DEBUG_ABBREV}, + + {/*4*/ DW_SECTION_REL_DEBUG_ARANGES, + DW_SECTNAME_REL_DEBUG_ARANGES, + DW_SECTNAME_RELA_DEBUG_ARANGES}, + + {/*5*/ DW_SECTION_REL_DEBUG_FRAME, + DW_SECTNAME_REL_DEBUG_FRAME, + DW_SECTNAME_RELA_DEBUG_FRAME}, + + {/*6*/ DW_SECTION_REL_DEBUG_LOC, + DW_SECTNAME_REL_DEBUG_LOC, + DW_SECTNAME_RELA_DEBUG_LOC}, + + {/*7*/ DW_SECTION_REL_DEBUG_RANGES, + DW_SECTNAME_REL_DEBUG_RANGES, + DW_SECTNAME_RELA_DEBUG_RANGES}, + + {/*8*/ DW_SECTION_REL_DEBUG_TYPES, + DW_SECTNAME_REL_DEBUG_TYPES, + DW_SECTNAME_RELA_DEBUG_TYPES}, + }; + + Elf_Data *data; + int index; + for (index = 0; index < DW_SECTION_REL_DEBUG_NUM; ++index) { + const char *n = rel_info[index].name_rel; + const char *na = rel_info[index].name_rela; + if (strcmp(scn_name, n) == 0) { + SECT_DATA_SET(rel_info[index].index,sh_type,n) + return TRUE; + } + if (strcmp(scn_name, na) == 0) { + SECT_DATA_SET(rel_info[index].index,sh_type,na) + return TRUE; + } + } + return FALSE; +} + +void +print_relocinfo(Dwarf_Debug dbg, unsigned reloc_map) +{ + Elf *elf; + char *endr_ident; + int is_64bit; + int res; + int i; + + for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) { + sect_data[i].display = reloc_map & (1 << i); + sect_data[i].buf = 0; + sect_data[i].size = 0; + sect_data[i].type = SHT_NULL; + } + res = dwarf_get_elf(dbg, &elf, &err); + if (res != DW_DLV_OK) { + print_error(dbg, "dwarf_get_elf error", res, err); + } + if ((endr_ident = elf_getident(elf, NULL)) == NULL) { + print_error(dbg, "DW_ELF_GETIDENT_ERROR", res, err); + } + is_64bit = (endr_ident[EI_CLASS] == ELFCLASS64); + if (is_64bit) { + print_relocinfo_64(dbg, elf); + } else { + print_relocinfo_32(dbg, elf); + } +} + +static void +print_relocinfo_64(Dwarf_Debug dbg, Elf * elf) +{ +#ifdef HAVE_ELF64_GETEHDR + Elf_Scn *scn = NULL; + Elf64_Ehdr *ehdr64 = 0; + Elf64_Shdr *shdr64 = 0; + char *scn_name = 0; + int i = 0; + Elf64_Sym *sym_64 = 0; + char **scn_names = 0; + int scn_names_cnt = 0; + + ehdr64 = elf64_getehdr(elf); + if (ehdr64 == NULL) { + print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err); + } + + /* Make the section name array big enough + that we don't need to check for overrun in the loop. */ + scn_names = (char **)calloc(ehdr64->e_shnum + 1, sizeof(char *)); + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + + shdr64 = elf64_getshdr(scn); + if (shdr64 == NULL) { + print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err); + } + scn_name = elf_strptr(elf, ehdr64->e_shstrndx, shdr64->sh_name); + if (scn_name == NULL) { + print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err); + } + + if (scn_names) { + /* elf_nextscn() skips section with index '0' */ + scn_names[++scn_names_cnt] = scn_name; + } + if (shdr64->sh_type == SHT_SYMTAB) { + size_t sym_size = 0; + size_t count = 0; + + sym_64 = (Elf64_Sym *) get_scndata(scn, &sym_size); + if (sym_64 == NULL) { + print_error(dbg, "no symbol table data", DW_DLV_OK, + err); + } + count = sym_size / sizeof(Elf64_Sym); + sym_64++; + free(sym_data_64); + sym_data_64 = read_64_syms(sym_64, count, elf, shdr64->sh_link); + sym_data_64_entry_count = count; + if (sym_data_64 == NULL) { + print_error(dbg, "problem reading symbol table data", + DW_DLV_OK, err); + } + } else if (!get_reloc_section(dbg,scn,scn_name,shdr64->sh_type)) { + continue; + } + } /* while */ + + /* Set the relocation names based on the machine type */ + set_relocation_table_names(ehdr64->e_machine); + + for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) { + if (sect_data[i].display && + sect_data[i].buf != NULL && + sect_data[i].size > 0) { + print_reloc_information_64(i, sect_data[i].buf, + sect_data[i].size, sect_data[i].type,scn_names, + scn_names_cnt); + } + } + + if (scn_names) { + free(scn_names); + scn_names = 0; + scn_names_cnt = 0; + } +#endif +} + +static void +print_relocinfo_32(Dwarf_Debug dbg, Elf * elf) +{ + Elf_Scn *scn = NULL; + Elf32_Ehdr *ehdr32 = 0; + Elf32_Shdr *shdr32 = 0; + char *scn_name = 0; + int i = 0; + Elf32_Sym *sym = 0; + char **scn_names = 0; + int scn_names_cnt = 0; + + ehdr32 = elf32_getehdr(elf); + if (ehdr32 == NULL) { + print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err); + } + + /* Make the section name array big enough + that we don't need to check for overrun in the loop. */ + scn_names = (char **)calloc(ehdr32->e_shnum + 1, sizeof(char *)); + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + shdr32 = elf32_getshdr(scn); + if (shdr32 == NULL) { + print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err); + } + scn_name = elf_strptr(elf, ehdr32->e_shstrndx, shdr32->sh_name); + if (scn_name == NULL) { + print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err); + } + + if (scn_names) { + /* elf_nextscn() skips section with index '0' */ + scn_names[++scn_names_cnt] = scn_name; + } + + if (shdr32->sh_type == SHT_SYMTAB) { + size_t sym_size = 0; + size_t count = 0; + + sym = (Elf32_Sym *) get_scndata(scn, &sym_size); + if (sym == NULL) { + print_error(dbg, "no symbol table data", DW_DLV_OK, + err); + } + sym = (Elf32_Sym *) get_scndata(scn, &sym_size); + count = sym_size / sizeof(Elf32_Sym); + sym++; + free(sym_data); + sym_data = readsyms(sym, count, elf, shdr32->sh_link); + sym_data_entry_count = count; + if (sym_data == NULL) { + print_error(dbg, "problem reading symbol table data", + DW_DLV_OK, err); + } + } else if (!get_reloc_section(dbg,scn,scn_name,shdr32->sh_type)) { + continue; + } + } /* End while. */ + + /* Set the relocation names based on the machine type */ + set_relocation_table_names(ehdr32->e_machine); + + for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) { + if (sect_data[i].display && + sect_data[i].buf != NULL && + sect_data[i].size > 0) { + print_reloc_information_32(i, sect_data[i].buf, + sect_data[i].size,sect_data[i].type,scn_names, + scn_names_cnt); + } + } + + if (scn_names) { + free(scn_names); + scn_names = 0; + scn_names_cnt = 0; + } +} + +#if HAVE_ELF64_R_INFO +#ifndef ELF64_R_TYPE +#define ELF64_R_TYPE(x) 0 /* FIXME */ +#endif +#ifndef ELF64_R_SYM +#define ELF64_R_SYM(x) 0 /* FIXME */ +#endif +#ifndef ELF64_ST_TYPE +#define ELF64_ST_TYPE(x) 0 /* FIXME */ +#endif +#ifndef ELF64_ST_BIND +#define ELF64_ST_BIND(x) 0 /* FIXME */ +#endif +#endif /* HAVE_ELF64_R_INFO */ + + +static void +print_reloc_information_64(int section_no, Dwarf_Small * buf, + Dwarf_Unsigned size, Elf64_Xword type, + char **scn_names, int scn_names_count) +{ + /* Include support for Elf64_Rel and Elf64_Rela */ + Dwarf_Unsigned add = 0; + Dwarf_Half rel_size = SHT_RELA == type ? + sizeof(Elf64_Rela) : sizeof(Elf64_Rel); + Dwarf_Unsigned off = 0; + + printf("\n%s:\n", type== SHT_RELA?sectnamesa[section_no]: + sectnames[section_no]); + + /* Print some headers and change the order for better reading */ + printf("Offset Addend %-26s Index Symbol Name\n","Reloc Type"); + +#if HAVE_ELF64_GETEHDR + for (off = 0; off < size; off += rel_size) { +#if HAVE_ELF64_R_INFO + /* This works for the Elf64_Rel in linux */ + Elf64_Rel *p = (Elf64_Rel *) (buf + off); + char *name = 0; + if(sym_data ) { + size_t index = ELF64_R_SYM(p->r_info) - 1; + if(index < sym_data_entry_count) { + name = sym_data[index].name; + } + } else if (sym_data_64) { + size_t index = ELF64_R_SYM(p->r_info) - 1; + if(index < sym_data_64_entry_count) { + name = sym_data_64[index].name; + } + } + + /* When the name is not available, use the + section name as a reference for the name.*/ + if (!name || !name[0]) { + size_t index = ELF64_R_SYM(p->r_info) - 1; + if(index < sym_data_64_entry_count) { + SYM64 *sym_64 = &sym_data_64[index]; + if (sym_64->type == STT_SECTION && + sym_64->shndx < scn_names_count) { + name = scn_names[sym_64->shndx]; + } + } + } + if(!name || !name[0]) { + name = "<no name>"; + } + + if (SHT_RELA == type) { + Elf64_Rela *pa = (Elf64_Rela *)p; + add = pa->r_addend; + } + + printf("0x%08lx 0x%08lx %-26s <%5ld> %s\n", + (unsigned long int) (p->r_offset), + (unsigned long int) (add), + get_reloc_type_names(ELF64_R_TYPE(p->r_info)), + (long)ELF64_R_SYM(p->r_info), + name); +#else + /* sgi/mips -64 does not have r_info in the 64bit relocations, + but seperate fields, with 3 types, actually. Only one of + which prints here, as only one really used with dwarf */ + Elf64_Rel *p = (Elf64_Rel *) (buf + off); + char *name = 0; + if(sym_data ) { + size_t index = p->r_sym - 1; + if(index < sym_data_entry_count) { + name = sym_data[index].name; + } + } else if (sym_data_64) { + size_t index = p->r_sym - 1; + if(index < sym_data_64_entry_count) { + name = sym_data_64[index].name; + } + } + if(!name || !name[0]) { + name = "<no name>"; + } + printf("%5" DW_PR_DUu " %-26s <%3ld> %s\n", + (Dwarf_Unsigned) (p->r_offset), + get_reloc_type_names(p->r_type), + (long)p->r_sym, + name); +#endif + } +#endif /* HAVE_ELF64_GETEHDR */ +} + +static void +print_reloc_information_32(int section_no, Dwarf_Small * buf, + Dwarf_Unsigned size, Elf64_Xword type, char **scn_names, + int scn_names_count) +{ + /* Include support for Elf32_Rel and Elf32_Rela */ + Dwarf_Unsigned add = 0; + Dwarf_Half rel_size = SHT_RELA == type ? + sizeof(Elf32_Rela) : sizeof(Elf32_Rel); + Dwarf_Unsigned off = 0; + + printf("\n%s:\n", type== SHT_RELA?sectnamesa[section_no]: + sectnames[section_no]); + + + /* Print some headers and change the order for better reading. */ + printf("Offset Addend %-26s Index Symbol Name\n","Reloc Type"); + + for (off = 0; off < size; off += rel_size) { + Elf32_Rel *p = (Elf32_Rel *) (buf + off); + char *name = 0; + + if(sym_data) { + size_t index = ELF32_R_SYM(p->r_info) - 1; + if(index < sym_data_entry_count) { + name = sym_data[index].name; + } + } + + /* When the name is not available, use the + section name as a reference for the name. */ + if (!name || !name[0]) { + size_t index = ELF32_R_SYM(p->r_info) - 1; + if(index < sym_data_entry_count) { + SYM *sym = &sym_data[index]; + if (sym->type == STT_SECTION&& + sym->shndx < scn_names_count) { + name = scn_names[sym->shndx]; + } + } + } + if(!name || !name[0]) { + name = "<no name>"; + } + if (SHT_RELA == type) { + Elf32_Rela *pa = (Elf32_Rela *)p; + add = pa->r_addend; + } + printf("0x%08lx 0x%08lx %-26s <%5ld> %s\n", + (unsigned long int) (p->r_offset), + (unsigned long int) (add), + get_reloc_type_names(ELF32_R_TYPE(p->r_info)), + (long)ELF32_R_SYM(p->r_info), + name); + } +} + +static SYM * +readsyms(Elf32_Sym * data, size_t num, Elf * elf, Elf32_Word link) +{ + SYM *s, *buf; + indx_type i; + + buf = (SYM *) calloc(num, sizeof(SYM)); + if (buf == NULL) { + return NULL; + } + s = buf; /* save pointer to head of array */ + for (i = 1; i < num; i++, data++, buf++) { + buf->indx = i; + buf->name = (char *) elf_strptr(elf, link, data->st_name); + buf->value = data->st_value; + buf->size = data->st_size; + buf->type = ELF32_ST_TYPE(data->st_info); + buf->bind = ELF32_ST_BIND(data->st_info); + buf->other = data->st_other; + buf->shndx = data->st_shndx; + } /* end for loop */ + return (s); +} + +static SYM64 * +read_64_syms(Elf64_Sym * data, size_t num, Elf * elf, Elf64_Word link) +{ +#ifdef HAVE_ELF64_GETEHDR + + SYM64 *s, *buf; + indx_type i; + + buf = (SYM64 *) calloc(num, sizeof(SYM64)); + if (buf == NULL) { + return NULL; + } + s = buf; /* save pointer to head of array */ + for (i = 1; i < num; i++, data++, buf++) { + buf->indx = i; + buf->name = (char *) elf_strptr(elf, link, data->st_name); + buf->value = data->st_value; + buf->size = data->st_size; + buf->type = ELF64_ST_TYPE(data->st_info); + buf->bind = ELF64_ST_BIND(data->st_info); + buf->other = data->st_other; + buf->shndx = data->st_shndx; + } /* end for loop */ + return (s); +#else + return 0; +#endif /* HAVE_ELF64_GETEHDR */ +} + +static void * +get_scndata(Elf_Scn * fd_scn, size_t * scn_size) +{ + Elf_Data *p_data; + + p_data = 0; + if ((p_data = elf_getdata(fd_scn, p_data)) == 0 || + p_data->d_size == 0) { + return NULL; + } + *scn_size = p_data->d_size; + return (p_data->d_buf); +} + +/* Cleanup of malloc space (some of the pointers will be 0 here) + so dwarfdump looks 'clean' to a malloc checker. +*/ +void +clean_up_syms_malloc_data() +{ + free(sym_data); + sym_data = 0; + free(sym_data_64); + sym_data_64 = 0; + sym_data_64_entry_count = 0; + sym_data_entry_count = 0; +} diff --git a/dwarfdump/print_reloc.h b/dwarfdump/print_reloc.h new file mode 100644 index 0000000..d511b71 --- /dev/null +++ b/dwarfdump/print_reloc.h @@ -0,0 +1,307 @@ +/*
+ Copyright (C) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved.
+ Portions Copyright (C) 2011 SN Systems Ltd. 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_reloc.c,v 1.11 2005/08/04 05:09:37 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.
+*/
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE 0
+#define R_PPC_ADDR32 1 /* 32bit absolute address */
+#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
+#define R_PPC_ADDR16 3 /* 16bit absolute address */
+#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
+#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN 8
+#define R_PPC_ADDR14_BRNTAKEN 9
+#define R_PPC_REL24 10 /* PC relative 26 bit */
+#define R_PPC_REL14 11 /* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN 12
+#define R_PPC_REL14_BRNTAKEN 13
+#define R_PPC_GOT16 14
+#define R_PPC_GOT16_LO 15
+#define R_PPC_GOT16_HI 16
+#define R_PPC_GOT16_HA 17
+#define R_PPC_PLTREL24 18
+#define R_PPC_COPY 19
+#define R_PPC_GLOB_DAT 20
+#define R_PPC_JMP_SLOT 21
+#define R_PPC_RELATIVE 22
+#define R_PPC_LOCAL24PC 23
+#define R_PPC_UADDR32 24
+#define R_PPC_UADDR16 25
+#define R_PPC_REL32 26
+#define R_PPC_PLT32 27
+#define R_PPC_PLTREL32 28
+#define R_PPC_PLT16_LO 29
+#define R_PPC_PLT16_HI 30
+#define R_PPC_PLT16_HA 31
+#define R_PPC_SDAREL16 32
+#define R_PPC_SECTOFF 33
+#define R_PPC_SECTOFF_LO 34
+#define R_PPC_SECTOFF_HI 35
+#define R_PPC_SECTOFF_HA 36
+
+/* Unused types */
+#define R_PPC_37 37
+#define R_PPC_38 38
+#define R_PPC_39 39
+#define R_PPC_40 40
+#define R_PPC_41 41
+#define R_PPC_42 42
+#define R_PPC_43 43
+#define R_PPC_44 44
+#define R_PPC_45 45
+#define R_PPC_46 46
+#define R_PPC_47 47
+#define R_PPC_48 48
+#define R_PPC_49 49
+#define R_PPC_50 50
+#define R_PPC_51 51
+#define R_PPC_52 52
+#define R_PPC_53 53
+#define R_PPC_54 54
+#define R_PPC_55 55
+
+/* Unused types */
+#define R_PPC_56 56
+#define R_PPC_57 57
+#define R_PPC_58 58
+#define R_PPC_59 59
+#define R_PPC_60 60
+#define R_PPC_61 61
+#define R_PPC_62 62
+#define R_PPC_63 63
+#define R_PPC_64 64
+#define R_PPC_65 65
+#define R_PPC_66 66
+
+/* PowerPC relocations defined for the TLS access ABI. */
+#define R_PPC_TLS 67 /* none (sym+add)@tls */
+#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
+#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
+#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
+
+/* Keep this the last entry. */
+#define R_PPC_NUM 95
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE R_PPC_NONE
+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address. */
+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned. */
+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address. */
+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of abs. address. */
+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of abs. address. */
+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned. */
+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24 R_PPC_REL24 /* PC relative 26 bit, word aligned. */
+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit. */
+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16 R_PPC_GOT16
+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
+
+#define R_PPC64_COPY R_PPC_COPY
+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32 R_PPC_UADDR32
+#define R_PPC64_UADDR16 R_PPC_UADDR16
+#define R_PPC64_REL32 R_PPC_REL32
+#define R_PPC64_PLT32 R_PPC_PLT32
+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2. */
+#define R_PPC64_ADDR64 38 /* doubleword64 S + A. */
+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A). */
+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A). */
+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A). */
+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A). */
+#define R_PPC64_UADDR64 43 /* doubleword64 S + A. */
+#define R_PPC64_REL64 44 /* doubleword64 S + A - P. */
+#define R_PPC64_PLT64 45 /* doubleword64 L + A. */
+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P. */
+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC. */
+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.). */
+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.). */
+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.). */
+#define R_PPC64_TOC 51 /* doubleword64 .TOC. */
+#define R_PPC64_PLTGOT16 52 /* half16* M + A. */
+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A). */
+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A). */
+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A). */
+
+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2. */
+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2. */
+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2. */
+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2. */
+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2. */
+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2. */
+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2. */
+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2. */
+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2. */
+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2. */
+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2. */
+
+/* PowerPC64 relocations defined for the TLS access ABI. */
+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
+
+/* Additional relocation types */
+#define R_PPC64_TOC32 107
+#define R_PPC64_DTPMOD32 108
+#define R_PPC64_TPREL32 109
+#define R_PPC64_DTPREL32 110
+
+/* Keep this the last entry. */
+#define R_PPC64_NUM 111
+
+/* Relocation types for MIPS */
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_ADD 2
+#define R_MIPS_REL 3
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL 7
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT 9
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL 11
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+
+#define R_MIPS_SHIFT5 16
+#define R_MIPS_SHIFT6 17
+#define R_MIPS_64 18
+#define R_MIPS_GOT_DISP 19
+#define R_MIPS_GOT_PAGE 20
+#define R_MIPS_GOT_OFST 21
+#define R_MIPS_GOT_HI16 22
+#define R_MIPS_GOT_LO16 23
+#define R_MIPS_SUB 24
+#define R_MIPS_INSERT_A 25
+#define R_MIPS_INSERT_B 26
+#define R_MIPS_DELETE 27
+#define R_MIPS_HIGHER 28
+#define R_MIPS_HIGHEST 29
+#define R_MIPS_CALL_HI16 30
+#define R_MIPS_CALL_LO16 31
+#define R_MIPS_SCN_DISP 32
+#define R_MIPS_REL16 33
+#define R_MIPS_ADD_IMMEDIATE 34
diff --git a/dwarfdump/print_sections.c b/dwarfdump/print_sections.c new file mode 100644 index 0000000..a5e6ef1 --- /dev/null +++ b/dwarfdump/print_sections.c @@ -0,0 +1,206 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" +#include "print_frames.h" + +/* + Print line number information: + filename + new basic-block + [line] [address] <new statement> +*/ + +int dwarf_names_print_on_error = 1; + +/* referred in dwarfdump.c */ +Dwarf_Die current_cu_die_for_print_frames; + +void +deal_with_name_offset_err(Dwarf_Debug dbg, + char *err_loc, + char *name, Dwarf_Unsigned die_off, + int nres, Dwarf_Error err) +{ + if (nres == DW_DLV_ERROR) { + Dwarf_Unsigned myerr = dwarf_errno(err); + + if (myerr == DW_DLE_OFFSET_BAD) { + printf("Error: bad offset %s, %s %" DW_PR_DUu + " (0x%08" DW_PR_DUx ")\n", + err_loc, + name, + die_off, + die_off); + } + print_error(dbg, err_loc, nres, err); + } +} + + + +/* The April 2005 dwarf_get_section_max_offsets() + in libdwarf returns all max-offsets, but we only + want one of those offsets. This function returns + the one we want from that set, + making functions needing this offset as readable as possible. + (avoiding code duplication). +*/ +Dwarf_Unsigned +get_info_max_offset(Dwarf_Debug dbg) +{ + Dwarf_Unsigned debug_info_size = 0; + Dwarf_Unsigned debug_abbrev_size = 0; + Dwarf_Unsigned debug_line_size = 0; + Dwarf_Unsigned debug_loc_size = 0; + Dwarf_Unsigned debug_aranges_size = 0; + Dwarf_Unsigned debug_macinfo_size = 0; + Dwarf_Unsigned debug_pubnames_size = 0; + Dwarf_Unsigned debug_str_size = 0; + Dwarf_Unsigned debug_frame_size = 0; + Dwarf_Unsigned debug_ranges_size = 0; + Dwarf_Unsigned debug_pubtypes_size = 0; + + dwarf_get_section_max_offsets(dbg, + &debug_info_size, + &debug_abbrev_size, + &debug_line_size, + &debug_loc_size, + &debug_aranges_size, + &debug_macinfo_size, + &debug_pubnames_size, + &debug_str_size, + &debug_frame_size, + &debug_ranges_size, + &debug_pubtypes_size); + + return debug_info_size; +} + +/* + decode ULEB +*/ +Dwarf_Unsigned +local_dwarf_decode_u_leb128(unsigned char *leb128, + unsigned int *leb128_length) +{ + unsigned char byte = 0; + Dwarf_Unsigned number = 0; + unsigned int shift = 0; + unsigned int byte_length = 1; + + byte = *leb128; + for (;;) { + number |= (byte & 0x7f) << shift; + shift += 7; + + if ((byte & 0x80) == 0) { + if (leb128_length != NULL) + *leb128_length = byte_length; + return (number); + } + + byte_length++; + byte = *(++leb128); + } +} + +#define BITSINBYTE 8 +Dwarf_Signed +local_dwarf_decode_s_leb128(unsigned char *leb128, + unsigned int *leb128_length) +{ + Dwarf_Signed number = 0; + Dwarf_Bool sign = 0; + Dwarf_Signed shift = 0; + unsigned char byte = *leb128; + Dwarf_Signed byte_length = 1; + + /* byte_length being the number of bytes of data absorbed so far in + turning the leb into a Dwarf_Signed. */ + + for (;;) { + sign = byte & 0x40; + number |= ((Dwarf_Signed) ((byte & 0x7f))) << shift; + shift += 7; + + if ((byte & 0x80) == 0) { + break; + } + ++leb128; + byte = *leb128; + byte_length++; + } + + if ((shift < sizeof(Dwarf_Signed) * BITSINBYTE) && sign) { + number |= -((Dwarf_Signed) 1 << shift); + } + + if (leb128_length != NULL) + *leb128_length = byte_length; + return (number); +} + + +/* Dumping a dwarf-expression as a byte stream. */ +void +dump_block(char *prefix, char *data, Dwarf_Signed len) +{ + char *end_data = data + len; + char *cur = data; + int i = 0; + + printf("%s", prefix); + for (; cur < end_data; ++cur, ++i) { + if (i > 0 && i % 4 == 0) + printf(" "); + printf("%02x", 0xff & *cur); + + } +} + diff --git a/dwarfdump/print_sections.h b/dwarfdump/print_sections.h new file mode 100644 index 0000000..63015cd --- /dev/null +++ b/dwarfdump/print_sections.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 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 + + +*/ + + +extern int dwarf_names_print_on_error; + +void deal_with_name_offset_err(Dwarf_Debug dbg, + char *err_loc, + char *name, + Dwarf_Unsigned die_off, + int nres, + Dwarf_Error err); + +Dwarf_Unsigned get_info_max_offset(Dwarf_Debug dbg); + +void print_pubname_style_entry(Dwarf_Debug dbg, + char *line_title, + char *name, + Dwarf_Unsigned die_off, + Dwarf_Unsigned cu_off, + Dwarf_Unsigned global_cu_off, + Dwarf_Unsigned maxoff); diff --git a/dwarfdump/print_static_funcs.c b/dwarfdump/print_static_funcs.c new file mode 100644 index 0000000..c3dc59d --- /dev/null +++ b/dwarfdump/print_static_funcs.c @@ -0,0 +1,137 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" +#include "print_frames.h" + + +/* Get all the data in .debug_static_funcs + On error, this allows some dwarf memory leaks. +*/ +extern void +print_static_funcs(Dwarf_Debug dbg) +{ + Dwarf_Func *funcbuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + int gfres = 0; + + current_section_id = DEBUG_STATIC_FUNC; + + if (!do_print_dwarf) { + return; + } + + printf("\n.debug_static_func\n"); + gfres = dwarf_get_funcs(dbg, &funcbuf, &count, &err); + if (gfres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_funcs", gfres, err); + } else if (gfres == DW_DLV_NO_ENTRY) { + /* no static funcs */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (i = 0; i < count; i++) { + int fnres = 0; + int cures3 = 0; + Dwarf_Unsigned global_cu_off = 0; + char *name = 0; + + fnres = dwarf_func_name_offsets(funcbuf[i], &name, &die_off, + &cu_off, &err); + deal_with_name_offset_err(dbg, "dwarf_func_name_offsets", + name, die_off, fnres, err); + cures3 = dwarf_func_cu_offset(funcbuf[i], + &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_global_cu_offset", cures3, err); + } + + if (check_pubname_attr) { + Dwarf_Bool has_attr; + int ares; + int dres; + Dwarf_Die die; + + /* get die at die_off */ + dres = dwarf_offdie(dbg, die_off, &die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_offdie", dres, err); + } + + + ares = + dwarf_hasattr(die, DW_AT_external, &has_attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "hassattr on DW_AT_external", ares, + err); + } + if (checking_this_compiler()) { + DWARF_CHECK_COUNT(pubname_attr_result,1); + if (ares == DW_DLV_OK && has_attr) { + /* Should the value of flag be examined? */ + } else { + DWARF_CHECK_ERROR2(pubname_attr_result,name, + "pubname (in static funcs section) does not have DW_AT_external"); + } + } + dwarf_dealloc(dbg, die, DW_DLA_DIE); + } + + if (do_print_dwarf || record_dwarf_error) { + print_pubname_style_entry(dbg, + "static-func", name, die_off, + cu_off, global_cu_off, maxoff); + record_dwarf_error = FALSE; /* Clear error condition */ + } + } + dwarf_funcs_dealloc(dbg, funcbuf, count); + } +} /* print_static_funcs() */ diff --git a/dwarfdump/print_static_vars.c b/dwarfdump/print_static_vars.c new file mode 100644 index 0000000..5e42b67 --- /dev/null +++ b/dwarfdump/print_static_vars.c @@ -0,0 +1,104 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" +#include "print_frames.h" + +/* Get all the data in .debug_static_vars */ +extern void +print_static_vars(Dwarf_Debug dbg) +{ + Dwarf_Var *varbuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + char *name = 0; + int gvres = 0; + + current_section_id = DEBUG_STATIC_VARS; + + if (!do_print_dwarf) { + return; + } + + printf("\n.debug_static_vars\n"); + gvres = dwarf_get_vars(dbg, &varbuf, &count, &err); + if (gvres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_vars", gvres, err); + } else if (gvres == DW_DLV_NO_ENTRY) { + /* no static vars */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (i = 0; i < count; i++) { + int vnres = 0; + int cures3 = 0; + Dwarf_Off global_cu_off = 0; + + vnres = dwarf_var_name_offsets(varbuf[i], &name, &die_off, + &cu_off, &err); + deal_with_name_offset_err(dbg, + "dwarf_var_name_offsets", + name, die_off, vnres, err); + cures3 = dwarf_var_cu_offset(varbuf[i], + &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_global_cu_offset", cures3, err); + } + + print_pubname_style_entry(dbg, + "static-var", + name, die_off, cu_off, + global_cu_off, maxoff); + + /* print associated die too? */ + } + dwarf_vars_dealloc(dbg, varbuf, count); + } +} /* print_static_vars */ + diff --git a/dwarfdump/print_strings.c b/dwarfdump/print_strings.c new file mode 100644 index 0000000..0cd67b3 --- /dev/null +++ b/dwarfdump/print_strings.c @@ -0,0 +1,80 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" + +/* print data in .debug_string */ +extern void +print_strings(Dwarf_Debug dbg) +{ + Dwarf_Signed length = 0; + string name; + Dwarf_Off offset = 0; + int sres = 0; + + current_section_id = DEBUG_STR; + printf("\n.debug_string\n"); + while ((sres = dwarf_get_str(dbg, offset, &name, &length, &err)) + == DW_DLV_OK) { + if (display_offsets) { + printf("name at offset 0x%" DW_PR_XZEROS DW_PR_DUx + ", length %4" DW_PR_DSd " is '%s'\n", + (Dwarf_Unsigned)offset, length, name); + } else { + printf("name: length %4" DW_PR_DSd " is '%s'\n", + length, name); + } + offset += length + 1; + } + /* An inability to find the section is not necessarily + a real error, so do not report error unless we've + seen a real record. */ + if(sres == DW_DLV_ERROR && offset != 0) { + print_error(dbg, "dwarf_get_str failure", sres, err); + } +} diff --git a/dwarfdump/print_types.c b/dwarfdump/print_types.c new file mode 100644 index 0000000..f3fddba --- /dev/null +++ b/dwarfdump/print_types.c @@ -0,0 +1,141 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" +#include "print_frames.h" + +/* get all the data in .debug_types */ +extern void +print_types(Dwarf_Debug dbg, enum type_type_e type_type) +{ + Dwarf_Type *typebuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + char *name = NULL; + int gtres = 0; + + char *section_name = NULL; + char *offset_err_name = NULL; + char *section_open_name = NULL; + char *print_name_prefix = NULL; + int (*get_types) (Dwarf_Debug, Dwarf_Type **, Dwarf_Signed *, + Dwarf_Error *) = 0; + int (*get_offset) (Dwarf_Type, char **, Dwarf_Off *, Dwarf_Off *, + Dwarf_Error *) = NULL; + int (*get_cu_offset) (Dwarf_Type, Dwarf_Off *, Dwarf_Error *) = + NULL; + void (*dealloctype) (Dwarf_Debug, Dwarf_Type *, Dwarf_Signed) = + NULL; + + /* Do nothing if in check mode */ + if (!do_print_dwarf) { + return; + } + + + if (type_type == DWARF_PUBTYPES) { + section_name = ".debug_pubtypes"; + offset_err_name = "dwarf_pubtype_name_offsets"; + section_open_name = "dwarf_get_pubtypes"; + print_name_prefix = "pubtype"; + get_types = dwarf_get_pubtypes; + get_offset = dwarf_pubtype_name_offsets; + get_cu_offset = dwarf_pubtype_cu_offset; + dealloctype = dwarf_pubtypes_dealloc; + } else { + /* SGI_TYPENAME */ + section_name = ".debug_typenames"; + offset_err_name = "dwarf_type_name_offsets"; + section_open_name = "dwarf_get_types"; + print_name_prefix = "type"; + get_types = dwarf_get_types; + get_offset = dwarf_type_name_offsets; + get_cu_offset = dwarf_type_cu_offset; + dealloctype = dwarf_types_dealloc; + } + + + + gtres = get_types(dbg, &typebuf, &count, &err); + if (gtres == DW_DLV_ERROR) { + print_error(dbg, section_open_name, gtres, err); + } else if (gtres == DW_DLV_NO_ENTRY) { + /* no types */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + /* Before July 2005, the section name was printed + unconditionally, now only prints if non-empty section really + exists. */ + printf("\n%s\n", section_name); + + for (i = 0; i < count; i++) { + int tnres = 0; + int cures3 = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + Dwarf_Off global_cu_off = 0; + + tnres = + get_offset(typebuf[i], &name, &die_off, &cu_off, &err); + deal_with_name_offset_err(dbg, offset_err_name, name, + die_off, tnres, err); + cures3 = get_cu_offset(typebuf[i], &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_var_cu_offset", cures3, err); + } + print_pubname_style_entry(dbg, + print_name_prefix, + name, die_off, cu_off, + global_cu_off, maxoff); + + /* print associated die too? */ + } + dealloctype(dbg, typebuf, count); + } +} /* print_types() */ diff --git a/dwarfdump/print_weaknames.c b/dwarfdump/print_weaknames.c new file mode 100644 index 0000000..fd60ea8 --- /dev/null +++ b/dwarfdump/print_weaknames.c @@ -0,0 +1,104 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2009-2011 SN Systems Ltd. All rights reserved. + Portions Copyright 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 "dwconf.h" +#include "esb.h" + +#include "print_sections.h" + +/* Get all the data in .debug_weaknames */ +extern void +print_weaknames(Dwarf_Debug dbg) +{ + Dwarf_Weak *weaknamebuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + char *name = NULL; + int wkres = 0; + + current_section_id = DEBUG_WEAKNAMES; + + if (!do_print_dwarf) { + return; + } + printf("\n.debug_weaknames\n"); + wkres = dwarf_get_weaks(dbg, &weaknamebuf, &count, &err); + if (wkres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_weaks", wkres, err); + } else if (wkres == DW_DLV_NO_ENTRY) { + /* no weaknames */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (i = 0; i < count; i++) { + int tnres = 0; + int cures3 = 0; + Dwarf_Unsigned global_cu_off = 0; + + tnres = dwarf_weak_name_offsets(weaknamebuf[i], + &name, &die_off, &cu_off, + &err); + deal_with_name_offset_err(dbg, + "dwarf_weak_name_offsets", + name, die_off, tnres, err); + cures3 = dwarf_weak_cu_offset(weaknamebuf[i], + &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_weakname_cu_offset", + cures3, err); + } + print_pubname_style_entry(dbg, + "weakname", + name, die_off, cu_off, + global_cu_off, maxoff); + + /* print associated die too? */ + } + dwarf_weaks_dealloc(dbg, weaknamebuf, count); + } +} /* print_weaknames() */ diff --git a/dwarfdump/strstrnocase.c b/dwarfdump/strstrnocase.c new file mode 100755 index 0000000..082af66 --- /dev/null +++ b/dwarfdump/strstrnocase.c @@ -0,0 +1,118 @@ +/* + Copyright (C) 2009-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 + +*/ +/* The address of the Free Software Foundation is + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. */ + + + +/* +This tries to find the string 'contained' in the +string 'container'. it returns true if found, else false. +The comparisons are independent of case. + +Regrettably there is no generally accepted version that +does this job, though GNU Linux has strcasestr() which +does what we need. Our code here do not behave like +strstr or strcasestr in the case of +an empty 'contained' argument: we return FALSE (this +case is not interesting for dwarfdump). + +There is a public domain stristr(). But given that dwarfdump is GPL, +it would seem (IANAL) that we cannot mix public domain code +into the release. + +The software here is independently written and indeed trivial. + +The POSIX function tolower() is only properly defined on unsigned char, hence +the ugly casts. + +strstrnocase.c + +*/ +#include <ctype.h> +#include <stdio.h> +#include <globals.h> + +boolean +is_strstrnocase(const char * container, const char * contained) +{ + const unsigned char *ct = (const unsigned char *)container; + for( ; *ct; ++ct ) + { + const unsigned char * cntnd = (const unsigned char *)contained; + boolean innerwrong = TRUE; + for( ; *cntnd; ++cntnd,++ct) + { + char lct = tolower(*ct); + char tlc = tolower(*cntnd); + if(lct != tlc) { + innerwrong=TRUE; + break; /* Go to outer loop */ + } + innerwrong=FALSE; + } + if(!innerwrong) { + return TRUE; + } + } + return FALSE; +} + +#ifdef TEST +static void +test(const char *t1, const char *t2,int resexp) +{ + boolean res = is_strstrnocase(t1,t2); + if (res == resexp) { + return; + } + printf("Error,mismatch %s and %s. Expected %d got %d\n", + t1,t2,resexp,res); +} + +int main() +{ + test("aaaaa","a",1); + test("aaaaa","b",0); + test("abaaba","ba",1); + test("abaaxa","x",1); + test("abaabA","Ba",1); + test("a","ab",0); + test("b","c",0); + test("b","",0); + test("","c",0); + test("","",0); + test("aaaaa","aaaaaaaa",0); +} +#endif diff --git a/dwarfdump/tag_attr.c b/dwarfdump/tag_attr.c new file mode 100644 index 0000000..899a357 --- /dev/null +++ b/dwarfdump/tag_attr.c @@ -0,0 +1,286 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-2011 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/tag_attr.c,v 1.8 2005/12/01 17:34:59 davea Exp $ */ +#include <dwarf.h> +#include <stdio.h> +#include <stdlib.h> /* For exit() declaration etc. */ +#include <errno.h> /* For errno declaration. */ +#include <unistd.h> /* For getopt. */ + +#include "globals.h" +#include "libdwarf.h" +#include "common.h" +#include "tag_common.h" + +boolean ellipsis = FALSE; /* So we can use dwarf_names.c */ + +/* Expected input format + +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +... + +No blank lines or commentary allowed, no symbols, just numbers. + + +*/ + +unsigned int tag_attr_combination_table[ATTR_TABLE_ROW_MAXIMUM][ATTR_TABLE_COLUMN_MAXIMUM]; + + +static const char *usage[] = { + "Usage: tag_attr_build <options>", + " -i input-table-path", + " -o output-table-path", + " -s (Generate standard attribute table)", + " -e (Generate extended attribute table (common extensions))", + "" +}; + +char *program_name = 0; +char *input_name = 0; +char *output_name = 0; +int standard_flag = FALSE; +int extended_flag = FALSE; + +/* process arguments */ +void +process_args(int argc, char *argv[]) +{ + int c = 0; + boolean usage_error = FALSE; + + program_name = argv[0]; + + while ((c = getopt(argc, argv, "i:o:se")) != EOF) { + switch (c) { + case 'i': + input_name = optarg; + break; + case 'o': + output_name = optarg; + break; + case 'e': + extended_flag = TRUE; + break; + case 's': + standard_flag = TRUE; + break; + default: + usage_error = TRUE; + break; + } + } + + if (usage_error || 1 == optind || optind != argc) { + print_usage_message(argv[0],usage); + exit(FAILED); + } +} + + + +int +main(int argc, char **argv) +{ + int i = 0; + unsigned int num = 0; + int input_eof = 0; + int table_rows = 0; + int table_columns = 0; + int current_row = 0; + FILE * fileInp = 0; + FILE * fileOut = 0; + + print_version_details(argv[0],FALSE); + process_args(argc,argv); + print_args(argc,argv); + + if (!input_name ) { + fprintf(stderr,"Input name required, not supplied.\n"); + print_usage_message(argv[0],usage); + exit(FAILED); + } + fileInp = fopen(input_name,"r"); + if (!fileInp) { + fprintf(stderr,"Invalid input filename, could not open '%s'\n", + input_name); + print_usage_message(argv[0],usage); + exit(FAILED); + } + + + if (!output_name ) { + fprintf(stderr,"Output name required, not supplied.\n"); + print_usage_message(argv[0],usage); + exit(FAILED); + } + fileOut = fopen(output_name,"w"); + if (!fileOut) { + fprintf(stderr,"Invalid output filename, could not open: '%s'\n", + output_name); + print_usage_message(argv[0],usage); + exit(FAILED); + } + if ((standard_flag && extended_flag) || + (!standard_flag && !extended_flag)) { + fprintf(stderr,"Invalid table type\n"); + fprintf(stderr,"Choose -e or -s .\n"); + print_usage_message(argv[0],usage); + exit(FAILED); + } + + + if(standard_flag) { + table_rows = STD_ATTR_TABLE_ROWS; + table_columns = STD_ATTR_TABLE_COLUMNS; + } else { + table_rows = EXT_ATTR_TABLE_ROWS; + table_columns = EXT_ATTR_TABLE_COLS; + } + + input_eof = read_value(&num,fileInp); /* 0xffffffff */ + if (IS_EOF == input_eof) { + bad_line_input("Empty input file"); + } + if (num != MAGIC_TOKEN_VALUE) { + bad_line_input("Expected 0xffffffff"); + } + while (!feof(stdin)) { + unsigned int tag; + int curcol = 0; + + input_eof = read_value(&tag,fileInp); + if (IS_EOF == input_eof) { + /* Reached normal eof */ + break; + } + if(standard_flag) { + if (tag >= table_rows ) { + bad_line_input("tag value exceeds standard table size"); + } + } else { + if(current_row >= table_rows) { + bad_line_input("too many extended table rows."); + } + tag_attr_combination_table[current_row][0] = tag; + } + + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly.."); + } + curcol = 1; + while (num != MAGIC_TOKEN_VALUE) { + if(standard_flag) { + unsigned idx = num / BITS_PER_WORD; + unsigned bit = num % BITS_PER_WORD; + + if (idx >= table_columns) { + bad_line_input + ("too many attributes: table incomplete."); + } + tag_attr_combination_table[tag][idx] |= (1 << bit); + } else { + if (curcol >= table_columns) { + bad_line_input("too many attributes: table incomplete."); + } + tag_attr_combination_table[current_row][curcol] = num; + curcol++; + + } + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly."); + } + } + ++current_row; + } + fprintf(fileOut,"/* Generated code, do not edit. */\n"); + fprintf(fileOut,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(fileOut,"\n/* BEGIN FILE */\n\n"); + if (standard_flag) { + fprintf(fileOut,"#define ATTR_TREE_ROW_COUNT %d\n\n",table_rows); + fprintf(fileOut,"#define ATTR_TREE_COLUMN_COUNT %d\n\n",table_columns); + fprintf(fileOut, + "static unsigned int tag_attr_combination_table" + "[ATTR_TREE_ROW_COUNT][ATTR_TREE_COLUMN_COUNT] = {\n"); + } + else { + fprintf(fileOut,"/* Common extensions */\n"); + fprintf(fileOut,"#define ATTR_TREE_EXT_ROW_COUNT %d\n\n",table_rows); + fprintf(fileOut,"#define ATTR_TREE_EXT_COLUMN_COUNT %d\n\n", + table_columns); + fprintf(fileOut, + "static unsigned int tag_attr_combination_ext_table" + "[ATTR_TREE_EXT_ROW_COUNT][ATTR_TREE_EXT_COLUMN_COUNT] = {\n"); + } + + for (i = 0; i < table_rows; i++) { + int j = 0; + const char *name = 0; + if(standard_flag) { + dwarf_get_TAG_name(i,&name); + fprintf(fileOut,"/* %d %-37s*/\n",i,name); + } else { + int k = tag_attr_combination_table[i][0]; + dwarf_get_TAG_name(k,&name); + fprintf(fileOut,"/* %u %-37s*/\n",k,name); + } + fprintf(fileOut," { "); + for(j = 0; j < table_columns; ++j ) { + fprintf(fileOut,"0x%08x,",tag_attr_combination_table[i][j]); + } + fprintf(fileOut,"},\n"); + } + fprintf(fileOut,"};\n"); + fprintf(fileOut,"\n/* END FILE */\n"); + fclose(fileInp); + fclose(fileOut); + return (0); +} +/* A fake so we can use dwarf_names.c */ +void print_error (Dwarf_Debug dbg, string msg,int res, Dwarf_Error err) +{ +} + diff --git a/dwarfdump/tag_attr.list b/dwarfdump/tag_attr.list new file mode 100644 index 0000000..813ae18 --- /dev/null +++ b/dwarfdump/tag_attr.list @@ -0,0 +1,880 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_attr.list,v 1.7 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* + list for semantic check of tag-attr relation. + + 0xffffffff is a "punctuation." The final line of this file + must be 0xffffffff. The next line after each 0xffffffff + (except the final line) is a tag. The lines after this line + before the next 0xffffffff are the attributes that can be given + to the tag." + + For example, + + 0xffffffff + DW_TAG_access_declaration + DW_AT_decl_column + DW_AT_decl_file + DW_AT_decl_line + DW_AT_accessibility + DW_AT_name + DW_AT_sibling + 0xffffffff + + means "only DW_AT_decl_column, DW_AT_decl_file, DW_AT_decl_line, + DW_AT_accessibility, DW_AT_name and DW_AT_sibling can be given to + DW_TAG_access_declaration." + + This file is applied to the preprocessor, thus any C comment and + preprocessor control line is available. +*/ + +0xffffffff +DW_TAG_access_declaration +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_name +DW_AT_sibling +0xffffffff +DW_TAG_array_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_bit_stride +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_ordering +DW_AT_sibling +DW_AT_specification +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_base_type +DW_AT_allocated +DW_AT_associated +DW_AT_binary_scale +DW_AT_bit_offset +DW_AT_bit_size +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_bit_offset +DW_AT_data_location +DW_AT_decimal_scale +DW_AT_decimal_sign +DW_AT_description +DW_AT_digit_count +DW_AT_encoding +DW_AT_endianity +DW_AT_name +DW_AT_name +DW_AT_picture_string +DW_AT_sibling +DW_AT_small +0xffffffff +DW_TAG_catch_block +DW_AT_abstract_origin +DW_AT_high_pc +DW_AT_low_pc +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +0xffffffff +DW_TAG_class_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_visibility +0xffffffff +DW_TAG_common_block +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_declaration +DW_AT_location +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_visibility +0xffffffff +DW_TAG_common_inclusion +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_common_reference +DW_AT_declaration +DW_AT_sibling +DW_AT_visibility +0xffffffff +DW_TAG_compile_unit +DW_AT_base_types +DW_AT_comp_dir +DW_AT_identifier_case +DW_AT_high_pc +DW_AT_language +DW_AT_low_pc +DW_AT_macro_info +DW_AT_main_subprogram +DW_AT_name +DW_AT_producer +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +DW_AT_stmt_list +DW_AT_use_UTF8 +DW_AT_entry_pc +0xffffffff +DW_TAG_condition +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_name +DW_AT_sibling +0xffffffff +DW_TAG_const_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_constant +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_const_value +DW_AT_declaration +DW_AT_description +DW_AT_endianity +DW_AT_external +DW_AT_linkage_name +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_dwarf_procedure +DW_AT_location +0xffffffff +DW_TAG_entry_point +DW_AT_address_class +DW_AT_description +DW_AT_linkage_name +DW_AT_low_pc +DW_AT_name +DW_AT_return_addr +DW_AT_segment +DW_AT_sibling +DW_AT_static_link +DW_AT_type +0xffffffff +DW_TAG_enumeration_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_bit_stride +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_byte_stride +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_enum_class +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_enumerator +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_const_value +DW_AT_description +DW_AT_name +DW_AT_sibling +0xffffffff +DW_TAG_file_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_formal_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_artificial +DW_AT_const_value +DW_AT_default_value +DW_AT_description +DW_AT_endianity +DW_AT_is_optional +DW_AT_location +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_type +DW_AT_variable_parameter +0xffffffff +DW_TAG_friend +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_friend +DW_AT_sibling +0xffffffff +DW_TAG_imported_declaration +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_description +DW_AT_import +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_imported_module +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_import +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_imported_unit +DW_AT_import +0xffffffff +DW_TAG_inheritance +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_data_member_location +DW_AT_sibling +DW_AT_type +DW_AT_virtuality +0xffffffff +DW_TAG_inlined_subroutine +DW_AT_abstract_origin +DW_AT_call_column +DW_AT_call_file +DW_AT_call_line +DW_AT_const_expr +DW_AT_entry_pc +DW_AT_high_pc +DW_AT_low_pc +DW_AT_ranges +DW_AT_return_addr +DW_AT_segment +DW_AT_sibling +DW_AT_start_scope +DW_AT_trampoline +0xffffffff +DW_TAG_interface_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_label +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_description +DW_AT_low_pc +DW_AT_name +DW_AT_segment +DW_AT_start_scope +DW_AT_sibling +0xffffffff +DW_TAG_lexical_block +DW_AT_abstract_origin +DW_AT_description +DW_AT_high_pc +DW_AT_low_pc +DW_AT_name +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +0xffffffff +DW_TAG_member +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_bit_offset +DW_AT_bit_size +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_bit_offset +DW_AT_data_member_location +DW_AT_declaration +DW_AT_description +DW_AT_mutable +DW_AT_name +DW_AT_sibling +DW_AT_type +DW_AT_visibility +DW_AT_artificial +0xffffffff +DW_TAG_module +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_declaration +DW_AT_description +DW_AT_entry_pc +DW_AT_high_pc +DW_AT_low_pc +DW_AT_name +DW_AT_priority +DW_AT_segment +DW_AT_sibling +DW_AT_specification +DW_AT_visibility +0xffffffff +DW_TAG_namelist +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_abstract_origin +DW_AT_declaration +DW_AT_name +DW_AT_sibling +DW_AT_visibility +0xffffffff +DW_TAG_namelist_item +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_namelist_item +DW_AT_sibling +0xffffffff +DW_TAG_namespace +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_description +DW_AT_extension +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_packed_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_partial_unit +DW_AT_base_types +DW_AT_comp_dir +DW_AT_description +DW_AT_identifier_case +DW_AT_high_pc +DW_AT_language +DW_AT_low_pc +DW_AT_macro_info +DW_AT_main_subprogram +DW_AT_name +DW_AT_producer +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +DW_AT_stmt_list +DW_AT_use_UTF8 +0xffffffff +DW_TAG_pointer_type +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_specification +DW_AT_type +/* Comment from 1993: + "Though DWARF spec doesn't refer to DW_AT_byte_size, it may well be + given to DW_TAG_pointer_type." + Comment 31 January 2009: + Discussed in the dwarf-workgroup mailing list Jan 5 2009, that + DW_AT_byte_size is allowed. +*/ +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 (if DW_AT_byte_size allowed) */ +0xffffffff +DW_TAG_ptr_to_member_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_containing_type +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_type +DW_AT_use_location +DW_AT_visibility +0xffffffff +DW_TAG_rvalue_reference_type +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_reference_type +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +/* Comment from 1993: + "Though DWARF spec doesn't refer to DW_AT_byte_size, it may well be + given to DW_TAG_pointer_type." + Comment 31 January 2009: + Discussed in the dwarf-workgroup mailing list Jan 5 2009, that + DW_AT_byte_size is allowed. +*/ +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +0xffffffff +DW_TAG_template_alias +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_restrict_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_set_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_start_scope +DW_AT_sibling +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_shared_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_count +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_string_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_start_scope +DW_AT_string_length +DW_AT_visibility +0xffffffff +DW_TAG_structure_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_containing_type +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_visibility +0xffffffff +DW_TAG_subprogram +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_address_class +DW_AT_artificial +DW_AT_calling_convention +DW_AT_containing_type +DW_AT_declaration +DW_AT_description +DW_AT_elemental +DW_AT_entry_pc +DW_AT_explicit +DW_AT_external +DW_AT_frame_base +DW_AT_high_pc +DW_AT_inline +DW_AT_linkage_name +DW_AT_low_pc +DW_AT_main_subprogram +DW_AT_name +DW_AT_object_pointer +DW_AT_prototyped +DW_AT_pure +DW_AT_ranges +DW_AT_recursive +DW_AT_return_addr +DW_AT_segment +DW_AT_sibling +DW_AT_specification +DW_AT_start_scope +DW_AT_static_link +DW_AT_trampoline +DW_AT_type +DW_AT_visibility +DW_AT_virtuality +DW_AT_vtable_elem_location +0xffffffff +DW_TAG_subrange_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_bit_stride +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_byte_stride +DW_AT_count +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_lower_bound +DW_AT_name +DW_AT_sibling +DW_AT_threads_scaled +DW_AT_type +DW_AT_upper_bound +DW_AT_visibility +0xffffffff +DW_TAG_subroutine_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_prototyped +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_template_type_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_template_value_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_const_value +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_thrown_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_try_block +DW_AT_abstract_origin +DW_AT_high_pc +DW_AT_low_pc +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +0xffffffff +DW_TAG_typedef +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_union_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_visibility +0xffffffff +DW_TAG_unspecified_parameters +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_artificial +DW_AT_sibling +0xffffffff +DW_TAG_unspecified_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_description +DW_AT_sibling +0xffffffff +DW_TAG_variable +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_const_expr +DW_AT_const_value +DW_AT_declaration +DW_AT_description +DW_AT_endianity +DW_AT_external +DW_AT_linkage_name +DW_AT_location +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_specification +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +DW_AT_artificial +0xffffffff +DW_TAG_variant +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_abstract_origin +DW_AT_declaration +DW_AT_discr_list +DW_AT_discr_value +DW_AT_sibling +0xffffffff +DW_TAG_variant_part +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_abstract_origin +DW_AT_declaration +DW_AT_discr +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_volatile_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_with_stmt +DW_AT_accessibility +DW_AT_address_class +DW_AT_declaration +DW_AT_high_pc +DW_AT_location +DW_AT_low_pc +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_type_unit +DW_AT_language +0xffffffff + diff --git a/dwarfdump/tag_attr_ext.list b/dwarfdump/tag_attr_ext.list new file mode 100644 index 0000000..ce6d8b0 --- /dev/null +++ b/dwarfdump/tag_attr_ext.list @@ -0,0 +1,78 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_attr.list,v 1.7 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* list for semantic check of tag-attr relation. + See tag_attr.list for details. +*/ + +/* Common DWARF extensions */ + +0xffffffff +DW_TAG_member +DW_AT_GNU_guarded_by /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_pt_guarded_by /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_guarded /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_pt_guarded /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +0xffffffff +DW_TAG_array_type +DW_AT_GNU_vector +0xffffffff +DW_TAG_subprogram +DW_AT_MIPS_linkage_name /* Used by GNU, SGI-IRIX, and others. */ +DW_AT_MIPS_fde /* SGI-IRIX uses this */ +DW_AT_GNU_locks_excluded /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_exclusive_locks_required +DW_AT_GNU_shared_locks_required +0xffffffff +DW_TAG_variable +DW_AT_MIPS_linkage_name /* Used by GNU, SGI-IRIX, and others. */ +DW_AT_GNU_guarded_by +DW_AT_GNU_pt_guarded_by +DW_AT_GNU_guarded +DW_AT_GNU_pt_guarded +0xffffffff +DW_TAG_GNU_template_template_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_name +DW_AT_GNU_template_name +DW_AT_GNU_guarded_by /* GNU changed the name of 0x2108! */ +0xffffffff + diff --git a/dwarfdump/tag_common.c b/dwarfdump/tag_common.c new file mode 100644 index 0000000..28b2d2c --- /dev/null +++ b/dwarfdump/tag_common.c @@ -0,0 +1,145 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-2011 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/tag_common.c,v 1.8 2008/01/23 09:47:59 davea Exp $ */ + +#include <dwarf.h> +#include <stdio.h> +#include <stdlib.h>/* For exit() declaration etc. */ +#include <errno.h>/* For errno declaration. */ +#include <ctype.h> /* For isspace() declaration */ + +#include "globals.h" +#include "naming.h" +#include "tag_common.h" + +static int linecount = 0; +static char line_in[MAX_LINE_SIZE]; + +void +bad_line_input(char *msg) +{ + fprintf(stderr, + "tag_(tree,attr) table build failed %s, line %d: \"%s\" \n", + msg, linecount, line_in); + exit(FAILED); +} + +void +trim_newline(char *line, int max) +{ + char *end = line + max - 1; + + for (; *line && (line < end); ++line) { + if (*line == '\n') { + /* Found newline, drop it */ + *line = 0; + return; + } + } + return; +} + +/* Detect empty lines (and other lines we do not want to read) */ +boolean +is_skippable_line(char *pLine) +{ + boolean empty = TRUE; + + if(pLine[0] == '#') { + /* Preprocessor lines are of no interest. */ + return TRUE; + } + for (; *pLine && empty; ++pLine) { + empty = isspace(*pLine); + } + return empty; +} + +/* Reads a value from the text table. + Exits with non-zero status + if the table is erroneous in some way. +*/ +int +read_value(unsigned int *outval, FILE*file) +{ + char *res = 0; + unsigned long lval; + char *strout = 0; + boolean bBlankLine = TRUE; + + ++linecount; + *outval = 0; + + while (bBlankLine) { + res = fgets(line_in, sizeof(line_in), file); + if (res == 0) { + if (ferror(file)) { + fprintf(stderr, + "tag_attr: Error reading table, %d lines read\n", + linecount); + exit(FAILED); + } + + if (feof(file)) { + return IS_EOF; + } + + /* Impossible */ + fprintf(stderr, "tag_attr: Impossible error reading table, " + "%d lines read\n", linecount); + exit(FAILED); + } + + bBlankLine = is_skippable_line(line_in); + } + + trim_newline(line_in, sizeof(line_in)); + errno = 0; + lval = strtoul(line_in, &strout, 0); + + if (strout == line_in) { + bad_line_input("bad number input!"); + } + + if (errno != 0) { + int myerr = errno; + + fprintf(stderr, "tag_attr errno %d\n", myerr); + bad_line_input("invalid number on line"); + } + + *outval = (int) lval; + + return NOT_EOF; +} diff --git a/dwarfdump/tag_common.h b/dwarfdump/tag_common.h new file mode 100644 index 0000000..f06d9bd --- /dev/null +++ b/dwarfdump/tag_common.h @@ -0,0 +1,123 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-2011 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/tag_common.h,v 1.8 2008/01/23 09:47:59 davea Exp $ */ + +#ifndef tag_common_INCLUDED +#define tag_common_INCLUDED + + + +/* The following is the magic token used to + distinguish real tags/attrs from group-delimiters. + Blank lines have been eliminated by an awk script. +*/ +#define MAGIC_TOKEN_VALUE 0xffffffff + +/* TAG_TREE.LIST Expected input format + +0xffffffff +value of a tag +value of a standard tag that may be a child of that tag +... +0xffffffff +value of a tag +value of a standard tag that may be a child of that tag +... +0xffffffff +... + +No blank lines or commentary allowed, no symbols, just numbers. + +*/ + +/* TAG_ATTR.LIST Expected input format + +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +... + +No blank lines or commentary allowed, no symbols, just numbers. + +*/ + +/* We don't need really long lines: the input file is simple. */ +#define MAX_LINE_SIZE 1000 + +/* 1 more than the highest number in the DW_TAG defines, + this is for standard TAGs. Number of rows. */ +#define STD_TAG_TABLE_ROWS 0x44 +/* Enough entries to have a bit for each standard legal tag. */ +#define STD_TAG_TABLE_COLUMNS 7 + +/* TAG tree common extension maximums. */ +#define EXT_TAG_TABLE_ROWS 7 +#define EXT_TAG_TABLE_COLS 7 + +/* The following 2 used in tag_tree.c only. */ +#define TAG_TABLE_ROW_MAXIMUM STD_TAG_TABLE_ROWS +#define TAG_TABLE_COLUMN_MAXIMUM EXT_TAG_TABLE_COLS + +/* Number of attributes columns per tag. The array is bit fields, + BITS_PER_WORD fields per word. Dense and quick to inspect */ +#define COUNT_ATTRIBUTE_STD 7 + +#define STD_ATTR_TABLE_ROWS STD_TAG_TABLE_ROWS +#define STD_ATTR_TABLE_COLUMNS 7 +/* tag/attr tree common extension maximums. */ +#define EXT_ATTR_TABLE_ROWS 7 +#define EXT_ATTR_TABLE_COLS 7 + +/* The following 2 used in tag_attr.c only. */ +#define ATTR_TABLE_ROW_MAXIMUM STD_ATTR_TABLE_ROWS +#define ATTR_TABLE_COLUMN_MAXIMUM EXT_ATTR_TABLE_COLS + +/* Bits per 'int' to mark legal attrs. */ +#define BITS_PER_WORD 32 + +#define IS_EOF 1 +#define NOT_EOF 0 + +extern void bad_line_input(char *msg); +extern void trim_newline(char *line, int max); +extern boolean is_blank_line(char *pLine); +extern int read_value(unsigned int *outval,FILE *f); + +#endif /* tag_common_INCLUDED */ diff --git a/dwarfdump/tag_tree.c b/dwarfdump/tag_tree.c new file mode 100644 index 0000000..b508d06 --- /dev/null +++ b/dwarfdump/tag_tree.c @@ -0,0 +1,290 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2009-2010 SN Systems Ltd. All rights reserved. + Portions Copyright 2009-2011 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/tag_tree.c,v 1.8 2005/12/01 17:34:59 davea Exp $ */ +#include <dwarf.h> +#include <stdio.h> +#include <stdlib.h> /* For exit() declaration etc. */ +#include <errno.h> /* For errno declaration. */ +#include <unistd.h> /* For getopt. */ + +#include "globals.h" +#include "libdwarf.h" +#include "common.h" +#include "tag_common.h" + +unsigned int tag_tree_combination_table[TAG_TABLE_ROW_MAXIMUM][TAG_TABLE_COLUMN_MAXIMUM]; + +string program_name; + +boolean ellipsis = FALSE; /* So we can use dwarf_names.c */ + +/* Expected input format + +0xffffffff +value of a tag +value of a standard tag that may be a child ofthat tag +... +0xffffffff +value of a tag +value of a standard tag that may be a child ofthat tag +... +0xffffffff +... + +No commentary allowed, no symbols, just numbers. +Blank lines are allowed and are dropped. + +*/ + +static const char *usage[] = { + "Usage: tag_tree_build <options>", + "options:\t-t\tGenerate Tags table", + " -i Input-file-path", + " -o Output-table-path", + " -e (Want Extended table (common extensions))", + " -s (Want Standard table)", + "" +}; + +static char *input_name = 0; +static char *output_name = 0; +int extended_flag = FALSE; +int standard_flag = FALSE; + +static void +process_args(int argc, char *argv[]) +{ + int c = 0; + boolean usage_error = FALSE; + + program_name = argv[0]; + + while ((c = getopt(argc, argv, "i:o:es")) != EOF) { + switch (c) { + case 'i': + input_name = strdup(optarg); + break; + case 'o': + output_name = strdup(optarg); + break; + case 'e': + extended_flag = TRUE; + break; + case 's': + standard_flag = TRUE; + break; + + default: + usage_error = TRUE; + break; + } + } + + if (usage_error || 1 == optind || optind != argc) { + print_usage_message(argv[0],usage); + exit(FAILED); + } +} + + + +int +main(int argc, char **argv) +{ + int i = 0; + unsigned int num = 0; + int input_eof = 0; + int table_rows = 0; + int table_columns = 0; + int current_row = 0; + FILE *fileInp = 0; + FILE *fileOut = 0; + + + print_version_details(argv[0],FALSE); + process_args(argc,argv); + print_args(argc,argv); + + if (!input_name ) { + fprintf(stderr,"Input name required, not supplied.\n"); + print_usage_message(argv[0],usage); + exit(FAILED); + } + fileInp = fopen(input_name,"r"); + if (!fileInp) { + fprintf(stderr,"Invalid input filename, could not open '%s'\n", + input_name); + print_usage_message(argv[0],usage); + exit(FAILED); + } + + + if (!output_name ) { + fprintf(stderr,"Output name required, not supplied.\n"); + print_usage_message(argv[0],usage); + exit(FAILED); + } + fileOut = fopen(output_name,"w"); + if (!fileOut) { + fprintf(stderr,"Invalid output filename, could not open: '%s'\n", + output_name); + print_usage_message(argv[0],usage); + exit(FAILED); + } + if ((standard_flag && extended_flag) || (!standard_flag && !extended_flag)) { + fprintf(stderr,"Invalid table type\n"); + fprintf(stderr,"Choose -e or -s .\n"); + print_usage_message(argv[0],usage); + exit(FAILED); + } + if(standard_flag) { + table_rows = STD_TAG_TABLE_ROWS; + table_columns = STD_TAG_TABLE_COLUMNS; + } else { + table_rows = EXT_TAG_TABLE_ROWS; + table_columns = EXT_TAG_TABLE_COLS; + } + + + + input_eof = read_value(&num,fileInp); /* 0xffffffff */ + if (IS_EOF == input_eof) { + bad_line_input("Empty input file"); + } + if (num != MAGIC_TOKEN_VALUE) { + bad_line_input("Expected 0xffffffff"); + } + + while (!feof(stdin)) { + unsigned int tag = 0; + int nTagLoc = 0; + + input_eof = read_value(&tag,fileInp); + if (IS_EOF == input_eof) { + /* Reached normal eof */ + break; + } + if(standard_flag) { + if (tag >= table_rows ) { + bad_line_input("tag value exceeds standard table size"); + } + } else { + if(current_row >= table_rows) { + bad_line_input("too many extended table rows."); + } + tag_tree_combination_table[current_row][0] = tag; + } + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly.."); + } + nTagLoc = 1; + while (num != 0xffffffff) { + if(standard_flag) { + int idx = num / BITS_PER_WORD; + int bit = num % BITS_PER_WORD; + + if (idx >= table_columns) { + fprintf(stderr,"Want column %d, have only %d\n", + idx,table_columns); + bad_line_input("too many TAGs: table incomplete."); + } + tag_tree_combination_table[tag][idx] |= (1 << bit); + } else { + if(nTagLoc >= table_columns) { + printf("Attempting to use colum %d, max is %d\n", + nTagLoc,table_columns); + bad_line_input("too many subTAGs, table incomplete."); + } + tag_tree_combination_table[current_row][nTagLoc] = num; + nTagLoc++; + } + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly."); + } + } + ++current_row; /* for extended table */ + } + fprintf(fileOut,"/* Generated code, do not edit. */\n"); + fprintf(fileOut,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(fileOut,"\n/* BEGIN FILE */\n\n"); + if (standard_flag) { + fprintf(fileOut,"#define TAG_TREE_COLUMN_COUNT %d\n\n",table_columns); + fprintf(fileOut,"#define TAG_TREE_ROW_COUNT %d\n\n",table_rows); + fprintf(fileOut, + "static unsigned int tag_tree_combination_table" + "[TAG_TREE_ROW_COUNT][TAG_TREE_COLUMN_COUNT] = {\n"); + } else { + fprintf(fileOut,"#define TAG_TREE_EXT_COLUMN_COUNT %d\n\n", + table_columns); + fprintf(fileOut,"#define TAG_TREE_EXT_ROW_COUNT %d\n\n",table_rows); + fprintf(fileOut,"/* Common extensions */\n"); + fprintf(fileOut, + "static unsigned int tag_tree_combination_ext_table" + "[TAG_TREE_EXT_ROW_COUNT][TAG_TREE_EXT_COLUMN_COUNT] = {\n"); + } + + for (i = 0; i < table_rows; i++) { + int j = 0; + const char *name = 0; + if (standard_flag) { + dwarf_get_TAG_name(i,&name);; + fprintf(fileOut,"/* %d %-37s*/\n",i, name); + } else { + int k = tag_tree_combination_table[i][0]; + dwarf_get_TAG_name(i,&name);; + fprintf(fileOut,"/* %u %-37s*/\n", k, name); + } + fprintf(fileOut," { "); + for(j = 0; j < table_columns; ++j ) { + fprintf(fileOut,"0x%08x,",tag_tree_combination_table[i][j]); + } + fprintf(fileOut,"},\n"); + + } + fprintf(fileOut,"};\n"); + fprintf(fileOut,"\n/* END FILE */\n"); + fclose(fileInp); + fclose(fileOut); + return (0); +} + +/* A fake so we can use dwarf_names.c */ +void print_error (Dwarf_Debug dbg, string msg,int res, Dwarf_Error err) +{ +} + diff --git a/dwarfdump/tag_tree.list b/dwarfdump/tag_tree.list new file mode 100644 index 0000000..ebad794 --- /dev/null +++ b/dwarfdump/tag_tree.list @@ -0,0 +1,486 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_tree.list,v 1.6 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* + list for semantic check of tag-tree. + + 0xffffffff is a "punctuation." The final line of this file + must be 0xffffffff. The next line after each 0xffffffff + (except the final line) stands for "parent-tag." The lines + after this line before the next 0xffffffff are the tags that + can be children of the "parent-tag." + + For example, + + 0xffffffff + DW_TAG_array_type + DW_TAG_subrange_type + DW_TAG_enumeration_type + 0xffffffff + + means "only DW_TAG_subrange_type and DW_TAG_enumeration_type can + be children of DW_TAG_array_type. + + This file is applied to the preprocessor, thus any C comment and + preprocessor control line is available. +*/ + +0xffffffff +DW_TAG_access_declaration +0xffffffff +DW_TAG_array_type +DW_TAG_subrange_type +DW_TAG_enumeration_type +0xffffffff +DW_TAG_base_type +0xffffffff +DW_TAG_catch_block +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +0xffffffff +DW_TAG_class_type +DW_TAG_member +DW_TAG_inheritance +DW_TAG_access_declaration +DW_TAG_friend +DW_TAG_ptr_to_member_type +DW_TAG_subprogram +DW_TAG_template_type_parameter /* template instantiations */ +DW_TAG_template_value_parameter /* template instantiations */ +DW_TAG_typedef +DW_TAG_base_type +DW_TAG_pointer_type +DW_TAG_union_type +DW_TAG_const_type +DW_TAG_class_type /* Nested classes */ +DW_TAG_structure_type /* Nested structures */ +DW_TAG_enumeration_type /* Nested enums */ +DW_TAG_imported_declaration +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_common_block +DW_TAG_variable +0xffffffff +DW_TAG_common_inclusion +0xffffffff +DW_TAG_compile_unit +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_namespace +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_imported_module +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_type_unit +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_namespace +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_imported_module +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_condition /* COBOL */ +DW_TAG_constant +DW_TAG_subrange_type +0xffffffff +DW_TAG_const_type +0xffffffff +DW_TAG_constant +0xffffffff +DW_TAG_dwarf_procedure +0xffffffff +DW_TAG_entry_point +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_common_inclusion +0xffffffff +DW_TAG_enumeration_type +DW_TAG_enumerator +0xffffffff +DW_TAG_enumerator +0xffffffff +DW_TAG_file_type +0xffffffff +DW_TAG_formal_parameter +0xffffffff +DW_TAG_friend +0xffffffff +DW_TAG_imported_declaration +0xffffffff +DW_TAG_imported_module +0xffffffff +DW_TAG_imported_unit +0xffffffff +DW_TAG_inheritance +0xffffffff +DW_TAG_inlined_subroutine +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_lexical_block +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_inlined_subroutine +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +0xffffffff +DW_TAG_interface_type +DW_TAG_member +DW_TAG_subprogram +0xffffffff +DW_TAG_label +0xffffffff +DW_TAG_lexical_block +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_inlined_subroutine +DW_TAG_lexical_block +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_formal_parameter +0xffffffff +DW_TAG_member +0xffffffff +DW_TAG_module +0xffffffff +DW_TAG_namelist +DW_TAG_namelist_item +0xffffffff +DW_TAG_namelist_item +0xffffffff +DW_TAG_namespace +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_namespace /* Allow a nested namespace */ +DW_TAG_imported_module /* Allow imported module */ +0xffffffff +DW_TAG_packed_type +0xffffffff +DW_TAG_partial_unit +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +0xffffffff +DW_TAG_pointer_type +DW_TAG_rvalue_reference_type +DW_TAG_reference_type +DW_TAG_restrict_type +DW_TAG_ptr_to_member_type +0xffffffff +DW_TAG_ptr_to_member_type +DW_TAG_rvalue_reference_type +DW_TAG_reference_type +DW_TAG_pointer_type +DW_TAG_restrict_type +0xffffffff +DW_TAG_reference_type +DW_TAG_rvalue_reference_type +DW_TAG_reference_type +DW_TAG_pointer_type +DW_TAG_restrict_type +DW_TAG_ptr_to_member_type +0xffffffff +DW_TAG_rvalue_reference_type +DW_TAG_pointer_type +DW_TAG_restrict_type +DW_TAG_ptr_to_member_type +DW_TAG_reference_type +0xffffffff +DW_TAG_restrict_type +DW_TAG_pointer_type +DW_TAG_ptr_to_member_type +DW_TAG_rvalue_reference_type +0xffffffff +DW_TAG_set_type +0xffffffff +DW_TAG_shared_type +0xffffffff +DW_TAG_string_type +0xffffffff +DW_TAG_structure_type +DW_TAG_member +DW_TAG_inheritance +DW_TAG_access_declaration +DW_TAG_friend +DW_TAG_ptr_to_member_type +DW_TAG_variant_part +DW_TAG_subprogram +DW_TAG_template_type_parameter /* template instantiations */ +DW_TAG_template_value_parameter /* template instantiations */ +DW_TAG_typedef +DW_TAG_base_type +DW_TAG_pointer_type +DW_TAG_union_type +DW_TAG_const_type +DW_TAG_structure_type /* nested structures */ +DW_TAG_enumeration_type /* nested enums */ +DW_TAG_class_type /* nested classes */ +DW_TAG_imported_declaration /* References to namespaces */ +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_subprogram +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_thrown_type +DW_TAG_template_type_parameter +DW_TAG_template_value_parameter +DW_TAG_common_inclusion +DW_TAG_common_block +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_lexical_block +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_inlined_subroutine +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_label +DW_TAG_imported_module /* References to namespaces */ +DW_TAG_imported_declaration /* References to namespaces */ +0xffffffff +DW_TAG_subrange_type +0xffffffff +DW_TAG_subroutine_type +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +0xffffffff +DW_TAG_template_type_parameter +0xffffffff +DW_TAG_template_value_parameter +0xffffffff +DW_TAG_thrown_type +0xffffffff +DW_TAG_try_block +0xffffffff +DW_TAG_typedef +0xffffffff +DW_TAG_union_type +DW_TAG_friend +DW_TAG_member +DW_TAG_class_type /* Nested classes */ +DW_TAG_enumeration_type /* Nested enums */ +DW_TAG_structure_type /* Nested structures */ +DW_TAG_typedef /* Nested typedef */ +DW_TAG_subprogram +DW_TAG_template_type_parameter /* template instantiations */ +DW_TAG_template_value_parameter /* template instantiations */ +0xffffffff +DW_TAG_template_alias +DW_TAG_template_type_parameter +DW_TAG_template_value_parameter +0xffffffff +DW_TAG_unspecified_parameters +0xffffffff +DW_TAG_unspecified_type +0xffffffff +DW_TAG_variable +0xffffffff +DW_TAG_variant +DW_TAG_variant_part +0xffffffff +DW_TAG_variant_part +0xffffffff +DW_TAG_volatile_type +0xffffffff +DW_TAG_with_stmt +0xffffffff diff --git a/dwarfdump/tag_tree_ext.list b/dwarfdump/tag_tree_ext.list new file mode 100644 index 0000000..e671373 --- /dev/null +++ b/dwarfdump/tag_tree_ext.list @@ -0,0 +1,63 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2009-2010 SN Systems Ltd. All rights reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_attr.list,v 1.7 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* list for semantic check of tag-tree relation. + See tag_tree.list for details. + +*/ + +/* Common DWARF extensions */ + +0xffffffff +DW_TAG_structure_type +DW_TAG_variable /* GNU gcc usage. */ +0xffffffff +DW_TAG_class_type +DW_TAG_variable /* GNU gcc usage. */ +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff +DW_TAG_structure_type +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff +DW_TAG_subprogram +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff +DW_TAG_union_type +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff diff --git a/dwarfdump/testesb.c b/dwarfdump/testesb.c new file mode 100644 index 0000000..c3ea2f0 --- /dev/null +++ b/dwarfdump/testesb.c @@ -0,0 +1,78 @@ +/* testesb.c + test code for esb.h esb.c + + Not part of a compiled dwarfdump. + +*/ + +#include <stdio.h> +#include <string.h> +typedef char *string; + +#include "esb.h" + +void +check(string msg, struct esb_s *data, string v) +{ + string b = esb_get_string(data); + size_t l = 0; + size_t alloc = 0; + + if (strcmp(b, v)) { + fprintf(stderr, "ERROR: %s content error %s != %s\n", msg, b, + v); + } + + l = esb_string_len(data); + + if (l != strlen(v)) { + fprintf(stderr, "ERROR: %s length error %lu != %lu\n", msg, + (unsigned long) l, (unsigned long) strlen(v)); + } + alloc = esb_get_allocated_size(data); + if (l > alloc) { + fprintf(stderr, "ERROR: %s allocation error %lu > %lu\n", msg, + (unsigned long) l, (unsigned long) alloc); + + } + + return; +} + +int +main(void) +{ + struct esb_s data; + + + esb_alloc_size(2); /* small to get all code paths tested. */ + esb_constructor(&data); + + esb_append(&data, "a"); + esb_appendn(&data, "bc", 1); + esb_append(&data, "d"); + esb_append(&data, "e"); + check("test 1", &data, "abde"); + + esb_destructor(&data); + esb_constructor(&data); + + esb_append(&data, "abcdefghij" "0123456789"); + check("test 2", &data, "abcdefghij" "0123456789"); + + esb_destructor(&data); + esb_constructor(&data); + esb_append(&data, "abcdefghij" "0123456789"); + + esb_append(&data, "abcdefghij" "0123456789"); + + esb_append(&data, "abcdefghij" "0123456789"); + + esb_append(&data, "abcdefghij" "0123456789"); + check("test 3", &data, "abcdefghij" + "0123456789" + "abcdefghij" + "0123456789" + "abcdefghij" "0123456789" "abcdefghij" "0123456789"); + return 0; +} diff --git a/dwarfdump/uri.c b/dwarfdump/uri.c new file mode 100644 index 0000000..1353ab8 --- /dev/null +++ b/dwarfdump/uri.c @@ -0,0 +1,493 @@ +/* + Copyright 2011 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 + +*/ + +/* 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 "esb.h" +#include "uri.h" +#include <stdio.h> +#include <ctype.h> + +/* dwarfdump_ctype table. See uritablebuild.c */ +static char dwarfdump_ctype_table[256] = { +0, /* NUL 0x00 */ +0, /* control 0x01 */ +0, /* control 0x02 */ +0, /* control 0x03 */ +0, /* control 0x04 */ +0, /* control 0x05 */ +0, /* control 0x06 */ +0, /* control 0x07 */ +0, /* control 0x08 */ +0, /* whitespace 0x09 */ +0, /* whitespace 0x0a */ +0, /* whitespace 0x0b */ +0, /* whitespace 0x0c */ +0, /* whitespace 0x0d */ +0, /* control 0x0e */ +0, /* control 0x0f */ +0, /* control 0x10 */ +0, /* control 0x11 */ +0, /* control 0x12 */ +0, /* control 0x13 */ +0, /* control 0x14 */ +0, /* control 0x15 */ +0, /* control 0x16 */ +0, /* control 0x17 */ +0, /* control 0x18 */ +0, /* control 0x19 */ +0, /* control 0x1a */ +0, /* control 0x1b */ +0, /* control 0x1c */ +0, /* control 0x1d */ +0, /* control 0x1e */ +0, /* control 0x1f */ +1, /* ' ' 0x20 */ +1, /* '!' 0x21 */ +0, /* '"' 0x22 */ +1, /* '#' 0x23 */ +1, /* '$' 0x24 */ +0, /* '%' 0x25 */ +1, /* '&' 0x26 */ +0, /* ''' 0x27 */ +1, /* '(' 0x28 */ +1, /* ')' 0x29 */ +1, /* '*' 0x2a */ +1, /* '+' 0x2b */ +1, /* ',' 0x2c */ +1, /* '-' 0x2d */ +1, /* '.' 0x2e */ +1, /* '/' 0x2f */ +1, /* '0' 0x30 */ +1, /* '1' 0x31 */ +1, /* '2' 0x32 */ +1, /* '3' 0x33 */ +1, /* '4' 0x34 */ +1, /* '5' 0x35 */ +1, /* '6' 0x36 */ +1, /* '7' 0x37 */ +1, /* '8' 0x38 */ +1, /* '9' 0x39 */ +1, /* ':' 0x3a */ +0, /* ';' 0x3b */ +1, /* '<' 0x3c */ +1, /* '=' 0x3d */ +1, /* '>' 0x3e */ +1, /* '?' 0x3f */ +1, /* '@' 0x40 */ +1, /* 'A' 0x41 */ +1, /* 'B' 0x42 */ +1, /* 'C' 0x43 */ +1, /* 'D' 0x44 */ +1, /* 'E' 0x45 */ +1, /* 'F' 0x46 */ +1, /* 'G' 0x47 */ +1, /* 'H' 0x48 */ +1, /* 'I' 0x49 */ +1, /* 'J' 0x4a */ +1, /* 'K' 0x4b */ +1, /* 'L' 0x4c */ +1, /* 'M' 0x4d */ +1, /* 'N' 0x4e */ +1, /* 'O' 0x4f */ +1, /* 'P' 0x50 */ +1, /* 'Q' 0x51 */ +1, /* 'R' 0x52 */ +1, /* 'S' 0x53 */ +1, /* 'T' 0x54 */ +1, /* 'U' 0x55 */ +1, /* 'V' 0x56 */ +1, /* 'W' 0x57 */ +1, /* 'X' 0x58 */ +1, /* 'Y' 0x59 */ +1, /* 'Z' 0x5a */ +1, /* '[' 0x5b */ +1, /* '\' 0x5c */ +1, /* ']' 0x5d */ +1, /* '^' 0x5e */ +1, /* '_' 0x5f */ +0, /* '`' 0x60 */ +1, /* 'a' 0x61 */ +1, /* 'b' 0x62 */ +1, /* 'c' 0x63 */ +1, /* 'd' 0x64 */ +1, /* 'e' 0x65 */ +1, /* 'f' 0x66 */ +1, /* 'g' 0x67 */ +1, /* 'h' 0x68 */ +1, /* 'i' 0x69 */ +1, /* 'j' 0x6a */ +1, /* 'k' 0x6b */ +1, /* 'l' 0x6c */ +1, /* 'm' 0x6d */ +1, /* 'n' 0x6e */ +1, /* 'o' 0x6f */ +1, /* 'p' 0x70 */ +1, /* 'q' 0x71 */ +1, /* 'r' 0x72 */ +1, /* 's' 0x73 */ +1, /* 't' 0x74 */ +1, /* 'u' 0x75 */ +1, /* 'v' 0x76 */ +1, /* 'w' 0x77 */ +1, /* 'x' 0x78 */ +1, /* 'y' 0x79 */ +1, /* 'z' 0x7a */ +1, /* '{' 0x7b */ +1, /* '|' 0x7c */ +1, /* '}' 0x7d */ +1, /* '~' 0x7e */ +0, /* DEL 0x7f */ +1, /* 0x80 */ +1, /* 0x81 */ +1, /* 0x82 */ +1, /* 0x83 */ +1, /* 0x84 */ +1, /* 0x85 */ +1, /* 0x86 */ +1, /* 0x87 */ +1, /* 0x88 */ +1, /* 0x89 */ +1, /* 0x8a */ +1, /* 0x8b */ +1, /* 0x8c */ +1, /* 0x8d */ +1, /* 0x8e */ +1, /* 0x8f */ +1, /* 0x90 */ +1, /* 0x91 */ +1, /* 0x92 */ +1, /* 0x93 */ +1, /* 0x94 */ +1, /* 0x95 */ +1, /* 0x96 */ +1, /* 0x97 */ +1, /* 0x98 */ +1, /* 0x99 */ +1, /* 0x9a */ +1, /* 0x9b */ +1, /* 0x9c */ +1, /* 0x9d */ +1, /* 0x9e */ +1, /* 0x9f */ +0, /* other: 0xa0 */ +1, /* 0xa1 */ +1, /* 0xa2 */ +1, /* 0xa3 */ +1, /* 0xa4 */ +1, /* 0xa5 */ +1, /* 0xa6 */ +1, /* 0xa7 */ +1, /* 0xa8 */ +1, /* 0xa9 */ +1, /* 0xaa */ +1, /* 0xab */ +1, /* 0xac */ +1, /* 0xad */ +1, /* 0xae */ +1, /* 0xaf */ +1, /* 0xb0 */ +1, /* 0xb1 */ +1, /* 0xb2 */ +1, /* 0xb3 */ +1, /* 0xb4 */ +1, /* 0xb5 */ +1, /* 0xb6 */ +1, /* 0xb7 */ +1, /* 0xb8 */ +1, /* 0xb9 */ +1, /* 0xba */ +1, /* 0xbb */ +1, /* 0xbc */ +1, /* 0xbd */ +1, /* 0xbe */ +1, /* 0xbf */ +1, /* 0xc0 */ +1, /* 0xc1 */ +1, /* 0xc2 */ +1, /* 0xc3 */ +1, /* 0xc4 */ +1, /* 0xc5 */ +1, /* 0xc6 */ +1, /* 0xc7 */ +1, /* 0xc8 */ +1, /* 0xc9 */ +1, /* 0xca */ +1, /* 0xcb */ +1, /* 0xcc */ +1, /* 0xcd */ +1, /* 0xce */ +1, /* 0xcf */ +1, /* 0xd0 */ +1, /* 0xd1 */ +1, /* 0xd2 */ +1, /* 0xd3 */ +1, /* 0xd4 */ +1, /* 0xd5 */ +1, /* 0xd6 */ +1, /* 0xd7 */ +1, /* 0xd8 */ +1, /* 0xd9 */ +1, /* 0xda */ +1, /* 0xdb */ +1, /* 0xdc */ +1, /* 0xdd */ +1, /* 0xde */ +1, /* 0xdf */ +1, /* 0xe0 */ +1, /* 0xe1 */ +1, /* 0xe2 */ +1, /* 0xe3 */ +1, /* 0xe4 */ +1, /* 0xe5 */ +1, /* 0xe6 */ +1, /* 0xe7 */ +1, /* 0xe8 */ +1, /* 0xe9 */ +1, /* 0xea */ +1, /* 0xeb */ +1, /* 0xec */ +1, /* 0xed */ +1, /* 0xee */ +1, /* 0xef */ +1, /* 0xf0 */ +1, /* 0xf1 */ +1, /* 0xf2 */ +1, /* 0xf3 */ +1, /* 0xf4 */ +1, /* 0xf5 */ +1, /* 0xf6 */ +1, /* 0xf7 */ +1, /* 0xf8 */ +1, /* 0xf9 */ +1, /* 0xfa */ +1, /* 0xfb */ +1, /* 0xfc */ +1, /* 0xfd */ +1, /* 0xfe */ +0, /* other: 0xff */ +}; +static char * +xchar(int c, char *buf, int size) +{ + snprintf(buf, size,"%%%02x",c); + return buf; +} + +/* Translate dangerous and some other characters to safe + %xx form. +*/ +void +translate_to_uri(const char * filename, struct esb_s *out) +{ + char buf[8]; + const char *cp = 0; + for(cp = filename ; *cp; ++cp) { + char v[2]; + int c = 0xff & (unsigned char)*cp; + if(dwarfdump_ctype_table[c]) { + v[0] = c; + v[1] = 0; + esb_append(out,v); + } else { + char *b = xchar(c,buf,sizeof(buf)); + esb_append(out,b); + } + } +} + +/* This is not very efficient, but it is seldom called. */ +static char +hexdig(char c) +{ + char ochar = 0; + if(c >= 0 && c <= '9') { + ochar = (c - '0'); + return ochar; + } + if(c >= 'a' && c <= 'f') { + ochar = (c - 'a')+10; + return ochar; + } + if(c >= 'A' && c <= 'F') { + ochar = (c - 'A')+10; + return ochar; + } + // We have an input botch here. + fprintf(stderr,"Translating from uri: " + "A supposed hexadecimal input character is " + "not 0-9 or a-f or A-F, it is (shown as hex here): %x\n",c); + return ochar; +} + +static char tohex(char c1, char c2) +{ + char out = (hexdig(c1) << 4) | hexdig(c2); + return out; +} +static int +hexpairtochar(const char *cp, char*myochar) +{ + char ochar = 0; + int olen = 0; + char c = cp[0]; + if(c) { + char c2 = cp[1]; + if(c2) { + ochar = tohex(c,c2); + olen = 2; + } else { + fprintf(stderr,"Translating from uri: " + "A supposed hexadecimal input character pair " + "runs off the end of the input after 1 hex digit.\n"); + /* botched input. */ + ochar = c; + olen = 1; + } + } else { + /* botched input. */ + fprintf(stderr,"Translating from uri: " + "A supposed hexadecimal input character pair " + "runs off the end of the input.\n"); + ochar = '%'; + olen = 0; + } + *myochar = ochar; + return olen; +} + +void +translate_from_uri(const char * input, struct esb_s* out) +{ + const char *cp = input; + char tempstr[2]; + for(; *cp; ++cp) { + char c = *cp; + if(c == '%') { + int increment = 0; + char c2 = cp[1]; + // hexpairtochar deals with c2 being NUL. + if ( c2 == '%') { + tempstr[0] = c; + tempstr[1] = 0; + esb_append(out,tempstr); + ++cp; + continue; + } + + increment = hexpairtochar(cp+1,&c); + tempstr[0] = c; + tempstr[1] = 0; + esb_append(out,tempstr); + cp +=increment; + continue; + } + tempstr[0] = c; + tempstr[1] = 0; + esb_append(out,tempstr); + } +} + + + + +#ifdef TEST + +unsigned errcnt = 0; + +static void +mytestfrom(const char * in,const char *expected,int testnum) +{ + struct esb_s out; + esb_constructor(&out); + translate_from_uri(in, &out); + if(strcmp(expected, esb_get_string(&out))) { + printf(" Fail test %d expected \"%s\" got \"%s\"\n", + testnum,expected,esb_get_string(&out)); + ++errcnt; + } + esb_destructor(&out); +} + + +static void +mytest(char *in,char *expected,int testnum) +{ + struct esb_s out; + esb_constructor(&out); + translate_to_uri(in, &out); + if(strcmp(expected, esb_get_string(&out))) { + printf(" Fail test %d expected %s got %s\n",testnum,expected,esb_get_string(&out)); + ++errcnt; + } + esb_destructor(&out); +} + + +int +main() +{ + /* We no longer translate space to %20, that + turns out not to help all that much. */ + mytest("aaa","aaa",1); + mytest(" bc"," bc",2); + mytest(";bc","%3bbc",3); + mytest(" bc\n"," bc%0a",4); + mytest(";bc\n","%3bbc%0a",5); + mytest(" bc\r"," bc%0d",6); + mytest(";bc\r","%3bbc%0d",7); + mytest(" \x01"," %01",8); + mytest(";\x01","%3b%01",9); + mytestfrom("abc","abc",10); + mytestfrom("a%20bc","a bc",11); + mytestfrom("a%%20bc","a%20bc",12); + mytestfrom("a%%%20bc","a% bc",13); + mytestfrom("a%%%%20bc","a%%20bc",14); + mytestfrom("a%20","a ",15); + /* The following is mistaken input. */ + mytestfrom("a%2","a2",16); + mytestfrom("a%","a%",17); + mytest("%bc","%25bc",18); + + if(errcnt) { + printf("uri errcount ",errcnt); + } + return errcnt? 1:0; +} +#endif + diff --git a/dwarfdump/uri.h b/dwarfdump/uri.h new file mode 100644 index 0000000..0dfa386 --- /dev/null +++ b/dwarfdump/uri.h @@ -0,0 +1,37 @@ +/* + Copyright 2011 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 + +*/ + + +void translate_to_uri(const char * filename, struct esb_s *out); +void translate_from_uri(const char * input, struct esb_s *out); + diff --git a/dwarfdump/uritablebuild.c b/dwarfdump/uritablebuild.c new file mode 100644 index 0000000..c8c5501 --- /dev/null +++ b/dwarfdump/uritablebuild.c @@ -0,0 +1,146 @@ +/* + Copyright 2011 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 + +*/ + +/* 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 <stdio.h> +#include <ctype.h> + +/* Generates a table which identifies a few dangerous characters. + Ones one does not want to appear in output. + + It's a bit arbitrary in that we allow lots of shell-interpreted + characters through, and most characters generally. + + But not control characters or single or double quotes. + The quotes would be particularly problematic for post-processing + dwarfdump output sensibly. + +*/ +static void +print_entry(int c) +{ + char v[2]; + v[0] = c; + v[1] = 0; + if(c == 0) { + printf("0, /* NUL 0x%02x */\n",c); + return; + } + if(isalnum(c) || c == ' ' ) { + /* We let the space character print as space since + lots of files are named that way in Mac and Windows. + */ + printf("1, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if(c == 0x21 || c == 0x23 || c == 0x26) { + /* We let the space character print as space since + lots of files are named that way in Mac and Windows. + */ + printf("1, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if(isspace(c) ) { + /* Other white space translated. */ + printf("0, /* whitespace 0x%02x */\n",c); + return; + } + if(c == 0x7f) { + printf("0, /* DEL 0x%02x */\n",c); + return; + } + if(c >= 0x01 && c <= 0x20 ) { + /* ASCII control characters. */ + printf("0, /* control 0x%02x */\n",c); + return; + } + if(c == '\'' || c == '\"' || c == '%' || c == ';' ) { + printf("0, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if(c >= 0x3a && c <= 0x40 ) { + /* ASCII */ + printf("1, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if(c == 0xa0 || c == 0xff ) { + printf("0, /* other: 0x%02x */\n",c); + return; + } + if(c >= 0x27 && c <= 0x2f ) { + /* ASCII */ + printf("1, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if(c >= 0x5b && c <= 0x5f ) { + /* ASCII */ + printf("1, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if(c >= 0x60 && c <= 0x60 ) { + /* ASCII */ + printf("0, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if(c >= 0x7b && c <= 0x7e ) { + /* ASCII */ + printf("1, /* \'%s\' 0x%02x */\n",v,c); + return; + } + if (c < 0x7f) { + /* ASCII */ + printf("1, /* \'%s\' 0x%02x */\n",v,c); + return; + } + /* We are allowing other iso 8859 characters through unchanged. */ + printf("1, /* 0x%02x */\n",c); +} + + +int +main() +{ + int i = 0; + printf("/* dwarfdump_ctype table */\n"); + printf("char dwarfdump_ctype_table[256] = { \n"); + for ( i = 0 ; i <= 255; ++i) { + print_entry(i); + } + printf("};\n"); +} + diff --git a/dwarfdump2/COPYING b/dwarfdump2/COPYING new file mode 100644 index 0000000..355bd60 --- /dev/null +++ b/dwarfdump2/COPYING @@ -0,0 +1,31 @@ + +David Anderson: December 2006 +The code in the dwarfdump directory is (if you look +in each file) covered by the GPL (not the LGPL). The +DWARFDUMPCOPYRIGHT file, though, said (before December 24, +2006) the copyright is LGPL. There is no doubt in my (David +Anderson) mind that the intent was always that dwarfdump be +GPL and the copyright markings in each file are correct. + +There are three files marked with the LGPL: tag_tree.list +tag_attr.list acconfig.h. These markings are left as is and +these are are therefore LGPL files. + +The DWARFDUMPCOPYRIGHT file now (Dec 24 2006) has both +copyrights and an explanation of where each applies. + + + +------------------------------------------- +The text present for years, thru Dec 23, 2006: +The files: + dwarfdump.c + and all the .h and .c files in this implementation of + dwarfdump are copyrighted according to the file + DWARFDUMPCOPYRIGHT. + + + +$Source: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/COPYING,v $ +$Revision: 1.1 $ +$Date: 2001/01/16 17:47:55 $ diff --git a/dwarfdump2/ChangeLog b/dwarfdump2/ChangeLog new file mode 100644 index 0000000..5c56ac1 --- /dev/null +++ b/dwarfdump2/ChangeLog @@ -0,0 +1,2 @@ +2012-04-10 DavidAnderson <davea42@earthlink.net> + * dwarfdump.cc, common.cc: Updated version string. diff --git a/dwarfdump2/ChangeLog2009 b/dwarfdump2/ChangeLog2009 new file mode 100644 index 0000000..e3cecb9 --- /dev/null +++ b/dwarfdump2/ChangeLog2009 @@ -0,0 +1,156 @@ +2009-12-30 DavidAnderson <davea42@earthlink.net> + * configure: Regenerated with autoconf 2.64. +2009-11-24 DavidAnderson <davea42@earthlink.net> + * tag_common.h: Updated 'standard tag table row' and + tag table column maximums now the DWARF4 entries are + in the .list files. Removed dos 'CR' characters at line ends. + * tag_tree.list, tag_attr.list: Added various + DWARF4 entries and added DW_TAG_enumeration_type + under DW_TAG_union_type. +2009-11-17 DavidAnderson <davea42@earthlink.net> + * dwarfdump.1: Document the -u option more fully. + * print_die.cc: Check for both info_flag and + cu_name_flag to decide when to print DIEs. +2009-10-12 DavidAnderson <davea42@earthlink.net> + * dwarfdump.cc: Updated dwarfdump version string to today. +2009-09-30 DavidAnderson <davea42@earthlink.net> + * dwarfdump.cc: Added globals for aranges checking and + to print the resulting error count. + * print_aranges.cc: Added checking that all 3 ways + of computing a cu_die_offset from an arange get + the same offset (checked with -r -ka). + * print_frames.cc: DW_CFA_cfa_offset_extended_sf + corrected to DW_CFA_offset_extended_sf. + The print_frames code now uses the dwarf_get_CFA_name() call + from libdwarf to print frame operation names. + * globals.h: New function SpaceSurround() so we can use + dwarf_get_CFA_name concisely in print_frames.cc. + Added aranges_result + and check_aranges so print_aranges.cc can use them. +2009-09-01 DavidAnderson <davea42@earthlink.net> + * tag_tree.list: We add + DW_TAG_class_type as a valid child of a DW_TAG_union_type. +2009-08-05 DavidAnderson <davea42@earthlink.net> + * gennames.c: Change include from getopt.h to unistd.h + so the code is more universally compilable. +2009-06-23: David Anderson <davea42@earthlink.net> + * strstrnocase.cc: Corrected typo in TEST code and + added a new test. +2009-06-22: David Anderson <davea42@earthlink.net> + * Makefile.in: switched to personally written + string comparison, strstrnocase.c. + * stristr.c: deleted. + * strstrnocase.c: New code, written by me so no + license issues. + * print_die.c: Call is_strstrnocase(), + the new function. Change a local variable to unsigned + to avoid a compiler warning about signed/unsigned comparison. + * dwarfdump.1: More fully document -S. + * globals.h: Create extern for is_strstrnocase(). +2009-06-18: David Anderson <davea42@earthlink.net> + * configure: Regenerated. + * Makefile.in: Added stristr.o + * dieholder.h,print_die.cc, dwarfdump.cc,print_lines.cc,print_aranges.cc: + Added support for -S + * Test for regex, set HAV_REGEX for -S support. + * dwarfdump.1: document -S + * stristr.cc: New public domain source file. + * config.h.in: Adding HAVE_REGEX default value. + * globals.h: Adding support for -S. +2009-06-06: David Anderson <davea42@earthlink.net> + * fderegs.h: Remove unused line and switch + an argument to unsigned to avoid -Wall warning. + * naming.cc,naming.h: New files that implement the + ellipsis functionality of dwarfdump and defer to + libdwarf to get the names of the TAGs, FORMs, etc.. + * gennames.cc: This file has moved to libdwarf, no longer + present in dwarfdump. + * print_static_vars.cc,print_static_funcs.cc, + print_sections.cc,print_strings.cc, print_locs.cc, + print_lines.cc, print_pubnames.cc,print_ranges.cc, + print_macros.cc,print_types.cc,tag_common.cc, + print_weaknames.cc, print_aranges.cc: Include + changed from dwarf_names.h to naming.h + * dwarfdump.cc: Updated DWARFDUMP_VERSION string. + * tag_tree.cc,tag_attr.cc: Include changed from + dwarf_names.h to naming.h. Remove dbg argument to get_TAG_name. + * print_die.cc,print_abbrevs.cc: Include changed from + dwarf_names.h to naming.h. + Calls to get_TAG_name (etc) no longer have a dbg argument. + * Makefile.in: We no longer build generated file names.c, + we build naming.c (hand coded, not generated). + * tag_common.h: Delete table of TAG names, libdwarf provides + the name strings now. +2009-05-10: David Anderson <davea42@earthlink.net> + * dwarfdump.cc: updated DWARF_VERSION string. + * print_frames.cc: When using the older frame register + interface with -v, suggest use of -R instead of erroring off + or segfaulting in dwarfdump. +2009-05-07: David Anderson <davea42@earthlink.net> + * Makefile.in: The dwarf_names* files are all + generated by C++ now, so clean cleans them out. +2009-05-04: David Anderson <davea42@earthlink.net> + * dwarf_names.awk, at_list.awk: deleted. gennames.cc replaces these. + * common.h, common.cc: Extracted simple utility routines + into their own files. + * tag_common.c, tag_common.h: Removed the simple utility + routines from these files to simplify dependencies. + * tag_attr.cc, tag_tree.cc: Include new common.h. + * print_frames.cc, print_frames.h: Adding address_size argument to call. + * print_locs.cc: Gets and uses CU-specific address_size. + * print_ranges.cc: Adding commentary. + * print_die.cc: adding DIE argument to ensure correct + address size used for the CU in question. + * Makefile.in: Now handles common.* and gennames.cc changes. + * gennames.cc: New code emitting string 'get name' source. + * print_frames.h: Adding new address_size argument to + get_string_from_locs(). + * dwarf_names_new.h: Deleted from svn, this is generated. +2009-04-03: David Anderson <davea42@earthlink.net> + * Makefile.in: clean up 'clean' and 'distclean' + so that distributed files are not cleaned out by 'clean' + and all generated files (even those shipped in distribution) + are cleaned out by distclean. + * fderegs.h: New class that reads interface 2 and 3 libdwarf + and reduces to a common interface to simplify print_frames.cc + It also radically speeds up frame printing when there are + large numbers of registers in the ABI by using a different + libdwarf interface than before. + * print_frames.cc: Uses FdeRegs class to simplify and unify + getting frame registers. Uses a different libdwarf interface + to speed up register acquisition. + * dwarfdump.cc: Added calls to libdwarf to specify the correct + 'same value' and 'undefined value' pseudo-register numbers. + * dwarfdump.1: Amplified -R and -x abi= documentation. + * dwconf.cc: Added comments and deleted a few duplicated lines. + * dwarfdump.conf: Added generic500 generic100 abis. + Now all ABIs have same_val_reg: and undefined_val_reg: + defined. + * dwarf_names_enum.h: delete dwarf_names_enum.h from svn, + it is a generated file. +2009-03-29: David Anderson <davea42@earthlink.net> + * Makefile.in: References dieholder.h and srcfilesholder.h. + * dieholder.h: New: Implements DieHolder class. + * srcfilesholder.h: New: Implements SrcfilesHolder class. + * print_aranges.cc: Use SrcfilesHolder and DieHolder classes. + * print_sections.cc: The dwarf_names_print_on_error flag + is now a bool. + * globals.h: Some interfaces use SrcfilesHolder and DieHolder classes. + Some values now external so they are visible (used in print_infos() + which is now in print_die.cc. + The dwarf_names_print_on_error flag is now a bool. + * print_lines.cc: Use SrcefilesHolder and DieHolder classes. + * dwarfdump.cc: If should_skip_this_cu() we need to + continue; and this fixes the omission of the continue. + print_infos() moved out of here. + * print_die.cc: Moved print_infos() to here. Interfaces use + DieHolder and SrcfilesHolder classes now. + * print_locs.cc: Add a new -v (verbose) output field so + entries can be matched to .debug_info output. + * dwarf_names.awk: The 'print on error' arg is now a bool. + Removed a superfluous space from the generated code. + * print_macros.cc: A ) was missing from the output. + * tag_tree.cc,tag_attr.cc: The 'print on error' argument + of the generated code (and all uses) is now a bool. +2009-02-28: David Anderson <davea42@earthlink.net> + * Created a new source base based on dwarfdump. diff --git a/dwarfdump2/ChangeLog2010 b/dwarfdump2/ChangeLog2010 new file mode 100644 index 0000000..084e3fa --- /dev/null +++ b/dwarfdump2/ChangeLog2010 @@ -0,0 +1,77 @@ +2010-09-30 DavidAnderson <davea42@earthlink.net> + * dwarfdump.cc: Now -a no longer implies -c because + the -c option is not guaranteed to work by the DWARF spec, + nor is -c really necessary. + * README: More tweaks on the 'install' issue. +2010-09-29 DavidAnderson <davea42@earthlink.net> + * README, Makefile.in: Amplified make install instructions. +2010-09-20 DavidAnderson <davea42@earthlink.net> + * dwarfdump.1: The -c option is not guaranteed to work. + Because .debug_loc can have garbage bytes in areas + not referenced by .debug_info. +2010-04-22 DavidAnderson <davea42@earthlink.net> + * print_die.cc: If a location form is wrong report + an error but continue operating. + * dwarfdump.cc: Implement print_error_and_continue(). + Fix typos in usage message. + * globals.h: Declare print_error_and_continue(). +2010-04-02 DavidAnderson <davea42@earthlink.net> + * dwarfdump.cc,print_lines.cc: Ensure that + the error checks counts are as accurate as possible. + New version date. + * print_frames.cc: Ensure that + the error checks counts are as accurate as possible. + Modify a message about fdes to get the strings to match + print_frames.c dwarfdump. +2010-03-31 DavidAnderson <davea42@earthlink.net> + * dwarfdump.1: Added some text about 'harmless' + errors. + * dwarfdump.c: Change the harmless error list maximum + to 50. Change harmless error reporting to be associated + with -k flags. + * print_frames.cc: Change harmless error reporting to be + associated with -k flags. + * print_aranges.cc: Call dwarf_get_arange_info_b allowing + for segmented architectures which are really only + defined properly in aranges for DWARF4. + Change harmless error reporting to be + associated with -k flags. + * globals.h: Declarations added for 'harmless' error + reporting. +2010-03-28 DavidAnderson <davea42@earthlink.net> + * dwarf_globals.h: Added interface to print_any_harmless_errors(). + * dwarfdump.cc: Added print_any_harmless_errors() implementation + and we call it just before closing libdwarf. + * print_frames.cc: Call print_any_harmless_errors after + getting cie/fde list. + * dwarfdump.conf: Add abi named 'arm' for Arm users. +2010-02-14 DavidAnderson <davea42@earthlink.net> + * print_die.cc: Add newer DW_OP operators, remove + bogus test of DW_OP_nop as the highest valid operator. + Add table of DW_OPs to simplify testing for zero-operand + operators. + Revise so that the FORM of all attributes print with -M. + * tag_attr.list: Updated copyright. + * tag_tree_ext.list, tag_attr_ext.list: Added GNU template + parameter tags, attributes. Updated copyright. + * tag_tree.list: Added template parameter tags. Added + entry for nested classes. Updated copyright. + * tag_common.h: Increased STD_TAG_TABLE_COLUMNS and + EXT_ATTR_TABLE_COLS. +2010-01-30 DavidAnderson <davea42@earthlink.net> + * print_die.c: Changed the spelling of one + 'DW_AT_type offset does not point to type info' error message so + one can distinguish which check lead to the message. +2010-01-26 DavidAnderson <davea42@earthlink.net> + * dwconf.cc, fderegs.h, dwconf.h, dwarfdump.1, + dwarfdump.conf: The default frame values in frame + output are now generic registers like r0 to r99 + instead of MIPS register names. + For the MIPS register names use '-x abi=mips'. +2010-01-17 DavidAnderson <davea42@earthlink.net> + * print_die.cc: The special case DW_AT_SUN_func_offsets + now prints identically in dwarfdump and dwarfdump2. +2010-01-03 DavidAnderson <davea42@earthlink.net> + * tag_common.cc, common.cc, common.h: Remove <cr> + line terminator characters and update copyright year. + * All other files: Update copyright year. diff --git a/dwarfdump2/DWARFDUMPCOPYRIGHT b/dwarfdump2/DWARFDUMPCOPYRIGHT new file mode 100644 index 0000000..cf465e2 --- /dev/null +++ b/dwarfdump2/DWARFDUMPCOPYRIGHT @@ -0,0 +1,85 @@ + +========The dwarfdump copyright======= + +The full text of the GPL version 2 is provided in the file GPL.txt. + +Nearly all the files in this directory have contained a GPL +copyright, not an LGPL copyright, for years. The following +is an example of that copyright as used in the dwarfdump +source, and is what SGI always intended (in David +Anderson's opinion) to have present in +the DWARFDUMPCOPYRIGHT file. (tag_tree.list tag_attr.list +acconfig.h have long been marked LGPL and therefore the LGPL +copyright, not GPL, applies to those three files.) This GPL +copyright text added here to DWARFDUMPCOPYRIGHT Dec 4, 2006 + + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, 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 + + +The following was the entire content of this file before +December 24 2006, Being the LGPL text this is in conflict +with the individual source files and I (David Anderson) +believe the source file copyright was intended for dwarfdump +not the LGPL source directly following this note. However the +3 files tag_tree.list tag_attr.list acconfig.h have long been +marked LGPL and the following copyright applies to those three. + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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 + diff --git a/dwarfdump2/GPL.txt b/dwarfdump2/GPL.txt new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/dwarfdump2/GPL.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/dwarfdump2/Makefile.in b/dwarfdump2/Makefile.in new file mode 100644 index 0000000..1691337 --- /dev/null +++ b/dwarfdump2/Makefile.in @@ -0,0 +1,175 @@ +# +# Makefile for dwarfdump +# This is made very simple so it should work with +# any 'make'. +# The Makefile does assume that libdwarf is at ../libdwarf +# from the dwarfdump2 source directory. +# + +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +mandir = $(exec_prefix)/share/man +man1dir = $(mandir)/man1 + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +DATAROOT = @datarootdir@ +SHELL = /bin/sh +CXX = @CXX@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +RM = rm +RANLIB = @RANLIB@ +DEFS = @DEFS@ +# ../libdwarf gets us to local headers +DIRINC = $(srcdir)/../libdwarf +LIBS = @LIBS@ -L../libdwarf -ldwarf -lelf +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libdwarf +CXXFLAGS = $(PREINCS) @CXXFLAGS@ $(INCLUDES) -DCONFPREFIX=${libdir} $(POSTINCS) +LDFLAGS = $(PRELIBS) @LDFLAGS@ $(LIBS) $(POSTLIBS) + + +INSTALL = cp + +binprefix = + +FINALOBJECTS = \ + checkutil.o \ + dwarfdump.o \ + dwconf.o \ + print_abbrevs.o \ + print_aranges.o \ + print_die.o \ + print_frames.o \ + print_lines.o \ + print_locs.o \ + print_macros.o \ + print_pubnames.o \ + print_ranges.o \ + print_reloc.o \ + print_sections.o \ + print_static_funcs.o \ + print_static_vars.o \ + print_strings.o \ + print_types.o \ + print_weaknames.o \ + strstrnocase.o \ + uri.o +GEN_HFILES = \ + tmp-tt-table.cc \ + tmp-ta-table.cc \ + tmp-ta-ext-table.cc \ + tmp-tt-ext-table.cc + +all: dwarfdump + +HEADERS = $(srcdir)/globals.h \ + $(srcdir)/checkutil.h \ + $(srcdir)/dieholder.h \ + $(srcdir)/srcfilesholder.h \ + $(srcdir)/print_frames.h \ + $(srcdir)/dwconf.h \ + $(srcdir)/fderegs.h \ + $(srcdir)/common.h \ + $(srcdir)/naming.h \ + $(srcdir)/tag_common.h \ + $(srcdir)/print_frames.h \ + $(srcdir)/uri.h + +$(FINALOBJECTS): $(GEN_HFILES) $(HEADERS) $(srcdir)/naming.cc + +default: $(TARGETS) + + +dwarfdump: $(FINALOBJECTS) naming.o common.o + $(CXX) $(CXXFLAGS) -o $@ $(FINALOBJECTS) naming.o common.o tag_common.o $(LDFLAGS) + +tag_common.o: $(srcdir)/tag_common.cc $(HEADERS) + $(CXX) $(CXXFLAGS) -c $(srcdir)/tag_common.cc +common.o: $(srcdir)/common.cc $(srcdir)/common.h + $(CXX) $(CXXFLAGS) -c $(srcdir)/common.cc + + +# We need this as naming.o has external references we cannot have +# in the tree builds. +trivial_naming.o: $(srcdir)/naming.cc + $(CXX) $(CXXFLAGS) -DTRIVIAL_NAMING -c $(srcdir)/naming.cc -o trivial_naming.o + +tag_tree_build: $(srcdir)/tag_tree.cc $(DIRINC)/dwarf.h $(HEADERS) tag_common.o trivial_naming.o common.o + $(CXX) $(CXXFLAGS) $(srcdir)/tag_tree.cc trivial_naming.o tag_common.o common.o $(LDFLAGS) -o tag_tree_build + +tag_attr_build: $(srcdir)/tag_attr.cc $(DIRINC)/dwarf.h $(HEADERS) trivial_naming.o tag_common.o naming.o common.o + $(CXX) $(CXXFLAGS) $(srcdir)/tag_attr.cc trivial_naming.o tag_common.o common.o $(LDFLAGS) -o tag_attr_build + +tmp-tt-table.cc tmp-tt-ext-table.cc: $(srcdir)/tag_tree_ext.list $(srcdir)/tag_tree.list tag_tree_build + # gcc -E tag_tree.list does not work, so use a .cc name + -rm -f tmp-t1.cc + cp $(srcdir)/tag_tree.list tmp-t1.cc + $(CXX) $(CXXFLAGS) -E tmp-t1.cc > ./tmp-tag-tree-build1.tmp + ./tag_tree_build -s -i tmp-tag-tree-build1.tmp -o tmp-tt-table.cc + -rm -f tmp-t4.cc + cp $(srcdir)/tag_tree_ext.list tmp-t4.cc + $(CXX) $(CXXFLAGS) -E tmp-t4.cc > ./tmp-tag-tree-build4.tmp + ./tag_tree_build -e -i tmp-tag-tree-build4.tmp -o tmp-tt-ext-table.cc + +tmp-ta-table.cc tmp-ta-ext-table.cc: $(srcdir)/tag_attr_ext.list $(srcdir)/tag_attr.list tag_attr_build + # gcc -E tag_attr.list does not work, so use a .cc name + -rm -f tmp-t2.cc + cp $(srcdir)/tag_attr.list tmp-t2.cc + $(CXX) $(CXXFLAGS) -E tmp-t2.cc > ./tmp-tag-attr-build2.tmp + ./tag_attr_build -s -i tmp-tag-attr-build2.tmp -o tmp-ta-table.cc + -rm -f tmp-t3.cc + cp $(srcdir)/tag_attr_ext.list tmp-t3.cc + $(CXX) $(CXXFLAGS) -E tmp-t3.cc > ./tmp-tag-attr-build3.tmp + ./tag_attr_build -e -i tmp-tag-attr-build3.tmp -o tmp-ta-ext-table.cc + +# This simply assumes that a default INSTALL (cp) command +# will work and leave sensible permissions on the resulting files. +# Some adjustment might be required, see README. +install: all + $(INSTALL) dwarfdump $(bindir)/dwarfdump + $(INSTALL) $(srcdir)/dwarfdump.1 $(man1dir)/dwarfdump.1 + $(INSTALL) $(srcdir)/dwarfdump.conf $(libdir)/dwarfdump.conf + +uninstall: + -rm -f $(bindir)/dwarfdump + -rm -f $(man1dir)/dwarfdump.1 + -rm -f $(libdir)/dwarfdump.conf + +clean: + rm -f *.o dwarfdump + rm -f _tag_attr_table.cc + rm -f _tag_attr_ext_table.cc + rm -f _tag_tree_table.cc + rm -f _tag_tree_table.cc + -rm -f tag_attr_build*.tmp + -rm -f tag_tree_build*.tmp + rm -f tag_tree_build + rm -f tag_attr_build + rm -f printfuncs + -rm -f _*.cc _*.h + -rm -f tmp-*.cc tmp-*.h tmp-*.tmp + rm -f gennames + rm -f dwarf_names_enum.h dwarf_names_new.cc dwarf_names_new.h + rm -f dwarf_names.cc dwarf_names.h + +distclean: clean + rm -f config.log config.h config.cache config.status + rm -rf autom4te.cache + rm -f Makefile + + +shar: + @echo "shar not set up yet" +dist: + @echo "dist not set up yet" + +test: + $(CXX) $(CXXFLAGS) $(srcdir)/test_printfuncs.cc -o printfuncs + ./printfuncs diff --git a/dwarfdump2/NEWS b/dwarfdump2/NEWS new file mode 100644 index 0000000..a38609c --- /dev/null +++ b/dwarfdump2/NEWS @@ -0,0 +1,52 @@ +December 13, 2011 + Now prints missing line table column number as 0 (now + matching the DWARF spec), the previous + practice of printing -1 was always wrong. + And prints the DWARF3/4 new line table fields (when present). +October 29, 2011 + Added support for printing .debug_types (type unit) data. +October 26, 2011 + Added new features to Makefile.in and documented in README + how to build dwarfdump with headers or libraries in + non-standard places. +October 23, 2011 + By default the various places with string option values + and file paths all use URI transformation on input and + if the transformation does anything at all dwarfdump reports + the input and transformed strings. This makes it easy + to deal with strings and expressions and file paths + that are difficult to express in a shell (or that getopt + mangles). Options -q and -U give you control over this process. +October 06, 2011 + The -x abi=mips frame register abi in dwarfdump.conf is now + usable with modern MIPS objects as well as old IRIX objects. + There are other mips-* frame register setups described + in dwarfdump.conf for anyone testing that nothing new has + been added that conflicts with old IRIX/MIPS frame generation. +October 04, 2011 + Revised in major ways to do the additional checks and produce the same + output as dwarfdump. But making use of C++ features. +March 29, 2011 + All indentations changed to a consistent 4 characters per level. + This was a massive but simple change. +January 26, 2010 + Changed the default frame-data register names from MIPS to + a generic set of registers. + Try '-x abi=mips' to get the traditional old MIPS register + naming. +June 22, 2009 + Added the -S option to dwarfdump. +June 10, 2009 + Moved the gennames.c code to libdwarf. +May 4, 2009 + Replaced awk source-generation of certain functions + with new gennames.c code. +April 04, 2009 + Now frame printing (-f and -F) uses a different interface + to libdwarf which is far more efficient for the particular + purpose of printing all the register rules. Reduces + MxN print time to M (one extreme case reduces from 2 hours + to 2 minutes). +Feb 28, 2009 + Created this new source base in C++ (from dwarfdump, which + is C). diff --git a/dwarfdump2/README b/dwarfdump2/README new file mode 100644 index 0000000..b9470b3 --- /dev/null +++ b/dwarfdump2/README @@ -0,0 +1,86 @@ +Dwarfdump2 is a C++ version of dwarfdump. It's intended to +have improved features and better performance and be easier +to understand than dwarfdump, but the printed output is intended +to be the same as dwarfdump (aside from the new features and +improvements). + +If this does not work for you, please let me know. + +To build dwarfdump, first build libdwarf in the neighboring +directory then type + ./configure + make + +Installation is a bit primitive. + sudo make install +may or may not work. +Some or all of the following might be required on Unix or Linux or MacOS: + sudo mkdir -p /usr/local/share/man/man1/ + sudo mkdir -p /usr/local/lib + sudo mkdir -p /usr/local/bin +Then retry the 'sudo make install' and (if necessary) try + sudo chmod a+x /usr/local/bin/dwarfdump + sudo chmod a+r /usr/local/share/man/man1/dwarfdump.1 + sudo chmod a+r /usr/local/lib/dwarfdump.conf +You don't really need the dwarfdump.1 man page, +but you might as well have it. If the man page is not visible +with 'man dwarfdump' try 'man manpath' for hints. + +If you don't need others using dwarfdump on your computer, +just + cp dwarfdump $HOME/bin/dwarfdump +(by convention many people put personal executables in $HOME/bin +and fix up $PATH to refer there) which suffices as 'installation'. +Also + cp dwarfdump.conf $HOME + +To use dwarf or libdwarf, you may want to install dwarf.h +and libdwarf.h somewhere convenient. +You can just copy those two headers to /usr/local/include by hand +(or anywhere, really, that you have permission to copy to) +(you may need to use -I/usr/local/include on compile lines +to reference them there, but see below on configure and make). + +Notice that dwarf_names.cc and dwarf_names.h are supplied by +the release though the Makefile can and may rebuild them. +Some users find it difficult to get a reliable awk(1) program, +so for them these prebuilt versions may be useful. + +If your headers or libelf/libdwarf are not in the expected places, +use the make command line to add flags and include directories. +For example + ./configure + PREINCS="-I /usr/local/include" POSTINCS="-I /home/x/include" make +PREINCS content is inserted before CFLAGS as make(1) is running. +POSTINCS content is added after the CFLAGS value. + +To set LDFLAGS, +do so at configure time, for example: + ./configure LDFLAGS="-L /some/dir" +And/or use PRELIBS and/or POSTLIBS at 'make' time similar to the use +of PREINCS and POSTINCS. + +If the libdwarf directory +has both libdwarf.so and libdwarf.a, the libdwarf.so +will be picked up and + "./tag_tree_build: error while loading shared libraries: + libdwarf.so: cannot open shared object file: + No such file or directory" +will probably result. +Either: remove libdwarf.so and rebuild or set +the environment variable LD_LIBRARY_PATH to the directory +containing the .so or use LDFLAGS to set rpath (see just below). +It is perhaps simpler to ensure that the libdwarf directory +only has an archive, not a shared-library. +But sometimes one wants a shared library. +In that case +one can set ld's -rpath on the gcc command line like this: + LDFLAGS="-Wl,-rpath=/some/path/libdir" +so the shared library can be found at run time automatically. + +The same problem may arise with libelf, and the same approach +will solve the problem. + + + +David Anderson. davea42 at earthlink dot net. diff --git a/dwarfdump2/checkutil.cc b/dwarfdump2/checkutil.cc new file mode 100644 index 0000000..2373700 --- /dev/null +++ b/dwarfdump2/checkutil.cc @@ -0,0 +1,156 @@ +/* + Copyright (C) 2011 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. + +*/ +/* + + These simple list-processing functions are in support + of checking DWARF for compiler-errors of various sorts. + + +*/ + +#include "globals.h" +#include <assert.h> +using std::cout; +using std::cerr; +using std::endl; + + +bool +AddressRangesData::IsAddressInAddressRange(Dwarf_Unsigned pc) +{ + if(pc < low_pc_) { + return false; + } + if(pc > high_pc_) { + return false; + } + for(std::list<AddressRangeEntry>::iterator it = + address_range_data_.begin(); it != address_range_data_.end(); + ++it) { + if (it->inThisRange(pc) ) { + return true; + } + } + return false; + +} + +void +AddressRangeEntry::printAddressRangeEntry(unsigned ct) +{ + cout <<"[" << IToDec(ct,6) << "] Low = " << + IToHex(range_low_pc_, 10 ) << + ", High = " << + IToHex(range_high_pc_, 10) << std::endl; +}; + +// Leave overall high/low as is, delete the details. +void +AddressRangesData::ResetRangesList() +{ + address_range_data_.clear(); +} + +// We might want to sort these by low-address rather than printing +// in random order! +void +AddressRangesData::PrintRangesData() +{ + unsigned ct = 0; + cout << "Begin Traversing, Low = "<< + IToHex(low_pc_,10) << + " High = " << + IToHex(high_pc_,10); + for(std::list<AddressRangeEntry>::iterator it = + address_range_data_.begin(); it != address_range_data_.end(); + ++it,++ct) { + + it->printAddressRangeEntry(ct); + } +} +void +AddressRangesData::AddAddressRange(Dwarf_Unsigned low_pc, Dwarf_Unsigned high_pc) +{ + // Presently we are not checking for duplicates, so some + // can be present. + address_range_data_.push_back(AddressRangeEntry(low_pc,high_pc)); +}; + +void +AddressRangesData::SetLimitsAddressRange(Dwarf_Unsigned low_pc, Dwarf_Unsigned high_pc) +{ + if(low_pc < high_pc) { + low_pc_ = low_pc; + high_pc_ = high_pc; + } +}; + +void +LinkOnceEntry::printLinkOnceEntry(unsigned ct) +{ + cout <<"[" << IToDec(ct,6) << "] Low = " << + IToHex(lo_section_low_pc_, 10 ) << + ", High = " << + IToHex(lo_section_high_pc_, 10) << + ", section index = " << + lo_section_index_ << + ", section = " << + lo_section_name_ << std::endl; +}; + +void +LinkOnceData::PrintLinkOnceData() +{ + unsigned ct = 0; + for(std::list<LinkOnceEntry>::iterator it = + link_once_data_.begin(); it != link_once_data_.end(); + ++it,++ct) { + + it->printLinkOnceEntry(ct); + } +} + +bool LinkOnceData::FindLinkOnceEntry(Dwarf_Unsigned pc) +{ + std::list<LinkOnceEntry>::iterator it; + for( it = link_once_data_.begin(); it != link_once_data_.end(); + ++it) { + if (it->inThisLinkOnceRange(pc) ) { + return true; + } + } + return false; +} +bool LinkOnceData::FindLinkOnceEntry(const std::string &secname,Dwarf_Unsigned lopc,Dwarf_Unsigned hipc) +{ + std::list<LinkOnceEntry>::iterator it; + for( it = link_once_data_.begin(); it != link_once_data_.end(); + ++it) { + if (it->inThisLinkOnceRange(secname,lopc,hipc) ) { + return true; + } + } + return false; +} + diff --git a/dwarfdump2/checkutil.h b/dwarfdump2/checkutil.h new file mode 100644 index 0000000..0594f67 --- /dev/null +++ b/dwarfdump2/checkutil.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2011 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. + +*/ + +#ifndef CHECKUTIL_H +#define CHECKUTIL_H + +// A list of section address ranges with identifying +// information. Provides the ability to check whether +// some line data that does not match .text does match +// some linkonce section data. +struct LinkOnceEntry { +public: + LinkOnceEntry(Dwarf_Unsigned section, Dwarf_Unsigned lowpc, + Dwarf_Unsigned high_pc, const std::string name): + lo_section_index_(section),lo_section_low_pc_(lowpc), + lo_section_high_pc_(high_pc),lo_section_name_(name) {}; + ~LinkOnceEntry () {}; + bool inThisLinkOnceRange(Dwarf_Unsigned pc) { + if(pc >= lo_section_low_pc_ && pc <= lo_section_high_pc_) { + return true; + } + return false; + } + bool inThisLinkOnceRange(const std::string &sname,Dwarf_Unsigned lopc, + Dwarf_Unsigned hipc) { + if(sname == lo_section_name_ ) { + if((lopc >= lo_section_low_pc_ && lopc <= + lo_section_high_pc_) && + (hipc >= lo_section_low_pc_ && hipc <= + lo_section_high_pc_)) { + return true; + } + } + return false; + }; + void printLinkOnceEntry(unsigned index); +private: + Dwarf_Unsigned lo_section_index_; + Dwarf_Unsigned lo_section_low_pc_; + Dwarf_Unsigned lo_section_high_pc_; + // There are normally relatively few sections (not thousands + // or millions). + std::string lo_section_name_; +}; + +// In C dwarfdump see pLinkonceInfo. +class LinkOnceData { +public: + LinkOnceData() {}; + ~LinkOnceData() {}; + void AddLinkOnceEntry(const LinkOnceEntry &e) { + link_once_data_.push_back(e); + }; + bool FindLinkOnceEntry(Dwarf_Unsigned pc); + bool FindLinkOnceEntry(const std::string &secname,Dwarf_Unsigned lopc, + Dwarf_Unsigned hipc); + void PrintLinkOnceData(); +private: + std::list<LinkOnceEntry> link_once_data_; +}; + +extern LinkOnceData *pLinkOnceData; + +struct AddressRangeEntry { +public: + AddressRangeEntry(Dwarf_Unsigned lowpc, + Dwarf_Unsigned high_pc): + range_low_pc_(lowpc), + range_high_pc_(high_pc){}; + ~AddressRangeEntry () {}; + bool inThisRange(Dwarf_Unsigned pc) { + if(pc < range_low_pc_ || pc > range_high_pc_) { + return false; + } + return true; + }; + void printAddressRangeEntry(unsigned index); +private: + Dwarf_Unsigned range_low_pc_; + Dwarf_Unsigned range_high_pc_; +}; + + +// In C dwarfdump see pRangesInfo. +// These address ranges are within the text section, +// and though rather like LinkOnceEntry data, we can +// rely on an overall valid range (before we check +// for the specific range) as a qualifier. So +// data that must fail the search is noted as such quickly. +class AddressRangesData { +public: + AddressRangesData():low_pc_(0xffffffffffffffff),high_pc_(0) {}; + ~AddressRangesData() {}; + void AddAddressRange(Dwarf_Unsigned low_pc, Dwarf_Unsigned high_pc); + void SetLimitsAddressRange(Dwarf_Unsigned low_pc, Dwarf_Unsigned high_pc); + bool IsAddressInAddressRange(Dwarf_Unsigned pc); + void PrintRangesData(); + void ResetRangesList(); +private: + Dwarf_Unsigned low_pc_; + Dwarf_Unsigned high_pc_; + std::list<AddressRangeEntry> address_range_data_; +}; + +extern AddressRangesData *pAddressRangesData; + +// In C dwarfdump see pVisitedInfo. +// VisitedOffsetData is used to track offsets so +// recursion and invalid references can be noted. +class VisitedOffsetData { +public: + typedef std::set<Dwarf_Unsigned,std::less<Dwarf_Unsigned> > VODtype; + VisitedOffsetData () { offset_ = new VODtype; }; + ~VisitedOffsetData () { delete offset_;}; + void reset() { + delete offset_; + offset_ = new VODtype; + } + void AddVisitedOffset(Dwarf_Unsigned off) { + offset_->insert(off); + }; + void DeleteVisitedOffset(Dwarf_Unsigned off) { + offset_->erase(off); + }; + bool IsKnownOffset(Dwarf_Unsigned off) { + VODtype::size_type v = offset_->count(off); + if( v) { + return true; + } + return false; + }; +private: + VODtype *offset_; +}; + +extern VisitedOffsetData *pVisitedOffsetData; +#endif /* CHECKUTIL_H */ diff --git a/dwarfdump2/common.cc b/dwarfdump2/common.cc new file mode 100644 index 0000000..cea678b --- /dev/null +++ b/dwarfdump2/common.cc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2008-2010 SN Systems. All Rights Reserved. + Portions Copyright (C) 2008-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 + +*/ + +#include <string> +#include <iostream> +#include "common.h" +#define DWARFDUMP_VERSION " Tue Apr 10 11:43:32 PDT 2012 " +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +void +print_version_details(const std::string & name,bool alwaysprint) +{ +#ifdef WIN32 +# ifdef _DEBUG + char *acType = "Debug"; +# else + char *acType = "Release"; +# endif /* _DEBUG */ + static char acVersion[32]; + snprintf(acVersion,sizeof(acVersion), + "[%s %s %s]",__DATE__,__TIME__,acType); + cout << name << " " << acVersion << endl; +#else /* !WIN32 */ + if(alwaysprint) { + cout << DWARFDUMP_VERSION << endl; + } +#endif /* WIN32 */ +} + + +void +print_args(int argc, char *argv[]) +{ +#ifdef WIN32 + int nIndex; + cout << "Arguments:"; + for (nIndex = 1; nIndex < argc; ++nIndex) { + cout << " " << argv[nIndex] ; + } + cout << endl; +#endif +} + +void +print_usage_message(const std::string &progname, + const char **text) +{ +#ifndef WIN32 + cerr <<"Usage: " << progname<<" <options> <object file>" << endl; +#endif + for (unsigned i = 0; *text[i]; ++i) { + cerr << text[i] << endl; + } +} diff --git a/dwarfdump2/common.h b/dwarfdump2/common.h new file mode 100644 index 0000000..f60d262 --- /dev/null +++ b/dwarfdump2/common.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2008-2010 SN Systems. All Rights Reserved. + Portions Copyright (C) 2008-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 + +*/ + +#ifndef common_INCLUDED +#define common_INCLUDED + +#include <stdio.h> + + +void print_args(int argc, char *argv[]); +void print_usage_message(const std::string &program_name, + const char **options); +void print_version_details(const std::string& name,bool alwaysprint); + +#endif /* common_INCLUDED */ diff --git a/dwarfdump2/config.h.in b/dwarfdump2/config.h.in new file mode 100644 index 0000000..6c53389 --- /dev/null +++ b/dwarfdump2/config.h.in @@ -0,0 +1,94 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the elf64_getehdr function is in libelf.a. */ +#undef HAVE_ELF64_GETEHDR + +/* Define to 1 if the Elf64_Rel structure has r_info field. */ +#undef HAVE_ELF64_R_INFO + +/* Define to 1 if you have the <elf.h> header file. */ +#undef HAVE_ELF_H + +/* Define to 1 if you have the <getopt.h> header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <libelf.h> header file. */ +#undef HAVE_LIBELF_H + +/* Define to 1 if you have the <libelf/libelf.h> header file. */ +#undef HAVE_LIBELF_LIBELF_H + +/* Define 1 if off64 is defined via libelf with GNU_SOURCE. */ +#undef HAVE_LIBELF_OFF64_OK + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define 1 if need nonstandard printf format for 64bit */ +#undef HAVE_NONSTANDARD_PRINTF_64_FORMAT + +/* Define 1 if plain libelf builds. */ +#undef HAVE_RAW_LIBELF_OK + +/* Define 1 if regex seems to be defined */ +#undef HAVE_REGEX + +/* Define to 1 if you have the <sgidefs.h> header file. */ +#undef HAVE_SGIDEFS_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* See if __uint32_t is predefined in the compiler. */ +#undef HAVE___UINT32_T + +/* Define 1 if sys/types.h defines __uint32_t. */ +#undef HAVE___UINT32_T_IN_SYS_TYPES_H + +/* See if __uint64_t is predefined in the compiler. */ +#undef HAVE___UINT64_T + +/* Define to header that first defines elf. */ +#undef LOCATION_OF_LIBELFHEADER + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS diff --git a/dwarfdump2/configure b/dwarfdump2/configure new file mode 100755 index 0000000..15c06f1 --- /dev/null +++ b/dwarfdump2/configure @@ -0,0 +1,5354 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.68. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="dwarfdump.cc" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +AR +RANLIB +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +EGREP +GREP +CPP +ac_ct_CXX +CXXFLAGS +CXX +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_nonstandardprintf +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-nonstandardprintf + Use a special printf format for 64bit (default is + NO) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.68 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.68. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if ${ac_cv_prog_gcc_traditional+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgtty.h> +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <termio.h> +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in elf.h getopt.h libelf.h libelf/libelf.h sgidefs.h sys/types.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for elf64_getehdr in -lelf" >&5 +$as_echo_n "checking for elf64_getehdr in -lelf... " >&6; } +if ${ac_cv_lib_elf_elf64_getehdr+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lelf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char elf64_getehdr (); +int +main () +{ +return elf64_getehdr (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_elf_elf64_getehdr=yes +else + ac_cv_lib_elf_elf64_getehdr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_elf_elf64_getehdr" >&5 +$as_echo "$ac_cv_lib_elf_elf64_getehdr" >&6; } +if test "x$ac_cv_lib_elf_elf64_getehdr" = xyes; then : + +$as_echo "#define HAVE_ELF64_GETEHDR 1" >>confdefs.h + +fi + + +if test "$ac_cv_header_elf_h" = yes; then + +$as_echo "#define LOCATION_OF_LIBELFHEADER <elf.h>" >>confdefs.h + +elif test "$ac_cv_header_libelf_h" = yes; then + +$as_echo "#define LOCATION_OF_LIBELFHEADER <libelf.h>" >>confdefs.h + +elif test "$ac_cv_header_libelf_libelf_h" = yes; then + +$as_echo "#define LOCATION_OF_LIBELFHEADER <libelf/libelf.h>" >>confdefs.h + +fi + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include LOCATION_OF_LIBELFHEADER +int +main () +{ +Elf64_Rel *p; int i; i = p->r_info; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_ELF64_R_INFO 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__uint32_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__uint64_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> +int +main () +{ + __uint32_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T_IN_SYS_TYPES_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <regex.h> +int +main () +{ + int i; + regex_t r; + int cflags = REG_EXTENDED; + const char *s = "abc"; + i = regcomp(&r,s,cflags); + regfree(&r); + ; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_REGEX 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +# Check whether --enable-nonstandardprintf was given. +if test "${enable_nonstandardprintf+set}" = set; then : + enableval=$enable_nonstandardprintf; +$as_echo "#define HAVE_NONSTANDARD_PRINTF_64_FORMAT 1" >>confdefs.h + +fi + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include <libelf.h> + +int +main () +{ + int p; p = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_RAW_LIBELF_OK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _GNU_SOURCE +#include <libelf.h> + +int +main () +{ + off64_t p; p = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_LIBELF_OFF64_OK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.68. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.68, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/dwarfdump2/configure.in b/dwarfdump2/configure.in new file mode 100644 index 0000000..b6b2256 --- /dev/null +++ b/dwarfdump2/configure.in @@ -0,0 +1,70 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(dwarfdump.cc) +AC_CONFIG_HEADER(config.h) + +AC_PROG_CC +AC_PROG_CXX +AC_GCC_TRADITIONAL +AC_PROG_INSTALL +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(AR, ar) +dnl AC_ARFLAGS + +AC_CHECK_HEADERS(elf.h getopt.h libelf.h libelf/libelf.h sgidefs.h sys/types.h) +AC_CHECK_LIB(elf,elf64_getehdr, + AC_DEFINE(HAVE_ELF64_GETEHDR,1, + [Define to 1 if the elf64_getehdr function is in libelf.a.])) + +dnl Find out where the elf header is. +if test "$ac_cv_header_elf_h" = yes; then + AC_DEFINE(LOCATION_OF_LIBELFHEADER,[<elf.h>], [Define to header that first defines elf]) +elif test "$ac_cv_header_libelf_h" = yes; then + AC_DEFINE(LOCATION_OF_LIBELFHEADER, [<libelf.h>], + [Define to header that first defines elf.]) +elif test "$ac_cv_header_libelf_libelf_h" = yes; then + AC_DEFINE(LOCATION_OF_LIBELFHEADER,[<libelf/libelf.h>], + [Define to header that first defines elf.]) +fi + +AC_TRY_COMPILE([#include LOCATION_OF_LIBELFHEADER], Elf64_Rel *p; int i; i = p->r_info; ,AC_DEFINE(HAVE_ELF64_R_INFO,1, + [Define to 1 if the Elf64_Rel structure has r_info field.])) +AC_TRY_COMPILE([], __uint32_t p; p = 3; ,AC_DEFINE(HAVE___UINT32_T, + 1,[See if __uint32_t is predefined in the compiler. ])) +AC_TRY_COMPILE([], __uint64_t p; p = 3; ,AC_DEFINE(HAVE___UINT64_T, + 1,[See if __uint64_t is predefined in the compiler. ])) +AC_TRY_COMPILE([#include <sys/types.h>],[ __uint32_t p; p = 3]; , + AC_DEFINE(HAVE___UINT32_T_IN_SYS_TYPES_H,1, + [Define 1 if sys/types.h defines __uint32_t.])) + +AC_TRY_COMPILE([#include <sys/types.h> + #include <regex.h>],[ int i; + regex_t r; + int cflags = REG_EXTENDED; + const char *s = "abc"; + i = regcomp(&r,s,cflags); + regfree(&r); + ]; , + AC_DEFINE(HAVE_REGEX,1, + [Define 1 if regex seems to be defined])) + +AC_ARG_ENABLE(nonstandardprintf,AC_HELP_STRING([--enable-nonstandardprintf], + [Use a special printf format for 64bit (default is NO)]), + [ AC_DEFINE([HAVE_NONSTANDARD_PRINTF_64_FORMAT],[1], + [Define 1 if need nonstandard printf format for 64bit] )], + []) + +AC_TRY_COMPILE([ +#include <libelf.h> +],[ int p; p = 0; ] , + AC_DEFINE(HAVE_RAW_LIBELF_OK,1, + [Define 1 if plain libelf builds.])) +AC_TRY_COMPILE([ +#define _GNU_SOURCE +#include <libelf.h> +],[ off64_t p; p = 0;] , + AC_DEFINE(HAVE_LIBELF_OFF64_OK,1, + [Define 1 if off64 is defined via libelf with GNU_SOURCE.])) + + + +AC_OUTPUT(Makefile) diff --git a/dwarfdump2/dieholder.h b/dwarfdump2/dieholder.h new file mode 100644 index 0000000..9f6a77a --- /dev/null +++ b/dwarfdump2/dieholder.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2009-2011 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 + + +*/ + +#ifndef DIEHOLDER_H +#define DIEHOLDER_H +// Reference counting eliminates confusion and bugs +// when deciding when to do dealloc. +class DieHolder { +public: + DieHolder():dbg_(0),die_(0),refcount_(new int(1)),die_printed_(false) { }; + DieHolder(Dwarf_Debug dbg, Dwarf_Die die): + dbg_(dbg),die_(die),refcount_(new int(1)),die_printed_(false) { }; + ~DieHolder() { + (*refcount_)--; + if( (*refcount_) == 0) { + delete refcount_; + if(die_) dwarf_dealloc(dbg_,die_,DW_DLA_DIE); + } + }; + DieHolder(const DieHolder & d):dbg_(d.dbg_),die_(d.die_), + refcount_(d.refcount_),die_printed_(d.die_printed_) { + (*refcount_)++; + }; + DieHolder & operator=(const DieHolder & d) { + if(this != &d) { + (*d.refcount_)++; + (*refcount_)--; + if( (*refcount_) == 0) { + delete refcount_; + if(die_) dwarf_dealloc(dbg_,die_,DW_DLA_DIE); + } + refcount_ = d.refcount_; + die_ = d.die_; + dbg_ = d.dbg_; + die_printed_ = d.die_printed_; + } + return *this; + }; + Dwarf_Die die() { return die_; }; + Dwarf_Debug dbg() { return dbg_; }; + bool die_printed() { return die_printed_; }; + void mark_die_printed() { die_printed_ = true; }; +private: + Dwarf_Debug dbg_; + Dwarf_Die die_; + int *refcount_; + bool die_printed_; +}; +#endif // DIEHOLDER_H diff --git a/dwarfdump2/dwarfdump.1 b/dwarfdump2/dwarfdump.1 new file mode 100644 index 0000000..bb7ee37 --- /dev/null +++ b/dwarfdump2/dwarfdump.1 @@ -0,0 +1,523 @@ +.TH DWARFDUMP +.SH NAME +dwarfdump \- dumps DWARF debug information of an ELF object +.SH SYNOPSIS +.B dwarfdump [options] \f2objectfilename\fP +.SH DESCRIPTION +The +.B dwarfdump +command prints or checks DWARF sections as requested by specific options. +With no options (but with the required \f2objectfilename\fP ) +all sections print (but some sections cannot be printed independently +safely, so those are only printed at offsets where the .debug_info section +refers to those sections). +.PP +As of June 2011 the printing options and the checking options +are mutually exclusive (if checking options are selected +the section details are not printed). When errors are encountered +dwarfdump does attempt to print sufficient context so that +one can understand exactly where the error is in the DWARF. +This change makes checking really large object files +much easier. +.PP +The format is intended to be human readable. +If a script is to parse the output, the +.B \-d +option is useful. +.PP +Not all sections actually exist in any given object file. +.PP +The format may change from release to release, so it is +unwise to depend too heavily on the format. +.PP +Frame information (.debug_frame and .eh_frame) is heavily +dependent on the ABI/ISA of the object file. +By default we use a generic set of register names +handling up to 100 registers named r0-100. +The '-R' option uses a built-in generic register name set +handling up to 1200 registers named r0-r1199. +The '-x abi=<abi>' +description below shows how to name an abi and use that to guide +the -f or -F processing. +Unless the cpu for the object file being dumped has many registers, +do not use -R or -x abi=generic as those can be needlessly +slow dumping frame sections. Instead, use the correct +abi (if it exists in dwarfdump.conf) or a generic such +as -x abi=generic100 or -x abi=generic500. +To get MIPS/IRIX register names names and call the old version 2 libdwarf +frame interface use the option '-x abi=mips'. +Without '-R' or '-x abi=<abi>' dwarfdump ignores +the dwarfdump.conf file and uses compiled-in generic set of +register names. +If no '-x name=<path>' is given, dwarfdump +looks for "./dwarfdump.conf", "$HOME/.dwarfdump.conf", "<install-prefix>/lib/dwarfdump.conf" and takes the first it finds. +If one or more '-x name=<path>' is given the last of these is +used and all other such files are ignored. +.PP +Some -k (checking) options print so-called harmless errors. +These are compiler errors that do not cause any +known problem and are only detected inside libdwarf itself. +These are difficult to properly report in dwarfdump and +any error strings may not appear close to the time the +error was encountered. +.SH URI STYLE INPUT STRINGS +.PP +The <objectfilename> and the options taking name strings look for URIs and +translate the URI strings to characters by default +(see -x, -c<compiler name>, -S, -u). +So any single % character is treated as if the following two +characters are hex digits representing the underlying true character. +Various characters are meaningful to shells (such as bash or sh) +and to getopt (such as the space character) +If the URI translation does anything it prints the before and after +of the URI translation on standard output, so inspection of the first +lines of output will show if URI did anything. +The actual options themselves are assumed to be non-URI. +So in the option '-cS&T' the -c portion must be non-URI, but the +& character might cause input issues so '-cS%26T' could be used instead. +To actually input a single % character (in a name, for example), +double it to %% on the command line. +.PP +Options -U (turning off URI interpretation) and -q (making finding +URI sequences silent) give finer control of URI interpretation. +PP +As an example, to get a string'a b' make the string 'a%20b' +(here the quote (') is for exposition not part of the string, though +quote is certainly problematic in a name). +Instead of escaping " quotes in the string, type %25, as in + 'a "b' should be typed 'a%20%25b' +Any characters can be typed in URI style, not just characters +which are problematic to the shell or getopt. +We strongly suggest you not type URI-style characters where +such are not needed or use +the % character itself in command line strings unless you must. +.SH PRINTING OPTIONS +.TP +.B \-a +Print each section as independently as possible. Sections that +can safely be printed independently (like .debug_abbrev) +have relevant info printed in the report (sometimes dependent +on -v). + +.TP +.B \-b +Print the .debug_abbrev section. Because the DWARF specfications +do not rule out garbage data areas in .debug_abbrev (if they are not +referenced from .debug_info) any garbage bytes can result in +this print failing. + +.TP +.B \-c +Print locations lists. + +.TP +.B \-f +Print the .debug_frame section. +.TP +.B \-F +Print the .eh_frame section. + +.TP +.B \-i +Print the .debug_info section. + +.TP +.B \-l +Print the .debug_info section and the associated line section data. + +.TP +.B \-m +Print the .debug_macinfo section. + +.TP +.B \-N +Print .debug_ranges section. Because the DWARF specfications +do not rule out garbage data areas in .debug_ranges (if they are not +referenced from .debug_info) any garbage bytes can result in +this print failing. + +.TP +.B \-p +Print the .debug_pubnames section. + +.TP +.B \-r +Print the .debug_aranges section. +.TP +.B \-s +Print .debug_string section. + +.TP +.B \-ta +Print the IRIX only sections .debug_static_funcs and .debug_static_vars. + +.TP +.B \-tf +Print the IRIX only section .debug_static_funcs. +.TP +.B \-tv +Print the IRIX only section .debug_static_vars. + +.TP +.B \-w +Print the IRIX-only .debug_weaknames section. + +.TP +.B \-y +Print the .debug_pubtypes section (and .debug_typenames, +an SGI IRIX-only section). + +.PP +Having dwarfdump print relocations may help establish whether +dwarfdump understands any relocations that might exist. + +.TP +.B \-o +Print all relocation records as well as we can manage. +.TP +.B \-oi +Print .rel*debug_info relocations. +.TP +.B \-ol +Print .rel*debug_line relocation. +.TP +.B \-op +Print .rel*debug_pubnames relocation. +.TP +.B \-oa +Has no effect. +.TP +.B \-or +Print .rel*debug_aranges relocations. +.TP +.B \-of +Print .rel*debug_frame relocations. +.TP +.B \-oo +Print .rel*debug_loc relocations. +.TP +.B \-oR +Print .rel*debug_ranges relocations. + +.TP +.B \-g +Normally used only for testing libdwarf, this tells dwarfdump to +print .debug_info and use an older dwarf_loclist() interface +function (a function that cannot handle all current +location lists). +.TP +.B \-V +Print a dwarfdump date/version string and stop. + +.SH CHECKING OPTIONS +.TP +.B \-cg +Restricts checking to compilers whose +producer string starts with 'GNU' +and turns off -cs . + +.TP +.B \-cs +Restricts checking to compilers whose +producer string starts with 'SN' +and turns off -cg . +.TP +.B \-cname +Restricts checking to compilers whose +producer string contains 'name' (not case sensitive). +The 'name' is read as a URI string. + +.TP +.B \ +-ka : Turns on all checking options except -kxe (-kxe might + be slow enough one mignt not want to use it routinely.) + +.TP +.B \ +-kb : Checks for certain abbreviations section errors when reading + DIEs. +.TP +.B \-kc +Checks for errors in constants in debug_info. +.TP +.B \-kd +Turns on full reporting of error totals per producer. +(the default shows less detail). +.TP +.B \-ke +Turns on reading pubnames and checking for fde errors. +.TP +.B \-kf +Turns on checking for FDE errors. +.TP +.B \-kF +Turns on checking for line table errors. +.TP +.B \-kg +Turns on checking for unused gaps in .debug_info (these +gaps are not an error, just a waste of space). + +.TP +.B \-ki +Causes a summary of checking results per compiler (producer) +to be printed at the end. +.TP +.B \-kl +Turns on locations list checking. +.TP +.B \-km +Turns on checking of ranges. +.TP +.B \-kM +Turns on checking of aranges. +.TP +.B \-kr +Turns on DIE tag-attr combinations checking. +.TP +.B \-kR +Turns on reading DIEs and checking for forward declarations +rom DW_AT_specification attributes. +(which are not an error but can be a source of inefficiency +for debuggers). +.TP +.B \-ks +Turns on extra reporting for some DIE errors checking detects . +.TP +.B \-kS +Turns on checking DIE references for circular references. +.TP +.B \-kt +Turns on tag-tag combinations checking. +.TP +.B \-kx +Turns on check_frames. +.TP +.B \-kxe +Turns off basic check_frames and turns on extended frame checking. +.TP +.B \-ky +Turns on type_offset, decl_file checking, + +.SH OPTION MODIFIERS + +.TP +.B \-C +Normally when checking for tag-tag or tag-attribute combinations +both the standard combinations and some common extensions are allowed. +With -C the extensions are taken out of the allowed class of combinations. + +.TP +.B \-d +When printing DIEs, put all the attributes for each DIE on the same (long) +line as the TAG. This makes searching for DIE information +(as with grep) much simpler as the entire DIE is on one line. + +.TP +.B \-D +Turns off the display of section offsets and attribute values in printed output. +So the .debug_info output isjust TAGs and Attributes. +For pubnames (and the like) it removes offsets from the output. +For locations lists it removes offsets from the output, but that +is useless since the attribute values don't show so neither does +the location data. + +.TP +.B \-e +Turns on truncation of attribute and tag names. For example +DW_TAG_foo becomes foo . Not compatible with +checking, only useful for printing DIEs. + +.TP +.B \-G +When printing, add global offsets to the offsets printed. + +.TP +.B \-H number +When printing or checking .debug_info, this terminates +the search after 'number' compilation units. When printing +frame information this terminates the FDE reporting +after 'number' FDEs and the CIE reporting (which occurs if one adds -v) +after 'number' CIEs. Example '-H 1' + +.TP +.B \-M +When printing, this means one want to have the FORM show for each attribute. +If a -v is also added (or more than one) then details of any form indirection +are also shown. + +.TP +.B \-n +When printing frames, this turns off the search for function names. +In a really large object the search can take more time than +one wants to wait, so this avoids the search. + +.TP +.B \-Q +Suppresses section data printing (set automatically with a checking option). + +.TP +.B \-R +When printing frames for ABIs with lots of registers, this allows +up to 1200 registers to be named (like R999) without choosing an ABI +with, for example '-x abi=ppc' + +.TP +.B \-v +Increases the detail shown when printing. +In some sections, using more -v options +will increase the detail (one to three are useful) or may +change the report to show, for example, the actual +line-data-commands instead of the resultant line-table. + +.SH SELECTIVE ENTRY PRINTING + +.PP +These -S options stand alone and basic print information about the compilation +unit and DIE where the string(s) appear. +At most one of each of the following is effective (so for example +one can only have one 'match', but one can +have a 'match', an 'any', and a 'regex'). +Any -S causes the .debug_info section to be inspected. +No checking options or printing options should be supplied with -S. + +.TP +.B \-S match=string +When printing DIEs +for each tag value or attribute name that matches 'string' exactly +print the compilation unit information and its section offset. +Any CU with no match is not printed. +The 'string' is read as a URI string. +.TP +.B \-S any=string +When printing DIEs +for each tag value or attribute name that contains 'string' +somewhere in the tag or attribute (case insensitive) +print the compilation unit information and its section offset. +Any CU with no match is not printed. +The 'string' is read as a URI string. +.TP +.B \-S regex=string +When printing DIEs +for each tag value or attribute name where the 'string' reqular +expression matches print the compilation unit information +and its section offset. +Any CU with no match is not printed. +The 'string' is read as a URI string. + +.PP +The string cannot have spaces or other characters which are +meaningful to getopt(3) and the shell will strip off quotes and +other characters. +So the string is assumed to be in URI style and is translated. +In other words, to match 'a b' make the -S string 'a%20b' +Instead of escaping " quotes in the string, type %25, as in + 'a "b' should be typed 'a%20%25b' +(the ' are for exposition here, not part of the strings). +Any characters can be typed in URI style, not just characters +which are problematic to the shell or getopt. +.PP +The -S any= and -S regex= options are only usable +if the library functions required are found at configure time. +.PP +The -W option is a modifier to the -S option, and +increases the amount of output -W prints. +Now we show the -W in context with a -S option. + +.TP +.B \-S match=string1 -W +Prints the parent tree and the children tree for the +DIEs that -S matches. + +.TP +.B \-S match=string2 -Wp +Prints the parent tree for the DIEs that -S matches. + +.TP +.B \-S match=string3 -Wc +Prints the parent tree for the DIEs that -S matches. + +.SH OTHER OPTIONS + +.TP +.B \-# number +This option controls internal debugging output, +higher numbers mean more debug actions. See the source code. + + +.TP +.B \-x name=/p/a/t/h.conf +The file path given is the name of a file assumed to be +a dwarfdump.conf-like file. +The file path is read as a URI string. + +.TP +.B \-x abi=ppc +Selects the abi (from a dwarfdump.conf file) to be used in +printing frame information (here using ppc as an example). +The abi is read as a URI string. + +.TP +.B \-P +When checking this adds the list of compilation-unit names +seen for each producer-compiler to the printed checking results. +.TP +.B \-q +When a URI is found and translated while reading +the command line, be quiet about +the URI translation. That is, don't print the +original and translated option strings. + +.TP +.B \-E +Turns on printing object-internal header data for some +systems (for Unix/Linux does nothing). + +.TP +.B \-u cuname +Turns on selective printing of DIEs (printing like -i). +Only the DIEs for a compilation unit that match the +name provided are printed. +If the compilation unit is ./a/b/c.c +the 'cuname' you provide should be c.c as the characters +through the final path-separating / are ignored. +If 'cuname' begins with a / then the entire name string +of a compilation unit must match 'cuname'. +The 'cuname' is read as a URI string. + +.TP +.B \-U +Turn off the URI interpretation of the command line +strings entirely. Must be be on the command line before +any URI strings encountered to be fully effective. + +.TP +.B \-z +No longer suported. + + +.SH FILES +dwarfdump + +dwarfdump.conf + +./dwarfdump.conf + +$(HOME)/.dwarfdump.conf + +$(HOME)/dwarfdump.conf + +<install-prefix>/lib/dwarfdump.conf +.SH NOTES +In some cases compilers use DW_FORM_data1 (for example) +and in such cases the signedness of the value must be taken +from context. Rather than attempt to determine the +context, dwarfdump prints the value with both signednesses +whenever there is ambiguity about the correct interpretation. +For example, +"DW_AT_const_value 176(as signed = -80)". +For normal DWARF consumers that correctly and fully +evaluate all attributes there is no ambiguity of signedness: +the ambiguity for dwarfdump is due to dwarfdump evaluating +DIEs in a simple order and not keeping track of much context. +.SH BUGS +Support for DWARF3 is being completed but may not be complete. diff --git a/dwarfdump2/dwarfdump.cc b/dwarfdump2/dwarfdump.cc new file mode 100644 index 0000000..cbec341 --- /dev/null +++ b/dwarfdump2/dwarfdump.cc @@ -0,0 +1,2258 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 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" +#include <vector> +#include <algorithm> // for sort +#include <iomanip> + +/* for 'open' */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <limits.h> +#include <unistd.h> /* For getopt. */ +#include "dwconf.h" +#include "common.h" +#include "naming.h" +#include "uri.h" +#define DWARFDUMP_VERSION " Tue Apr 10 11:43:32 PDT 2012 " + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +#define OKAY 0 +#define BYTES_PER_INSTRUCTION 4 + +extern char *optarg; +static string process_args(int argc, char *argv[]); +static void increment_compilers_detected(bool beyond); +static void increment_compilers_targeted(bool beyond); + +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}; + + + +std::string program_name; +int check_error = 0; +LinkOnceData *pLinkOnceData; +AddressRangesData *pAddressRangesData; +VisitedOffsetData *pVisitedOffsetData; + +/* Options to enable debug tracing */ +int nTrace[MAX_TRACE_LEVEL + 1]; + +/* Build section information */ +void build_linkonce_info(Dwarf_Debug dbg); +static string do_uri_translation(const string &s, const std::string &context); +static void reset_overall_CU_error_data(); + +bool info_flag = false; + +/* This so both dwarf_loclist() + and dwarf_loclist_n() can be + tested. Defaults to new + dwarf_loclist_n() */ +bool use_old_dwarf_loclist = false; + +bool line_flag = false; +static bool abbrev_flag = false; +static bool frame_flag = false; /* .debug_frame section. */ +static bool eh_frame_flag = false; /* GNU .eh_frame section. */ +static bool pubnames_flag = false; +static bool macinfo_flag = false; +static bool loc_flag = false; +static bool aranges_flag = false; +static bool ranges_flag = false; /* .debug_ranges section. */ +static bool string_flag = false; +static bool reloc_flag = false; +static bool static_func_flag = false; +static bool static_var_flag = false; +static bool type_flag = false; +static bool weakname_flag = false; +static bool header_flag = false; /* Control printing of Elf header. */ +bool 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; +bool dense = false; +bool ellipsis = false; +bool show_global_offsets = false; +bool show_form_used = false; +bool display_offsets = true; /* Emit offsets */ + +bool check_abbrev_code = false; +bool check_pubname_attr = false; +bool check_reloc_offset = false; +bool check_attr_tag = false; +bool check_tag_tree = false; +bool check_type_offset = false; +bool check_decl_file = false; +bool check_lines = false; +bool check_fdes = false; +bool check_ranges = false; +bool check_aranges = false; +bool check_harmless = false; +bool check_abbreviations = false; +bool check_dwarf_constants = false; +bool check_di_gaps = false; +bool check_forward_decl = false; +bool check_self_references = false; +bool generic_1200_regs = false; +bool suppress_check_extensions_tables = false; +// suppress_nested_name_search is a band-aid. +// A workaround. A real fix for N**2 behavior is needed. +bool suppress_nested_name_search = false; +static bool uri_options_translation = true; +static bool 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; + +bool check_names = false; +bool check_verbose_mode = true; /* During '-k' mode, display errors */ +bool check_frames = false; +bool check_frames_extended = false; /* Extensive frames check */ +bool check_locations = false; /* Location list check */ + +static bool check_all_compilers = true; +static bool check_snc_compiler = false; /* Check SNC compiler */ +static bool check_gcc_compiler = false; +static bool print_summary_all = false; + + +/* Records information about compilers (producers) found in the + debug information, including the check results for several + categories (see -k option). */ +struct Compiler { + Compiler():verified_(false) { results_.resize((int)LAST_CATEGORY); }; + ~Compiler() {}; + std::string name_; + bool verified_; + std::vector<std::string> cu_list_; + std::vector<Dwarf_Check_Result> results_; +}; + +/* 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. +*/ + +static std::vector<Compiler> compilers_detected; + +/* 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. +*/ +static std::vector<Compiler> compilers_targeted; +static int current_compiler = 0; + +static void PRINT_CHECK_RESULT(const std::string &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. */ +bool do_check_dwarf = false; +bool do_print_dwarf = false; +bool check_show_results = false; /* Display checks results. */ +bool 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). */ +struct Error_Message_Data error_message_data; + +bool display_parent_tree = false; +bool display_children_tree = false; +int stop_indent_level = 0; + +/* Print search results in wide format? */ +bool search_wide_format = false; + + + + + + + + + + +bool search_is_on; +std::string search_any_text; +std::string search_match_text; +std::string search_regex_text; +#ifdef HAVE_REGEX +regex_t search_re; +#endif + + +/* These configure items are for the + frame data. */ +static string config_file_path; +static string config_file_abi; +static const char * config_file_defaults[] = { + "dwarfdump.conf", + "./dwarfdump.conf", + /* Note: HOME location uses .dwarfdump.conf or 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; + +string cu_name; +bool 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) { + cerr <<"Warning: check flag turned off, " + "checking and printing are separate." << + endl; + } + 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 string &file_name, int archive, + struct dwconf_s *conf); +static int +open_a_file(const string &name) +{ + int f = 0; + +#ifdef __CYGWIN__ + f = open(name.c_str(), O_RDONLY | O_BINARY); +#else + f = open(name.c_str(), O_RDONLY); +#endif + return f; + +} + +/* Iterate through dwarf and print all info. */ +int +main(int argc, char *argv[]) +{ + int archive = 0; + + print_version_details(argv[0],false); + + // Ensure we have the zero entry of the vectors in + // these three data structures. + pAddressRangesData = new AddressRangesData; + pLinkOnceData = new LinkOnceData; + pVisitedOffsetData = new VisitedOffsetData; + + increment_compilers_detected(false); + increment_compilers_targeted(false); + (void) elf_version(EV_NONE); + if (elf_version(EV_CURRENT) == EV_NONE) { + cerr << "dwarfdump: libelf.a out of date." << endl; + exit(1); + } + /* 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); + string file_name = process_args(argc, argv); + int f = open_a_file(file_name); + if (f == -1) { + cerr << program_name << " ERROR: can't open " << + file_name << endl; + return (FAILED); + } + + Elf_Cmd cmd = ELF_C_READ; + Elf *arf = elf_begin(f, cmd, (Elf *) 0); + if (elf_kind(arf) == ELF_K_AR) { + archive = 1; + } + Elf *elf = 0; + 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 quiet when not an object */ + } 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_syms_malloc_data(); + delete pAddressRangesData; + delete pLinkOnceData; + delete pVisitedOffsetData; +#ifdef HAVE_REGEX + if(!search_regex_text.empty()) { + regfree(&search_re); + } +#endif + + + 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) { + cout << endl; + cout << "*** HARMLESS ERROR COUNT: " << IToDec(totalcount) << + " ***" << endl; + } + for(i = 0 ; buf[i]; ++i) { + ++printcount; + DWARF_CHECK_COUNT(harmless_result,1); + DWARF_CHECK_ERROR(harmless_result,buf[i]); + } + if(totalcount > printcount) { + DWARF_CHECK_COUNT(harmless_result,(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 */ + cout << endl; + cout << "Object Header:" << endl; + cout << "e_ident:" << endl; + cout <<" File ID = " << eh_literals.e_ident_file_id <<endl; + cout <<" File class = " << + IToHex0N(eh32->e_ident[EI_CLASS],4)<< + eh_literals.e_ident_file_class << endl; + cout <<" Data encoding = " << + IToHex0N(eh32->e_ident[EI_DATA],4)<< + eh_literals.e_ident_data_encoding << endl; + cout <<" File version = "<< + IToHex0N(eh32->e_ident[EI_VERSION],4)<< + eh_literals.e_ident_file_version << endl; + cout <<" OS ABI = " << + IToHex0N(eh32->e_ident[EI_VERSION],4)<< + " (" <<eh_literals.e_ident_os_abi_s << + ") (" <<eh_literals.e_ident_os_abi_l << + ")" <<endl; + //printf(" ABI version = %02x (%s)\n", + // eh32->e_ident[EI_ABIVERSION], eh_literals.e_ident_abi_version); + cout <<"e_type : " << + << IToHex(eh32->e_type)<< + " ("<< eh_literals.e_type << ")" << endl; + cout <<"e_machine: " << + << IToHex(eh32->e_machine)<< + " (" << eh_literals.e_machine_s << + ") (" << eh_literals.e_machine_l << ")" << endl; + cout <<"e_version: " << IToHex(eh32->e_version) << endl; + //printf("e_entry = 0x%I64x\n", eh32->e_entry); + cout <<"e_flags : " << IToHex(eh32->e_version); + cout <<"e_flags : "<< IToHex(eh32->e_flags) << endl; + cout <<"e_phnum : "<<IToHex( eh32->e_phnum) << endl; + cout <<"e_shnum : " <<IToHex(eh32->e_shnum) << endl; + } + 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 */ + cout << endl; + cout << "Object Header:" << endl; + cout << "e_ident:" << endl; + cout <<" File ID = " << eh_literals.e_ident_file_id <<endl; + cout <<" File class = " << + IToHex0N(eh64->e_ident[EI_CLASS],4)<< + eh_literals.e_ident_file_class << endl; + cout <<" Data encoding = " << + IToHex0N(eh64->e_ident[EI_DATA],4)<< + eh_literals.e_ident_data_encoding << endl; + cout <<" File version = "<< + IToHex0N(eh64->e_ident[EI_VERSION],4)<< + eh_literals.e_ident_file_version << endl; + cout <<" OS ABI = " << + IToHex0N(eh64->e_ident[EI_VERSION],4)<< + " (" <<eh_literals.e_ident_os_abi_s << + ") (" <<eh_literals.e_ident_os_abi_l << + ")" <<endl; + //printf(" ABI version = %02x (%s)\n", + // eh64->e_ident[EI_ABIVERSION], eh_literals.e_ident_abi_version); + cout <<"e_type : " << + << IToHex(eh64->e_type)<< + " ("<< eh_literals.e_type << ")" << endl; + cout <<"e_machine: " << + << IToHex(eh64->e_machine)<< + " (" << eh_literals.e_machine_s << + ") (" << eh_literals.e_machine_l << ")" << endl; + cout <<"e_version: " << IToHex(eh64->e_version) << endl; + //printf("e_entry = 0x%I64x\n", eh64->e_entry); + cout <<"e_flags : " << IToHex(eh64->e_version); + cout <<"e_flags : "<< IToHex(eh64->e_flags) << endl; + cout <<"e_phnum : "<<IToHex( eh64->e_phnum) << endl; + cout <<"e_shnum : " <<IToHex(eh64->e_shnum) << endl; + } +#endif /* HAVE_ELF64_GETEHDR */ + } +#endif /* WIN32 */ +} + + +/* Print checks and errors for a specific compiler */ +static void +print_specific_checks_results(Compiler *pCompiler) +{ + cerr << endl; + cerr << "DWARF CHECK RESULT" << endl; + cerr << "<item> <checks> <errors>" << endl; + 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); +} + +// StrictWeakOrdering, like LessThanComparable. +// But reversed... !! +static bool +sort_compare_compiler(const Compiler &cmp1,const Compiler &cmp2) +{ + int cnt1 = cmp1.results_[total_check_result].errors_; + int cnt2 = cmp2.results_[total_check_result].errors_; + + if (cnt1 > cnt2) { + return true; + } + /* When error counts match, sort on name. */ + if(cnt1 == cnt2) { + if (cmp1.name_ > cmp2.name_) { + return true; + } + } + return false; +} +/* Print a summary of checks and errors */ +static void +print_checks_results() +{ + + cerr.flush(); + cout.flush(); + + if(compilers_detected.size() > 1) { + std::stable_sort(compilers_detected.begin()+ 1, + compilers_detected.end(),sort_compare_compiler); + } + + /* Print list of CUs for each compiler detected */ + if (producer_children_flag) { + + unsigned count = 0; + unsigned total = 0; + + cerr << endl; + cerr << "*** CU NAMES PER COMPILER ***"<< endl; + for (unsigned index = 1; index < compilers_detected.size(); ++index) { + const Compiler& c = compilers_detected[index]; + cerr << endl; + cerr << IToDec0N(index,2) << ": " << c.name_; + cerr << endl; + count = 0; + for (unsigned nc = 0; + nc < c.cu_list_.size(); + ++nc ) { + + ++count; + cerr << endl; + cerr << " " << IToDec0N(count,2) <<": '" << + c.cu_list_[nc]<< "'" ; + } + total += count; + cerr << endl; + } + cerr << endl; + cerr<< "Detected " << total << " CU names" << endl; + } + + /* 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 compilers_not_detected = 0; + int compilers_verified = 0; + + /* Find out how many compilers have been verified. */ + for (unsigned index = 1; index < compilers_detected.size(); ++index) { + if (compilers_detected[index].verified_) { + ++compilers_verified; + } + } + /* Find out how many compilers have been not detected. */ + for (unsigned index = 1; index < compilers_targeted.size(); ++index) { + if (!compilers_targeted[index].verified_) { + ++compilers_not_detected; + } + } + + /* Print compilers detected list */ + cerr << endl; + cerr << compilers_detected.size() -1 << " Compilers detected:" + << endl; + for (unsigned index = 1; index < compilers_detected.size(); ++index) { + cerr << IToDec0N(index,2) << ": " << + compilers_detected[index].name_<< endl; + } + + /* Print compiler list specified by the user with the + '-c<str>', that were not detected. */ + if (compilers_not_detected) { + unsigned count = 0; + cerr << endl; + cerr << compilers_not_detected << " Compilers not detected:" + << endl; + for (unsigned index = 1; index < compilers_targeted.size(); ++index) { + Compiler *pCompiler = &compilers_targeted[index]; + if (!pCompiler->verified_) { + ++count; + cerr << IToDec0N(count,2) << ": '" << + pCompiler->name_ << "'" << endl; + } + } + } + + unsigned count2 = 0; + cerr << endl; + cerr << compilers_verified << " Compilers verified:" + << endl; + for (unsigned index = 1; index < compilers_detected.size(); ++index) { + if (compilers_detected[index].verified_) { + ++count2; + Compiler *pCompiler = &compilers_detected[index]; + cerr << IToDec0N(count2,2) << ": errors = "<< + IToDec(pCompiler->results_[total_check_result].errors_,5) + << ", " << + pCompiler->name_ << + endl; + } + } + + /* 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) { + int count = 0; + cerr << endl; + cerr << "*** ERRORS PER COMPILER ***" << endl; + for (unsigned index = 1; index < compilers_detected.size(); ++index) { + Compiler *pCompiler = &compilers_detected[index]; + if (pCompiler->verified_) { + ++count; + cerr << IToDec0N(count,2) << ": " << + pCompiler->name_ << endl; + print_specific_checks_results(pCompiler); + } + } + } + + /* Print general summary (all compilers checked) */ + cerr << endl; + cerr <<"*** TOTAL ERRORS FOR ALL COMPILERS ***" << endl; + 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 string & file_name, int archive, + struct dwconf_s *config_file_data) +{ + Dwarf_Debug dbg; + int dres = 0; + + dres = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &err); + if (dres == DW_DLV_NO_ENTRY) { + cout <<"No DWARF information present in " << file_name <<endl; + return 0; + } + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_elf_init", dres, err); + } + + if (archive) { + Elf_Arhdr *mem_header = elf_getarhdr(elf); + + cout << endl; + cout << "archive member \t" << + (mem_header ? mem_header->ar_name : "") << endl; + } + 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); + + dres = dwarf_get_address_size(dbg, + &error_message_data.elf_address_size,&err); + if (dres != DW_DLV_OK) { + print_error(dbg, "get_location_list", dres, err); + } + error_message_data.elf_max_address = + (error_message_data.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 */ + pAddressRangesData->SetLimitsAddressRange(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(); + 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_checks_results(); + + dres = dwarf_finish(dbg, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_finish", dres, err); + } + cout << endl; + cerr.flush(); + return 0; + +} + +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; +} + +/* Remove matching leading/trailing quotes. + Does not alter the passed in string. + If quotes removed does a makename on a modified string. */ +static string +remove_quotes_pair(char *text) +{ + static char single_quote = '\''; + static char double_quote = '\"'; + string out; + char quote = 0; + 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) { + out = string(p+1,p+len-1); + return out; + } + } + return p; +} + + +/* process arguments and return object filename */ +static string +process_args(int argc, char *argv[]) +{ + extern int optind; + int c = 0; + bool usage_error = false; + int oarg = 0; + + program_name = argv[0]; + + suppress_check_dwarf(); + /* j q unused */ + if (argv[1] != NULL && argv[1][0] != '-') { + do_all(); + } + + while ((c = + getopt(argc, argv, + "#:abc::CdDeEfFgGhH:ik:lmMnNo::pPqQrRsS:t:u:UvVwW::x:yz")) != EOF) { + + switch (c) { + 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 */ + { + string path; + string abi; + + /* -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 (path.empty()) + goto badopt; + config_file_path = path; + } else if (strncmp(optarg, "abi=", 4) == 0) { + abi = do_uri_translation(&optarg[4],"-x abi="); + if (abi.empty()) + goto badopt; + config_file_abi = abi; + break; + } else { + + badopt: + cerr << "-x name=<path-to-conf>" <<endl; + cerr << " and " << endl; + cerr << "-x abi=<abi-in-conf> " << endl; + cerr << "are legal, not -x " << optarg<< endl; + 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 { + check_all_compilers = false; + increment_compilers_targeted(true); + unsigned cc = compilers_targeted.size() -1; + compilers_targeted[cc].name_ = + do_uri_translation(optarg,"-c<compiler name>"); + // Assume a compiler version to check, + // most likely a substring of a compiler name. + } + } + } 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-translate 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' */ + { + bool err = true; + search_is_on = true; + /* -S text */ + if (strncmp(optarg,"match=",6) == 0) { + string noquotes = remove_quotes_pair(&optarg[6]); + search_match_text = do_uri_translation(noquotes,"-S match="); + if (search_match_text.size() > 0) { + err = false; + } + } + else { + if (strncmp(optarg,"any=",4) == 0) { + string noquotes = remove_quotes_pair(&optarg[4]); + search_any_text=do_uri_translation(noquotes,"-S any="); + if (search_any_text.size() > 0) { + err = false; + } + } +#ifdef HAVE_REGEX + else { + if (strncmp(optarg,"regex=",6) == 0) { + string noquotes = remove_quotes_pair(&optarg[6]); + search_regex_text = do_uri_translation(noquotes,"-S regex="); + if (search_regex_text.size() > 0) { + if (regcomp(&search_re, + search_regex_text.c_str(), + REG_EXTENDED)) { + cerr << + "regcomp: unable to compile " << + search_regex_text << endl; + } + else { + err = false; + } + } + } + } +#endif /* HAVE_REGEX */ + } + if (err) { + cerr << + "-S any=<text> or -S match=<text> or -S regex=<text>" + << endl; + cerr << "is allowed, not -S " <<optarg << endl; + usage_error = true; + } + } + break; + case 'a': + suppress_check_dwarf(); + do_all(); + break; + case 'v': + verbose++; + break; + case 'V': + { + cout << DWARFDUMP_VERSION << endl; + exit(0); + } + 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); + 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 */ + cu_name_flag = true; + cu_name = do_uri_translation(optarg,"-u<cu name>"); + break; + case 'U': /* Suppress URI translation. */ + 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': + cerr << "-z is no longer supported:ignored" << endl; + 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.empty()) && generic_1200_regs) { + cout << "Specifying both -R and -x abi= is not allowed. Use one " + "or the other. -x abi= ignored." <<endl; + config_file_abi = ""; + } + if(generic_1200_regs) { + init_generic_config_1200_regs(&config_file_data); + } + if ((!config_file_abi.empty()) && (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) { + cout << + "Frame not configured due to error(s). Giving up."<<endl; + 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"); +} + +/* ARGSUSED */ +void +print_error(Dwarf_Debug dbg, const string & msg, int dwarf_code, + Dwarf_Error err) +{ + print_error_and_continue(dbg,msg,dwarf_code,err); + exit(FAILED); +} +/* ARGSUSED */ +void +print_error_and_continue(Dwarf_Debug dbg, const string & msg, int dwarf_code, + Dwarf_Error err) +{ + cout.flush(); + cerr.flush(); + cerr << endl; + if (dwarf_code == DW_DLV_ERROR) { + string errmsg = dwarf_errmsg(err); + Dwarf_Unsigned myerr = dwarf_errno(err); + cerr << program_name << + " ERROR: " << msg << ": " << errmsg << " (" << myerr<< + ")" << endl; + } else if (dwarf_code == DW_DLV_NO_ENTRY) { + cerr << program_name << + " NO ENTRY: " << msg << ": " << endl; + } else if (dwarf_code == DW_DLV_OK) { + cerr << program_name<< ": " << msg << endl; + } else { + cerr << program_name<< " InternalError: "<< msg << + ": code " << dwarf_code << endl; + } + cerr.flush(); + + // 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.*/ +bool +should_skip_this_cu(DieHolder& hcu_die, Dwarf_Error err) +{ + Dwarf_Half tag = 0; + Dwarf_Attribute attrib; + Dwarf_Half theform = 0; + Dwarf_Die cu_die = hcu_die.die(); + Dwarf_Debug dbg = hcu_die.dbg(); + + int tres = dwarf_tag(cu_die, &tag, &err); + if (tres != DW_DLV_OK) { + print_error(dbg, "dwarf_tag when checking if cu skippable ", + tres, err); + } + int dares = dwarf_attr(cu_die, DW_AT_name, &attrib, &err); + if (dares != DW_DLV_OK) { + print_error(dbg, + "dwarf cu_die has no name, when checking if cu skippable", + dares, err); + } + int 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++; + } + } + if (strcmp(cu_name.c_str(), p)) { + // skip this cu. + return true; + } + } 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) +{ + Dwarf_Half tag = 0; + Dwarf_Attribute attrib = 0; + Dwarf_Half theform = 0; + string attr_name; + + int tres = dwarf_tag(cu_die, &tag, &err); + if (tres != DW_DLV_OK) { + print_error(dbg, "dwarf_tag in aranges", + tres, err); + } + int 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); + } + int 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++; + } + } + attr_name.append(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 attr_name; +} + +/* Returns the cu name of the CU */ +int get_cu_name(DieHolder &hcu_die, + Dwarf_Error err, string &short_name, string &long_name) +{ + Dwarf_Attribute name_attr = 0; + + int ares = dwarf_attr(hcu_die.die(),DW_AT_name, &name_attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(hcu_die.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 */ + + SrcfilesHolder srcfiles; + get_attr_value(hcu_die.dbg(), DW_TAG_compile_unit, + hcu_die.die(), name_attr, + srcfiles, + long_name, + false /*show_form_used*/,0 /* verbose */); + /* Generate the short name (filename) */ + const char * filename = strrchr(long_name.c_str(),'/'); + if (!filename) { + filename = strrchr(long_name.c_str(),'\\'); + } + if (filename) { + ++filename; + } else { + filename = long_name.c_str(); + } + short_name = filename; + } + } + dwarf_dealloc(hcu_die.dbg(), name_attr, DW_DLA_ATTR); + return ares; +} + +/* Returns the producer of the CU */ +int get_producer_name(DieHolder &hcu_die, + Dwarf_Error err, string &producer_name) +{ + Dwarf_Attribute producer_attr = 0; + + int ares = dwarf_attr(hcu_die.die(), DW_AT_producer, &producer_attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(hcu_die.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()). */ + string esb_producer; + SrcfilesHolder srcfiles; + get_attr_value(hcu_die.dbg(), DW_TAG_compile_unit, + hcu_die.die(), producer_attr, + srcfiles,producer_name, + false /*show_form_used*/, + 0 /* verbose */); + } + } + + dwarf_dealloc(hcu_die.dbg(), producer_attr, DW_DLA_ATTR); + return ares; +} + +/* GCC linkonce names */ +const char *lo_text = ".text."; /*".gnu.linkonce.t.";*/ +const char *lo_debug_abbr = ".gnu.linkonce.wa."; +const char *lo_debug_aranges = ".gnu.linkonce.wr."; +const char *lo_debug_frame_1 = ".gnu.linkonce.wf."; +const char *lo_debug_frame_2 = ".gnu.linkonce.wF."; +const char *lo_debug_info = ".gnu.linkonce.wi."; +const char *lo_debug_line = ".gnu.linkonce.wl."; +const char *lo_debug_macinfo = ".gnu.linkonce.wm."; +const char *lo_debug_loc = ".gnu.linkonce.wo."; +const char *lo_debug_pubnames = ".gnu.linkonce.wp."; +const char *lo_debug_ranges = ".gnu.linkonce.wR."; +const char *lo_debug_str = ".gnu.linkonce.ws."; + +/* SNC compiler/linker linkonce names */ +const char *nlo_text = ".text."; +const char *nlo_debug_abbr = ".debug.wa."; +const char *nlo_debug_aranges = ".debug.wr."; +const char *nlo_debug_frame_1 = ".debug.wf."; +const char *nlo_debug_frame_2 = ".debug.wF."; +const char *nlo_debug_info = ".debug.wi."; +const char *nlo_debug_line = ".debug.wl."; +const char *nlo_debug_macinfo = ".debug.wm."; +const char *nlo_debug_loc = ".debug.wo."; +const char *nlo_debug_pubnames = ".debug.wp."; +const char *nlo_debug_ranges = ".debug.wR."; +const 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 const 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, + §ion_name, + §ion_addr, + §ion_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 */ + pLinkOnceData->AddLinkOnceEntry( + LinkOnceEntry( + section_index, + section_addr, + section_addr + section_size, + section_name)); + break; + } + } + } + } + + if (dump_linkonce_info) { + pLinkOnceData->PrintLinkOnceData(); + } +} + +/* 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 */ + error_message_data.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) { + pAddressRangesData->ResetRangesList(); + } + /* 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 */ + error_message_data.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 */ + error_message_data.seen_PU = true; + error_message_data.seen_PU_base_address = false; + error_message_data.seen_PU_high_address = false; + error_message_data.PU_name = ""; + error_message_data.need_PU_valid_code = true; + } + break; + } +} + +/* Indicates if the current CU is a target */ +static bool current_cu_is_checked_compiler = true; + +/* Are we checking for errors from the + compiler of the current compilation unit? +*/ +bool +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; +} + +static void +increment_compilers_detected(bool beyond) +{ + if( compilers_detected.empty()) { + // For the standard 'all' entry [0]. + Compiler c; + compilers_detected.push_back(c); + } + if (beyond) { + Compiler c; + compilers_detected.push_back(c); + } +} +static void +increment_compilers_targeted(bool beyond) +{ + if( compilers_targeted.empty()) { + // For the standard 'all' entry [0]. + Compiler c; + compilers_targeted.push_back(c); + } + if (beyond) { + Compiler c; + compilers_targeted.push_back(c); + } +} + + +/* 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 string &producer_name) +{ + unsigned index = 0; + + error_message_data.CU_producer = 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.empty()) { + for (index = 1; index < compilers_targeted.size(); ++index) { + if (is_strstrnocase(error_message_data.CU_producer.c_str(), + compilers_targeted[index].name_.c_str())) { + compilers_targeted[index].verified_ = true; + current_cu_is_checked_compiler = true; + break; + } + } + } else { + /* Take into account that internally all strings are double quoted */ + bool snc_compiler = hasprefix( + error_message_data.CU_producer.c_str(), + "\"SN")? true : false; + bool gcc_compiler = hasprefix( + error_message_data.CU_producer.c_str(), + "\"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 */ + bool cFound = false; + for (index = 1; index < compilers_detected.size(); ++index) { + if ( +#if WIN32 + !stricmp(compilers_detected[index].name_.c_str(), + error_message_data.CU_producer.c_str()) +#else + compilers_detected[index].name_ == error_message_data.CU_producer +#endif + ) { + /* Set current compiler index */ + current_compiler = index; + cFound = true; + break; + } + } + if (!cFound) { + /* Record a new detected compiler name. */ + increment_compilers_detected(true); + current_compiler = compilers_detected.size()-1; + compilers_detected[current_compiler].name_ = + error_message_data.CU_producer; + } +} + +/* 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(const string & name) +{ + if (current_compiler < 1) { + cerr << "Current compiler set to " << current_compiler << + "cannot add Compilation unit name. Giving up." << endl; + exit(1); + } + compilers_detected[current_compiler].cu_list_.push_back(name); +} + +/* 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 string default_cu_producer("<unknown>"); +static void +reset_overall_CU_error_data() +{ + error_message_data.CU_name = default_cu_producer; + error_message_data.CU_producer = default_cu_producer; + error_message_data.DIE_offset = 0; + error_message_data.DIE_overall_offset = 0; + error_message_data.DIE_CU_offset = 0; + error_message_data.DIE_CU_overall_offset = 0; + error_message_data.CU_base_address = 0; + error_message_data.CU_high_address = 0; +} + +static bool +cu_data_is_set() +{ + if(error_message_data.CU_name != default_cu_producer || + error_message_data.CU_producer != default_cu_producer) { + return true; + } + if(error_message_data.DIE_offset || + error_message_data.DIE_overall_offset) { + return true; + } + if(error_message_data.CU_base_address || + error_message_data.CU_high_address) { + return true; + } + return false; +} + +/* Print CU basic information */ +void PRINT_CU_INFO() +{ + cerr.flush(); + cout.flush(); + if (error_message_data.current_section_id == DEBUG_LINE || + error_message_data.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. */ + error_message_data.DIE_offset = error_message_data.DIE_CU_offset; + error_message_data.DIE_overall_offset = + error_message_data.DIE_CU_overall_offset; + } + if(!cu_data_is_set()) { + return; + } + cout << endl; + cout <<"CU Name = " <<error_message_data.CU_name << endl; + cout << "CU Producer = " <<error_message_data.CU_producer << endl; + cout <<"DIE OFF = "<< IToHex0N(error_message_data.DIE_offset,10) << + " GOFF = "<< IToHex0N(error_message_data.DIE_overall_offset,10); + cout <<", Low PC = " << + IToHex0N(error_message_data.CU_base_address,10) << + ", High PC = " << + IToHex0N(error_message_data.CU_high_address,10); + cout << endl; + cout.flush(); +} + +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) { + 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) { + compilers_detected[current_compiler].results_[category].errors_ += inc; + compilers_detected[current_compiler].results_[total_check_result].errors_ + += inc; + } +} + +static void +PRINT_CHECK_RESULT(const string &str, + Compiler *pCompiler, Dwarf_Check_Categories category) +{ + Dwarf_Check_Result result = pCompiler->results_[category]; + cerr << std::setw(24) << std::left << str << + IToDec(result.checks_,10) << + " " << + IToDec(result.errors_,10) << endl; +} + +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 std::string& str) +{ + if (checking_this_compiler()) { + DWARF_ERROR_COUNT(category,1); + if (check_verbose_mode) { + cout << endl; + cout << "*** DWARF CHECK: " << str << " ***" << + endl; + } + DWARF_CHECK_ERROR_PRINT_CU(); + } +} + +void DWARF_CHECK_ERROR2(Dwarf_Check_Categories category, + const std::string & str1, const std::string & str2) +{ + if (checking_this_compiler()) { + DWARF_ERROR_COUNT(category,1); + if (check_verbose_mode) { + cout << endl; + cout << "*** DWARF CHECK: " << str1 << ": " << + str2 << " ***" << + endl; + } + DWARF_CHECK_ERROR_PRINT_CU(); + } +} + +void DWARF_CHECK_ERROR3(Dwarf_Check_Categories category, + const std::string &str1, const std::string &str2, + const std::string &strexpl) +{ + if (checking_this_compiler()) { + DWARF_ERROR_COUNT(category,1); + if (check_verbose_mode) { + cout << endl; + cout << "*** DWARF CHECK: " << str1 << " -> " << + str2 << ": " << + strexpl << " ***" << + endl; + } + DWARF_CHECK_ERROR_PRINT_CU(); + } +} + +static string +do_uri_translation(const string &s,const string&context) +{ + string out; + if (!uri_options_translation) { + return s; + } + translate_from_uri(s.c_str(),out); + if (do_print_uri_in_input) { + if(s != out) { + cout << "Uri Translation on option " << context << endl; + cout << " \'" << s << "\'"<< endl; + cout << " \'" << out << "\'"<< endl; + } + } + return out; +} + diff --git a/dwarfdump2/dwarfdump.conf b/dwarfdump2/dwarfdump.conf new file mode 100644 index 0000000..d70bab8 --- /dev/null +++ b/dwarfdump2/dwarfdump.conf @@ -0,0 +1,810 @@ +# MIPS/IRIX ISA/ABI +# Used to configure dwarfdump printing of .debug_frame and +# .eh_frame. + +# Any number of abi's can be described. Only one can be selected +# in a given dwarfdump run (see dwarfdump options) +# Available commands are +# beginabi: <abiname> +# reg: <regname> <dwarf regnumber> +# frame_interface: <integer value 2 or 3> +# cfa_reg: <number> +# initial_reg_value: <number: often 1034 or 1035 > +# same_val_reg: 1035 +# undefined_val_reg: 1034 +# reg_table_size: <size of table> +# address_size: <4 or 8, Rarely needed, see example below. > +# includeabi: <abiname Inserts the referenced abi as if its text was +# directly inserted at this point.> +# endabi: <abiname> +# +# Symbolic names do not work here, use literal numbers +# where applicable (in C standard decimal, octal (leading 0) or +# hexadecimal <leading 0x>). +# +# Whitespace is required to separate command: from operands and +# operands from each other on a line. +# +# There is no ordering required within a beginabi/endabi pair. +# As many ABIs as required may be listed. +# dwarfdump will choose exactly one abi to dump frame information. +# + + +# MIPS abi,the old IRIX form, not to be used on modern objects. +# Begin with abi name (use here and on dwarfdump command line). +beginabi: mips-irix + +# Instructs dwarfdump to default to the older frame interface. +# Use value 3 to use the newer interface. +# The '2' interface is supported but deprecated (deprecated +# because it cannot work with all popular ABIs: mixing +# the cfa-rule into the table column set was not a good idea +# but it is part of the MIPS/IRIX standard usage). +frame_interface: 2 + +# If (and only if) using frame_interface: 2 tell dwarfdump +# what table colum that DW_FRAME_CFA_COL is. +# If using frame_interface: 3 cfa_reg: should be +# DW_FRAME_CFA_COL3 (1436) +cfa_reg: 0 + +# For MIPS, the same as DW_FRAME_SAME_VAL (1035). +# For other ISA/ABIs 1034 (DW_FRAME_UNDEFINED_VAL) might be better. +# Depends on the ABI convention, if set wrong way too many +# regs will be listed in the frame output. +# This instructs dwarfdump to set libdwarf to this value, +# overriding the libdwarf default. +# If initial_reg_value not set the libdwarf default is used +# (see libdwarf.h DW_FRAME_REG_INITIAL_VALUE). +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +same_val_reg: 1035 +undefined_val_reg: 1034 + +# Built in to frame_interface: 2 as 66. +reg_table_size: 66 + + +# Only name registers for wich a r4 (for example) is not what you +# want to see +# No particular order of the reg: lines required. +reg: cfa 0 # Used with MIPS/IRIX original DWARF2 interface +reg: r1/at 1 +reg: r2/v0 2 +reg: r3/v1 3 +reg: r4/a0 4 +reg: r5/a1 5 +reg: r6/a2 6 +reg: r7/a3 7 +reg: r8/t0 8 +reg: r9/t1 9 +reg: r10/t2 10 +reg: r11/t3 11 +reg: r12/t4 12 +reg: r13/t5 13 +reg: r14/t6 14 +reg: r15/t7 15 +reg: r16/s0 16 +reg: r17/s1 17 +reg: r18/s2 18 +reg: r19/s3 19 +reg: r20/s4 20 +reg: r21/s5 21 +reg: r22/s6 22 +reg: r23/s7 23 +reg: r24/t8 24 +reg: r25/t9 25 +reg: r26/k0 26 +reg: r27/k1 27 +reg: r28/gp 28 +reg: r29/sp 29 +reg: r30/s8 30 +reg: r31 31 + +reg: $f0 32 +reg: $f1 33 +reg: $f2 34 +reg: $f3 35 +reg: $f4 36 +reg: $f5 37 +reg: $f6 38 +reg: $f7 39 +reg: $f8 40 +reg: $f9 41 +reg: $f10 42 +reg: $f11 43 +reg: $f12 44 +reg: $f13 45 +reg: $f14 46 +reg: $f15 47 +reg: $f16 48 +reg: $f17 49 +reg: $f18 50 +reg: $f19 51 +reg: $f20 52 +reg: $f21 53 +reg: $f22 54 +reg: $f23 55 +reg: $f24 56 +reg: $f25 57 +reg: $f26 58 +reg: $f27 59 +reg: $f28 60 +reg: $f29 61 +reg: $f30 62 +reg: $f31 63 +reg: ra 64 +reg: slk 65 + + +# End of abi definition. +endabi: mips-irix + + +# Make 'mips' abi be a modern MIPS, not an old IRIX version. +beginabi: mips +includeabi: mips-simple3 +endabi: mips + + +# MIPS/IRIX ISA/ABI for testing libdwarf. +beginabi: mips-irix2 +frame_interface: 2 +reg_table_size: 66 +cfa_reg: 0 +same_val_reg: 1035 +undefined_val_reg: 1034 +initial_reg_value: 1035 + +reg: cfa 0 # Used with MIPS/IRIX original DWARF2 interface +reg: ra 64 +reg: slk 65 + +# End of abi definition. +endabi: mips-irix2 + +# MIPS/IRIX ISA/ABI for testing the new frame interface +# with libdwarf. +beginabi: mips-simple3 +frame_interface: 3 + +# When using frame_interface: 3 the size of the register table +# is not fixed. It can be as large as needed. +reg_table_size: 66 +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +initial_reg_value: 1035 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# No cfa as a 'normal' register. +# Rule 0 is just register 0, which is not used +# in frame descriptions. +# (so cfa does not have a number here, and dwarfdump gives +# it the name 'cfa' automatically). +reg: ra 64 +reg: slk 65 +# End of abi definition. +endabi: mips-simple3 + + +beginabi: ia64 +frame_interface: 3 +initial_reg_value: 1034 # DW_FRAME_UNDEFINED_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 695 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# The following register names are not necessarily correct... +# Register indexes r32-r127 not used. +reg: f0 128 +# ... +reg: f127 255 +reg: b0 321 +reg: b1 322 +reg: b2 323 +reg: b3 324 +reg: b4 325 +reg: b5 326 +reg: b6 327 +reg: b7 328 +reg: vfp 329 +reg: vrap 330 +reg: pr 331 +reg: ip 332 +reg: psr 333 +reg: cfm 334 +reg: k0 335 +reg: k1 336 +reg: k2 337 +reg: k3 338 +reg: k4 339 +reg: k5 340 +reg: k6 341 +reg: k7 342 +reg: rsc 350 +reg: bsp 351 +reg: bspstore 352 +reg: rnat 353 +reg: fcr 355 +reg: eflag 358 +reg: csd 359 +reg: ssd 360 +reg: cflg 361 +reg: fsr 362 +reg: fir 363 +reg: fdr 364 +reg: pfs 398 +reg: lc 399 +reg: ec 400 + +endabi: ia64 + + +beginabi: x86 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +reg_table_size: 66 # more than large enough, hopefully. +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# The following register names are not necessarily correct... +reg: eax 0 +reg: ecx 1 +reg: edx 2 +reg: ebx 3 +reg: esp 4 +reg: ebp 5 +reg: esi 6 +reg: edi 7 +reg: eip 8 +reg: eflags 9 + +reg: trapno 10 +reg: st0 11 +reg: st1 12 +reg: st2 13 +reg: st3 14 +reg: st4 15 +reg: st5 16 +reg: st6 17 +reg: st7 18 +# 19 is ? 20 is ? +reg: xmm0 21 +reg: xmm1 22 +reg: xmm2 23 +reg: xmm3 24 +reg: xmm4 25 +reg: xmm5 26 +reg: xmm6 27 +reg: xmm7 28 + +reg: mm0 29 +reg: mm1 30 +reg: mm2 31 +reg: mm3 32 +reg: mm4 33 +reg: mm5 34 +reg: mm6 35 +reg: mm7 36 + +reg: fcw 37 +reg: fsw 38 +reg: mxcsr 39 + +reg: es 40 +reg: cs 41 +reg: ss 42 +reg: ds 43 +reg: fs 44 +reg: gs 45 +# 46 47 are ? +reg: tr 48 +reg: ldtr 49 + + +endabi: x86 + + +beginabi: x86_64 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +reg_table_size: 66 # more than large enough, hopefully. +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1035 +undefined_val_reg: 1034 + +# The following register names are not necessarily correct... +reg: rax 0 +reg: rdx 1 +reg: rcx 2 +reg: rbx 3 +reg: rsi 4 +reg: rdi 5 +reg: rbp 6 +reg: rsp 7 +reg: r8 8 +reg: r9 9 +reg: r10 10 +reg: r11 11 +reg: r12 12 +reg: r13 13 +reg: r14 14 +reg: r15 15 +reg: rip 16 +reg: xmm0 17 +reg: xmm1 18 +reg: xmm2 19 +reg: xmm3 20 +reg: xmm4 21 +reg: xmm5 22 +reg: xmm6 23 +reg: xmm7 24 +reg: xmm8 25 +reg: xmm9 26 +reg: xmm10 27 +reg: xmm11 28 +reg: xmm12 29 +reg: xmm13 30 +reg: xmm14 31 +reg: xmm15 32 + +reg: st0 33 +reg: st1 34 +reg: st2 35 +reg: st3 36 +reg: st4 37 +reg: st5 38 +reg: st6 39 +reg: st7 40 + +reg: mm0 41 +reg: mm1 42 +reg: mm2 43 +reg: mm3 44 +reg: mm4 45 +reg: mm5 46 +reg: mm6 47 +reg: mm7 48 + +reg: rflags 49 +reg: es 50 +reg: cs 51 +reg: ss 52 +reg: ds 53 +reg: fs 54 +reg: gs 55 +# 56, 57 are ? +reg: fs.base 58 +reg: gs.base 59 +# 60 61 are ? +reg: tr 62 +reg: ldtr 63 + +endabi: x86_64 + +beginabi: m68k +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +reg_table_size: 66 # more than large enough, hopefully. +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1035 +undefined_val_reg: 1034 + +reg: d0 0 +reg: d1 1 +reg: d2 2 +reg: d3 3 +reg: d4 4 +reg: d5 5 +reg: d6 6 +reg: d7 7 + +reg: a0 8 +reg: a1 9 +reg: a2 10 +reg: a3 11 +reg: a4 12 +reg: a5 13 +reg: a6 14 +reg: sp 15 + +reg: fp0 16 +reg: fp1 17 +reg: fp2 18 +reg: fp3 19 +reg: fp4 20 +reg: fp5 21 +reg: fp6 22 +reg: pc 23 + +endabi: m68k + +# Demonstrates use of address_size and includeabi keywords. +# address_size is useful when an Elf64 object has DWARF2 +# 32bit (4 byte) address-size frame data (which has no address_size field) +# and no .debug_info section to provide the 32bit address size. +beginabi: ppc32bitaddress +address_size: 4 +includeabi: ppc +endabi: ppc32bitaddress + +beginabi: ppc +# This abi defined Oct 2008 based on: +# http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html +frame_interface: 3 +# abi dwarf table uses up thru 1155. +# As of Oct 2008, the only ABI requiring a higher +# DW_FRAME_SAME_VAL and DW_FRAME_CFA_COL3. +initial_reg_value: 1235 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +same_val_reg: 1235 +undefined_val_reg: 1234 +reg_table_size: 1200 + +reg: r0 0 +reg: f0 32 +reg: f1 33 +reg: f2 34 +reg: f3 35 +reg: f4 36 +reg: f5 37 +reg: f6 38 +reg: f7 39 +reg: f8 40 +reg: f9 41 +reg: f10 42 +reg: f11 43 +reg: f12 44 +reg: f13 45 +reg: f14 46 +reg: f16 47 +reg: f17 48 +reg: f18 49 +reg: f19 50 +reg: f20 51 +reg: f21 52 +reg: f22 53 +reg: f23 54 +reg: f24 55 +reg: f25 56 +reg: f26 57 +reg: f27 58 +reg: f28 59 +reg: f29 60 +reg: f30 62 +reg: f31 63 +reg: cr 64 +reg: fpcsr 65 +# spr0 is also called MQ +reg: spr0 100 +# spr1 is also called XER +reg: spr1 101 +# spr4 also called rtcu +reg: spr4 104 +# spr5 also called rtcl +reg: spr5 105 +#spr8 also called LR +reg: spr8 108 +# spr9 also called ctr +reg: spr9 109 +reg: msr 66 +reg: sr0 70 +reg: sr1 71 +reg: sr2 72 +reg: sr3 73 +reg: sr4 74 +reg: sr5 75 +reg: sr6 76 +reg: sr7 77 +reg: sr8 78 +reg: sr9 79 + +#dsisr also called spr18 +reg: spr18 118 +# dar also called spr19 +reg: spr19 119 +#dec also called spr22 +reg: spr22 122 +#sdr1 also called spr25 +reg: spr25 125 +#srr0 also called spr26 +reg: spr26 126 +#srr1 also called spr27 +reg: spr27 127 + +#vrsave also called spr256 +reg: spr256 356 +#sprg0 also called spr272 +reg: spr272 372 +#sprg1 also called spr273 +reg: spr273 373 +#sprg2 also called spr274 +reg: spr274 374 +#sprg3 also called spr275 +reg: spr275 375 +#asr also called spr280 +reg: spr280 380 +#ear also called spr282 +reg: spr282 382 +#tb also called spr284 +reg: spr284 384 +#tbu also called spr285 +reg: spr285 385 +#pvr also called spr287 +reg: spr287 387 +#ibat0u also called spr528 +reg: spr528 628 +#ibat0l also called spr529 +reg: spr529 629 +#ibat1u also called spr530 +reg: spr530 630 +#ibat1l also called spr531 +reg: spr531 631 +#ibat2u also called spr532 +reg: spr532 632 +#ibat2l also called spr533 +reg: spr533 633 +#ibat3u also called spr534 +reg: spr534 634 +#ibat3l also called spr535 +reg: spr535 635 +#dbat0u also called spr536 +reg: spr536 636 +#dbat0l also called spr537 +reg: spr537 637 +#dbat1u also called spr538 +reg: spr538 638 +#dbat1l also called spr539 +reg: spr539 639 +#dbat2u also called spr540 +reg: spr540 640 +#dbat2l also called spr541 +reg: spr541 641 +#dbat3u also called spr542 +reg: spr542 642 +#dbat3l also called spr543 +reg: spr543 643 + +#hid0 also called spr1008 +reg: spr1008 1108 +#hid1 also called spr1009 +reg: spr1009 1109 +#hid2 also called iabr or spr1010 +reg: spr1010 1110 +#hid5 also called dabr or spr1013 +reg: spr1013 1113 +#hid15 also called pir or spr1023 +reg: spr1023 1123 + +# vector registers 0-31 +reg: vr0 1124 +reg: vr1 1125 +reg: vr2 1126 +reg: vr3 1127 +reg: vr4 1128 +reg: vr5 1129 +reg: vr6 1130 +reg: vr7 1131 +reg: vr8 1132 +reg: vr9 1133 +reg: vr10 1134 +reg: vr11 1135 +reg: vr12 1136 +reg: vr13 1137 +reg: vr14 1138 +reg: vr15 1130 +reg: vr16 1140 +reg: vr17 1141 +reg: vr18 1142 +reg: vr19 1143 +reg: vr20 1144 +reg: vr21 1145 +reg: vr22 1146 +reg: vr23 1147 +reg: vr24 1148 +reg: vr25 1149 +reg: vr26 1150 +reg: vr27 1151 +reg: vr28 1152 +reg: vr29 1153 +reg: vr30 1154 +reg: vr31 1155 +endabi: ppc + +# 'Generic 1000 register abi'. +# This is useful as a 'general' ABI settings for +# cpus using up to 1000 registers. The register names +# show as a number, like 'r991'. +beginabi: generic +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 1000 +same_val_reg: 1035 +undefined_val_reg: 1034 +reg: r0 0 +endabi: generic + +# 'Generic 500 register abi'. +# This is useful as a 'general' ABI settings for +# cpus using up to 500 registers. The register names +# show as a number, like 'r91'. +beginabi: generic500 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 500 +same_val_reg: 1035 +undefined_val_reg: 1034 +reg: r0 0 +endabi: generic500 + +# 'Generic 100 register abi'. +# This is useful as a 'general' ABI settings for +# cpus using up to 100 registers. The register names +# show as a number, like 'r91'. +beginabi: generic100 +frame_interface: 3 +initial_reg_value: 1035 # DW_FRAME_SAME_VAL +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +reg_table_size: 100 +same_val_reg: 1035 +undefined_val_reg: 1034 +reg: r0 0 +endabi: generic100 + + +beginabi: arm +frame_interface: 3 +# When using frame_interface: 3 the size of the register +# table is not fixed. It can be as large as needed. +reg_table_size: 288 +cfa_reg: 1436 # DW_FRAME_CFA_COL3 +initial_reg_value: 1034 +same_val_reg: 1035 +undefined_val_reg: 1034 +# If the vendor co-processor registers are allowed +# or other numbers above 287 used then +# the reg_table_size must be increased and (possibly) +# the cfa, same_value, undefined_value reg values changed +# here. +# r0-r15 are 0 through 15. +# Numbers 16 through 63 had meaning +# in some ARM DWARF register mappings. +reg: s0 64 +reg: s1 65 +reg: s2 66 +reg: s3 67 +reg: s4 68 +reg: s5 69 +reg: s6 70 +reg: s7 71 +reg: s8 72 +reg: s9 73 +reg: s10 74 +reg: s11 75 +reg: s12 76 +reg: s13 77 +reg: s14 78 +reg: s15 79 +reg: s16 80 +reg: s17 81 +reg: s18 82 +reg: s19 83 +reg: s20 84 +reg: s21 85 +reg: s22 86 +reg: s23 87 +reg: s24 88 +reg: s25 89 +reg: s26 90 +reg: s27 91 +reg: s28 92 +reg: s29 93 +reg: s30 94 +reg: s31 95 +reg: f0 96 +reg: f1 97 +reg: f2 98 +reg: f3 99 +reg: f4 100 +reg: f5 101 +reg: f6 102 +reg: f7 103 +reg: wcgr0 104 +reg: wcgr0 105 +reg: wcgr0 106 +reg: wcgr0 107 +reg: wcgr0 108 +reg: wcgr0 109 +reg: wcgr0 110 +reg: wcgr0 111 +reg: wr0 112 +reg: wr1 113 +reg: wr2 114 +reg: wr3 115 +reg: wr4 116 +reg: wr5 117 +reg: wr6 118 +reg: wr7 119 +reg: wr8 120 +reg: wr9 121 +reg: wr10 122 +reg: wr11 123 +reg: wr12 124 +reg: wr13 125 +reg: wr14 126 +reg: wr15 127 +reg: spsr 128 +reg: spsr_fiq 129 +reg: spsr_irq 130 +reg: spsr_abt 131 +reg: spsr_und 132 +reg: spsr_svc 133 +reg: r8_usr 144 +reg: r9_usr 145 +reg: r10_usr 146 +reg: r11_usr 147 +reg: r12_usr 148 +reg: r13_usr 149 +reg: r14_usr 150 +reg: r8_fiq 151 +reg: r9_fiq 152 +reg: r10_fiq 153 +reg: r11_fiq 154 +reg: r12_fiq 155 +reg: r13_fiq 156 +reg: r14_fiq 157 +reg: r13_riq 158 +reg: r14_riq 159 +reg: r14_abt 160 +reg: r13_abt 161 +reg: r14_und 162 +reg: r13_und 163 +reg: r14_svc 164 +reg: r13_svc 165 +reg: wc0 192 +reg: wc1 193 +reg: wc2 192 +reg: wc3 192 +reg: wc4 192 +reg: wc5 197 +reg: wc6 198 +reg: wc7 199 +reg: d0 256 +reg: d1 257 +reg: d2 258 +reg: d3 259 +reg: d4 260 +reg: d5 261 +reg: d6 262 +reg: d7 263 +reg: d8 264 +reg: d9 265 +reg: d10 266 +reg: d11 267 +reg: d12 268 +reg: d13 269 +reg: d14 270 +reg: d15 271 +reg: d16 272 +reg: d17 273 +reg: d18 274 +reg: d19 275 +reg: d20 266 +reg: d21 277 +reg: d22 278 +reg: d23 279 +reg: d24 280 +reg: d25 281 +reg: d26 282 +reg: d27 283 +reg: d28 284 +reg: d29 285 +reg: d30 286 +reg: d31 287 +# End of abi definition. +endabi: arm + diff --git a/dwarfdump2/dwconf.cc b/dwarfdump2/dwconf.cc new file mode 100644 index 0000000..b484a93 --- /dev/null +++ b/dwarfdump2/dwconf.cc @@ -0,0 +1,1291 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2009-2011 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/dwconf.c,v 1.4 2006/04/18 18:05:57 davea Exp $ */ + + +#include "globals.h" +#include <vector> +#include <ctype.h> +#include "dwconf.h" +using std::string; +using std::cerr; +using std::cout; +using std::endl; + +// The nesting level is arbitrary, 2 should suffice. +// But at least this prevents an infinite loop. +#define MAX_NEST_LEVEL 3 + + + +struct token_s { + token_s() {}; + ~token_s() {}; + const char *c_str() { return tk_data.c_str(); }; + string tk_data; +}; +enum linetype_e { + LT_ERROR, + LT_COMMENT, + LT_BLANK, + LT_BEGINABI, + LT_REG, + LT_FRAME_INTERFACE, + LT_CFA_REG, + LT_INITIAL_REG_VALUE, + LT_SAME_VAL_REG, + LT_UNDEFINED_VAL_REG, + LT_REG_TABLE_SIZE, + LT_ADDRESS_SIZE, + LT_INCLUDEABI, + LT_ENDABI +}; + +struct comtable_s { + enum linetype_e type; + string name; +}; + +/* Count errors found in this scan of the configuration file. */ +static int errcount = 0; + +static string name_begin_abi("beginabi:"); +static string name_reg("reg:"); +static string name_frame_interface("frame_interface:"); +static string name_cfa_reg("cfa_reg:"); +static string name_initial_reg_value("initial_reg_value:"); +static string name_same_val_reg("same_val_reg:"); +static string name_undefined_val_reg("undefined_val_reg:"); +static string name_reg_table_size("reg_table_size:"); +static string name_address_size("address_size:"); +static string name_includeabi("includeabi:"); +static string name_endabi("endabi:"); + +static struct comtable_s comtable[] = { + {LT_BEGINABI, name_begin_abi}, + {LT_REG, name_reg}, + {LT_FRAME_INTERFACE, name_frame_interface}, + {LT_CFA_REG, name_cfa_reg}, + {LT_INITIAL_REG_VALUE, name_initial_reg_value}, + {LT_SAME_VAL_REG,name_same_val_reg}, + {LT_UNDEFINED_VAL_REG,name_undefined_val_reg}, + {LT_REG_TABLE_SIZE, name_reg_table_size}, + {LT_ADDRESS_SIZE, name_address_size}, + {LT_INCLUDEABI, name_includeabi}, + {LT_ENDABI, name_endabi}, +}; +static unsigned size_of_comtable = sizeof(comtable) / sizeof(comtable[0]); + +struct conf_internal_s { + conf_internal_s(struct dwconf_s *out): beginabi_lineno(0), + frame_interface_lineno(0), initial_reg_value_lineno(0), + reg_table_size_lineno(0),address_size_lineno(0), + same_val_reg_lineno(0), + undefined_val_reg_lineno(0), cfa_reg_lineno(0), + regcount(0), + conf_out(out),conf_defaults(0) {}; + ~conf_internal_s() {}; + unsigned long beginabi_lineno; + unsigned long frame_interface_lineno; + unsigned long initial_reg_value_lineno; + unsigned long reg_table_size_lineno; + unsigned long address_size_lineno; + unsigned long same_val_reg_lineno; + unsigned long undefined_val_reg_lineno; + unsigned long cfa_reg_lineno; + unsigned long regcount; + std::string conf_name_used; + struct dwconf_s *conf_out; + std::string conf_named_used; + const char ** conf_defaults; +private: + // Do not use this, not implemented. + conf_internal_s(); +}; + + + +static FILE *find_a_file(const string &named_file, const char **defaults, + string & name_used); +static bool find_abi_start(FILE * stream, const string &abi_name, long *offset, + unsigned long *lineno_out); +static bool parse_abi(FILE * stream, const std::string &fname, + const std::string &abiname, + struct conf_internal_s *out, unsigned long lineno,unsigned nestlevel); +static char * get_token(char *cp, token_s *tok); + + + + + +/* This finds a dwarfdump.conf file and + then parses it. It updates + conf_out as appropriate. + + This finds the first file (looking in a set of places) + with that name. It then looks for the right ABI entry. + If the first file it finds does not have that ABI entry it + gives up. + + It would also be reasonable to search every 'dwarfdump.conf' + it finds for the abi. But we stop at the first dwarfdump.conf + we find. + + This is the internal call to read the configure file. + Implements a crude 'includeabi' feature. + + Returns the number of errors found. +*/ +int +find_conf_file_and_read_config_inner(const string &named_file, + const string &named_abi, + struct conf_internal_s *conf_internal, + unsigned nest_level) +{ + + errcount = 0; + + string name_used; + FILE *conf_stream = find_a_file(named_file, + conf_internal->conf_defaults, name_used); + if (!conf_stream) { + ++errcount; + cout << "dwarfdump found no file \"" << + named_file << "\"!"<< endl; + cout << "(add options -v -v to see what file names tried)"<< + endl; + return errcount; + } + if (verbose > 1) { + cout << "dwarfdump using configuration file " << + name_used << endl; + } + conf_internal->conf_name_used = name_used; + + long offset = 0; + unsigned long lineno = 0; + bool res = find_abi_start(conf_stream, named_abi, &offset, &lineno); + if (!res) { + ++errcount; + cout << "dwarfdump found no ABI " << + named_abi << " in file " << + name_used << "." <<endl; + return errcount; + } + int seekres = fseek(conf_stream, offset, SEEK_SET); + if (seekres != 0) { + ++errcount; + cout << "dwarfdump seek to " << + offset << " offset in " << + name_used << + " failed!" << endl; + return errcount; + } + parse_abi(conf_stream, name_used, named_abi, conf_internal, lineno, + nest_level); + fclose(conf_stream); + return errcount; +} + +// This is the exteral-facing call to read the configure file. +int +find_conf_file_and_read_config(const string &named_file, + const string &named_abi, + const char **defaults, + struct dwconf_s *conf_out) +{ + // The cf_regs are to be set below, not from + // the default set, so clear the exsting data out. + conf_out->cf_regs.clear(); + // Ensure a reasonable minimum vector size. + conf_out->cf_regs.resize(100); + conf_internal_s conf_internal(conf_out); + conf_internal.conf_defaults = defaults; + + int res = find_conf_file_and_read_config_inner(named_file, + named_abi, + &conf_internal,0); + return res; +} + +/* Given path strings, attempt to make a canonical file name: + that is, avoid superfluous '/' so that no + '//' (or worse) is created in the output. The path components + are to be separated so at least one '/' + is to appear between the two 'input strings' when + creating the output. */ +static bool +canonical_append(string &target, + const string &first_string, const string &second_string) +{ + // Do not take any ending / + size_t firstlen = first_string.size(); + for (; firstlen > 0 && first_string[firstlen - 1] == '/'; + --firstlen) { + } + + // Do not take any leading / + unsigned secondskipto = 0; + for (; second_string[secondskipto] == '/'; ++secondskipto) { + } + + target = first_string.substr(0,firstlen) + string("/") + + second_string.substr(secondskipto); + return true; +} + +#ifdef BUILD_FOR_TEST +struct canap_s { + const char *res_exp; + const char *first; + const char *second; +} canap[] = { + { + "ab/c", "ab", "c"}, { + "ab/c", "ab/", "c"}, { + "ab/c", "ab", "/c"}, { + "ab/c", "ab////", "/////c"}, { + "ab/", "ab", ""}, { + "ab/", "ab////", ""}, { + "ab/", "ab////", ""}, { + "/a", "", "a"}, { + 0, "/abcdefgbijkl", "pqrstuvwxyzabcd"}, { + 0, 0, 0} +}; +static void +test_canonical_append(void) +{ + unsigned failcount = 0; + + cout <<"Entry test_canonical_append" << endl; + for (unsigned i = 0;; ++i) { + + if (canap[i].first == 0 && canap[i].second == 0) + break; + + string targ; + bool ok = canonical_append(targ, canap[i].first, + canap[i].second); + if (ok) { + if (canap[i].res_exp == 0) { + /* GOOD */ + cout <<"PASS " << i <<endl; + } else { + ++failcount; + cout << "FAIL: entry " << i << + " wrong, expected " << canap[i].res_exp << + " got NULL " << endl; + } + } else { + // Impossible now. + ++failcount; + cout << "FAIL: entry " << i << + " wrong, expected an ok result " << endl; + } + } + cout << "FAIL count " << failcount << endl; + +} +#endif /* BUILD_FOR_TEST */ +/* Try to find a file as named and open for read. + We treat each name as a full name, we are not + combining separate name and path components. + This is an arbitrary choice... + + The defaults are listed in dwarfdump.c in the array + config_file_defaults[]. +*/ +static FILE * +find_a_file(const std::string &named_file, const char **defaults, + string & name_used_out) +{ + string lname = named_file; + const char *type = "rw"; + +#ifdef BUILD_FOR_TEST + test_canonical_append(); +#endif /* BUILD_FOR_TEST */ + + if (!lname.empty()) { + /* Name given, just assume it is fully correct, try no other. */ + if (verbose > 1) { + cout << "dwarfdump looking for configuration as " << + lname << endl; + } + FILE *fin = fopen(lname.c_str(), type); + if (fin) { + name_used_out = lname; + return fin; + } + return 0; + } + /* No name given, find a default, if we can. */ + for (unsigned i = 0; defaults[i]; ++i) { + string lname2 = defaults[i]; + if (strncmp(lname2.c_str(), "HOME/", 5) == 0) { + char *homedir = getenv("HOME"); + if (homedir) { + string tname; + canonical_append(tname,homedir, lname2.substr(5)); + lname2 = tname; + } + } + if (verbose > 1) { + cout << "dwarfdump looking for configuration as " << + lname2 << endl; + } + FILE *fin = fopen(lname2.c_str(), type); + if (fin) { + name_used_out = lname2; + return fin; + } + } + return 0; +} + +/* Start at a token begin, see how long it is, + return length. */ +unsigned +find_token_len(char *cp) +{ + unsigned len = 0; + for (; *cp; ++cp) { + if (isspace(*cp)) { + return len; + } + if (*cp == '#') { + return len; /* begins comment */ + } + ++len; + } + return len; +} + +/* + Skip past all whitespace: the only code that even knows + what whitespace is. +*/ +static char * +skipwhite(char *cp) +{ + for (; *cp; ++cp) { + if (!isspace(*cp)) { + return cp; + } + } + return cp; +} + +/* Return TRUE if ok. FALSE if find more tokens. + Emit error message if error. */ +static bool +ensure_has_no_more_tokens(char *cp, const string &fname, unsigned long lineno) +{ + token_s tok ; + get_token(cp, &tok); + if (!tok.tk_data.empty() ) { + cout << "dwarfdump.conf error: " << + "extra characters after command operands, found " << + "\"" << tok.tk_data << "\" in " << fname << + " line " << lineno << endl; + ++errcount; + return false; + } + return true; +} + + +/* There may be many beginabi: lines in a dwarfdump.conf file, + find the one we want and return its file offset. */ +static bool +find_abi_start(FILE * stream, const string &abi_name, + long *offset, unsigned long *lineno_out) +{ + char buf[100]; + unsigned long lineno = 0; + + for (; !feof(stream);) { + + long loffset = ftell(stream); + + char *line = fgets(buf, sizeof(buf), stream); + ++lineno; + if (!line) { + ++errcount; + return false; + } + + token_s tok; + line = get_token(buf, &tok); + + if (tok.tk_data != name_begin_abi ) { + continue; + } + token_s tok2; + get_token(line,&tok2); + if (tok2.tk_data != abi_name) { + continue; + } + + *offset = loffset; + *lineno_out = lineno; + return true; + } + + ++errcount; + return false; +} + +/* The tokenizer for our simple parser. */ +static char * +get_token(char *cp, token_s *outtok) +{ + char *lcp = skipwhite(cp); + unsigned tlen = find_token_len(lcp); + + if (tlen > 0) { + string s(lcp); + outtok->tk_data = s.substr(0,tlen); + } else { + outtok->tk_data = ""; + } + return lcp + tlen; + +} + +/* Given a line of the table, determine if it is a command + or not, and if a command, which one is it. + Return LT_ERROR if it's not recognized. */ +static enum linetype_e +which_command(char *cp, struct comtable_s **tableentry) +{ + + if (*cp == '#') { + return LT_COMMENT; + } + if (!*cp) { + return LT_BLANK; + } + token_s tok; + get_token(cp, &tok); + for (unsigned i = 0; i < size_of_comtable; ++i) { + if (tok.tk_data == comtable[i].name) { + *tableentry = &comtable[i]; + return comtable[i].type; + } + } + return LT_ERROR; +} + +/* We are promised it's an abiname: command + find the name on the line. */ +static bool +parsebeginabi(char *cp, const string &fname, const string &abiname, + unsigned long lineno, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + size_t abinamelen = abiname.size(); + + cp = cp + clen + 1; + cp = skipwhite(cp); + token_s tok; + get_token(cp, &tok); + if (tok.tk_data.size() != abinamelen || + strncmp(cp, abiname.c_str(), abinamelen) != 0) { + ++errcount; + cout << "dwarfdump internal error: mismatch " << + cp << " with " << tok.tk_data << " " << + fname << " line " << lineno <<endl; + return false; + } + bool res = ensure_has_no_more_tokens(cp + tok.tk_data.size(), + fname, lineno); + return res; +} + +/* This expands register names as required, but does not + ensure no names duplicated. */ +static void +add_to_reg_table(struct dwconf_s *conf, + const string &rname, unsigned long rval, + const string &fname, + unsigned long lineno) +{ + if( rval >= conf->cf_regs.size()) { + conf->cf_regs.resize(rval+1); + } + conf->cf_regs[rval] = rname; + return; +} + +/* Our input is supposed to be a number. + Determine the value (and return it) or generate an error message. */ +static int +make_a_number(const string &cmd, const string &filename, + unsigned long lineno, struct token_s *tok, unsigned long *val_out) +{ + char *endnum = 0; + unsigned long val = 0; + const char *begin = tok->tk_data.c_str(); + val = strtoul(begin, &endnum, 0); + if (val == 0 && endnum == begin) { + ++errcount; + cout << "dwarfdump.conf error: " << + cmd << " missing register number (\"" << + tok->tk_data << "\" not valid) " << + filename << " line " << lineno <<endl; + return false; + } + if (endnum != (begin + tok->tk_data.size())) { + ++errcount; + cout << "dwarfdump.conf error: " << + cmd << " Missing register number (\"" << + tok->tk_data << "\" not valid) " << + filename << " line " << lineno <<endl; + return false; + } + *val_out = val; + return true; + + + +} + +/* We are guaranteed it's a reg: command, so parse that command + and record the interesting data. */ +static bool +parsereg(char *cp, const string &fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + token_s regnum; + token_s tokreg; + + cp = cp + clen + 1; + cp = get_token(cp, &tokreg); + cp = get_token(cp, ®num); + if (tokreg.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: reg: missing register name " << + fname << " line " << lineno <<endl; + return false; + + } + if (regnum.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: reg: Missing register name " << + fname << " line " << lineno <<endl; + return false; + } + + unsigned long val = 0; + bool ok = make_a_number(comtab->name, fname, lineno, ®num, &val); + + if (!ok) { + ++errcount; + return false; + } + + add_to_reg_table(conf->conf_out, tokreg.tk_data, val, fname, lineno); + + { + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + + return res; + } +} + +/* We are guaranteed it's an frame_interface: command. + Parse it and record the value data. */ +static bool +parseframe_interface(char *cp, const string &fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + cp = cp + clen + 1; + token_s tok; + cp = get_token(cp, &tok); + if (tok.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " missing interface number " << + fname << " line " << lineno << endl; + return false; + } + + unsigned long val = 0; + bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return false; + } + if (val != 2 && val != 3) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " only interface numbers 2 or 3 are allowed, not " << + val << + ". " << + fname << " line " << lineno << endl; + return false; + } + + conf->conf_out->cf_interface_number = (int) val; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +/* We are guaranteed it's a cfa_reg: command. Parse it + and record the important data. */ +static bool +parsecfa_reg(char *cp, const string &fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + token_s tok; + unsigned long val = 0; + bool ok = false; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " missing cfa_reg number " << + fname << " line " << lineno << endl; + return false; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return false; + } + conf->conf_out->cf_cfa_reg = (int) val; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + +/* We are guaranteed it's an initial_reg_value: command, + parse it and put the reg value where it will be remembered. +*/ +static bool +parseinitial_reg_value(char *cp, const string &fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + cp = cp + clen + 1; + struct token_s tok; + cp = get_token(cp, &tok); + if (tok.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " missing initial reg value " << + fname << " line " << lineno << endl; + return false; + } + + unsigned long val = 0; + bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return false; + } + conf->conf_out->cf_initial_rule_value = (int) val; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} +/* We are guaranteed it's an initial_reg_value: command, + parse it and put the reg value where it will be remembered. */ +static bool +parsesame_val_reg(char *cp, const string &fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + cp = cp + clen + 1; + struct token_s tok; + cp = get_token(cp, &tok); + if (tok.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " missing same_val_reg value " << + fname << " line " << lineno << endl; + return false; + } + + unsigned long val = 0; + bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return false; + } + conf->conf_out->cf_same_val = (int) val; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} +/* We are guaranteed it's an initial_reg_value: command, + parse it and put the reg value where it will be remembered. */ +static bool +parseundefined_val_reg(char *cp, const string &fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + cp = cp + clen + 1; + struct token_s tok; + cp = get_token(cp, &tok); + if (tok.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " missing undefined_val_reg value " << + fname << " line " << lineno << endl; + return false; + } + + unsigned long val = 0; + bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return false; + } + conf->conf_out->cf_undefined_val = (int) val; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + + + +/* We are guaranteed it's a table size command, parse it + and record the table size. +*/ +static bool +parsereg_table_size(char *cp, const string &fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + token_s tok; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " missing reg table size value " << + fname << " line " << lineno << endl; + return false; + } + + unsigned long val = 0; + bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return false; + } + conf->conf_out->cf_table_entry_count = (unsigned long) val; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} +/* We are guaranteed it's an address size command, parse it + and record the address size. +*/ +static bool +parseaddress_size(char *cp, const string &fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + token_s tok; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_data.empty()) { + ++errcount; + cout << "dwarfdump.conf error: " << + comtab->name << + " missing address size value " << + fname << " line " << lineno << endl; + return false; + } + + unsigned long val = 0; + bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return false; + } + conf->conf_out->cf_address_size = (unsigned long) val; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + + +/* We are guaranteed it's an endabi: command, parse it and + check we have the right abi. +*/ +static bool +parseendabi(char *cp, const string &fname, + const string &abiname, unsigned long lineno, + struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + + + cp = cp + clen + 1; + struct token_s tok; + cp = get_token(cp, &tok); + if (abiname != tok.tk_data) { + ++errcount; + cout << comtab->name << + " error: mismatch abi name " << + tok.tk_data << " (here) vs. " << + abiname << + " (beginabi:) " << + fname << " line " << lineno << endl; + return false; + } + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +static int +parseincludeabi(char *cp,const string &fname,unsigned long lineno, + std::string &abiname_out,struct comtable_s *comtab) +{ + size_t clen = comtab->name.size(); + struct token_s tok; + cp = cp + clen + 1; + cp = get_token(cp,&tok); + abiname_out = tok.tk_data; + bool res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + + + + +/* Return TRUE if we succeeded and filed in *out. + Return FALSE if we failed (and fill in nothing). + beginabi: <abiname> + reg: <regname> <dwarf regnumber> + frame_interface: <integer value 2 or 3> + cfa_reg: <number> + initial_reg_value: <number: normally 1034 or 1035 > + same_value 'reg number' : <number: normally 1034 > + undefined_value 'reg number' : <number: normally 1035 > + reg_table_size: <size of table> + endabi: <abiname> + + We are positioned at the start of a beginabi: line when + called. + +*/ +static bool +parse_abi(FILE * stream, const string &fname, const string &abiname, + struct conf_internal_s *conf_internal, unsigned long lineno, + unsigned int nest_level) +{ + struct dwconf_s *localconf = conf_internal->conf_out; + + if( nest_level > MAX_NEST_LEVEL) { + ++errcount; + cout <<"dwarfdump.conf: includeabi nest too deep in " << + fname << " at line " << lineno<<endl; + return false; + } + + for (; !feof(stream);) { + + char *line = 0; + char buf[1000]; + /* long loffset = ftell(stream); */ + line = fgets(buf, sizeof(buf), stream); + if (!line) { + ++errcount; + cout << "dwarfdump: end of file or error before endabi: in "<< + fname << ", line " << lineno << endl; + return false; + } + ++lineno; + line = skipwhite(line); + // comtabp points to the table entry + // of interest (identified by which_command()). + struct comtable_s *comtabp = 0; + int comtype = which_command(line, &comtabp); + switch (comtype) { + case LT_ERROR: + ++errcount; + cout << "dwarfdump: Unknown text in "<< + fname << " is \"" << + line << "\" at line " << lineno << endl; + break; + case LT_COMMENT: + break; + case LT_BLANK: + break; + case LT_BEGINABI: + if (conf_internal->beginabi_lineno > 0 && + nest_level == 0) { + ++errcount; + cout << "dwarfdump: Encountered beginabi: when not expected. " + << fname << + " line " << lineno << + " previous beginabi line " << + conf_internal->beginabi_lineno << endl; + } + conf_internal->beginabi_lineno = lineno; + parsebeginabi(line, fname, abiname, lineno, comtabp); + break; + + case LT_REG: + parsereg(line, fname, lineno, conf_internal, comtabp); + conf_internal->regcount++; + break; + case LT_FRAME_INTERFACE: + if (conf_internal->frame_interface_lineno > 0) { + ++errcount; + cout << "dwarfdump: Encountered duplicate frame_interface: " + << fname << + " line " << lineno << + " previous frame_interface: line " << + conf_internal->frame_interface_lineno << endl; + } + conf_internal->frame_interface_lineno = lineno; + parseframe_interface(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_CFA_REG: + if (conf_internal->cfa_reg_lineno > 0) { + ++errcount; + cout << "dwarfdump: Encountered duplicate cfa_reg: " + << fname << + " line " << lineno << + " previous cfa_reg line " << + conf_internal->cfa_reg_lineno << endl; + } + conf_internal->cfa_reg_lineno = lineno; + parsecfa_reg(line, fname, lineno, conf_internal, comtabp); + break; + case LT_INITIAL_REG_VALUE: + if (conf_internal->initial_reg_value_lineno > 0) { + ++errcount; + cout << + "dwarfdump: Encountered duplicate " << + "initial_reg_value: " << + fname << + " line " << lineno << + " previous initial_reg_value: line " << + conf_internal->initial_reg_value_lineno<< endl; + } + conf_internal->initial_reg_value_lineno = lineno; + parseinitial_reg_value(line, fname, + lineno,conf_internal, comtabp); + break; + case LT_SAME_VAL_REG: + if (conf_internal->same_val_reg_lineno > 0) { + ++errcount; + cout << + "dwarfdump: Encountered duplicate " << + "same_val_reg: " << + fname << + " line " << lineno << + " previous same_reg_value: line " << + conf_internal->same_val_reg_lineno << endl; + } + conf_internal->same_val_reg_lineno = lineno; + parsesame_val_reg(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_UNDEFINED_VAL_REG: + if (conf_internal->undefined_val_reg_lineno > 0) { + ++errcount; + cout << + "dwarfdump: Encountered duplicate " << + "undefined_val_reg: " << + fname << + " line " << lineno << + " previous same_val_reg: line " << + conf_internal->same_val_reg_lineno << endl; + } + conf_internal->undefined_val_reg_lineno = lineno; + parseundefined_val_reg(line, fname, + lineno, conf_internal, comtabp); + break; + + case LT_REG_TABLE_SIZE: + if (conf_internal->reg_table_size_lineno > 0) { + ++errcount; + cout << "dwarfdump: duplicate reg_table_size: " + << fname << + " line " << lineno << + " previous reg_table_size: line " << + conf_internal->reg_table_size_lineno << endl; + } + conf_internal->reg_table_size_lineno = lineno; + parsereg_table_size(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_ENDABI: + parseendabi(line, fname, abiname, lineno, comtabp); + + if (conf_internal->regcount > localconf->cf_table_entry_count) { + ++errcount; + cout << "dwarfdump: more registers named than in " + << abiname << + " ( " << conf_internal->regcount << + " named vs " << name_reg_table_size << + " " << localconf->cf_table_entry_count << + ") " << + fname << " line " << lineno << endl; + } + + return true; + case LT_ADDRESS_SIZE: + if (conf_internal->address_size_lineno > 0) { + ++errcount; + cout << "dwarfdump: duplicate address_size:: " + << fname << + " line " << lineno << + " previous address_size: line " << + conf_internal->address_size_lineno << endl; + } + conf_internal->address_size_lineno = lineno; + parseaddress_size(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_INCLUDEABI: { + std::string abiname_inner; + unsigned long abilno = conf_internal->beginabi_lineno; + bool ires = parseincludeabi(line,fname,lineno,abiname_inner, + comtabp); + if (ires == false) { + return ires; + } + // For the nested abi read, the abi line number must be + // set as if not-yet-read, and then restored. + conf_internal->beginabi_lineno = 0; + find_conf_file_and_read_config_inner(conf_internal->conf_name_used, + abiname_inner,conf_internal,nest_level+1); + conf_internal->beginabi_lineno = abilno; + } + break; + default: + cout << "dwarfdump internal error, impossible line type " << + comtype << " " << fname << " " << lineno <<endl; + exit(1); + + } + } + ++errcount; + cout << "End of file, no endabi: found. " << + fname << ", line " << lineno << endl; + return false; +} + +/* MIPS/IRIX frame register names. + For alternate name sets, use dwarfdump.conf or + revise dwarf.h and libdwarf.h and this table. +*/ +static const char *mipsregnames[] = { + "cfa", + "r1/at", "r2/v0", "r3/v1", + "r4/a0", "r5/a1", "r6/a2", "r7/a3", + "r8/t0", "r9/t1", "r10/t2", "r11/t3", + "r12/t4", "r13/t5", "r14/t6", "r15/t7", + "r16/s0", "r17/s1", "r18/s2", "r19/s3", + "r20/s4", "r21/s5", "r22/s6", "r23/s7", + "r24/t8", "r25/t9", "r26/k0", "r27/k1", + "r28/gp", "r29/sp", "r30/s8", "r31", + + "$f0", "$f1", + "$f2", "$f3", + "$f4", "$f5", + "$f6", "$f7", + "$f8", "$f9", + "$f10", "$f11", + "$f12", "$f13", + "$f14", "$f15", + "$f16", "$f17", + "$f18", "$f19", + "$f20", "$f21", + "$f22", "$f23", + "$f24", "$f25", + "$f26", "$f27", + "$f28", "$f29", + "$f30", "$f31", + "ra", "slk", +}; + +/* Naming a few registers makes printing these just + a little bit faster. +*/ +static const char *genericregnames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20" +}; + +/* This is a simple generic set of registers. The + table entry count is pretty arbitrary. +*/ +void +init_conf_file_data(struct dwconf_s *config_file_data) +{ + config_file_data->cf_interface_number = 3; + config_file_data->cf_table_entry_count = 100; + config_file_data->cf_initial_rule_value = DW_FRAME_UNDEFINED_VAL; + config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL3; + config_file_data->cf_address_size = 0; + config_file_data->cf_same_val = DW_FRAME_SAME_VAL; + config_file_data->cf_undefined_val = DW_FRAME_UNDEFINED_VAL; + unsigned generic_table_count = + sizeof(genericregnames) / sizeof(genericregnames[0]); + config_file_data->cf_regs.clear(); + config_file_data->cf_regs.reserve(generic_table_count); + for(unsigned i = 0; i < generic_table_count; ++i) { + config_file_data->cf_regs.push_back(genericregnames[i]); + } +} + +/* These defaults match MIPS/IRIX ABI defaults, but this + function is not actually used. + For a 'generic' ABI, see -R or init_conf_file_data(). + To really get the old MIPS, use '-x abi=mips'. + For other ABIs, see -x abi=<whatever> + to configure dwarfdump (and libdwarf) frame + data reporting at runtime. +*/ +void +init_mips_conf_file_data(struct dwconf_s *config_file_data) +{ + /* Interface 2 is deprecated, but for testing purposes + is acceptable. */ + config_file_data->cf_interface_number = 2; + config_file_data->cf_table_entry_count = DW_REG_TABLE_SIZE; + config_file_data->cf_initial_rule_value = + DW_FRAME_REG_INITIAL_VALUE; + config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL; + config_file_data->cf_address_size = 0; + config_file_data->cf_same_val = DW_FRAME_SAME_VAL; + config_file_data->cf_undefined_val = DW_FRAME_UNDEFINED_VAL; + unsigned mips_table_count = + sizeof(mipsregnames) / sizeof(mipsregnames[0]); + config_file_data->cf_regs.clear(); + config_file_data->cf_regs.reserve(mips_table_count); + for(unsigned i = 0; i < mips_table_count; ++i) { + config_file_data->cf_regs.push_back(mipsregnames[i]); + } + return; +} + + +/* A 'generic' ABI. For up to 1200 registers. +*/ +void +init_generic_config_1200_regs(struct dwconf_s *config_file_data) +{ + config_file_data->cf_interface_number = 3; + config_file_data->cf_table_entry_count = 1200; + /* There is no defined name for cf_initial_rule_value, + cf_same_val, or cf_undefined_val in libdwarf.h, + these must just be high enough to be higher than + any real register number. + DW_FRAME_CFA_COL3 must also be higher than any + real register number. */ + config_file_data->cf_initial_rule_value = 1235; /* SAME VALUE */ + config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL3; + config_file_data->cf_address_size = 0; + config_file_data->cf_same_val = 1235; + config_file_data->cf_undefined_val = 1234; + unsigned generic_table_count = + sizeof(genericregnames) / sizeof(genericregnames[0]); + config_file_data->cf_regs.clear(); + config_file_data->cf_regs.reserve(generic_table_count); + for(unsigned i = 0; i < generic_table_count; ++i) { + config_file_data->cf_regs.push_back(genericregnames[i]); + } +} + +/* Print the 'right' string for the register we are given. + Deal sensibly with the special regs as well as numbers + we know and those we have not been told about. +*/ +void +print_reg_from_config_data(Dwarf_Signed reg, + struct dwconf_s *config_data) +{ + + if (reg == config_data->cf_cfa_reg) { + cout << "cfa"; + return; + } + if (reg == config_data->cf_undefined_val) { + cout << "u"; + return; + } + if (reg == config_data->cf_same_val) { + cout << "s"; + return; + } + if ( reg < 0 || + reg >= config_data->cf_regs.size()) { + cout << "r" << reg; + return; + } + const string &name = config_data->cf_regs[reg]; + if (name.empty()) { + /* Can happen, the reg names table can be sparse. */ + cout << "r" << reg; + return; + } + cout << name; + return; +} diff --git a/dwarfdump2/dwconf.h b/dwarfdump2/dwconf.h new file mode 100644 index 0000000..e4f567d --- /dev/null +++ b/dwarfdump2/dwconf.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 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/dwconf.h,v 1.2 2006/04/18 04:29:39 davea Exp $ */ + + +/* Declarations helping configure the frame reader. +*/ +struct dwconf_s { + dwconf_s():cf_interface_number(0), + cf_table_entry_count(0),cf_initial_rule_value(0), + cf_same_val(0),cf_undefined_val(0), cf_cfa_reg(0), + cf_address_size(0) {}; + ~dwconf_s() {}; + + std::string cf_config_file_path; + std::string cf_abi_name; + + // 2 for old, 3 for frame interface 3. 2 means use the old + // mips-abi-oriented frame interface. 3 means use the new + // DWARF3-capable and configureable-abi interface. + + // Now, anyone who revises dwarf.h and libdwarf.h to match their + // abi-of-interest will still be able to use cf_interface_number 2 + // as before. But most folks don't update those header files and + // instead of making *them* configurable we make dwarfdump (and + // libdwarf) configurable sufficiently to print frame information + // sensibly. + unsigned cf_interface_number; + + // The number of table rules , aka columns. For MIPS/IRIX is 66. + unsigned long cf_table_entry_count; + + // Array of cf_table_entry_count reg names. Names not filled in + // from dwarfdump.conf have empty value. + + std::vector<std::string> cf_regs; + + // The 'default initial value' when intializing a table. for MIPS + // is DW_FRAME_SAME_VAL(1035). For other ISA/ABIs may be + // DW_FRAME_UNDEFINED_VAL(1034). + unsigned cf_initial_rule_value; + unsigned cf_same_val; + unsigned cf_undefined_val; + + // The number of the cfa 'register'. For cf_interface_number 2 of + // MIPS this is 0. For other architectures (and anytime using + // cf_interface_number 3) this should be outside the table, a + // special value such as 1036, not a table column at all). + unsigned cf_cfa_reg; + + /* If non-zero it is the number of bytes in an address + for the frame data. Normally it will be zero because + there are usually other sources for the correct address size. + However, with DWARF2 frame data there is no explicit address + size in the frame data and the object file might not have + other .debug_ sections to work with. + If zero, no address size was supplied, and that is normal and + the already-set (or defaulted) address size is to be used. + Only an exceptional frame configure will specify address + size here. This won't work at all if the object needing + this setting has different address size in different CUs. */ + unsigned cf_address_size; + +}; + + +// Returns DW_DLV_OK if works. DW_DLV_ERROR if cannot do what is asked. +int find_conf_file_and_read_config(const std::string & named_file, + const std::string &named_abi, + const char **defaults, + struct dwconf_s *conf_out); +void init_conf_file_data(struct dwconf_s *config_file_data); +void init_mips_conf_file_data(struct dwconf_s *config_file_data); + +void print_reg_from_config_data(Dwarf_Signed reg, + struct dwconf_s *config_data); + +void init_generic_config_1200_regs(struct dwconf_s *conf); diff --git a/dwarfdump2/fderegs.h b/dwarfdump2/fderegs.h new file mode 100644 index 0000000..fcfc77b --- /dev/null +++ b/dwarfdump2/fderegs.h @@ -0,0 +1,136 @@ +/* + Copyright (C) 2009-2011 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 + +*/ + + +// Abstracts out calling dwarf to get fde register values +// at a pc value. + +// Assumes libdwarf.h etc already included. +// +// Should speed up printing a frame by nearly N times +// where N is the number of register rules (columns). + +class FdeRegs { +public: + FdeRegs(Dwarf_Fde fde,struct dwconf_s *config_data): + fde_(fde),interfaceNumber_(config_data->cf_interface_number), + confData_(*config_data),pcAddr_(0),rowPc_(0) { + // regTable_ is a C struct from libdwarf.h + memset(®Table_,0,sizeof(regTable_)); + unsigned count = confData_.cf_table_entry_count; + regTable_.rt3_reg_table_size = count; + regTable_.rt3_rules = new Dwarf_Regtable_Entry3_s[count]; + tableByteCount_ = sizeof(Dwarf_Regtable_Entry3_s) *count; + zeroRegTab(); + }; + ~FdeRegs() { delete [] regTable_.rt3_rules;}; + + int getInterfaceNumber() { return interfaceNumber_; }; + + void setPc(Dwarf_Addr pcval) { pcAddr_ = pcval;}; + int preliminaryRead(Dwarf_Error *err) { + zeroRegTab(); + if(interfaceNumber_ == 2) { + // Interface 2 is deprecated. Ok to use for testing. + static Dwarf_Regtable t; + Dwarf_Regtable regtab2; + regtab2 = t; + int res = dwarf_get_fde_info_for_all_regs(fde_, + pcAddr_, ®tab2 ,&rowPc_,err); + if(res == DW_DLV_OK) { + // Transform to form 3. + for(unsigned i = 0; i < confData_.cf_table_entry_count; ++i) { + Dwarf_Regtable_Entry3 *out = + regTable_.rt3_rules+i; + Dwarf_Regtable_Entry *in = + ®tab2.rules[i]; + out->dw_offset_relevant = in->dw_offset_relevant; + out->dw_value_type = in->dw_value_type; + out->dw_regnum = in->dw_regnum; + out->dw_offset_or_block_len = in->dw_offset; + out->dw_block_ptr = 0; + } + } + return res; + } else if(interfaceNumber_ == 3) { + //int rulecount = confData_.cf_table_entry_count; + int res = dwarf_get_fde_info_for_all_regs3(fde_, + pcAddr_, ®Table_,&rowPc_,err); + return res; + } else { + return DW_DLV_ERROR; + } + }; + + // Interface number 3 only. + int getCfaRegdata( Dwarf_Regtable_Entry3 * entry_out, + Dwarf_Addr * rowpc_out, + Dwarf_Error *err) { + if (interfaceNumber_ != 3) { + // Really a programmer botch here. + return DW_DLV_NO_ENTRY; + }; + *rowpc_out = rowPc_; + *entry_out = regTable_.rt3_cfa_rule; + return DW_DLV_OK; + }; + // Interfaces 2 and 3. + int getRegdata(unsigned table_col, + Dwarf_Regtable_Entry3 * entry_out, Dwarf_Addr * rowpc_out, + Dwarf_Error *err) { + if ( table_col >= confData_.cf_table_entry_count) { + return DW_DLV_ERROR; + } + *rowpc_out = rowPc_; + *entry_out = regTable_.rt3_rules[table_col]; + return DW_DLV_OK; + }; + +private: + Dwarf_Fde fde_; + int interfaceNumber_; + struct dwconf_s confData_; + Dwarf_Addr pcAddr_; + Dwarf_Addr rowPc_; + Dwarf_Regtable3_s regTable_; + unsigned tableByteCount_; + + void zeroRegTab() { + memset( regTable_.rt3_rules,0, tableByteCount_); + memset( ®Table_.rt3_cfa_rule,0, sizeof(Dwarf_Regtable_Entry3_s)); + // Do not set rt3_reg_table_size here. Set already. + } + + // Unimplemented. + FdeRegs(); +}; diff --git a/dwarfdump2/globals.h b/dwarfdump2/globals.h new file mode 100644 index 0000000..11aa961 --- /dev/null +++ b/dwarfdump2/globals.h @@ -0,0 +1,587 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2011 SN Systems Ltd. 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/globals.h,v 1.25 2006/04/17 00:09:56 davea Exp $ */ + +#ifndef globals_INCLUDED +#define globals_INCLUDED + +#include "config.h" +#if (!defined(HAVE_RAW_LIBELF_OK) && defined(HAVE_LIBELF_OFF64_OK) ) +/* At a certain point libelf.h requires _GNU_SOURCE. + here we assume the criteria in configure determine that + usefully. +*/ +#define _GNU_SOURCE 1 +#endif + + +/* We want __uint32_t and __uint64_t and __int32_t __int64_t + properly defined but not duplicated, since duplicate typedefs + are not legal C. +*/ +/* + HAVE___UINT32_T + HAVE___UINT64_T will be set by configure if + our 4 types are predefined in compiler +*/ + + +#if (!defined(HAVE___UINT32_T)) && defined(HAVE_SGIDEFS_H) +#include <sgidefs.h> /* sgidefs.h defines them */ +#define HAVE___UINT32_T 1 +#define HAVE___UINT64_T 1 +#endif + + + +#if (!defined(HAVE___UINT32_T)) && defined(HAVE_SYS_TYPES_H) && defined(HAVE___UINT32_T_IN_SYS_TYPES_H) +# include <sys/types.h> +/* We assume __[u]int32_t and __[u]int64_t defined + since __uint32_t defined in the sys/types.h in use */ +#define HAVE___UINT32_T 1 +#define HAVE___UINT64_T 1 +#endif + +#ifndef HAVE___UINT32_T +typedef int __int32_t; +typedef unsigned __uint32_t; +#define HAVE___UINT32_T 1 +#endif +#ifndef HAVE___UINT64_T +typedef long long __int64_t; +typedef unsigned long long __uint64_t; +#define HAVE___UINT64_T 1 +#endif + + +#include <stdio.h> +#include <stdlib.h> +#include <string> +#include <iostream> +#include <sstream> // For IToDec +#include <iomanip> // For setw +#include <list> +#include <map> +#include <set> +#include <string.h> +#ifdef HAVE_ELF_H +#include <elf.h> +#endif +#ifdef HAVE_LIBELF_H +#include <libelf.h> +#else +#ifdef HAVE_LIBELF_LIBELF_H +#include <libelf/libelf.h> +#endif +#endif +#include <dwarf.h> +#include <libdwarf.h> +#ifdef HAVE_REGEX +#include <regex.h> +#endif + +#ifndef FAILED +#define FAILED 1 +#endif + +#include "dieholder.h" +#include "srcfilesholder.h" +#include "checkutil.h" + +struct Dwarf_Check_Result { + Dwarf_Check_Result ():checks_(0),errors_(0) {}; + ~Dwarf_Check_Result() {}; + int checks_; + int errors_; +}; + +extern bool search_is_on; +extern std::string search_any_text; +extern std::string search_match_text; +extern std::string search_regex_text; +#ifdef HAVE_REGEX +extern regex_t search_re; +#endif +extern bool is_strstrnocase(const char * container, const char * contained); + + +extern bool do_check_dwarf; +extern bool do_print_dwarf; +extern bool record_dwarf_error; /* 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). */ + +// Compilation Unit information for improved error messages. +struct Error_Message_Data { + Error_Message_Data(): + seen_PU(false), + seen_CU(false), + need_CU_name(false), + need_CU_base_address(false), + need_CU_high_address(false), + need_PU_valid_code(false), + seen_PU_base_address(false), + seen_PU_high_address(false), + PU_base_address(0), + PU_high_address(0), + DIE_offset(0), + DIE_overall_offset(0), + DIE_CU_offset(0), + DIE_CU_overall_offset(0), + current_section_id(0), + CU_base_address(0), + CU_high_address(0), + elf_max_address(0), + elf_address_size(0) + {}; + ~Error_Message_Data() {}; + std::string PU_name; + std::string CU_name; + std::string CU_producer; + bool seen_PU; // Detected a PU. + bool seen_CU; // Detected a CU. + bool need_CU_name; + bool need_CU_base_address; // Need CU Base address. + bool need_CU_high_address; // Need CU High address. + bool need_PU_valid_code; // Need PU valid code. + + bool seen_PU_base_address; // Detected a Base address for PU + bool seen_PU_high_address; // Detected a High address for PU + Dwarf_Addr PU_base_address;// PU Base address + Dwarf_Addr PU_high_address;// PU High address + + Dwarf_Off DIE_offset; // DIE offset in compile unit. + Dwarf_Off DIE_overall_offset; // DIE offset in .debug_info. + + Dwarf_Off DIE_CU_offset; // CU DIE offset in compile unit + Dwarf_Off DIE_CU_overall_offset; // CU DIE offset in .debug_info + int current_section_id; // Section being process. + + Dwarf_Addr CU_base_address;// CU Base address. + Dwarf_Addr CU_high_address;// CU High address. + + Dwarf_Addr elf_max_address;// Largest representable address offset. + Dwarf_Half elf_address_size;// Target pointer size. +}; +extern struct Error_Message_Data error_message_data; + +// Display parent/children when in wide format. +extern bool display_parent_tree; +extern bool display_children_tree; +extern int stop_indent_level; + +// Print search results when in wide format. +extern bool search_wide_format; +extern bool search_is_on; + +extern std::string search_any_text; +extern std::string search_match_text; +extern std::string search_regex_text; +#ifdef HAVE_REGEX +extern regex_t search_re; +#endif +extern bool is_strstrnocase(const char *data, const char *pattern); + +// Options to enable debug tracing. +#define MAX_TRACE_LEVEL 10 +extern int nTrace[MAX_TRACE_LEVEL + 1]; +#define DUMP_RANGES_INFO 1 // Dump RangesInfo Table. +#define DUMP_LOCATION_SECTION_INFO 2 // Dump Location (.debug_loc) Info. +#define DUMP_RANGES_SECTION_INFO 3 // Dump Ranges (.debug_ranges) Info. +#define DUMP_LINKONCE_INFO 4 // Dump Linkonce Table. +#define DUMP_VISITED_INFO 5 // Dump Visited Info. + +#define dump_ranges_info nTrace[DUMP_RANGES_INFO] +#define dump_location_section_info nTrace[DUMP_LOCATION_SECTION_INFO] +#define dump_ranges_section_info nTrace[DUMP_RANGES_SECTION_INFO] +#define dump_linkonce_info nTrace[DUMP_LINKONCE_INFO] +#define dump_visited_info nTrace[DUMP_VISITED_INFO] + +/* Section IDs */ +#define DEBUG_ABBREV 1 +#define DEBUG_ARANGES 2 +#define DEBUG_FRAME 3 +#define DEBUG_INFO 4 +#define DEBUG_LINE 5 +#define DEBUG_LOC 6 +#define DEBUG_MACINFO 7 +#define DEBUG_PUBNAMES 8 +#define DEBUG_RANGES 9 +#define DEBUG_STATIC_VARS 10 +#define DEBUG_STATIC_FUNC 11 +#define DEBUG_STR 12 +#define DEBUG_WEAKNAMES 13 +#define DEBUG_TYPES 14 + +extern int verbose; +extern bool dense; +extern bool ellipsis; +extern bool use_mips_regnames; +extern bool show_global_offsets; +extern bool show_form_used; +extern bool display_offsets; + +extern bool check_pubname_attr; +extern bool check_attr_tag; +extern bool check_tag_tree; +extern bool check_type_offset; +extern bool check_decl_file; +extern bool check_lines; +extern bool check_ranges; +extern bool check_fdes; +extern bool check_aranges; +extern bool check_harmless; +extern bool check_abbreviations; +extern bool check_dwarf_constants; +extern bool check_di_gaps; +extern bool check_forward_decl; +extern bool check_self_references; +extern bool suppress_nested_name_search; +extern bool suppress_check_extensions_tables; + +extern int break_after_n_units; + +extern bool check_names; // Check for invalid names. +extern bool check_verbose_mode; // During '-k' mode, display errors. +extern bool check_frames; // Frames check. +extern bool check_frames_extended;// Extensive frames check. +extern bool check_locations; // Location list check. + + +// Check categories corresponding to the -k option +enum Dwarf_Check_Categories{ // Dwarf_Check_Categories + abbrev_code_result, // 0 + pubname_attr_result, + reloc_offset_result, + attr_tag_result, + tag_tree_result, + type_offset_result, // 5 + decl_file_result, + ranges_result, + lines_result, //8 + aranges_result, + // Harmless errors are errors detected inside libdwarf but + // not reported via DW_DLE_ERROR returns because the errors + // won't really affect client code. The 'harmless' errors + // are reported and otherwise ignored. It is difficult to report + // the error when the error is noticed by libdwarf, the error + // is reported at a later time. + // The other errors dwarfdump reports are also generally harmless + // but are detected by dwarfdump so it's possble to report the + // error as soon as the error is discovered. + harmless_result, //10 + fde_duplication, + frames_result, + locations_result, + names_result, + abbreviations_result, // 15 + dwarf_constants_result, + di_gaps_result, + forward_decl_result, + self_references_result, + total_check_result, //20 + LAST_CATEGORY // Must be last. +} ; + + +extern bool info_flag; +extern bool line_flag; +extern bool use_old_dwarf_loclist; +extern bool producer_children_flag; // List of CUs per compiler + +extern std::string cu_name; +extern bool cu_name_flag; +extern Dwarf_Unsigned cu_offset; +extern Dwarf_Off fde_offset_for_cu_low; +extern Dwarf_Off fde_offset_for_cu_high; + +/* Process TAGs for checking mode and reset pRangesInfo table + if appropriate. */ +extern void tag_specific_checks_setup(Dwarf_Half val,int die_indent_level); + +extern std::string program_name; +extern Dwarf_Error err; + +extern void print_error_and_continue (Dwarf_Debug dbg, const std::string& msg,int res, Dwarf_Error err); +extern void print_error (Dwarf_Debug dbg, const std::string& msg,int res, Dwarf_Error err); + +// The dwarf_names_print_on_error is so other apps (tag_tree.cc) +// can use the generated code in dwarf_names.cc (etc) easily. +// It is not ever set false in dwarfdump. +extern bool dwarf_names_print_on_error; + +extern void print_line_numbers_this_cu (DieHolder &hdie); +struct dwconf_s; +extern void print_frames (Dwarf_Debug dbg, int print_debug_frame, + int print_eh_frame,struct dwconf_s *); +extern void print_ranges (Dwarf_Debug dbg); +extern void print_pubnames (Dwarf_Debug dbg); +extern void print_macinfo (Dwarf_Debug dbg); +extern void print_infos (Dwarf_Debug dbg,bool is_info); +extern void print_locs (Dwarf_Debug dbg); +extern void print_abbrevs (Dwarf_Debug dbg); +extern void print_strings (Dwarf_Debug dbg); +extern void print_aranges (Dwarf_Debug dbg); +extern void print_relocinfo (Dwarf_Debug dbg, unsigned reloc_map); +extern void print_static_funcs(Dwarf_Debug dbg); +extern void print_static_vars(Dwarf_Debug dbg); +enum type_type_e {SGI_TYPENAME, DWARF_PUBTYPES} ; +extern void print_types(Dwarf_Debug dbg,enum type_type_e type_type); +extern void print_weaknames(Dwarf_Debug dbg); +extern void print_exception_tables(Dwarf_Debug dbg); +struct esb_s; +extern std::string print_ranges_list_to_extra(Dwarf_Debug dbg, + Dwarf_Unsigned off, + Dwarf_Ranges *rangeset, + Dwarf_Signed rangecount, + Dwarf_Unsigned bytecount); +extern bool should_skip_this_cu(DieHolder &cu_die, Dwarf_Error err); + +int get_cu_name(DieHolder &hcu_die, + Dwarf_Error err,std::string &short_name_out,std::string &long_name_out); +int get_producer_name(DieHolder &hcu_die, + Dwarf_Error err,std::string &producer_name_out); + +/* Get number of abbreviations for a CU */ +extern void get_abbrev_array_info(Dwarf_Debug dbg,Dwarf_Unsigned offset); +/* Validate an abbreviation */ +extern void validate_abbrev_code(Dwarf_Debug dbg,Dwarf_Unsigned abbrev_code); + +extern void print_die_and_children( + DieHolder &in_die, + Dwarf_Bool is_info, + SrcfilesHolder &srcfiles); +extern bool print_one_die( + DieHolder &hdie_in, + bool print_information, + int indent_level, + SrcfilesHolder &srcfiles, + bool ignore_die_printed_flag); + +// Check for specific compiler. +extern bool checking_this_compiler(); +extern void update_compiler_target(const std::string & producer_name); +extern void add_cu_name_compiler_target(const std::string &name); + + +/* General error reporting routines. These were + macros for a short time and when changed into functions + they kept (for now) their capitalization. + The capitalization will likely change. */ +extern void PRINT_CU_INFO(); +extern void DWARF_CHECK_COUNT(Dwarf_Check_Categories category, int inc); +extern void DWARF_ERROR_COUNT(Dwarf_Check_Categories category, int inc); +extern void DWARF_CHECK_ERROR_PRINT_CU(); +extern void DWARF_CHECK_ERROR(Dwarf_Check_Categories category, + const std::string &str); +extern void DWARF_CHECK_ERROR2(Dwarf_Check_Categories category, + const std::string &str1, + const std::string &str2); +extern void DWARF_CHECK_ERROR3(Dwarf_Check_Categories category, + const std::string & str1, + const std::string & str2, + const std::string & strexpl); + + +extern void printreg(Dwarf_Signed reg,struct dwconf_s *config_data); +extern void print_frame_inst_bytes(Dwarf_Debug dbg, + Dwarf_Ptr cie_init_inst, Dwarf_Signed len, + Dwarf_Signed data_alignment_factor, + int code_alignment_factor, Dwarf_Half addr_size, + struct dwconf_s *config_data); + +bool +get_proc_name(Dwarf_Debug dbg, Dwarf_Die die, + std::string & proc_name, Dwarf_Addr & low_pc_out); + + +void get_attr_value(Dwarf_Debug dbg, Dwarf_Half tag, + Dwarf_Die die, + Dwarf_Attribute attrib, + SrcfilesHolder &srcfiles, + std::string &str_out,bool show_form, + int local_verbose); + + + +extern Dwarf_Unsigned local_dwarf_decode_u_leb128(unsigned char *leb128, + unsigned int *leb128_length); + +extern Dwarf_Signed local_dwarf_decode_s_leb128(unsigned char *leb128, + unsigned int *leb128_length); + +extern void dump_block(const std::string &prefix, char *data, Dwarf_Signed len); + +extern void format_sig8_string(Dwarf_Sig8 *data,std::string &out); + +int +dwarfdump_print_one_locdesc(Dwarf_Debug dbg, + Dwarf_Locdesc * llbuf, + int skip_locdesc_header, + std::string &string_out); +void clean_up_syms_malloc_data(); + +void print_any_harmless_errors(Dwarf_Debug dbg); + +/* Definitions for printing relocations. */ +#define DW_SECTION_REL_DEBUG_INFO 0 +#define DW_SECTION_REL_DEBUG_LINE 1 +#define DW_SECTION_REL_DEBUG_PUBNAMES 2 +#define DW_SECTION_REL_DEBUG_ABBREV 3 +#define DW_SECTION_REL_DEBUG_ARANGES 4 +#define DW_SECTION_REL_DEBUG_FRAME 5 +#define DW_SECTION_REL_DEBUG_LOC 6 +#define DW_SECTION_REL_DEBUG_RANGES 7 +#define DW_SECTION_REL_DEBUG_TYPES 8 + +template <typename T > +std::string IToDec(T v,unsigned l=0) +{ + std::ostringstream s; + if (l > 0) { + s << std::setw(l) << v; + } else { + s << v ; + } + return s.str(); +}; +template <typename T > +std::string IToHex(T v,unsigned l=0) +{ + if(v == 0) { + // For a zero value, above does not insert 0x. + // So we do zeroes here. + std::string out = "0x0"; + if(l > 3) { + out.append(l-3,'0'); + } + return out; + } + std::ostringstream s; + s.setf(std::ios::hex,std::ios::basefield); + s.setf(std::ios::showbase); + if (l > 0) { + s << std::setw(l); + } + s << v ; + return s.str(); +}; + +inline std::string IToHex02(unsigned v) +{ + std::ostringstream s; + // NO showbase here. + s.setf(std::ios::hex,std::ios::basefield); + s << std::setfill('0'); + s << std::setw(2) << (0xff & v); + return s.str(); +} +template <typename T> +std::string IToHex0N(T v,unsigned len=0) +{ + std::ostringstream s; + s.setf(std::ios::hex,std::ios::basefield); + //s.setf(std::ios::showbase); + s << std::setfill('0'); + if(len > 2 ) { + s << std::setw(len-2) << v; + } else { + s << v; + } + return std::string("0x") + s.str(); +} +template <typename T> +std::string IToDec0N(T v,unsigned len=0) +{ + std::ostringstream s; + if (v < 0 && len > 2 ) { + // Special handling for negatives: + // 000-27 is not what we want for example. + s << v; + // ASSERT: s.str().size() >= 1 + if( len > ((s.str().size()))) { + // Ignore the leading - and take the rest. + std::string rest = s.str().substr(1); + std::string::size_type zeroscount = len - (rest.size()+1); + std::string final; + if(zeroscount > 0) { + final.append(zeroscount,'0'); + final.append(rest); + } else { + final = rest; + } + return std::string("-") + final; + } + return s.str(); + } + s << std::setfill('0'); + if(len > 0) { + s << std::setw(len) << v; + } else { + s << v; + } + return s.str(); +} +inline std::string LeftAlign(unsigned minlen,const std::string &s) +{ + if(minlen <= s.size()) { + return s; + } + std::string out = s; + std::string::size_type spaces = minlen - out.size(); + out.append(spaces,' '); + return out; +} + +inline std::string SpaceSurround(const std::string &s) +{ + std::string out(" "); + out.append(s); + out.append(" "); + return out; +}; +inline std::string BracketSurround(const std::string &s) +{ + std::string out("<"); + out.append(s); + out.append(">"); + return out; +}; + + +#endif /* globals_INCLUDED */ + diff --git a/dwarfdump2/install.sh b/dwarfdump2/install.sh new file mode 100755 index 0000000..0ff4b6a --- /dev/null +++ b/dwarfdump2/install.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/dwarfdump2/naming.cc b/dwarfdump2/naming.cc new file mode 100644 index 0000000..4526538 --- /dev/null +++ b/dwarfdump2/naming.cc @@ -0,0 +1,264 @@ + +/* + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 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 + +*/ + +/* 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 "dwarf.h" +#include "libdwarf.h" + +using std::string; +using std::cerr; +using std::endl; + +static const char * +skipunder(const char *v) +{ + const char *cp = v; + int undercount = 0; + for( ; *cp ; ++cp) { + if( *cp == '_') { + ++undercount; + if(undercount == 2) { + return cp+1; + } + } + } + return ""; +}; + +static string +ellipname(int res, unsigned int val_in, const char *v,const char *ty,bool printonerr) +{ +#ifndef TRIVIAL_NAMING + if (check_dwarf_constants && checking_this_compiler()) { + DWARF_CHECK_COUNT(dwarf_constants_result,1); + } +#endif + if(res != DW_DLV_OK) { + if(printonerr) { +#ifndef TRIVIAL_NAMING + if(printonerr && check_dwarf_constants && checking_this_compiler()) { + if (check_verbose_mode) { + std::cerr << ty << " of " << val_in << " (" << + IToHex(val_in) << + ") is unknown to dwarfdump. " << + "Continuing. " << endl; + } + DWARF_ERROR_COUNT(dwarf_constants_result,1); + DWARF_CHECK_ERROR_PRINT_CU(); + } +#else + /* This is for the tree-generation, not dwarfdump itself. */ + if(printonerr) { + std::cerr << ty << " of " << val_in << + " (" << IToHex(val_in,0) << + ") is unknown to dwarfdump. Continuing. " << std::endl; + } +#endif + } + return "<Unknown " + string(ty) + " value " + + IToHex(val_in,0) + ">"; + } + if(ellipsis) { + return skipunder(v); + } + return v; +}; + +std::string get_TAG_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_TAG_name(val_in,&v); + return ellipname(res,val_in,v,"TAG",printonerr); +} +std::string get_children_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_children_name(val_in,&v); + return ellipname(res,val_in,v,"children",printonerr); +} +std::string get_FORM_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_FORM_name(val_in,&v); + return ellipname(res,val_in,v,"FORM",printonerr); +} +std::string get_AT_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_AT_name(val_in,&v); + return ellipname(res,val_in,v,"AT",printonerr); +} +std::string get_OP_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_OP_name(val_in,&v); + return ellipname(res,val_in,v,"OP",printonerr); +} +std::string get_ATE_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_ATE_name(val_in,&v); + return ellipname(res,val_in,v,"ATE",printonerr); +} +std::string get_DS_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_DS_name(val_in,&v); + return ellipname(res,val_in,v,"DS",printonerr); +} +std::string get_END_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_END_name(val_in,&v); + return ellipname(res,val_in,v,"END",printonerr); +} +std::string get_ATCF_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_ATCF_name(val_in,&v); + return ellipname(res,val_in,v,"ATCF",printonerr); +} +std::string get_ACCESS_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_ACCESS_name(val_in,&v); + return ellipname(res,val_in,v,"ACCESS",printonerr); +} +std::string get_VIS_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_VIS_name(val_in,&v); + return ellipname(res,val_in,v,"VIS",printonerr); +} +std::string get_VIRTUALITY_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_VIRTUALITY_name(val_in,&v); + return ellipname(res,val_in,v,"VIRTUALITY",printonerr); +} +std::string get_LANG_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_LANG_name(val_in,&v); + return ellipname(res,val_in,v,"LANG",printonerr); +} +std::string get_ID_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_ID_name(val_in,&v); + return ellipname(res,val_in,v,"ID",printonerr); +} +std::string get_CC_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_CC_name(val_in,&v); + return ellipname(res,val_in,v,"CC",printonerr); +} +std::string get_INL_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_INL_name(val_in,&v); + return ellipname(res,val_in,v,"INL",printonerr); +} +std::string get_ORD_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_ORD_name(val_in,&v); + return ellipname(res,val_in,v,"ORD",printonerr); +} +std::string get_DSC_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_DSC_name(val_in,&v); + return ellipname(res,val_in,v,"DSC",printonerr); +} +std::string get_LNS_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_LNS_name(val_in,&v); + return ellipname(res,val_in,v,"LNS",printonerr); +} +std::string get_LNE_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_LNE_name(val_in,&v); + return ellipname(res,val_in,v,"LNE",printonerr); +} +std::string get_MACINFO_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_MACINFO_name(val_in,&v); + return ellipname(res,val_in,v,"MACINFO",printonerr); +} +std::string get_CFA_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_CFA_name(val_in,&v); + return ellipname(res,val_in,v,"CFA",printonerr); +} +std::string get_EH_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_EH_name(val_in,&v); + return ellipname(res,val_in,v,"EH",printonerr); +} +std::string get_FRAME_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_FRAME_name(val_in,&v); + return ellipname(res,val_in,v,"FRAME",printonerr); +} +std::string get_CHILDREN_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_CHILDREN_name(val_in,&v); + return ellipname(res,val_in,v,"CHILDREN",printonerr); +} +std::string get_ADDR_name(unsigned int val_in,bool printonerr) +{ + const char *v = 0; + int res = dwarf_get_ADDR_name(val_in,&v); + return ellipname(res,val_in,v,"ADDR",printonerr); +} + + diff --git a/dwarfdump2/naming.h b/dwarfdump2/naming.h new file mode 100644 index 0000000..1314ab4 --- /dev/null +++ b/dwarfdump2/naming.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 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 + +*/ + +/* 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. +*/ + +/* naming.h */ + +extern std::string get_TAG_name(unsigned int val_in,bool printonerr); +extern std::string get_children_name(unsigned int val_in,bool printonerr); +extern std::string get_FORM_name(unsigned int val_in,bool printonerr); +extern std::string get_AT_name(unsigned int val_in,bool printonerr); +extern std::string get_OP_name(unsigned int val_in,bool printonerr); +extern std::string get_ATE_name(unsigned int val_in,bool printonerr); +extern std::string get_DS_name(unsigned int val_in,bool printonerr); +extern std::string get_END_name(unsigned int val_in,bool printonerr); +extern std::string get_ATCF_name(unsigned int val_in,bool printonerr); +extern std::string get_ACCESS_name(unsigned int val_in,bool printonerr); +extern std::string get_VIS_name(unsigned int val_in,bool printonerr); +extern std::string get_VIRTUALITY_name(unsigned int val_in,bool printonerr); +extern std::string get_LANG_name(unsigned int val_in,bool printonerr); +extern std::string get_ID_name(unsigned int val_in,bool printonerr); +extern std::string get_CC_name(unsigned int val_in,bool printonerr); +extern std::string get_INL_name(unsigned int val_in,bool printonerr); +extern std::string get_ORD_name(unsigned int val_in,bool printonerr); +extern std::string get_DSC_name(unsigned int val_in,bool printonerr); +extern std::string get_LNS_name(unsigned int val_in,bool printonerr); +extern std::string get_LNE_name(unsigned int val_in,bool printonerr); +extern std::string get_MACINFO_name(unsigned int val_in,bool printonerr); +extern std::string get_CFA_name(unsigned int val_in,bool printonerr); +extern std::string get_EH_name(unsigned int val_in,bool printonerr); +extern std::string get_FRAME_name(unsigned int val_in,bool printonerr); +extern std::string get_CHILDREN_name(unsigned int val_in,bool printonerr); +extern std::string get_ADDR_name(unsigned int val_in,bool printonerr); + + diff --git a/dwarfdump2/print_abbrevs.cc b/dwarfdump2/print_abbrevs.cc new file mode 100644 index 0000000..b0ed7f0 --- /dev/null +++ b/dwarfdump2/print_abbrevs.cc @@ -0,0 +1,307 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* print data in .debug_abbrev */ +extern void +print_abbrevs(Dwarf_Debug dbg) +{ + Dwarf_Abbrev ab; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned attr_count = 0; + Dwarf_Half attr = 0; + Dwarf_Signed form = 0; + Dwarf_Off off = 0; + string child_name; + Dwarf_Unsigned abbrev_num = 1; + Dwarf_Signed child_flag = 0; + int abres = 0; + + error_message_data.current_section_id = DEBUG_ABBREV; + if (do_print_dwarf) { + cout << endl; + cout << ".debug_abbrev" << endl; + } + while ((abres = dwarf_get_abbrev(dbg, offset, &ab, + &length, &attr_count, + &err)) == DW_DLV_OK) { + + if (attr_count == 0) { + /* Simple innocuous zero : null abbrev entry */ + if (dense) { + cout << BracketSurround(IToDec(abbrev_num)); + cout << BracketSurround(IToHex0N(offset,10)); + // 0 is abbrev_code. + cout << BracketSurround(IToDec(0)); + cout << BracketSurround("null .debug_abbrev entry") << endl; + } else { + cout << BracketSurround(IToDec(abbrev_num,5)); + cout << BracketSurround(IToHex0N(offset,10)); + // 0 is abbrev_code. + cout << BracketSurround(string("code: ") +IToDec(0,3)); + cout << " null .debug_abbrev entry" << endl; + } + + offset += length; + ++abbrev_num; + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + continue; + } + Dwarf_Half tag = 0; + int tres = dwarf_get_abbrev_tag(ab, &tag, &err); + if (tres != DW_DLV_OK) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_tag", tres, err); + } + Dwarf_Unsigned abbrev_code = 0; + tres = dwarf_get_abbrev_code(ab, &abbrev_code, &err); + if (tres != DW_DLV_OK) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_code", tres, err); + } + if (dense) { + cout << BracketSurround(IToDec(abbrev_num)); + cout << BracketSurround(IToHex0N(offset,10)); + cout << BracketSurround(IToDec(abbrev_code)); + cout << BracketSurround(get_TAG_name(tag, + dwarf_names_print_on_error)); + } + else { + cout << BracketSurround(IToDec(abbrev_num,5)); + cout << BracketSurround(IToHex0N(offset,10)); + cout << BracketSurround(string("code: ") +IToDec(abbrev_code,3)); + cout << " "; + cout << LeftAlign(20,get_TAG_name(tag, + dwarf_names_print_on_error)); + } + ++abbrev_num; + int acres = dwarf_get_abbrev_children_flag(ab, &child_flag, &err); + if (acres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_children_flag", acres, + err); + } + if (acres == DW_DLV_NO_ENTRY) { + child_flag = 0; + } + child_name = get_children_name(child_flag, + dwarf_names_print_on_error); + if (dense) { + cout << " " << child_name; + } else { + cout << " " << child_name << endl; + } + /* Abbrev just contains the format of a die, which debug_info + then points to with the real data. So here we just print the + given format. */ + for (Dwarf_Unsigned i = 0; i < attr_count; i++) { + int aeres = + dwarf_get_abbrev_entry(ab, i, &attr, &form, &off, &err); + if (aeres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + print_error(dbg, "dwarf_get_abbrev_entry", aeres, err); + } + if (aeres == DW_DLV_NO_ENTRY) { + attr = -1LL; + form = -1LL; + } + if (dense) { + cout << " " << BracketSurround(IToDec(off)); + cout << get_AT_name(attr,dwarf_names_print_on_error); + cout << BracketSurround(get_FORM_name((Dwarf_Half) form, + dwarf_names_print_on_error)); + } else { + cout << " " << BracketSurround(IToHex0N(off,10)); + cout << " "; + cout << LeftAlign(28,get_AT_name( + attr,dwarf_names_print_on_error)); + cout << get_FORM_name(form, + dwarf_names_print_on_error); + cout << endl; + } + } + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + offset += length; + if (dense) { + cout << endl; + } + } + if (abres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_abbrev", abres, err); + } +} + + +/* Abbreviations array info for checking abbrev tags. + The [zero] entry is not used. + We never shrink the array, but it never grows beyond + the largest abbreviation count of all the CUs. + + +*/ + +static std::vector<Dwarf_Signed>abbrev_vec; +#define ABBREV_ARRAY_INITIAL_SIZE 64 +/* Number of abbreviations for current CU */ +static Dwarf_Unsigned CU_high_abbrev_code; +static Dwarf_Unsigned CU_abbrev_count; + +static void +increaseTo(unsigned nsize) +{ + unsigned csize = abbrev_vec.size(); + if(nsize < csize) { + // Nothing to do here. + return; + } + abbrev_vec.resize(nsize); + for(unsigned i = csize; i < nsize; ++i) { + abbrev_vec[i] = 0; + } + +} + +/* Calculate the number of abbreviations for the + current CU and set up a basic abbreviations array info, + storing the number of attributes per abbreviation. +*/ +void +get_abbrev_array_info(Dwarf_Debug dbg, Dwarf_Unsigned offset_in) +{ + Dwarf_Unsigned offset = offset_in; + if (check_abbreviations) { + Dwarf_Abbrev ab; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned abbrev_entry_count = 0; + Dwarf_Unsigned abbrev_code; + int abres = DW_DLV_OK; + Dwarf_Error err; + + bool bMore = true; + CU_abbrev_count = 0; + CU_high_abbrev_code = 0; + + if (!abbrev_vec.empty()) { + for(unsigned i = 0; i < abbrev_vec.size(); ++i) { + abbrev_vec[i] = 0; + } + } + + while (bMore && (abres = dwarf_get_abbrev(dbg, offset, &ab, + &length, &abbrev_entry_count, + &err)) == DW_DLV_OK) { + dwarf_get_abbrev_code(ab,&abbrev_code,&err); + if (abbrev_code == 0) { + /* End of abbreviation table for this CU */ + ++offset; /* Skip abbreviation code */ + bMore = false; + } else { + /* Valid abbreviation code */ + if (abbrev_code > 0) { + increaseTo(abbrev_code+1); + abbrev_vec[abbrev_code] = abbrev_entry_count; + if(abbrev_code > CU_high_abbrev_code) { + CU_high_abbrev_code = abbrev_code; + } + ++CU_abbrev_count; + offset += length; + } else { + /* Invalid abbreviation code */ + print_error(dbg, "get_abbrev_array_info", abres, err); + } + } + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + } + } +} + + + +/* The following relevent for one specific Linker. */ +#define SNLINKER_MAX_ATTRIB_COUNT 16 + +/* Validate an abbreviation for the current CU. */ +void +validate_abbrev_code(Dwarf_Debug dbg,Dwarf_Unsigned abbrev_code) +{ + char buf[128]; + + DWARF_CHECK_COUNT(abbreviations_result,1); + if (abbrev_code < 0 || (abbrev_code && abbrev_code > CU_high_abbrev_code)) { + snprintf(buf, sizeof(buf), + "Abbrev code %" DW_PR_DUu + " outside valid range of [0-%" DW_PR_DUu "]", + abbrev_code,CU_high_abbrev_code); + DWARF_CHECK_ERROR2(abbreviations_result,buf, + "Invalid abbreviation code."); + } else { + Dwarf_Signed abbrev_entry_count = + abbrev_vec[abbrev_code]; + if (abbrev_entry_count < 0 || + abbrev_entry_count > SNLINKER_MAX_ATTRIB_COUNT) { + snprintf(buf, sizeof(buf), + "Abbrev code %" DW_PR_DUu + ", with %" DW_PR_DUu " attributes: " + "outside valid range.", + abbrev_code, + abbrev_entry_count); + DWARF_CHECK_ERROR2(abbreviations_result,buf, + "Invalid number of attributes."); + } + } +} + + diff --git a/dwarfdump2/print_aranges.cc b/dwarfdump2/print_aranges.cc new file mode 100644 index 0000000..1265624 --- /dev/null +++ b/dwarfdump2/print_aranges.cc @@ -0,0 +1,266 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + + +static void +do_checking(Dwarf_Debug dbg, Dwarf_Arange *arange_buf,Dwarf_Signed i, + Dwarf_Off cu_die_offset,Dwarf_Bool first_cu, + Dwarf_Off cu_die_offset_prev, Dwarf_Die cu_die ) +{ + Dwarf_Off cuhdroff = 0; + Dwarf_Off cudieoff3 = 0; + int dres = dwarf_get_arange_cu_header_offset( + arange_buf[i],&cuhdroff,&err); + if(dres == DW_DLV_OK) { + Dwarf_Off cudieoff2 = 0; + + /* Get the CU offset for easy error reporting */ + if (first_cu || cu_die_offset != cu_die_offset_prev) { + cu_die_offset_prev = cu_die_offset; + dres = dwarf_die_offsets(cu_die, + &error_message_data.DIE_overall_offset, + &error_message_data.DIE_offset,&err); + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_die_offsets", dres, err); + } + } + dres = dwarf_get_cu_die_offset_given_cu_header_offset( + dbg,cuhdroff,&cudieoff2,&err); + if(dres == DW_DLV_OK) { + /* 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); + DWARF_CHECK_COUNT(aranges_result,1); + if(cudieoff2 != cu_die_offset) { + cout << "Error, cu_die offsets mismatch, " << + IToHex(cu_die_offset) << " != " << + IToHex(cudieoff2) << " from arange data"; + DWARF_CHECK_ERROR(aranges_result, + " dwarf_get_cu_die_offset_given_cu..." + " gets wrong offset"); + } + } else { + print_error(dbg, "dwarf_get_cu_die_offset_given...", dres, err); + } + } else { + print_error(dbg, "dwarf_get_arange_cu_header_offset", dres, err); + } + dres = dwarf_get_cu_die_offset(arange_buf[i],&cudieoff3, + &err); + if(dres == DW_DLV_OK) { + DWARF_CHECK_COUNT(aranges_result,1); + if(cudieoff3 != cu_die_offset) { + cout << "Error, cu_die offsets (b) mismatch , "<< + IToHex(cu_die_offset) << " != " << + IToHex(cudieoff3) << " from arange data"; + DWARF_CHECK_ERROR(aranges_result, + " dwarf_get_cu_die_offset " + " gets wrong offset"); + } + } else { + print_error(dbg, "dwarf_get_cu_die_offset failed ", + dres,err); + } +} + +/* get all the data in .debug_aranges */ +extern void +print_aranges(Dwarf_Debug dbg) +{ + Dwarf_Signed count = 0; + Dwarf_Arange *arange_buf = NULL; + Dwarf_Off prev_off = 0; /* Holds previous CU offset */ + bool first_cu = true; + Dwarf_Off cu_die_offset_prev = 0; + + /* Reset the global state, so we can traverse the debug_info */ + 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.current_section_id = DEBUG_ARANGES; + if (do_print_dwarf) { + cout << endl; + cout << ".debug_aranges" << endl; + } + int ares = dwarf_get_aranges(dbg, &arange_buf, &count, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_aranges", ares, err); + } else if (ares == DW_DLV_NO_ENTRY) { + /* no arange is included */ + } else { + Dwarf_Unsigned segment = 0; + Dwarf_Unsigned segment_entry_size = 0; + Dwarf_Addr start = 0; + Dwarf_Unsigned length = 0; + Dwarf_Off cu_die_offset = 0; + Dwarf_Die cu_die = 0; + for (Dwarf_Signed i = 0; i < count; i++) { + int aires = dwarf_get_arange_info_b(arange_buf[i], + &segment,&segment_entry_size, + &start, &length, + &cu_die_offset, &err); + if (aires != DW_DLV_OK) { + print_error(dbg, "dwarf_get_arange_info", aires, err); + } else { + int dres; + string producer_name; + /* Get basic locations for error reporting */ + dres = dwarf_offdie(dbg, cu_die_offset, &cu_die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_offdie", dres, err); + } + DieHolder hcu_die(dbg,cu_die); + + if (cu_name_flag) { + if(should_skip_this_cu(hcu_die,err)) { + continue; + } + } + /* Get producer name for this CU and update compiler list */ + get_producer_name(hcu_die,err,producer_name); + update_compiler_target(producer_name); + if (!checking_this_compiler()) { + continue; + } + + + if (check_aranges) { + do_checking(dbg,arange_buf,i,cu_die_offset,first_cu, + cu_die_offset_prev,cu_die); + } + + if(start || length) { + Dwarf_Off off = 0; + int cures3 = dwarf_get_arange_cu_header_offset( + arange_buf[i], &off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_get_cu_hdr_offset", + cures3, err); + } + + /* Print the CU information if different. */ + if (prev_off != off || first_cu) { + first_cu = false; + prev_off = off; + /* We are faking the indent level. We do not know + what level it is, really. + + If do_check_dwarf we do not want to do + the die print call as it will do + check/print we may not have asked for. + And if we did ask for debug_info checks + this will do the checks a second time! + So only call print_one_die if printing. + */ + if(do_print_dwarf){ + /* There is no die if its a set-end entry */ + SrcfilesHolder hsrcfiles; + print_one_die(hcu_die, + /* print_information= */ 1, + /* indent_level = */0, + hsrcfiles, + /* ignore_die_printed_flag= */true); + } + /* Reset the state, so we can traverse the debug_info */ + error_message_data.seen_CU = false; + error_message_data.need_CU_name = true; + if (do_print_dwarf) { + cout << endl; + } + } + + if (do_print_dwarf) { + /* Print current aranges record */ + if(segment_entry_size) { + cout << endl; + cout << + "arange starts at seg,off " << + IToHex0N(segment,10) << + "," << IToHex0N(start,10); + } else { + cout << endl; + cout << + "arange starts at " << + IToHex0N(start,10); + } + cout << ", length of " << IToHex0N(length,10) << + ", cu_die_offset = "<< IToHex0N(cu_die_offset,10); + } + if (verbose && do_print_dwarf) { + cout << " cuhdr "<< IToHex0N(off,10) << endl; + } + } else { + /* Must be a range end. We really do want to print + this as there is a real record here, an + 'arange end' record. */ + if (do_print_dwarf) { + cout << endl; + cout << "arange end"; + } + }/* end start||length test */ + + } // End aires DW_DLV_OK test + /* print associated die too? */ + dwarf_dealloc(dbg, arange_buf[i], DW_DLA_ARANGE); + } + dwarf_dealloc(dbg, arange_buf, DW_DLA_LIST); + } +} + 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); +} + + diff --git a/dwarfdump2/print_frames.cc b/dwarfdump2/print_frames.cc new file mode 100644 index 0000000..291b681 --- /dev/null +++ b/dwarfdump2/print_frames.cc @@ -0,0 +1,1621 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 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_frames.c,v 1.5 2006/06/14 20:34:02 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 <vector> +#include <map> +#include <set> +#include "print_frames.h" +#include "dwconf.h" +#include "fderegs.h" + + + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +using std::map; +using std::set; + +static void +print_one_frame_reg_col(Dwarf_Debug dbg, + Dwarf_Unsigned rule_id, + Dwarf_Small value_type, + Dwarf_Unsigned reg_used, + Dwarf_Half address_size, + struct dwconf_s *config_data, + Dwarf_Signed offset_relevant, + Dwarf_Signed offset, Dwarf_Ptr block_ptr); + +typedef map<Dwarf_Addr,string> LowpcToNameMaptype; +typedef set<Dwarf_Addr> LowpcUsedSettype; + + + +/* For inlined or class mem functions, try to find name */ +static int +get_abstract_origin_or_spec_funcname(Dwarf_Debug dbg, + Dwarf_Attribute attr, + string &name_out) +{ + Dwarf_Off off = 0; + Dwarf_Die origin_die = 0; + Dwarf_Attribute *atlist = NULL; + Dwarf_Signed atcnt = 0; + bool name_found = false; + int res = dwarf_global_formref(attr,&off,&err); + if(res != DW_DLV_OK) { + return DW_DLV_NO_ENTRY; + } + int dres = dwarf_offdie(dbg,off,&origin_die,&err); + if(dres != DW_DLV_OK) { + return DW_DLV_NO_ENTRY; + } + int atres = dwarf_attrlist(origin_die, &atlist, &atcnt, &err); + if (atres != DW_DLV_OK) { + dwarf_dealloc(dbg,origin_die,DW_DLA_DIE); + return DW_DLV_NO_ENTRY; + } + for (Dwarf_Signed i = 0; i < atcnt; i++) { + Dwarf_Half lattr; + int ares; + ares = dwarf_whatattr(atlist[i], &lattr, &err); + if (ares == DW_DLV_ERROR) { + break; + } else if (ares == DW_DLV_OK) { + if(lattr == DW_AT_name) { + int sres = 0; + char* temps = 0; + sres = dwarf_formstring(atlist[i], &temps, &err); + if (sres == DW_DLV_OK) { + name_out = temps; + name_found = true; + break; + } + } + } + } + for (Dwarf_Signed i = 0; i < atcnt; i++) { + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); + dwarf_dealloc(dbg,origin_die,DW_DLA_DIE); + if(!name_found) { + return DW_DLV_NO_ENTRY; + } + return DW_DLV_OK; +} + + +/* Returns true this is a procedure with a name, and sets + the name in proc_name and the low pc in low_pc_out. + Else returns false. */ +bool +get_proc_name(Dwarf_Debug dbg, Dwarf_Die die, + string & proc_name, Dwarf_Addr & low_pc_out) +{ + Dwarf_Signed atcnt = 0; + Dwarf_Signed i = 0; + Dwarf_Attribute *atlist = NULL; + bool funcpcfound = false; + bool funcnamefound = false; + + int atres = dwarf_attrlist(die, &atlist, &atcnt, &err); + if (atres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_attrlist", atres, err); + return false; + } + if (atres == DW_DLV_NO_ENTRY) { + return false; + } + for (i = 0; i < atcnt; i++) { + Dwarf_Half attr; + int ares; + char *temps; + int sres; + int dres; + + if (funcnamefound == true && funcpcfound == true) { + /* stop as soon as both found */ + break; + } + ares = dwarf_whatattr(atlist[i], &attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "get_proc_name whatattr error", ares, err); + } else if (ares == DW_DLV_OK) { + switch (attr) { + case DW_AT_specification: + case DW_AT_abstract_origin: + { + if(!funcnamefound) { + string aotemp; + /* Only use this if we have not seen DW_AT_name + yet .*/ + int aores = get_abstract_origin_or_spec_funcname(dbg, + atlist[i], aotemp); + if(aores == DW_DLV_OK) { + /* FOUND THE NAME */ + proc_name = aotemp; + funcnamefound = 1; + } + } + } + break; + case DW_AT_name: + sres = dwarf_formstring(atlist[i], &temps, &err); + if (sres == DW_DLV_ERROR) { + print_error(dbg, + "formstring in get_proc_name failed", + sres, err); + /* 50 is safe wrong length since is bigger than the + actual string */ + proc_name = "ERROR in dwarf_formstring!"; + } else if (sres == DW_DLV_NO_ENTRY) { + /* 50 is safe wrong length since is bigger than the + actual string */ + proc_name = "NO ENTRY on dwarf_formstring?!"; + } else { + proc_name = temps; + } + funcnamefound = 1; /* FOUND THE NAME */ + break; + case DW_AT_low_pc: + dres = dwarf_formaddr(atlist[i], &low_pc_out, &err); + if (dres == DW_DLV_ERROR) { + print_error(dbg, "formaddr in get_proc_name failed", + dres, err); + } else if (dres == DW_DLV_OK) { + funcpcfound = true; + } + break; + default: + break; + } + } + } + for (i = 0; i < atcnt; i++) { + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); + if (funcnamefound == 0 || funcpcfound == 0 ) { + return false; + } + return true; +} + +/* Nested search since some languages, including SGI MP Fortran, + have nested functions. + + Loads all the subprogram names it can find in the current + sibling/child chain into the pcMap. + Do not stop except on error. */ +static void +load_nested_proc_names(Dwarf_Debug dbg, Dwarf_Die die, + string &proc_name, LowpcToNameMaptype & pcMap) +{ + Dwarf_Die curdie = die; + int die_locally_gotten = 0; + Dwarf_Half tag; + Dwarf_Error err = 0; + int chres = DW_DLV_OK; + while (chres == DW_DLV_OK) { + int tres = dwarf_tag(curdie, &tag, &err); + err = 0; + if (tres == DW_DLV_OK) { + int lchres; + + if (tag == DW_TAG_subprogram) { + Dwarf_Addr proc_low_pc = 0; + bool proc_name_v = get_proc_name(dbg, curdie, proc_name, + proc_low_pc); + if (proc_name_v) { + pcMap[proc_low_pc] = proc_name; + } + /* Check children of subprograms recursively. Should + this really be checking children of anything, + or just children of subprograms? */ + Dwarf_Die newchild = 0; + lchres = dwarf_child(curdie, &newchild, &err); + if (lchres == DW_DLV_OK) { + /* Look for inner subprogram. */ + load_nested_proc_names(dbg, newchild, + proc_name, pcMap); + dwarf_dealloc(dbg, newchild, DW_DLA_DIE); + } else if (lchres == DW_DLV_NO_ENTRY) { + /* nothing to do */ + } else { + print_error(dbg, + "load_nested_proc_names dwarf_child() failed ", + chres, err); + } + } /* end if TAG_subprogram */ + } else { + print_error(dbg, "no tag on child read ", tres, err); + break; + } + /* Try next sibling */ + Dwarf_Die newsibling = 0; + chres = dwarf_siblingof(dbg, curdie, &newsibling, &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_cu_header On Child read ", chres, + err); + break; + } else if (chres == DW_DLV_NO_ENTRY) { + // At the end of sibling chain of this nesting level. + break; + } else { /* DW_DLV_OK */ + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + curdie = newsibling; + die_locally_gotten = 1; + } + + } + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want to + dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return; +} + +/* For SGI MP Fortran and other languages, functions + nest! As a result, we must dig thru all functions, + not just the top level. + + This remembers the CU die and restarts each search at the start + of the current cu. + If we find nothing we return an empty string. */ +static string +get_fde_proc_name(Dwarf_Debug dbg, Dwarf_Addr low_pc, + LowpcToNameMaptype & pcMap, + bool & all_cus_seen) +{ + Dwarf_Unsigned cu_header_length = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half version_stamp = 0; + Dwarf_Half address_size = 0; + Dwarf_Unsigned next_cu_offset = 0; + int cures = DW_DLV_ERROR; + int chres = DW_DLV_ERROR; + string proc_name; + + LowpcToNameMaptype::const_iterator it = pcMap.find(low_pc); + if(it != pcMap.end()) { + string s = it->second; + return s; + } + if(all_cus_seen) { + return ""; + } + + // Loop through the CUs + for (;;) { + cures = dwarf_next_cu_header(dbg, &cu_header_length, + &version_stamp, &abbrev_offset, + &address_size, &next_cu_offset, + &err); + + if (cures == DW_DLV_NO_ENTRY) { + all_cus_seen = true; + break; + } else if (cures == DW_DLV_ERROR) { + // Nothing much we can do here. + all_cus_seen = true; + break; + } + + Dwarf_Die current_cu_die_for_print_frames(0); + int dres = dwarf_siblingof(dbg, NULL, + ¤t_cu_die_for_print_frames, &err); + if (dres == DW_DLV_ERROR) { + print_error(dbg, + "dwarf_cu_header Child Read finding proc name for .debug_frame", + chres, err); + continue; + } else if (dres == DW_DLV_NO_ENTRY) { + continue; + } + /* DW_DLV_OK */ + Dwarf_Die child = 0; + int chres = dwarf_child(current_cu_die_for_print_frames, &child, + &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf Child Read ", chres, err); + } else if (chres == DW_DLV_NO_ENTRY) { + + ; /* do nothing, loop on cu */ + } else { + /* DW_DLV_OK */ + // find All the subprograms for this CU and use + // pcMap to associate each name with its low_pc! + load_nested_proc_names(dbg, child, proc_name, + pcMap); + dwarf_dealloc(dbg, child, DW_DLA_DIE); + } + dwarf_dealloc(dbg, current_cu_die_for_print_frames, DW_DLA_DIE); + LowpcToNameMaptype::const_iterator it = pcMap.find(low_pc); + if(it != pcMap.end()) { + // If we need more CUs later we will process + // them as needed (later), but we have done enough + // CUs to satisfy this low_pc. + string s = it->second; + return s; + } + } + return ""; +} + + +/* + Gather the fde print logic here so the control logic + determining what FDE to print is clearer. +*/ +int +print_one_fde(Dwarf_Debug dbg, Dwarf_Fde fde, + Dwarf_Unsigned fde_index, + Dwarf_Cie * cie_data, + Dwarf_Signed cie_element_count, + Dwarf_Half address_size, int is_eh, + struct dwconf_s *config_data, + LowpcToNameMaptype & pcMap, + LowpcUsedSettype &lowpcSet, + bool &all_cus_seen) +{ + Dwarf_Addr low_pc = 0; + Dwarf_Unsigned func_length = 0; + Dwarf_Ptr fde_bytes = NULL; + Dwarf_Unsigned fde_bytes_length = 0; + Dwarf_Off cie_offset = 0; + Dwarf_Signed cie_index = 0; + Dwarf_Off fde_offset = 0; + Dwarf_Signed eh_table_offset = 0; + Dwarf_Error err = 0; + bool printed_intro_addr = false; + + int fres = dwarf_get_fde_range(fde, + &low_pc, &func_length, + &fde_bytes, + &fde_bytes_length, + &cie_offset, &cie_index, + &fde_offset, &err); + if (fres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_fde_range", fres, err); + } + if (fres == DW_DLV_NO_ENTRY) { + return DW_DLV_NO_ENTRY; + } + if (cu_name_flag && + fde_offset_for_cu_low != DW_DLV_BADOFFSET && + (fde_offset < fde_offset_for_cu_low || + fde_offset > fde_offset_for_cu_high)) { + return DW_DLV_NO_ENTRY; + } + /* eh_table_offset is IRIX ONLY. */ + fres = dwarf_get_fde_exception_info(fde, &eh_table_offset, &err); + if (fres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_fde_exception_info", fres, err); + } + string temps; + if(!suppress_nested_name_search) { + temps = get_fde_proc_name(dbg, low_pc, + pcMap,all_cus_seen); + LowpcUsedSettype::const_iterator it = lowpcSet.find(low_pc); + if(check_frames || check_frames_extended) { + DWARF_CHECK_COUNT(fde_duplication,1); + } + if (it != lowpcSet.end()) { + if(check_frames || check_frames_extended ) { + string msg = string("An fde low pc of ") + IToHex(low_pc) + + string(" is not the first fde with that pc. "); + if(temps.empty()) { + msg.append("The first is not named."); + } else { + msg.append(string("The first is named \"")+ + temps + string("\"") ); + } + DWARF_CHECK_ERROR(fde_duplication,msg); + } + } else { + lowpcSet.insert(low_pc); + } + } + if(!check_frames_extended) { + cout << BracketSurround(IToDec(cie_index,5)); + cout << BracketSurround(IToHex0N(low_pc,10) + string(":")+ + IToHex0N(low_pc + func_length,10)); + cout << BracketSurround(temps); + cout << BracketSurround(string("fde offset ") + + IToHex0N(fde_offset,10) + string(" length: ") + + IToHex0N(fde_bytes_length,10)); + } + + if (!is_eh) { + /* IRIX uses eh_table_offset. */ + if(!check_frames_extended) { + if (eh_table_offset == DW_DLX_NO_EH_OFFSET) { + cout << BracketSurround( + string("eh offset none")) << endl; + } else if (eh_table_offset == DW_DLX_EH_OFFSET_UNAVAILABLE) { + cout << BracketSurround( + string("eh offset unknown")) << endl; + } else { + cout << BracketSurround( + string("eh offset ") + IToHex(eh_table_offset)) << endl; + } + } + } else { + int ares = 0; + Dwarf_Small *data = 0; + Dwarf_Unsigned len = 0; + + ares = dwarf_get_fde_augmentation_data(fde, &data, &len, &err); + if (ares == DW_DLV_NO_ENTRY) { + /* do nothing. */ + } else if (ares == DW_DLV_OK) { + if(!check_frames_extended) { + cout << "<eh aug data len " << IToHex(len); + for (unsigned k2 = 0; k2 < len; ++k2) { + if (k2 == 0) { + cout <<" bytes 0x"; + } + cout << IToHex02(data[k2])<< " "; + } + cout << ">"; + } + } /* else DW_DLV_ERROR, do nothing */ + if(!check_frames_extended) { + cout << endl; + } + } + + for (Dwarf_Addr j = low_pc; j < low_pc + func_length; j++) { + FdeRegs fder(fde,config_data); + fder.setPc(j); + int fires = fder.preliminaryRead(&err); + if (fires == DW_DLV_ERROR) { + print_error(dbg, + "dwarf_get_fde_info_for_reg", fires, err); + } + if (fires == DW_DLV_NO_ENTRY) { + continue; + } + if (config_data->cf_interface_number == 3) { + Dwarf_Addr row_pc = 0; + Dwarf_Regtable_Entry3 cfadata; + // cfdata is a plain-C struct from libdwarf. + memset(&cfadata,0,sizeof(cfadata)); + int fires2 = fder.getCfaRegdata(&cfadata,&row_pc,&err); + if (fires2 == DW_DLV_ERROR) { + print_error(dbg, + "dwarf_get_fde_info_for_reg", fires, err); + } + if (fires2 == DW_DLV_NO_ENTRY) { + continue; + } + if (row_pc != j) { + /* duplicate row */ + continue; + } + if (!printed_intro_addr & !check_frames_extended) { + cout <<" "; + cout << IToHex0N(j,10); + cout <<": "; + printed_intro_addr = true; + } + print_one_frame_reg_col(dbg, config_data->cf_cfa_reg, + cfadata.dw_value_type, + cfadata.dw_regnum, + address_size, + config_data, + cfadata.dw_offset_relevant, + cfadata.dw_offset_or_block_len, + cfadata.dw_block_ptr); + } + for (unsigned k = 0; k < config_data->cf_table_entry_count; k++) { + Dwarf_Addr row_pc = 0; + Dwarf_Regtable_Entry3 cfadata; + memset(&cfadata,0, sizeof(cfadata)); + + int fires3 = fder.getRegdata(k,&cfadata,&row_pc,&err); + + if (fires3 == DW_DLV_ERROR) { + cout << endl; + print_error(dbg, + "dwarf_get_fde_info_for_reg", fires, err); + } + if (fires == DW_DLV_NO_ENTRY) { + continue; + } + if (row_pc != j) { + /* duplicate row */ + break; + } + if (!printed_intro_addr && !check_frames_extended) { + cout << " " << IToHex0N(j,10) << ": "; + printed_intro_addr = true; + } + print_one_frame_reg_col(dbg,k, + cfadata.dw_value_type, + cfadata.dw_regnum, + address_size, + config_data, + cfadata.dw_offset_relevant, + cfadata.dw_offset_or_block_len, + cfadata.dw_block_ptr); + } + if (printed_intro_addr) { + cout << endl; + printed_intro_addr = false; + } + } + if (verbose > 1) { + Dwarf_Off fde_off; + Dwarf_Off cie_off; + + /* Get the fde instructions and print them in raw form, just + like cie instructions */ + Dwarf_Ptr instrs; + Dwarf_Unsigned ilen; + int res; + + res = dwarf_get_fde_instr_bytes(fde, &instrs, &ilen, &err); + int offres = + dwarf_fde_section_offset(dbg, fde, &fde_off, &cie_off, + &err); + if (offres == DW_DLV_OK) { + if(!check_frames_extended) { + cout << " fde section offset " << IToDec(fde_off) << + " " << + IToHex0N(fde_off,10); + cout << " cie offset for fde: " << IToDec(cie_off) << + " " << + IToHex0N(cie_off,10); + cout << endl; + } + } + + if (res == DW_DLV_OK) { + int cires = 0; + Dwarf_Unsigned cie_length = 0; + Dwarf_Small version = 0; + Dwarf_Unsigned code_alignment_factor = 0; + Dwarf_Signed data_alignment_factor = 0; + Dwarf_Half return_address_register_rule = 0; + Dwarf_Ptr initial_instructions = 0; + Dwarf_Unsigned initial_instructions_length = 0; + + if (cie_index >= cie_element_count) { + cout << "Bad cie index " << IToDec(cie_index); + cout << " with fde index " << IToDec(fde_index); + cout << "! (table entry max " << IToDec(cie_element_count); + cout << ")" << endl; + exit(1); + } + + char *augmenter_arg = 0; + cires = dwarf_get_cie_info(cie_data[cie_index], + &cie_length, + &version, + &augmenter_arg, + &code_alignment_factor, + &data_alignment_factor, + &return_address_register_rule, + &initial_instructions, + &initial_instructions_length, + &err); + if (cires == DW_DLV_ERROR) { + cout << "Bad cie index " << IToDec(cie_index); + cout << " with fde index " << IToDec(fde_index); + cout << "!" << endl; + print_error(dbg, "dwarf_get_cie_info", cires, err); + } + if (cires == DW_DLV_NO_ENTRY) { + ; /* ? */ + } else { + if(!check_frames_extended) { + print_frame_inst_bytes(dbg, instrs, + (Dwarf_Signed) ilen, + data_alignment_factor, + (int) code_alignment_factor, + address_size, config_data); + } + } + } else if (res == DW_DLV_NO_ENTRY) { + cout <<"Impossible: no instr bytes for fde index " << + IToDec(fde_index) << endl; + } else { + /* DW_DLV_ERROR */ + cout << "Error: on gettinginstr bytes for fde index " << + IToDec(fde_index) << endl; + print_error(dbg, "dwarf_get_fde_instr_bytes", res, err); + } + + } + return DW_DLV_OK; +} + + +/* Print a cie. Gather the print logic here so the + control logic deciding what to print + is clearer. +*/ +int +print_one_cie(Dwarf_Debug dbg, Dwarf_Cie cie, + Dwarf_Unsigned cie_index, Dwarf_Half address_size, + struct dwconf_s *config_data) +{ + int cires = 0; + Dwarf_Unsigned cie_length = 0; + Dwarf_Small version = 0; + Dwarf_Unsigned code_alignment_factor = 0; + Dwarf_Signed data_alignment_factor = 0; + Dwarf_Half return_address_register_rule = 0; + Dwarf_Ptr initial_instructions = 0; + Dwarf_Unsigned initial_instructions_length = 0; + Dwarf_Off cie_off = 0; + Dwarf_Error err = 0; + + char *augmenter_arg = 0; + cires = dwarf_get_cie_info(cie, + &cie_length, + &version, + &augmenter_arg, + &code_alignment_factor, + &data_alignment_factor, + &return_address_register_rule, + &initial_instructions, + &initial_instructions_length, &err); + if (cires == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_cie_info", cires, err); + } + if (cires == DW_DLV_NO_ENTRY) { + cout << "Impossible DW_DLV_NO_ENTRY on cie " << + IToDec(cie_index) << endl; + return DW_DLV_NO_ENTRY; + } + { + if(!check_frames_extended) { + string augmenter = augmenter_arg; + cout << BracketSurround(IToDec(cie_index,5)); + cout << "\tversion\t\t\t\t" << static_cast<int>(version) << endl; + cires = dwarf_cie_section_offset(dbg, cie, &cie_off, &err); + if (cires == DW_DLV_OK) { + cout << "\tcie section offset\t\t" << IToDec(cie_off); + cout << " " << IToHex0N(cie_off,10) << endl; + } + + cout << "\taugmentation\t\t\t" << augmenter << endl; + cout << "\tcode_alignment_factor\t\t" << + code_alignment_factor << endl; + cout << "\tdata_alignment_factor\t\t" << + data_alignment_factor << endl; + cout << "\treturn_address_register\t\t" << + return_address_register_rule << endl; + } + { + int ares = 0; + Dwarf_Small *data = 0; + Dwarf_Unsigned len = 0; + + ares = + dwarf_get_cie_augmentation_data(cie, &data, &len, &err); + if (ares == DW_DLV_NO_ENTRY) { + /* do nothing. */ + } else if (ares == DW_DLV_OK && len > 0) { + if(!check_frames_extended) { + cout << " eh aug data len " << + IToHex(len); + for (unsigned k2 = 0; data && k2 < len; ++k2) { + if (k2 == 0) { + cout <<" bytes 0x"; + } + cout << IToHex02(data[k2]) << " "; + } + cout << endl; + } + } /* else DW_DLV_ERROR or no data, do nothing */ + } + + if(!check_frames_extended) { + cout << + "\tbytes of initial instructions\t" << + IToDec(initial_instructions_length) << endl; + cout <<"\tcie length\t\t\t" <<IToDec(cie_length) << endl; + cout << "\tinitial instructions" << endl; + print_frame_inst_bytes(dbg, initial_instructions, + (Dwarf_Signed) initial_instructions_length, + data_alignment_factor, + (int) code_alignment_factor, + address_size, config_data); + } + } + return DW_DLV_OK; +} + +void +get_string_from_locs(Dwarf_Debug dbg, + Dwarf_Ptr bytes_in, + Dwarf_Unsigned block_len, + Dwarf_Half addr_size, + string &out_string) +{ + + Dwarf_Locdesc *locdescarray = 0; + Dwarf_Signed listlen = 0; + Dwarf_Error err2 =0; + int skip_locdesc_header=1; + int res = 0; + int res2 = dwarf_loclist_from_expr_a(dbg, + bytes_in,block_len, + addr_size, + &locdescarray, + &listlen,&err2); + if (res2 == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_loclist_from_expr_a", + res2, err2); + } + if(res2==DW_DLV_NO_ENTRY) { + return; + } + /* lcnt is always 1 */ + + /* Use locdescarray here.*/ + res = dwarfdump_print_one_locdesc(dbg, + locdescarray, + skip_locdesc_header, + out_string); + if(res != DW_DLV_OK) { + cout <<"Bad status from _dwarf_print_one_locdesc " << + res << endl; + exit(1); + } + dwarf_dealloc(dbg, locdescarray->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(dbg, locdescarray, DW_DLA_LOCDESC); + return ; +} + +/* Print the frame instructions in detail for a glob of instructions. +*/ + +/*ARGSUSED*/ void +print_frame_inst_bytes(Dwarf_Debug dbg, + Dwarf_Ptr cie_init_inst, Dwarf_Signed len, + Dwarf_Signed data_alignment_factor, + int code_alignment_factor, Dwarf_Half addr_size, + struct dwconf_s *config_data) +{ + unsigned char *instp = (unsigned char *) cie_init_inst; + Dwarf_Unsigned uval = 0; + Dwarf_Unsigned uval2 = 0; + unsigned int uleblen = 0; + unsigned int off = 0; + unsigned int loff = 0; + unsigned short u16 = 0; + unsigned int u32 = 0; + unsigned long long u64 = 0; + + for (; len > 0;) { + unsigned char ibyte = *instp; + int top = ibyte & 0xc0; + int bottom = ibyte & 0x3f; + int delta = 0; + int reg = 0; + const char *cfa_name_x = 0; + string cfa_name("Unknown-frame-operator"); + int res = dwarf_get_CFA_name(top,&cfa_name_x); + // The odd character of DFA symbols because of + // the packing means DW_CFA_extended and DW_CFA_nop + // conflict. + if(res == DW_DLV_OK) { + cfa_name = cfa_name_x; + } + switch (top) { + case DW_CFA_advance_loc: + delta = ibyte & 0x3f; + cout << "\t" << IToDec(off,2); + cout << " DW_CFA_advance_loc " << + (delta * code_alignment_factor); + if (verbose) { + cout <<" (" << delta << " * " << + code_alignment_factor << ")"; + } + cout << endl; + break; + case DW_CFA_offset: + loff = off; + reg = ibyte & 0x3f; + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << " DW_CFA_offset " ; + printreg((Dwarf_Signed) reg, config_data); + cout << " " << (((Dwarf_Signed) uval) * data_alignment_factor); + if (verbose) { + cout << " (" << uval << " * " << data_alignment_factor << + ")"; + } + cout << endl; + break; + + case DW_CFA_restore: + reg = ibyte & 0x3f; + cout << "\t" << IToDec(off,2) << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) reg, config_data); + cout << endl; + break; + + default: + res = dwarf_get_CFA_name(bottom,&cfa_name_x); + if(res == DW_DLV_OK) { + cfa_name = cfa_name_x; + } + loff = off; + switch (bottom) { + case DW_CFA_set_loc: + /* operand is address, so need address size */ + /* which will be 4 or 8. */ + switch (addr_size) { + case 4: + { + __uint32_t v32 = 0; + memcpy(&v32, instp + 1, addr_size); + uval = v32; + } + break; + case 8: + { + __uint64_t v64 = 0; + memcpy(&v64, instp + 1, addr_size); + uval = v64; + } + break; + default: + cout << + "Error: Unexpected address size " << + addr_size << " in DW_CFA_set_loc!" << endl; + uval = 0; + } + + instp += addr_size; + len -= (Dwarf_Signed) addr_size; + off += addr_size; + cout << "\t" << IToDec(loff,2); + cout << " DW_CFA_set_loc " << uval << endl; + break; + case DW_CFA_advance_loc1: + delta = (unsigned char) *(instp + 1); + uval2 = delta; + instp += 1; + len -= 1; + off += 1; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << uval2 << endl; + break; + case DW_CFA_advance_loc2: + memcpy(&u16, instp + 1, 2); + uval2 = u16; + instp += 2; + len -= 2; + off += 2; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << uval2 << endl; + break; + case DW_CFA_advance_loc4: + memcpy(&u32, instp + 1, 4); + uval2 = u32; + instp += 4; + len -= 4; + off += 4; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << uval2 << endl; + break; + case DW_CFA_MIPS_advance_loc8: + memcpy(&u64, instp + 1, 8); + uval2 = u64; + instp += 8; + len -= 8; + off += 8; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << uval2 << endl; + break; + case DW_CFA_offset_extended: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << " " << (Dwarf_Signed) (((Dwarf_Signed) uval2) * + data_alignment_factor); + if (verbose) { + cout << " (" << uval2 << " * " << + data_alignment_factor << ")"; + } + cout << endl; + break; + + case DW_CFA_restore_extended: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << endl; + break; + case DW_CFA_undefined: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << endl; + break; + case DW_CFA_same_value: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << endl; + break; + case DW_CFA_register: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout <<" = "; + printreg((Dwarf_Signed) uval2, config_data); + cout << endl; + break; + case DW_CFA_remember_state: + cout << "\t" << IToDec(loff,2); + cout << " " << cfa_name; + cout << endl; + break; + case DW_CFA_restore_state: + cout << "\t" << IToDec(loff,2); + cout << " " << cfa_name; + cout << endl; + break; + case DW_CFA_def_cfa: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << " " << uval2; + cout << endl; + break; + case DW_CFA_def_cfa_register: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << endl; + break; + case DW_CFA_def_cfa_offset: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << uval; + cout << endl; + break; + + case DW_CFA_nop: + cout << "\t" << IToDec(loff,2); + // cfa name is wrong here due to + // cfa operation value conflict + cout << " " << "DW_CFA_nop"; + cout << endl; + break; + + case DW_CFA_def_cfa_expression: /* DWARF3 */ + { + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << + " " << cfa_name << " expr block len " << + block_len << endl; + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + cout << endl; + if(verbose) { + string exprstring; + get_string_from_locs(dbg, + instp+1,block_len, addr_size,exprstring); + cout << "\t\t" << exprstring << endl; + } + instp += block_len; + len -= block_len; + off += block_len; + } + break; + case DW_CFA_expression: /* DWARF3 */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << uval ; + cout << " expr block len " << block_len << endl; + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + cout << endl; + if(verbose) { + string exprstring; + get_string_from_locs(dbg, + instp+1,block_len, addr_size,exprstring); + cout<< "\t\t" <<exprstring << endl; + } + instp += block_len; + len -= block_len; + off += block_len; + } + + break; + case DW_CFA_offset_extended_sf: /* DWARF3 */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << " " << ((Dwarf_Signed) + ((sval2) * data_alignment_factor)); + if (verbose) { + cout << " (" << sval2 << " * "<< + data_alignment_factor << ")"; + } + } + cout << endl; + break; + case DW_CFA_def_cfa_sf: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << " "<< sval2 ; + cout << " (*data alignment factor=>" << + ((Dwarf_Signed)(sval2*data_alignment_factor)) << + ")"; + } + cout << endl; + break; + case DW_CFA_def_cfa_offset_sf: /* DWARF3 */ + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Signed sval = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << sval; + cout << " (*data alignment factor=> "<< + ((Dwarf_Signed)(sval*data_alignment_factor)) << + ")" << endl; + } + break; + case DW_CFA_val_offset: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed)uval, config_data); + cout << " " << + ((Dwarf_Signed) (sval2 * + data_alignment_factor)); + if (verbose) { + cout <<" ("<< sval2 << + " * " << data_alignment_factor; + } + } + cout << endl; + break; + case DW_CFA_val_offset_sf: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name); + printreg((Dwarf_Signed) uval, config_data); + cout << " " << ((sval2) * data_alignment_factor); + if (verbose) { + cout << " (" << sval2<< " * " << + data_alignment_factor << ")"; + } + } + cout << endl; + break; + case DW_CFA_val_expression: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << uval; + cout << " expr block len " << block_len << endl; + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + cout << endl; + if(verbose) { + string exprstring; + get_string_from_locs(dbg, + instp+1,block_len, addr_size,exprstring); + cout<< "\t\t" <<exprstring << endl; + } + instp += block_len; + len -= block_len; + off += block_len; + } + + + break; + + +#ifdef DW_CFA_GNU_window_save + case DW_CFA_GNU_window_save:{ + /* No information: this just tells unwinder to + the window registers from the previous + frame's window save area */ + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << endl; + } + break; +#endif +#ifdef DW_CFA_GNU_negative_offset_extended + case DW_CFA_GNU_negative_offset_extended:{ + cout << "\t" << IToDec(loff,2); + cout << SpaceSurround(cfa_name) << + endl; + } + break; +#endif +#ifdef DW_CFA_GNU_args_size + /* Single uleb128 is the current arg area size in + bytes. no register exists yet to save this in */ + case DW_CFA_GNU_args_size:{ + Dwarf_Unsigned lreg; + + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + lreg = local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + cout << "\t" << IToDec(loff,2); + cout << " " << cfa_name << " arg size: " << + lreg << endl; + instp += uleblen; + len -= uleblen; + off += uleblen; + } + break; +#endif + + default: + cout << "\t" << IToDec(loff,2); + cout << " Unexpected op " << + IToHex(bottom) << ":" << endl; + len = 0; + break; + } + } + instp++; + len--; + off++; + } +} + +/* Print our register names for the cases we have a name. + Delegate to the configure code to actually do the print. +*/ +void +printreg(Dwarf_Signed reg, struct dwconf_s *config_data) +{ + print_reg_from_config_data(reg, config_data); +} + + +/* Actually does the printing of a rule in the table. + This may print something or may print nothing! +*/ + +static void +print_one_frame_reg_col(Dwarf_Debug dbg, + Dwarf_Unsigned rule_id, + Dwarf_Small value_type, + Dwarf_Unsigned reg_used, + Dwarf_Half address_size, + struct dwconf_s *config_data, + Dwarf_Signed offset_relevant, + Dwarf_Signed offset, + Dwarf_Ptr block_ptr) +{ + string type_title = ""; + int print_type_title = 1; + if (check_frames_extended) { + return; + } + + if (config_data->cf_interface_number == 2) + print_type_title = 0; + + switch (value_type) { + case DW_EXPR_OFFSET: + type_title = "off"; + goto preg2; + case DW_EXPR_VAL_OFFSET: + type_title = "valoff"; + + preg2: + if (reg_used == config_data->cf_initial_rule_value) { + break; + } + if (print_type_title) + cout << "<" << type_title << " "; + printreg((Dwarf_Signed) rule_id, config_data); + cout << "="; + if (offset_relevant == 0) { + printreg((Dwarf_Signed) reg_used, config_data); + cout << " "; + } else { + cout << IToDec0N(offset,2); + cout << "("; + printreg((Dwarf_Signed) reg_used, config_data); + cout << ") "; + } + if (print_type_title) + cout << "> "; + break; + case DW_EXPR_EXPRESSION: + type_title = "expr"; + goto pexp2; + case DW_EXPR_VAL_EXPRESSION: + type_title = "valexpr"; + + pexp2: + if (print_type_title) + cout << "<" << type_title << " "; + printreg((Dwarf_Signed) rule_id, config_data); + cout << "="; + cout << "expr-block-len=" << offset; + if (print_type_title) + cout << "> "; + if (verbose) { + if(block_ptr == 0) { + // Wrong (old) register access used. + // -R being just one way to request the 'reg3' + // register interfaces. + cout << "<Use -R to see content>"; + } else { + string pref("<"); + pref.append(type_title); + pref.append("bytes:"); + dump_block(pref, reinterpret_cast<char *>(block_ptr), offset); + cout << "> "; + if(verbose) { + string exprstring; + get_string_from_locs(dbg, + block_ptr,offset, address_size,exprstring); + cout<< BracketSurround(string("expr:") + + exprstring); + } + } + } + break; + default: + cout <<"Internal error in libdwarf, value type " << + value_type << endl; + exit(1); + } + return; + +} + +/* get all the data in .debug_frame (or .eh_frame). + The '3' versions mean print using the dwarf3 new interfaces. + The non-3 mean use the old interfaces. + All combinations of requests are possible. */ +extern void +print_frames(Dwarf_Debug dbg, int print_debug_frame, int print_eh_frame, + struct dwconf_s *config_data) +{ + Dwarf_Half address_size = 0; + LowpcToNameMaptype map_lowpc_to_name; + + + error_message_data.current_section_id = DEBUG_FRAME; + + // The address size here will not be right for all frames. + // Only in DWARF4 is there a real address size known + // in the frame data itself. If any DIE + // is known then a real address size can be gotten from + // dwarf_get_die_address_size(). + int fres = dwarf_get_address_size(dbg, &address_size, &err); + if (fres != DW_DLV_OK) { + print_error(dbg, "dwarf_get_address_size", fres, err); + } + for (int framed = 0; framed < 2; ++framed) { + Dwarf_Cie *cie_data = NULL; + Dwarf_Signed cie_element_count = 0; + Dwarf_Fde *fde_data = NULL; + Dwarf_Signed fde_element_count = 0; + Dwarf_Signed i; + int frame_count = 0; + int cie_count = 0; + bool all_cus_seen(false); + LowpcUsedSettype lowpcSet; + string framename; + int silent_if_missing = 0; + int is_eh = 0; + + if (framed == 0) { + if (!print_debug_frame) { + continue; + } + framename = ".debug_frame"; + /* Big question here is how to print all the info? + Can print the logical matrix, but that is huge, + though could skip lines that don't change. + Either that, or print the instruction statement program + that describes the changes. */ + fres = dwarf_get_fde_list(dbg, &cie_data, &cie_element_count, + &fde_data, &fde_element_count, &err); + if(check_harmless) { + print_any_harmless_errors(dbg); + } + } else { + if (!print_eh_frame) { + continue; + } + is_eh = 1; + /* This is gnu g++ exceptions in a .eh_frame section. Which + is just like .debug_frame except that the empty, or + 'special' CIE_id is 0, not -1 (to distinguish fde from + cie). And the augmentation is "eh". As of egcs-1.1.2 + anyway. A non-zero cie_id is in a fde and is the + difference between the fde address and the beginning of + the cie it belongs to. This makes sense as this is + intended to be referenced at run time, and is part of + the running image. For more on augmentation strings, see + libdwarf/dwarf_frame.c. */ + + /* Big question here is how to print all the info? + Can print the logical matrix, but that is huge, + though could skip lines that don't change. + Either that, or print the instruction statement program + that describes the changes. */ + silent_if_missing = 1; + framename = ".eh_frame"; + fres = dwarf_get_fde_list_eh(dbg, &cie_data, + &cie_element_count, &fde_data, + &fde_element_count, &err); + if(check_harmless) { + print_any_harmless_errors(dbg); + } + } + /* Do not print any frame info if in check mode */ + if (check_frames) { + continue; + } + + if (fres == DW_DLV_ERROR) { + cout << endl; + cout << framename; + cout << endl; + print_error(dbg, "dwarf_get_fde_list", fres, err); + } else if (fres == DW_DLV_NO_ENTRY) { + if (!silent_if_missing) { + cout << endl; + cout << framename; + cout << endl; + } + /* no frame information */ + } else { /* DW_DLV_OK */ + + if( !check_frames_extended) { + cout << endl; + cout << framename; + cout << endl; + cout << endl; + cout << "fde:"; + cout << endl; + } + + for (i = 0; i < fde_element_count; i++) { + print_one_fde(dbg, fde_data[i], + i, cie_data, cie_element_count, + address_size, is_eh, config_data, + map_lowpc_to_name, + lowpcSet, + all_cus_seen); + ++frame_count; + if(frame_count >= break_after_n_units) { + break; + } + } + /* Print the cie set. */ + if (verbose) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + cout << endl; + cout << "cie:"; + cout << endl; + } + for (i = 0; i < cie_element_count; i++) { + print_one_cie(dbg, cie_data[i], i, address_size, + config_data); + ++cie_count; + if(cie_count >= break_after_n_units) { + break; + } + } + } + dwarf_fde_cie_list_dealloc(dbg, cie_data, cie_element_count, + fde_data, fde_element_count); + } + } +} + diff --git a/dwarfdump2/print_frames.h b/dwarfdump2/print_frames.h new file mode 100644 index 0000000..5bdc27d --- /dev/null +++ b/dwarfdump2/print_frames.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 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_frames.h,v 1.2 2006/04/17 00:09:56 davea Exp $ */ + +int +print_one_fde(Dwarf_Debug dbg, Dwarf_Fde fde, + Dwarf_Unsigned fde_index, + Dwarf_Cie * cie_data, + Dwarf_Signed cie_element_count, + Dwarf_Half address_size, + int is_eh, + struct dwconf_s * config_data); + +int +print_one_cie(Dwarf_Debug dbg, Dwarf_Cie cie, + Dwarf_Unsigned cie_index, + Dwarf_Half address_size, + struct dwconf_s * config_data); + +void +get_string_from_locs(Dwarf_Debug dbg, + Dwarf_Ptr bytes_in, + Dwarf_Unsigned block_len, + Dwarf_Half addr_size, + std::string &out_string); + + diff --git a/dwarfdump2/print_lines.cc b/dwarfdump2/print_lines.cc new file mode 100644 index 0000000..ce965ce --- /dev/null +++ b/dwarfdump2/print_lines.cc @@ -0,0 +1,435 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "uri.h" +#include "dwconf.h" + +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +static void +print_source_intro(Dwarf_Die cu_die) +{ + Dwarf_Off off = 0; + int ores = dwarf_dieoffset(cu_die, &off, &err); + + if (ores == DW_DLV_OK) { + cout << "Source lines (from CU-DIE at .debug_info offset "; + cout << IToHex0N(off,10); + cout << "):" << endl; + } else { + cout <<"Source lines (for the CU-DIE at unknown location):" << + endl; + } +} + +static void +record_line_error(const std::string &where, Dwarf_Error err) +{ + if(check_lines && checking_this_compiler()) { + string msg("Error getting line details calling "); + msg.append(where); + msg.append(" dwarf error is "); + + const char *estring = dwarf_errmsg(err); + + msg.append(estring); + DWARF_CHECK_ERROR(lines_result,msg); + } +} + +/* Print line number information: + + filename + new basic-block + [line] [address] <new statement> +*/ + +void +print_line_numbers_this_cu(DieHolder & hcudie) +{ + Dwarf_Die cu_die = hcudie.die(); + Dwarf_Debug dbg = hcudie.dbg(); + + bool SkipRecord = false; + + error_message_data.current_section_id = DEBUG_LINE; + if(do_print_dwarf) { + cout << endl; + cout << ".debug_line: line number info for a single cu"<< endl; + } + if ( verbose > 1) { + int errcount = 0; + print_source_intro(cu_die); + SrcfilesHolder hsrcfiles; + print_one_die(hcudie, /* print_information= */ 1, + /* indent_level= */ 0, + hsrcfiles, + /* ignore_die_printed_flag= */true); + DWARF_CHECK_COUNT(lines_result,1); + int lres = dwarf_print_lines(cu_die, &err,&errcount); + if(errcount > 0) { + DWARF_ERROR_COUNT(lines_result,errcount); + DWARF_CHECK_COUNT(lines_result,(errcount-1)); + } + if (lres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_srclines details", lres, err); + } + return; + } + if(check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + int line_errs = 0; + dwarf_check_lineheader(cu_die,&line_errs); + if(line_errs > 0) { + DWARF_CHECK_ERROR_PRINT_CU(); + DWARF_ERROR_COUNT(lines_result,line_errs); + DWARF_CHECK_COUNT(lines_result,(line_errs-1)); + } + } + Dwarf_Signed linecount = 0; + Dwarf_Line *linebuf = NULL; + int lres = dwarf_srclines(cu_die, &linebuf, &linecount, &err); + if (lres == DW_DLV_ERROR) { + /* Do not terminate processing. */ + if (check_decl_file) { + DWARF_CHECK_COUNT(decl_file_result,1); + DWARF_CHECK_ERROR2(decl_file_result,"dwarf_srclines", + dwarf_errmsg(err)); + record_dwarf_error = false; /* Clear error condition */ + } else { + print_error(dbg, "dwarf_srclines", lres, err); + } + } else if (lres == DW_DLV_NO_ENTRY) { + /* no line information is included */ + } else { + if(do_print_dwarf) { + print_source_intro(cu_die); + if (verbose) { + SrcfilesHolder hsrcfiles; + print_one_die(hcudie, /* print_information= */ 1, + /* indent_level= */ 0, + hsrcfiles, + /* ignore_die_printed_flag= */true); + } + cout << endl; + cout << + "<pc> [row,col] NS BB ET PE EB IS= DI= uri: \"filepath\"" + << endl; + cout << + "NS new statement, BB new basic block, ET end of text sequence" + << endl; + cout << + "PE prologue end, EB epilogue begin" + << endl; + cout << + "IA=val ISA number, DI=val discriminator value" + << endl; + } + string lastsrc = ""; + for (Dwarf_Signed i = 0; i < linecount; i++) { + Dwarf_Line line = linebuf[i]; + char *filenamearg = 0; + bool found_line_error = false; + Dwarf_Bool has_is_addr_set = 0; + string where; + + if (check_decl_file && checking_this_compiler()) { + /* A line record with addr=0 was detected */ + if (SkipRecord) { + /* Skip records that do not have Ãs_addr_set' */ + int ares1 = dwarf_line_is_addr_set(line, &has_is_addr_set, &err); + if (ares1 == DW_DLV_OK && has_is_addr_set) { + SkipRecord = false; + } else { + /* Keep ignoring records until we have + one with 'is_addr_set' */ + continue; + } + } + } + + + if (check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + } + string filename("<unknown>"); + int sres = dwarf_linesrc(line, &filenamearg, &err); + if (sres == DW_DLV_ERROR) { + where = "dwarf_linesrc()"; + found_line_error = true; + record_line_error(where,err); + } + if (sres == DW_DLV_OK) { + filename = filenamearg; + dwarf_dealloc(dbg, filenamearg, DW_DLA_STRING); + filenamearg = 0; + } + Dwarf_Addr pc = 0; + int ares = dwarf_lineaddr(line, &pc, &err); + if (ares == DW_DLV_ERROR) { + where = "dwarf_lineaddr()"; + found_line_error = true; + record_line_error(where,err); + } + if (ares == DW_DLV_NO_ENTRY) { + pc = 0; + } + Dwarf_Unsigned lineno = 0; + int lires = dwarf_lineno(line, &lineno, &err); + if (lires == DW_DLV_ERROR) { + where = "dwarf_lineno()"; + found_line_error = true; + record_line_error(where,err); + } + if (lires == DW_DLV_NO_ENTRY) { + lineno = -1LL; + } + Dwarf_Unsigned column = 0; + int cores = dwarf_lineoff_b(line, &column, &err); + if (cores == DW_DLV_ERROR) { + where = "dwarf_lineoff()"; + found_line_error = true; + record_line_error(where,err); + } + if (cores == DW_DLV_NO_ENTRY) { + /* Zero was always the correct default, meaning + the left edge. DWARF2/3/4 spec sec 6.2.2 */ + column = 0; + } + + /* Process any possible error condition, though + we won't be at the first such error. */ + if (check_decl_file && checking_this_compiler()) { + DWARF_CHECK_COUNT(decl_file_result,1); + if (found_line_error) { + DWARF_CHECK_ERROR2(decl_file_result,where,dwarf_errmsg(err)); + } else if (do_check_dwarf) { + /* Check the address lies with a valid [lowPC:highPC] + in the .text section*/ + if (pAddressRangesData->IsAddressInAddressRange(pc)) { + /* Valid values; do nothing */ + } else { + /* At this point may be we are dealing with + a linkonce symbol. The problem we have here + is we have consumed the deug_info section + and we are dealing just with the records + from the .debug_line, so no PU_name is + available and no high_pc. Traverse the linkonce + table if try to match the pc value with + one of those ranges. + */ + if (check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + } + if (pLinkOnceData->FindLinkOnceEntry(pc)){ + /* Valid values; do nothing */ + } else { + /* The SN Systems Linker generates + line records + with addr=0, when dealing with linkonce + symbols and no stripping */ + if (pc) { + char addr_tmp[100]; + if(check_lines && checking_this_compiler()) { + snprintf(addr_tmp,sizeof(addr_tmp), + ".debug_line: Address" + " 0x%" DW_PR_XZEROS DW_PR_DUx + " outside a valid .text range",pc); + DWARF_CHECK_ERROR(lines_result, + addr_tmp); + } + } else { + SkipRecord = true; + } + } + } + /* Check the last record for the .debug_line, + the one created by DW_LNE_end_sequence, + is the same as the high_pc + address for the last known user program + unit (PU) */ + if ((i + 1 == linecount) && + error_message_data.seen_PU_high_address) { + /* Ignore those PU that have been stripped + by the linker; their low_pc values are + set to -1 (snc linker only) */ + /* It is perfectly sensible for a compiler + to leave a few bytes of NOP or other stuff + after the last instruction in a subprogram, + for cache-alignment or other purposes, so + a mismatch here is not necessarily + an error. */ + + if (check_lines && checking_this_compiler()) { + DWARF_CHECK_COUNT(lines_result,1); + if ((pc != error_message_data.PU_high_address) && + (error_message_data.PU_base_address != + error_message_data.elf_max_address)) { + char addr_tmp[100]; + snprintf(addr_tmp,sizeof(addr_tmp), + ".debug_line: Address" + " 0x%" DW_PR_XZEROS DW_PR_DUx + " may be incorrect" + " as DW_LNE_end_sequence address",pc); + DWARF_CHECK_ERROR(lines_result, + addr_tmp); + } + } + } + } + } + + /* Display the error information */ + if (found_line_error || record_dwarf_error) { + if (check_verbose_mode) { + /* Print the record number for better error description */ + cout << "Record = " << + i << " Addr = " << IToHex0N(pc,10) << + " [" << IToDec(lineno,4) << + ","<< IToDec(column,2) << + "] '" << filename << "'" << endl; + /* Flush due to the redirection of stderr */ + cout.flush(); + /* The compilation unit was already printed */ + if (!check_decl_file) { + PRINT_CU_INFO(); + } + } + record_dwarf_error = false; + /* Due to a fatal error, skip current record */ + if (found_line_error) { + continue; + } + } + + if(do_print_dwarf) { + cout << IToHex0N(pc,10) << " [" << + IToDec(lineno,4) << "," << + IToDec(column,2) << + "]" ; + } + + Dwarf_Bool newstatement = 0; + int nsres = dwarf_linebeginstatement(line, &newstatement, &err); + if (nsres == DW_DLV_OK) { + if (do_print_dwarf && newstatement) { + cout <<" NS"; + } + } else if (nsres == DW_DLV_ERROR) { + print_error(dbg, "linebeginstatment failed", nsres, + err); + } + Dwarf_Bool new_basic_block = 0; + nsres = dwarf_lineblock(line, &new_basic_block, &err); + if (nsres == DW_DLV_OK) { + if (do_print_dwarf && new_basic_block) { + cout <<" BB"; + } + } else if (nsres == DW_DLV_ERROR) { + print_error(dbg, "lineblock failed", nsres, err); + } + Dwarf_Bool lineendsequence = 0; + nsres = dwarf_lineendsequence(line, &lineendsequence, &err); + if (nsres == DW_DLV_OK) { + if (do_print_dwarf && lineendsequence) { + cout <<" ET"; + } + } else if (nsres == DW_DLV_ERROR) { + print_error(dbg, "lineblock failed", nsres, err); + } + if (do_print_dwarf) { + Dwarf_Bool prologue_end = 0; + Dwarf_Bool epilogue_begin = 0; + Dwarf_Unsigned isa = 0; + Dwarf_Unsigned discriminator = 0; + int disres = dwarf_prologue_end_etc(line, + &prologue_end,&epilogue_begin, + &isa,&discriminator,&err); + if (disres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_prologue_end_etc() failed", + disres, err); + } + if(prologue_end) { + cout <<" PE"; + } + if(epilogue_begin) { + cout <<" EB"; + } + if(isa) { + cout <<" IS="; + cout << IToHex(isa); + } + if(discriminator) { + cout <<" DI="; + cout << IToHex(discriminator); + } + } + + // Here avoid so much duplication of long file paths. + if (i > 0 && verbose < 3 && filename == lastsrc ){ + /* print no name, leave blank. */ + } else { + string urs(" uri: \""); + translate_to_uri(filename.c_str(),urs); + urs.append("\""); + if (do_print_dwarf) { + cout << urs ; + } + lastsrc = filename; + } + if(do_print_dwarf) { + cout << endl; + } + } + dwarf_srclines_dealloc(dbg, linebuf, linecount); + } +} + diff --git a/dwarfdump2/print_locs.cc b/dwarfdump2/print_locs.cc new file mode 100644 index 0000000..b4c5edc --- /dev/null +++ b/dwarfdump2/print_locs.cc @@ -0,0 +1,131 @@ +/* + 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 2008-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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* print data in .debug_loc + There is no guarantee this will work because we are assuming + that all bytes are valid loclist data, that there are no + odd padding or garbage bytes. In normal use one gets + into here via an offset from .debug_info, so it could be + that bytes not referenced from .debug_info are garbage + or even zero padding. So this can fail (error off) as such bytes + can lead dwarf_get_loclist_entry() astray. + + It is also broken because we do not know what CU is involved + so if address_size varies by CU we cannot know that here. +*/ + +void +print_locs(Dwarf_Debug dbg) +{ + Dwarf_Unsigned offset = 0; + Dwarf_Addr hipc_offset = 0; + Dwarf_Addr lopc_offset = 0; + Dwarf_Ptr data = 0; + Dwarf_Unsigned entry_len = 0; + Dwarf_Unsigned next_entry = 0; + int index = 0; + int lres = 0; + Dwarf_Half address_size = 0; + + error_message_data.current_section_id = DEBUG_LOC; + if(!do_print_dwarf) { + return; + } + + /* This is sometimes wrong, we need a frame-specific size. */ + int fres = dwarf_get_address_size(dbg, &address_size, &err); + if (fres != DW_DLV_OK) { + print_error(dbg, "dwarf_get_address_size", fres, err); + } + + + cout << endl; + cout << ".debug_loc" << endl; + cout <<"Format <i o b e l>: " + "index section-offset begin-addr end-addr length-of-block-entry"; + cout << endl; + while ((lres = dwarf_get_loclist_entry(dbg, offset, + &hipc_offset, &lopc_offset, + &data, &entry_len, + &next_entry, + &err)) == DW_DLV_OK) { + + string exprstring; + get_string_from_locs(dbg,data,entry_len,address_size,exprstring); + if( display_offsets) { + ++index; + cout <<" <iobel> [" << IToDec(index,8); + cout <<"] " << IToHex0N(offset,10); + // We print this offset so it matches what the debug_info + // loclist offset shows (so we can relate them). + // This offset is the offset of the expression byte blob. + if(verbose) { + cout << string(" ") << + BracketSurround(string("expr-off ") + + IToHex0N(next_entry - entry_len,10)); + } + } + cout <<" "<< IToHex0N(lopc_offset,10); + cout <<" "<< IToHex0N(hipc_offset,10); + cout <<" "<< IToDec(entry_len,8); + cout <<" "<< exprstring; + cout << endl; + offset = next_entry; + } + if (lres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_loclist_entry", lres, err); + } +} + diff --git a/dwarfdump2/print_macros.cc b/dwarfdump2/print_macros.cc new file mode 100644 index 0000000..b79c281 --- /dev/null +++ b/dwarfdump2/print_macros.cc @@ -0,0 +1,208 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +struct macro_counts_s { + long mc_start_file; + long mc_end_file; + long mc_define; + long mc_undef; + long mc_extension; + long mc_code_zero; + long mc_unknown; +}; + +static void +print_one_macro_entry_detail(long i, + const std::string&type, + struct Dwarf_Macro_Details_s *mdp) +{ + /* "DW_MACINFO_*: section-offset file-index [line] string\n" */ + cout << IToDec(i,3); + cout <<" " << type; + cout <<": " << IToDec(mdp->dmd_offset,6); + cout <<" " << IToDec(mdp->dmd_fileindex,2); + cout <<" [" << IToDec(mdp->dmd_lineno,4); + if (mdp->dmd_macro) { + cout <<"] \"" << mdp->dmd_macro << "\" " << endl; + } else { + cout <<"] 0" << endl; + } +} + + + +static void +print_one_macro_entry(long i, + struct Dwarf_Macro_Details_s *mdp, + struct macro_counts_s *counts) +{ + + switch (mdp->dmd_type) { + case 0: + counts->mc_code_zero++; + print_one_macro_entry_detail(i, "DW_MACINFO_type-code-0", mdp); + break; + + case DW_MACINFO_start_file: + counts->mc_start_file++; + print_one_macro_entry_detail(i, "DW_MACINFO_start_file", mdp); + break; + + case DW_MACINFO_end_file: + counts->mc_end_file++; + print_one_macro_entry_detail(i, "DW_MACINFO_end_file ", mdp); + break; + + case DW_MACINFO_vendor_ext: + counts->mc_extension++; + print_one_macro_entry_detail(i, "DW_MACINFO_vendor_ext", mdp); + break; + + case DW_MACINFO_define: + counts->mc_define++; + print_one_macro_entry_detail(i, "DW_MACINFO_define ", mdp); + break; + + case DW_MACINFO_undef: + counts->mc_undef++; + print_one_macro_entry_detail(i, "DW_MACINFO_undef ", mdp); + break; + + default: + { + char create_type[50]; /* More than large enough. */ + + counts->mc_unknown++; + snprintf(create_type, sizeof(create_type), + "DW_MACINFO_0x%x", mdp->dmd_type); + print_one_macro_entry_detail(i, create_type, mdp); + } + break; + } +} + +/* print data in .debug_macinfo */ +/* FIXME: should print name of file whose index is in macro data + here -- somewhere. +*/ +/*ARGSUSED*/ extern void +print_macinfo(Dwarf_Debug dbg) +{ + Dwarf_Off offset = 0; + Dwarf_Unsigned max = 0; + Dwarf_Signed count = 0; + long group = 0; + Dwarf_Macro_Details *maclist = NULL; + int lres = 0; + + error_message_data.current_section_id = DEBUG_MACINFO; + if(!do_print_dwarf) { + return; + } + cout << endl; + cout << ".debug_macinfo" << endl; + + while ((lres = dwarf_get_macro_details(dbg, offset, + max, &count, &maclist, + &err)) == DW_DLV_OK) { + long i; + struct macro_counts_s counts; + + + memset(&counts, 0, sizeof(counts)); + + cout << endl; + cout << "compilation-unit .debug_macinfo # " << group << endl; + cout << + "num name section-offset file-index [line] \"string\"" << endl; + for (i = 0; i < count; i++) { + struct Dwarf_Macro_Details_s *mdp = &maclist[i]; + + print_one_macro_entry(i, mdp, &counts); + } + + if (counts.mc_start_file == 0) { + cout << + "DW_MACINFO file count of zero is invalid DWARF2/3" <<endl; + } + if (counts.mc_start_file != counts.mc_end_file) { + cout << "Counts of DW_MACINFO file (" << counts.mc_start_file; + cout << ") end_file (" << counts.mc_end_file; + cout << ") do not match!." << endl; + } + if (counts.mc_code_zero < 1) { + cout <<"Count of zeros in macro group should be non-zero " + "(1 preferred), count is " << + counts.mc_code_zero << endl; + } + cout << "Macro counts: start file " << counts.mc_start_file; + cout << ", end file " << counts.mc_end_file; + cout << ", define " << counts.mc_define; + cout << ", undef " << counts.mc_undef; + cout << ", ext " << counts.mc_extension; + cout << ", code-zero " << counts.mc_code_zero; + cout << ", unknown " << counts.mc_unknown << endl; + + /* int type= maclist[count - 1].dmd_type; */ + /* ASSERT: type is zero */ + + offset = maclist[count - 1].dmd_offset + 1; + dwarf_dealloc(dbg, maclist, DW_DLA_STRING); + ++group; + } + if (lres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_macro_details", lres, err); + } +} + diff --git a/dwarfdump2/print_pubnames.cc b/dwarfdump2/print_pubnames.cc new file mode 100644 index 0000000..18d2f9e --- /dev/null +++ b/dwarfdump2/print_pubnames.cc @@ -0,0 +1,277 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* This unifies the code for some error checks to + avoid code duplication. +*/ +void +check_info_offset_sanity(const string & sec, + const string &field, + const string &global, + Dwarf_Unsigned offset, Dwarf_Unsigned maxoff) +{ + if (maxoff == 0) { + /* Lets make a heuristic check. */ + if (offset > 0xffffffff) { + cout << "Warning: section " << sec << " " << + field << " " << global; + cout << " offset" << IToHex(offset); + cout << " exceptionally large" << endl; + } + return; + } + if (offset >= maxoff) { + cout << "Warning: section " << sec << " " << + field << " " << global; + cout << " offset "<< IToHex(offset); + cout << " larger than max of " << IToHex(maxoff) << endl; + } +} + + + +/* Unified pubnames style output. + The error checking here against maxoff may be useless + (in that libdwarf may return an error if the offset is bad + and we will not get called here). + But we leave it in nonetheless as it looks sensible. + In at least one gigantic executable such offsets turned out wrong. +*/ +void +print_pubname_style_entry(Dwarf_Debug dbg, + const string & line_title, + const string & name, + Dwarf_Unsigned die_off, + Dwarf_Unsigned cu_off, + Dwarf_Unsigned global_cu_offset, + Dwarf_Unsigned maxoff) +{ + Dwarf_Die die = NULL; + Dwarf_Die cu_die = NULL; + Dwarf_Off die_CU_off = 0; + + /* get die at die_off */ + int dres = dwarf_offdie(dbg, die_off, &die, &err); + if (dres != DW_DLV_OK) { + string details = string(line_title) + string(" dwarf_offdie : " + "die offset does not reference valid DIE. ") + + IToHex(die_off) + + string("."); + print_error(dbg, details.c_str(), dres, err); + } + DieHolder(dbg,die); + + + /* get offset of die from its cu-header */ + int ddres = dwarf_die_CU_offset(die, &die_CU_off, &err); + if (ddres != DW_DLV_OK) { + string details = string(line_title) + " cannot get CU die offset"; + print_error(dbg, details.c_str(), ddres, err); + } + + /* get die at offset cu_off */ + int cudres = dwarf_offdie(dbg, cu_off, &cu_die, &err); + if (cudres != DW_DLV_OK) { + string details = string(line_title) + string(" dwarf_offdie: " + "die offset does not reference valid CU DIE. ") + + IToHex(cu_off) + + string("."); + dwarf_dealloc(dbg, die, DW_DLA_DIE); + print_error(dbg, details.c_str(), cudres, err); + } + if( display_offsets) { + /* Print 'name'at the end for better layout */ + cout << line_title ; + cout << " die-in-sect " << IToHex0N(die_off,10); + cout << ", cu-in-sect " << IToHex0N(cu_off,10); + cout << ", die-in-cu " << IToHex0N(die_CU_off,10); + /* Following is absolute offset of the ** beginning of the + cu */ + cout << ", cu-header-in-sect " << + IToHex0N((die_off - die_CU_off),10); + } + + if ((die_off - die_CU_off) != global_cu_offset) { + cout << line_title << " error: real cuhdr "<< global_cu_offset << endl; + exit(1); + } + if (display_offsets && verbose) { + cout << " cuhdr " << IToHex0N(global_cu_offset,10); + } + cout << " '" << name << "'" << endl; + + + dwarf_dealloc(dbg, die, DW_DLA_DIE); + dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); + + check_info_offset_sanity(line_title, + "die offset", name, die_off, maxoff); + check_info_offset_sanity(line_title, + "die cu offset", name, die_CU_off, maxoff); + check_info_offset_sanity(line_title, + "cu offset", name, + (die_off - die_CU_off), maxoff); +} + + +/* get all the data in .debug_pubnames */ +extern void +print_pubnames(Dwarf_Debug dbg) +{ + Dwarf_Global *globbuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + char *name = 0; + /* Offset to previous CU */ + Dwarf_Off prev_cu_off = error_message_data.elf_max_address; + + error_message_data.current_section_id = DEBUG_PUBNAMES; + if (do_print_dwarf) { + cout << endl; + cout << ".debug_pubnames" << endl; + } + int res = dwarf_get_globals(dbg, &globbuf, &count, &err); + if (res == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_globals", res, err); + } else if (res == DW_DLV_NO_ENTRY) { + /* (err == 0 && count == DW_DLV_NOCOUNT) means there are no + pubnames. */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (i = 0; i < count; i++) { + int nres; + int cures3; + Dwarf_Off global_cu_off = 0; + + nres = dwarf_global_name_offsets(globbuf[i], + &name, &die_off, &cu_off, &err); + deal_with_name_offset_err(dbg, "pubnames dwarf_global_name_offsets", + name, die_off, nres, err); + cures3 = dwarf_global_cu_offset(globbuf[i], + &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "pubnames dwarf_global_cu_offset", + cures3, err); + } + if (check_pubname_attr) { + Dwarf_Bool has_attr; + int ares; + int dres; + Dwarf_Die die; + + /* We are processing a new set of pubnames + for a different CU; get the producer ID, at 'cu_off' + to see if we need to skip these pubnames */ + if (cu_off != prev_cu_off) { + string producer_name; + + /* Record offset for previous CU */ + prev_cu_off = cu_off; + + dres = dwarf_offdie(dbg, cu_off, &die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "print pubnames: dwarf_offdie a", dres,err); + } + + DieHolder hdie(dbg,die); + /* Get producer name for this CU and update compiler list */ + get_producer_name(hdie,err,producer_name); + update_compiler_target(producer_name); + } + + /* get die at die_off */ + dres = dwarf_offdie(dbg, die_off, &die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "print pubnames: dwarf_offdie b", dres, err); + } + + + ares = + dwarf_hasattr(die, DW_AT_external, &has_attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "hassattr on DW_AT_external", ares, + err); + } + + /* Check for specific compiler */ + if (checking_this_compiler()) { + DWARF_CHECK_COUNT(pubname_attr_result,1); + if (ares == DW_DLV_OK && has_attr) { + /* Should the value of flag be examined? */ + } else { + DWARF_CHECK_ERROR2(pubname_attr_result,name, + "pubname does not have DW_AT_external"); + } + } + dwarf_dealloc(dbg, die, DW_DLA_DIE); + } + + /* Now print pubname, after the test */ + if (do_print_dwarf || (record_dwarf_error && check_verbose_mode)) { + print_pubname_style_entry(dbg, + "global", + name, die_off, cu_off, + global_cu_off, maxoff); + record_dwarf_error = false; // Clear error condition. + } + } + dwarf_globals_dealloc(dbg, globbuf, count); + } +} /* print_pubnames() */ + diff --git a/dwarfdump2/print_ranges.cc b/dwarfdump2/print_ranges.cc new file mode 100644 index 0000000..338cd31 --- /dev/null +++ b/dwarfdump2/print_ranges.cc @@ -0,0 +1,121 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + + +/* Get all the data in .debug_ranges + Nothing in the DWARF standard guarantees just reading the + bytes in the section really works, but it will probably + normally work fine. + Here we don't have a DW_AT_ranges offset to get us + started. + + Because we do not know what DIE is involved, if the + object being printed has different address sizes + in different compilation units this will not work + properly: anything could happen. +*/ + +extern void +print_ranges(Dwarf_Debug dbg) +{ + Dwarf_Unsigned off = 0; + int group_number = 0; + int wasdense = 0; + + error_message_data.current_section_id = DEBUG_RANGES; + if (!do_print_dwarf) { + return; + } + + cout << endl; + cout << ".debug_ranges" << endl; + /* Turn off dense, we do not want print_ranges_list_to_extra + to use dense form here. */ + wasdense = dense; + dense = 0; + for(;;) { + Dwarf_Ranges *rangeset = 0; + Dwarf_Signed rangecount = 0; + Dwarf_Unsigned bytecount = 0; + + // We do not know what DIE is involved, we use the + // older call here. + int rres = dwarf_get_ranges(dbg,off,&rangeset, + &rangecount,&bytecount,&err); + if(rres == DW_DLV_OK) { + cout <<" Ranges group " << group_number << ":" << endl; + string exprstring = + print_ranges_list_to_extra(dbg,off, + rangeset,rangecount,bytecount); + dwarf_ranges_dealloc(dbg,rangeset,rangecount); + cout << exprstring; + ++group_number; + } else if (rres == DW_DLV_NO_ENTRY) { + cout << "End of .debug_ranges." << endl; + break; + } else { + /* ERROR, which does not quite mean a real error, + as we might just be misaligned reading things without + a DW_AT_ranges offset.*/ + cout << "End of .debug_ranges.." << endl; + break; + } + off += bytecount; + } + dense = wasdense; +} + + diff --git a/dwarfdump2/print_reloc.cc b/dwarfdump2/print_reloc.cc new file mode 100644 index 0000000..c95d3ce --- /dev/null +++ b/dwarfdump2/print_reloc.cc @@ -0,0 +1,1146 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 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_reloc.c,v 1.11 2005/08/04 05:09:37 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" +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +#define DW_SECTION_REL_DEBUG_NUM 9 /* Number of sections */ +/* .debug_abbrev should never have a relocation applied to it as it + never refers to another section! (other sections refer to + .debug_abbrev) */ + +#define DW_SECTNAME_RELA_DEBUG ".rela.debug_" +#define DW_SECTNAME_RELA_DEBUG_INFO ".rela.debug_info" +#define DW_SECTNAME_RELA_DEBUG_LINE ".rela.debug_line" +#define DW_SECTNAME_RELA_DEBUG_PUBNAMES ".rela.debug_pubnames" +#define DW_SECTNAME_RELA_DEBUG_ABBREV ".rela.debug_abbrev" +#define DW_SECTNAME_RELA_DEBUG_ARANGES ".rela.debug_aranges" +#define DW_SECTNAME_RELA_DEBUG_FRAME ".rela.debug_frame" +#define DW_SECTNAME_RELA_DEBUG_LOC ".rela.debug_loc" +#define DW_SECTNAME_RELA_DEBUG_RANGES ".rela.debug_ranges" +#define DW_SECTNAME_RELA_DEBUG_TYPES ".rela.debug_types" + +#define DW_SECTNAME_REL_DEBUG ".rel.debug_" +#define DW_SECTNAME_REL_DEBUG_INFO ".rel.debug_info" +#define DW_SECTNAME_REL_DEBUG_LINE ".rel.debug_line" +#define DW_SECTNAME_REL_DEBUG_PUBNAMES ".rel.debug_pubnames" +#define DW_SECTNAME_REL_DEBUG_ABBREV ".rel.debug_abbrev" +#define DW_SECTNAME_REL_DEBUG_ARANGES ".rel.debug_aranges" +#define DW_SECTNAME_REL_DEBUG_FRAME ".rel.debug_frame" +#define DW_SECTNAME_REL_DEBUG_LOC ".rel.debug_loc" +#define DW_SECTNAME_REL_DEBUG_RANGES ".rel.debug_ranges" +#define DW_SECTNAME_REL_DEBUG_TYPES ".rel.debug_types" + + +#define STRING_FOR_DUPLICATE " duplicate" +#define STRING_FOR_NULL " null" + +static const char *sectnames[] = { + DW_SECTNAME_REL_DEBUG_INFO, + DW_SECTNAME_REL_DEBUG_LINE, + DW_SECTNAME_REL_DEBUG_PUBNAMES, + DW_SECTNAME_REL_DEBUG_ABBREV, + DW_SECTNAME_REL_DEBUG_ARANGES, + DW_SECTNAME_REL_DEBUG_FRAME, + DW_SECTNAME_REL_DEBUG_LOC, + DW_SECTNAME_REL_DEBUG_RANGES, + DW_SECTNAME_REL_DEBUG_TYPES, +}; +static const char *sectnamesa[] = { + DW_SECTNAME_RELA_DEBUG_INFO, + DW_SECTNAME_RELA_DEBUG_LINE, + DW_SECTNAME_RELA_DEBUG_PUBNAMES, + DW_SECTNAME_RELA_DEBUG_ABBREV, + DW_SECTNAME_RELA_DEBUG_ARANGES, + DW_SECTNAME_RELA_DEBUG_FRAME, + DW_SECTNAME_RELA_DEBUG_LOC, + DW_SECTNAME_RELA_DEBUG_RANGES, + DW_SECTNAME_RELA_DEBUG_TYPES, +}; + +static const char *error_msg_duplicate[] = { + DW_SECTNAME_REL_DEBUG_INFO STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_LINE STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_PUBNAMES STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_ABBREV STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_ARANGES STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_FRAME STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_LOC STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_RANGES STRING_FOR_DUPLICATE, + DW_SECTNAME_REL_DEBUG_TYPES STRING_FOR_DUPLICATE, +}; + +static const char *error_msg_null[] = { + DW_SECTNAME_REL_DEBUG_INFO STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_LINE STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_PUBNAMES STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_ABBREV STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_ARANGES STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_FRAME STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_LOC STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_RANGES STRING_FOR_NULL, + DW_SECTNAME_REL_DEBUG_TYPES STRING_FOR_NULL, +}; + +/* Include Section type, to be able to deal with all the + Elf32_Rel, Elf32_Rela, Elf64_Rel, Elf64_Rela relocation types */ +#define SECT_DATA_SET(x,t,n) { \ + if (sect_data[(x)].buf != NULL) { \ + print_error(dbg, error_msg_duplicate[(x)],DW_DLV_OK, err); \ + } \ + if ((data = elf_getdata(scn, 0)) == NULL || data->d_size == 0) { \ + print_error(dbg, error_msg_null[(x)],DW_DLV_OK, err); \ + } \ + sect_data[(x)].buf = reinterpret_cast<Dwarf_Small *>(data -> d_buf); \ + sect_data[(x)].size = data -> d_size; \ + sect_data[(x)].type = t; \ + sect_data[(x)].name = n; \ + } + + +/* PowerPC relocations defined by the ABIs */ +static const char *reloc_type_names_PPC[] = { + "R_PPC_NONE", /* 00 */ + "R_PPC_ADDR32", /* 01 */ + "R_PPC_ADDR24", /* 02 */ + "R_PPC_ADDR16", /* 03 */ + "R_PPC_ADDR16_LO", /* 04 */ + "R_PPC_ADDR16_HI", /* 05 */ + "R_PPC_ADDR16_HA", /* 06 */ + "R_PPC_ADDR14", /* 07 */ + "R_PPC_ADDR14_BRTAKEN", /* 08 */ + "R_PPC_ADDR14_BRNTAKEN", /* 09 */ + "R_PPC_REL24", /* 10 */ + "R_PPC_REL14", /* 11 */ + "R_PPC_REL14_BRTAKEN", /* 12 */ + "R_PPC_REL14_BRNTAKEN", /* 13 */ + "R_PPC_GOT16", /* 14 */ + "R_PPC_GOT16_LO", /* 15 */ + "R_PPC_GOT16_HI", /* 16 */ + "R_PPC_GOT16_HA", /* 17 */ + "R_PPC_PLTREL24", /* 18 */ + "R_PPC_COPY", /* 19 */ + "R_PPC_GLOB_DAT", /* 20 */ + "R_PPC_JMP_SLOT", /* 21 */ + "R_PPC_RELATIVE", /* 22 */ + "R_PPC_LOCAL24PC", /* 23 */ + "R_PPC_UADDR32", /* 24 */ + "R_PPC_UADDR16", /* 25 */ + "R_PPC_REL32", /* 26 */ + "R_PPC_PLT32", /* 27 */ + "R_PPC_PLTREL32", /* 28 */ + "R_PPC_PLT16_LO", /* 29 */ + "R_PPC_PLT16_HI", /* 30 */ + "R_PPC_PLT16_HA", /* 31 */ + "R_PPC_SDAREL16", /* 32 */ + "R_PPC_SECTOFF", /* 33 */ + "R_PPC_SECTOFF_LO", /* 34 */ + "R_PPC_SECTOFF_HI", /* 35 */ + "R_PPC_SECTOFF_HA", /* 36 */ + "R_PPC_37", /* 37 */ + "R_PPC_38", /* 38 */ + "R_PPC_39", /* 39 */ + "R_PPC_40", /* 40 */ + "R_PPC_41", /* 41 */ + "R_PPC_42", /* 42 */ + "R_PPC_43", /* 43 */ + "R_PPC_44", /* 44 */ + "R_PPC_45", /* 45 */ + "R_PPC_46", /* 46 */ + "R_PPC_47", /* 47 */ + "R_PPC_48", /* 48 */ + "R_PPC_49", /* 49 */ + "R_PPC_50", /* 50 */ + "R_PPC_51", /* 51 */ + "R_PPC_52", /* 52 */ + "R_PPC_53", /* 53 */ + "R_PPC_54", /* 54 */ + "R_PPC_55", /* 55 */ + "R_PPC_56", /* 56 */ + "R_PPC_57", /* 57 */ + "R_PPC_58", /* 58 */ + "R_PPC_59", /* 59 */ + "R_PPC_60", /* 60 */ + "R_PPC_61", /* 61 */ + "R_PPC_62", /* 62 */ + "R_PPC_63", /* 63 */ + "R_PPC_64", /* 64 */ + "R_PPC_65", /* 65 */ + "R_PPC_66", /* 66 */ + "R_PPC_TLS", /* 67 */ + "R_PPC_DTPMOD32", /* 68 */ + "R_PPC_TPREL16", /* 69 */ + "R_PPC_TPREL16_LO", /* 70 */ + "R_PPC_TPREL16_HI", /* 71 */ + "R_PPC_TPREL16_HA", /* 72 */ + "R_PPC_TPREL32", /* 73 */ + "R_PPC_DTPREL16", /* 74 */ + "R_PPC_DTPREL16_LO", /* 75 */ + "R_PPC_DTPREL16_HI", /* 76 */ + "R_PPC_DTPREL16_HA", /* 77 */ + "R_PPC_DTPREL64", /* 78 */ + "R_PPC_GOT_TLSGD16", /* 79 */ + "R_PPC_GOT_TLSGD16_LO", /* 80 */ + "R_PPC_GOT_TLSGD16_HI", /* 81 */ + "R_PPC_GOT_TLSGD16_HA", /* 82 */ + "R_PPC_GOT_TLSLD16", /* 83 */ + "R_PPC_GOT_TLSLD16_LO", /* 84 */ + "R_PPC_GOT_TLSLD16_HI", /* 85 */ + "R_PPC_GOT_TLSLD16_HA", /* 86 */ + "R_PPC_GOT_TPREL16_DS", /* 87 */ + "R_PPC_GOT_TPREL16_LO", /* 88 */ + "R_PPC_GOT_TPREL16_HI", /* 89 */ + "R_PPC_GOT_TPREL16_HA", /* 90 */ + "R_PPC_GOT_DTPREL16", /* 91 */ + "R_PPC_GOT_DTPREL16_LO", /* 92 */ + "R_PPC_GOT_DTPREL16_HI", /* 93 */ + "R_PPC_GOT_DTPREL16_HA", /* 94 */ +}; + +/* PowerPC64 relocations defined by the ABIs */ +static const char *reloc_type_names_PPC64[] = { + "R_PPC64_NONE", /* 00 */ + "R_PPC64_ADDR32", /* 01 */ + "R_PPC64_ADDR24", /* 02 */ + "R_PPC64_ADDR16", /* 03 */ + "R_PPC64_ADDR16_LO", /* 04 */ + "R_PPC64_ADDR16_HI", /* 05 */ + "R_PPC64_ADDR16_HA", /* 06 */ + "R_PPC64_ADDR14", /* 07 */ + "R_PPC64_ADDR14_BRTAKEN", /* 08 */ + "R_PPC64_ADDR14_BRNTAKEN", /* 09 */ + "R_PPC64_REL24", /* 10 */ + "R_PPC64_REL14", /* 11 */ + "R_PPC64_REL14_BRTAKEN", /* 12 */ + "R_PPC64_REL14_BRNTAKEN", /* 13 */ + "R_PPC64_GOT16", /* 14 */ + "R_PPC64_GOT16_LO", /* 15 */ + "R_PPC64_GOT16_HI", /* 16 */ + "R_PPC64_GOT16_HA", /* 17 */ + "R_PPC64_PLTREL24", /* 18 */ + "R_PPC64_COPY", /* 19 */ + "R_PPC64_GLOB_DAT", /* 20 */ + "R_PPC64_JMP_SLOT", /* 21 */ + "R_PPC64_RELATIVE", /* 22 */ + "R_PPC64_LOCAL24PC", /* 23 */ + "R_PPC64_UADDR32", /* 24 */ + "R_PPC64_UADDR16", /* 25 */ + "R_PPC64_REL32", /* 26 */ + "R_PPC64_PLT32", /* 27 */ + "R_PPC64_PLTREL32", /* 28 */ + "R_PPC64_PLT16_LO", /* 29 */ + "R_PPC64_PLT16_HI", /* 30 */ + "R_PPC64_PLT16_HA", /* 31 */ + "R_PPC64_SDAREL16", /* 32 */ + "R_PPC64_SECTOFF", /* 33 */ + "R_PPC64_SECTOFF_LO", /* 34 */ + "R_PPC64_SECTOFF_HI", /* 35 */ + "R_PPC64_SECTOFF_HA", /* 36 */ + "R_PPC64_REL30", /* 37 */ + "R_PPC64_ADDR64", /* 38 */ + "R_PPC64_ADDR16_HIGHER", /* 39 */ + "R_PPC64_ADDR16_HIGHERA", /* 40 */ + "R_PPC64_ADDR16_HIGHEST", /* 41 */ + "R_PPC64_ADDR16_HIGHESTA", /* 42 */ + "R_PPC64_UADDR64", /* 43 */ + "R_PPC64_REL64", /* 44 */ + "R_PPC64_PLT64", /* 45 */ + "R_PPC64_PLTREL64", /* 46 */ + "R_PPC64_TOC16", /* 47 */ + "R_PPC64_TOC16_LO", /* 48 */ + "R_PPC64_TOC16_HI", /* 49 */ + "R_PPC64_TOC16_HA", /* 50 */ + "R_PPC64_TOC", /* 51 */ + "R_PPC64_PLTGOT16", /* 52 */ + "R_PPC64_PLTGOT16_LO", /* 53 */ + "R_PPC64_PLTGOT16_HI", /* 54 */ + "R_PPC64_PLTGOT16_HA", /* 55 */ + "R_PPC64_ADDR16_DS", /* 56 */ + "R_PPC64_ADDR16_LO_DS", /* 57 */ + "R_PPC64_GOT16_DS", /* 58 */ + "R_PPC64_GOT16_LO_DS", /* 59 */ + "R_PPC64_PLT16_LO_DS", /* 60 */ + "R_PPC64_SECTOFF_DS", /* 61 */ + "R_PPC64_SECTOFF_LO_DS", /* 62 */ + "R_PPC64_TOC16_DS", /* 63 */ + "R_PPC64_TOC16_LO_DS", /* 64 */ + "R_PPC64_PLTGOT16_DS", /* 65 */ + "R_PPC64_PLTGOT16_LO_DS", /* 66 */ + "R_PPC64_TLS", /* 67 */ + "R_PPC64_DTPMOD32", /* 68 */ + "R_PPC64_TPREL16", /* 69 */ + "R_PPC64_TPREL16_LO", /* 70 */ + "R_PPC64_TPREL16_HI", /* 71 */ + "R_PPC64_TPREL16_HA", /* 72 */ + "R_PPC64_TPREL32", /* 73 */ + "R_PPC64_DTPREL16", /* 74 */ + "R_PPC64_DTPREL16_LO", /* 75 */ + "R_PPC64_DTPREL16_HI", /* 76 */ + "R_PPC64_DTPREL16_HA", /* 77 */ + "R_PPC64_DTPREL64", /* 78 */ + "R_PPC64_GOT_TLSGD16", /* 79 */ + "R_PPC64_GOT_TLSGD16_LO", /* 80 */ + "R_PPC64_GOT_TLSGD16_HI", /* 81 */ + "R_PPC64_GOT_TLSGD16_HA", /* 82 */ + "R_PPC64_GOT_TLSLD16", /* 83 */ + "R_PPC64_GOT_TLSLD16_LO", /* 84 */ + "R_PPC64_GOT_TLSLD16_HI", /* 85 */ + "R_PPC64_GOT_TLSLD16_HA", /* 86 */ + "R_PPC64_GOT_TPREL16_DS", /* 87 */ + "R_PPC64_GOT_TPREL16_LO", /* 88 */ + "R_PPC64_GOT_TPREL16_HI", /* 89 */ + "R_PPC64_GOT_TPREL16_HA", /* 90 */ + "R_PPC64_GOT_DTPREL16", /* 91 */ + "R_PPC64_GOT_DTPREL16_LO", /* 92 */ + "R_PPC64_GOT_DTPREL16_HI", /* 93 */ + "R_PPC64_GOT_DTPREL16_HA", /* 94 */ + "R_PPC64_TPREL16_DS", /* 95 */ + "R_PPC64_TPREL16_LO_DS", /* 96 */ + "R_PPC64_TPREL16_HIGHER", /* 97 */ + "R_PPC64_TPREL16_HIGHERA", /* 98 */ + "R_PPC64_TPREL16_HIGHEST", /* 99 */ + "R_PPC64_TPREL16_HIGHESTA", /* 100 */ + "R_PPC64_DTPREL16_DS", /* 101 */ + "R_PPC64_DTPREL16_LO_DS", /* 102 */ + "R_PPC64_DTPREL16_HIGHER", /* 103 */ + "R_PPC64_DTPREL16_HIGHERA", /* 104 */ + "R_PPC64_DTPREL16_HIGHEST", /* 105 */ + "R_PPC64_DTPREL16_HIGHESTA", /* 106 */ + "R_PPC64_TOC32", /* 107 */ + "R_PPC64_DTPMOD32", /* 108 */ + "R_PPC64_TPREL32", /* 109 */ + "R_PPC64_DTPREL32", /* 110 */ +}; + +/* Relocation types for MIPS */ +static const char *reloc_type_names_MIPS[] = { + "R_MIPS_NONE", "R_MIPS_16", "R_MIPS_32", "R_MIPS_REL32", + "R_MIPS_26", "R_MIPS_HI16", "R_MIPS_LO16", "R_MIPS_GPREL16", + "R_MIPS_LITERAL", "R_MIPS_GOT16", "R_MIPS_PC16", "R_MIPS_CALL16", + "R_MIPS_GPREL32", /* 12 */ + "reloc type 13?", "reloc type 14?", "reloc type 15?", + "R_MIPS_SHIFT5", /* 16 */ + "R_MIPS_SHIFT6", /* 17 */ + "R_MIPS_64", /* 18 */ + "R_MIPS_GOT_DISP", /* 19 */ + "R_MIPS_GOT_PAGE", /* 20 */ + "R_MIPS_GOT_OFST", /* 21 */ + "R_MIPS_GOT_HI16", /* 22 */ + "R_MIPS_GOT_LO16", /* 23 */ + "R_MIPS_SUB", /* 24 */ + "R_MIPS_INSERT_A", /* 25 */ + "R_MIPS_INSERT_B", /* 26 */ + "R_MIPS_DELETE", /* 27 */ + "R_MIPS_HIGHER", /* 28 */ + "R_MIPS_HIGHEST", /* 29 */ + "R_MIPS_CALL_HI16", /* 30 */ + "R_MIPS_CALL_LO16", /* 31 */ + "R_MIPS_SCN_DISP", /* 32 */ + "R_MIPS_REL16", /* 33 */ + "R_MIPS_ADD_IMMEDIATE", /* 34 */ +}; + +/* ARM relocations defined by the ABIs */ +static const char *reloc_type_names_ARM[] = { + "R_ARM_NONE", /* 00 */ + "R_ARM_PC24", /* 01 */ + "R_ARM_ABS32", /* 02 */ + "R_ARM_REL32", /* 03 */ + "R_ARM_LDR_PC_G0", /* 04 */ + "R_ARM_ABS16", /* 05 */ + "R_ARM_ABS12", /* 06 */ + "R_ARM_THM_ABS5", /* 07 */ + "R_ARM_ABS8", /* 08 */ + "R_ARM_SBREL32", /* 09 */ + "R_ARM_THM_CALL", /* 10 */ + "R_ARM_THM_PC8", /* 11 */ + "R_ARM_BREL_ADJ", /* 12 */ + "R_ARM_TLS_DESC", /* 13 */ + "R_ARM_THM_SWI8", /* 14 */ + "R_ARM_XPC25", /* 15 */ + "R_ARM_THM_XPC22", /* 16 */ + "R_ARM_TLS_DTPMOD32", /* 17 */ + "R_ARM_TLS_DTPOFF32", /* 18 */ + "R_ARM_TLS_TPOFF32", /* 19 */ + "R_ARM_COPY", /* 20 */ + "R_ARM_GLOB_DAT", /* 21 */ + "R_ARM_JUMP_SLOT", /* 22 */ + "R_ARM_RELATIVE", /* 23 */ + "R_ARM_GOTOFF32", /* 24 */ + "R_ARM_BASE_PREL", /* 25 */ + "R_ARM_GOT_BREL", /* 26 */ + "R_ARM_PLT32", /* 27 */ + "R_ARM_CALL", /* 28 */ + "R_ARM_JUMP24", /* 29 */ + "R_ARM_THM_JUMP24", /* 30 */ + "R_ARM_BASE_ABS", /* 31 */ + "R_ARM_ALU_PCREL_7_0", /* 32 */ + "R_ARM_ALU_PCREL_15_8", /* 33 */ + "R_ARM_ALU_PCREL_23_15", /* 34 */ + "R_ARM_LDR_SBREL_11_0_NC", /* 35 */ + "R_ARM_ALU_SBREL_19_12_NC", /* 36 */ + "R_ARM_ALU_SBREL_27_20_CK", /* 37 */ + "R_ARM_TARGET1", /* 38 */ + "R_ARM_SBREL31", /* 39 */ + "R_ARM_V4BX", /* 40 */ + "R_ARM_TARGET2", /* 41 */ + "R_ARM_PREL31", /* 42 */ + "R_ARM_MOVW_ABS_NC", /* 43 */ + "R_ARM_MOVT_ABS", /* 44 */ + "R_ARM_MOVW_PREL_NC", /* 45 */ + "R_ARM_MOVT_PREL", /* 46 */ + "R_ARM_THM_MOVW_ABS_NC", /* 47 */ + "R_ARM_THM_MOVT_ABS", /* 48 */ + "R_ARM_THM_MOVW_PREL_NC", /* 49 */ + "R_ARM_THM_MOVT_PREL", /* 50 */ + "R_ARM_THM_JUMP19", /* 51 */ + "R_ARM_THM_JUMP6", /* 52 */ + "R_ARM_THM_ALU_PREL_11_0", /* 53 */ + "R_ARM_THM_PC12", /* 54 */ + "R_ARM_ABS32_NOI", /* 55 */ + "R_ARM_REL32_NOI", /* 56 */ + "R_ARM_ALU_PC_G0_NC", /* 57 */ + "R_ARM_ALU_PC_G0", /* 58 */ + "R_ARM_ALU_PC_G1_NC", /* 59 */ + "R_ARM_ALU_PC_G1", /* 60 */ + "R_ARM_ALU_PC_G2", /* 61 */ + "R_ARM_LDR_PC_G1", /* 62 */ + "R_ARM_LDR_PC_G2", /* 63 */ + "R_ARM_LDRS_PC_G0", /* 64 */ + "R_ARM_LDRS_PC_G1", /* 65 */ + "R_ARM_LDRS_PC_G2", /* 66 */ + "R_ARM_LDC_PC_G0", /* 67 */ + "R_ARM_LDC_PC_G1", /* 68 */ + "R_ARM_LDC_PC_G2", /* 69 */ + "R_ARM_ALU_SB_G0_NC", /* 70 */ + "R_ARM_ALU_SB_G0", /* 71 */ + "R_ARM_ALU_SB_G1_NC", /* 72 */ + "R_ARM_ALU_SB_G1", /* 73 */ + "R_ARM_ALU_SB_G2", /* 74 */ + "R_ARM_LDR_SB_G0", /* 75 */ + "R_ARM_LDR_SB_G1", /* 76 */ + "R_ARM_LDR_SB_G2", /* 77 */ + "R_ARM_LDRS_SB_G0", /* 78 */ + "R_ARM_LDRS_SB_G1", /* 79 */ + "R_ARM_LDRS_SB_G2", /* 80 */ + "R_ARM_LDC_SB_G0", /* 81 */ + "R_ARM_LDC_SB_G1", /* 82 */ + "R_ARM_LDC_SB_G2", /* 83 */ + "R_ARM_MOVW_BREL_NC", /* 84 */ + "R_ARM_MOVT_BREL", /* 85 */ + "R_ARM_MOVW_BREL", /* 86 */ + "R_ARM_THM_MOVW_BREL_NC", /* 87 */ + "R_ARM_THM_MOVT_BREL", /* 88 */ + "R_ARM_THM_MOVW_BREL", /* 89 */ + "R_ARM_TLS_GOTDESC", /* 90 */ + "R_ARM_TLS_CALL", /* 91 */ + "R_ARM_TLS_DESCSEQ", /* 92 */ + "R_ARM_THM_TLS_CALL", /* 93 */ + "R_ARM_PLT32_ABS", /* 94 */ + "R_ARM_GOT_ABS", /* 95 */ + "R_ARM_GOT_PREL", /* 96 */ + "R_ARM_GOT_BREL12", /* 97 */ + "R_ARM_GOTOFF12", /* 98 */ + "R_ARM_GOTRELAX", /* 99 */ + "R_ARM_GNU_VTENTRY", /* 100 */ + "R_ARM_GNU_VTINHERIT", /* 101 */ + "R_ARM_THM_JUMP11", /* 102 */ + "R_ARM_THM_JUMP8", /* 103 */ + "R_ARM_TLS_GD32", /* 104 */ + "R_ARM_TLS_LDM32", /* 105 */ + "R_ARM_TLS_LDO32", /* 106 */ + "R_ARM_TLS_IE32", /* 107 */ + "R_ARM_TLS_LE32", /* 108 */ + "R_ARM_TLS_LDO12", /* 109 */ + "R_ARM_TLS_LE12", /* 110 */ + "R_ARM_TLS_IE12GP", /* 111 */ + "R_ARM_TLS_MOVT_TPOFF32", /* 112 */ /* "R_ARM_PRIVATE_0" */ + "R_ARM_TLS_MOVW_TPOFF32", /* 113 */ /* "R_ARM_PRIVATE_1" */ + "R_ARM_THM_TLS_MOVT_TPOFF32", /* 114 */ /* "R_ARM_PRIVATE_2" */ + "R_ARM_THM_TLS_MOVT_TPOFF32", /* 115 */ /* "R_ARM_PRIVATE_3" */ + "R_ARM_PRIVATE_4", /* 116 */ + "R_ARM_PRIVATE_5", /* 117 */ + "R_ARM_PRIVATE_6", /* 118 */ + "R_ARM_PRIVATE_7", /* 119 */ + "R_ARM_PRIVATE_8", /* 120 */ + "R_ARM_PRIVATE_9", /* 121 */ + "R_ARM_PRIVATE_10", /* 122 */ + "R_ARM_PRIVATE_11", /* 123 */ + "R_ARM_PRIVATE_12", /* 124 */ + "R_ARM_PRIVATE_13", /* 125 */ + "R_ARM_PRIVATE_14", /* 126 */ + "R_ARM_PRIVATE_15", /* 127 */ + "R_ARM_ME_TOO", /* 128 */ + "R_ARM_THM_TLS_DESCSEQ16", /* 129 */ + "R_ARM_THM_TLS_DESCSEQ32", /* 130 */ +}; + +/* Record the relocation table name information */ +static const char **reloc_type_names = NULL; +static Dwarf_Small number_of_reloc_type_names = 0; + +/* Set the relocation names based on the machine type */ +static void +set_relocation_table_names(Dwarf_Small machine_type) +{ + switch (machine_type) { + case EM_MIPS: + reloc_type_names = reloc_type_names_MIPS; + number_of_reloc_type_names = + sizeof(reloc_type_names_MIPS) / sizeof(char *); + break; + case EM_PPC: + reloc_type_names = reloc_type_names_PPC; + number_of_reloc_type_names = + sizeof(reloc_type_names_PPC) / sizeof(char *); + break; + case EM_PPC64: + reloc_type_names = reloc_type_names_PPC64; + number_of_reloc_type_names = + sizeof(reloc_type_names_PPC64) / sizeof(char *); + break; + case EM_ARM: + reloc_type_names = reloc_type_names_ARM; + number_of_reloc_type_names = + sizeof(reloc_type_names_ARM) / sizeof(char *); + break; + default: + /* We don't have others covered. */ + reloc_type_names = 0; + number_of_reloc_type_names = 0; + break; + } +} + + + +/* return valid reloc type names. + if buf is used, it is static, so beware it + will be overrwritten by the next call. +*/ +static string +get_reloc_type_names(int index) +{ + string retval; + + if (index < 0 || index >= number_of_reloc_type_names) { + retval = "reloc type "; + retval.append(IToDec(index)); + retval.append(" unknown"); + } else { + retval = reloc_type_names[index]; + } + return retval; +} + +#ifndef HAVE_ELF64_GETEHDR +#define Elf64_Addr long +#define Elf64_Word unsigned long +#define Elf64_Xword unsigned long +#define Elf64_Sym long +#endif + +static struct { + Dwarf_Small *buf; + Dwarf_Unsigned size; + Dwarf_Bool display; // Display reloc if TRUE + const char *name; // Section name. + Elf64_Xword type; // To cover 32 and 64 records types. +} sect_data[DW_SECTION_REL_DEBUG_NUM]; + + +typedef size_t indx_type; + +typedef struct { + indx_type indx; + char *name; + Elf32_Addr value; + Elf32_Word size; + int type; + int bind; + unsigned char other; + Elf32_Half shndx; +} SYM; + + +typedef struct { + indx_type indx; + char *name; + Elf64_Addr value; + Elf64_Xword size; + int type; + int bind; + unsigned char other; + unsigned short shndx; +} SYM64; + +static void print_reloc_information_64(int section_no, + Dwarf_Small * buf, + Dwarf_Unsigned size, + Elf64_Xword type, + const char **scn_names, int scn_names_cnt); +static void print_reloc_information_32(int section_no, + Dwarf_Small * buf, + Dwarf_Unsigned size, + Elf64_Xword type, + const char **scn_names, int scn_names_cnt); +static SYM *readsyms(Elf32_Sym * data, size_t num, Elf * elf, + Elf32_Word link); +static SYM64 *read_64_syms(Elf64_Sym * data, size_t num, Elf * elf, + Elf64_Word link); +static void *get_scndata(Elf_Scn * fd_scn, size_t * scn_size); +static void print_relocinfo_64(Dwarf_Debug dbg, Elf * elf); +static void print_relocinfo_32(Dwarf_Debug dbg, Elf * elf); + +static SYM *sym_data; +static SYM64 *sym_data_64; +static unsigned long sym_data_entry_count; +static unsigned long sym_data_64_entry_count; + + +typedef struct { + indx_type index; + const char *name_rel; /* .rel.debug_* names */ + const char *name_rela; /* .rela.debug_* names */ +} REL_INFO; + + +/* If the incoming scn_name is known, record the name + in our reloc section names table. + For a given (debug) section there can be a .rel or a .rela, + not both. + The name-to-index in this table is fixed, invariant. + It has to match other tables like +*/ +static bool +get_reloc_section(Dwarf_Debug dbg, + Elf_Scn *scn, + const char *scn_name, + Elf64_Word sh_type) +{ + static REL_INFO rel_info[DW_SECTION_REL_DEBUG_NUM] = { + {/*0*/ DW_SECTION_REL_DEBUG_INFO, + DW_SECTNAME_REL_DEBUG_INFO, + DW_SECTNAME_RELA_DEBUG_INFO}, + + {/*1*/ DW_SECTION_REL_DEBUG_LINE, + DW_SECTNAME_REL_DEBUG_LINE, + DW_SECTNAME_RELA_DEBUG_LINE}, + + {/*2*/ DW_SECTION_REL_DEBUG_PUBNAMES, + DW_SECTNAME_REL_DEBUG_PUBNAMES, + DW_SECTNAME_RELA_DEBUG_PUBNAMES}, + + {/*3*/ DW_SECTION_REL_DEBUG_ABBREV, + DW_SECTNAME_REL_DEBUG_ABBREV, + DW_SECTNAME_RELA_DEBUG_ABBREV}, + + {/*4*/ DW_SECTION_REL_DEBUG_ARANGES, + DW_SECTNAME_REL_DEBUG_ARANGES, + DW_SECTNAME_RELA_DEBUG_ARANGES}, + + {/*5*/ DW_SECTION_REL_DEBUG_FRAME, + DW_SECTNAME_REL_DEBUG_FRAME, + DW_SECTNAME_RELA_DEBUG_FRAME}, + + {/*6*/ DW_SECTION_REL_DEBUG_LOC, + DW_SECTNAME_REL_DEBUG_LOC, + DW_SECTNAME_RELA_DEBUG_LOC}, + + {/*7*/ DW_SECTION_REL_DEBUG_RANGES, + DW_SECTNAME_REL_DEBUG_RANGES, + DW_SECTNAME_RELA_DEBUG_RANGES}, + + {/*8*/ DW_SECTION_REL_DEBUG_TYPES, + DW_SECTNAME_REL_DEBUG_TYPES, + DW_SECTNAME_RELA_DEBUG_TYPES}, + }; + + Elf_Data *data; + int index; + for (index = 0; index < DW_SECTION_REL_DEBUG_NUM; ++index) { + const char *n = rel_info[index].name_rel; + const char *na = rel_info[index].name_rela; + if (strcmp(scn_name, n) == 0) { + SECT_DATA_SET(rel_info[index].index,sh_type,n) + return true; + } + if (strcmp(scn_name, na) == 0) { + SECT_DATA_SET(rel_info[index].index,sh_type,na) + return true; + } + } + return false; +} + + + +void +print_relocinfo(Dwarf_Debug dbg, unsigned reloc_map) +{ + Elf *elf; + char *endr_ident; + int is_64bit; + int res; + int i; + + for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) { + sect_data[i].display = reloc_map & (1 << i); + sect_data[i].buf = 0; + sect_data[i].size = 0; + sect_data[i].type = SHT_NULL; + } + res = dwarf_get_elf(dbg, &elf, &err); + if (res != DW_DLV_OK) { + print_error(dbg, "dwarf_get_elf error", res, err); + } + if ((endr_ident = elf_getident(elf, NULL)) == NULL) { + print_error(dbg, "DW_ELF_GETIDENT_ERROR", res, err); + } + is_64bit = (endr_ident[EI_CLASS] == ELFCLASS64); + if (is_64bit) { + print_relocinfo_64(dbg, elf); + } else { + print_relocinfo_32(dbg, elf); + } +} + +static void +print_relocinfo_64(Dwarf_Debug dbg, Elf * elf) +{ +#ifdef HAVE_ELF64_GETEHDR + Elf_Scn *scn = NULL; + Elf64_Ehdr *ehdr64 = 0; + Elf64_Shdr *shdr64 = 0; + const char *scn_name = 0; + const char **scn_names = 0; + int i = 0; + Elf64_Sym *sym_64 = 0; + int scn_names_cnt = 0; + + ehdr64 = elf64_getehdr(elf); + if (ehdr64 == NULL) { + print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err); + } + scn_names = (const char **)calloc(ehdr64->e_shnum + 1, sizeof(char *)); + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + + shdr64 = elf64_getshdr(scn); + if (shdr64 == NULL) { + print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err); + } + scn_name = elf_strptr(elf, ehdr64->e_shstrndx, shdr64->sh_name); + if (scn_name == NULL) { + print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err); + } + if(scn_names) { + /* elf_nextscn() skips section with index '0' */ + scn_names[++scn_names_cnt] = scn_name; + } + if (shdr64->sh_type == SHT_SYMTAB) { + size_t sym_size = 0; + size_t count = 0; + + sym_64 = (Elf64_Sym *) get_scndata(scn, &sym_size); + if (sym_64 == NULL) { + print_error(dbg, "no symbol table data", DW_DLV_OK, + err); + } + count = sym_size / sizeof(Elf64_Sym); + sym_64++; + free(sym_data_64); + sym_data_64 = read_64_syms(sym_64, count, elf, shdr64->sh_link); + sym_data_64_entry_count = count; + if (sym_data_64 == NULL) { + print_error(dbg, "problem reading symbol table data", + DW_DLV_OK, err); + } + } else if (!get_reloc_section(dbg,scn,scn_name,shdr64->sh_type)) { + continue; + } + } /* while */ + /* Set the relocation names based on the machine type */ + set_relocation_table_names(ehdr64->e_machine); + for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) { + if (sect_data[i].display && + sect_data[i].buf != NULL && + sect_data[i].size > 0) { + print_reloc_information_64(i, sect_data[i].buf, + sect_data[i].size, sect_data[i].type,scn_names, + scn_names_cnt); + } + } + + if (scn_names) { + free(scn_names); + scn_names = 0; + scn_names_cnt = 0; + } +#endif +} + +static void +print_relocinfo_32(Dwarf_Debug dbg, Elf * elf) +{ + Elf_Scn *scn = NULL; + Elf32_Ehdr *ehdr32 = 0; + Elf32_Shdr *shdr32 = 0; + char *scn_name = 0; + int i = 0; + Elf32_Sym *sym = 0; + const char **scn_names = 0; + int scn_names_cnt = 0; + + + ehdr32 = elf32_getehdr(elf); + if (ehdr32 == NULL) { + print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err); + } + /* Make the section name array big enough + that we don't need to check for overrun in the loop. */ + scn_names = (const char **)calloc(ehdr32->e_shnum + 1, sizeof(char *)); + while ((scn = elf_nextscn(elf, scn)) != NULL) { + shdr32 = elf32_getshdr(scn); + if (shdr32 == NULL) { + print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err); + } + scn_name = elf_strptr(elf, ehdr32->e_shstrndx, shdr32->sh_name); + if (scn_name == NULL) { + print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err); + } + if (scn_names) { + /* elf_nextscn() skips section with index '0' */ + scn_names[++scn_names_cnt] = scn_name; + } + if (shdr32->sh_type == SHT_SYMTAB) { + size_t sym_size = 0; + size_t count = 0; + + sym = (Elf32_Sym *) get_scndata(scn, &sym_size); + if (sym == NULL) { + print_error(dbg, "no symbol table data", DW_DLV_OK, + err); + } + sym = (Elf32_Sym *) get_scndata(scn, &sym_size); + count = sym_size / sizeof(Elf32_Sym); + sym++; + free(sym_data); + sym_data = readsyms(sym, count, elf, shdr32->sh_link); + sym_data_entry_count = count; + if (sym_data == NULL) { + print_error(dbg, "problem reading symbol table data", + DW_DLV_OK, err); + } + } else if (!get_reloc_section(dbg,scn,scn_name,shdr32->sh_type)) { + continue; + } + } /* while */ + /* Set the relocation names based on the machine type */ + set_relocation_table_names(ehdr32->e_machine); + + for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) { + if (sect_data[i].display && + sect_data[i].buf != NULL && + sect_data[i].size > 0) { + print_reloc_information_32(i, sect_data[i].buf, + sect_data[i].size,sect_data[i].type,scn_names, + scn_names_cnt); + } + } + + if (scn_names) { + free(scn_names); + scn_names = 0; + scn_names_cnt = 0; + } + +} + +#if HAVE_ELF64_R_INFO +#ifndef ELF64_R_TYPE +#define ELF64_R_TYPE(x) 0 /* FIXME */ +#endif +#ifndef ELF64_R_SYM +#define ELF64_R_SYM(x) 0 /* FIXME */ +#endif +#ifndef ELF64_ST_TYPE +#define ELF64_ST_TYPE(x) 0 /* FIXME */ +#endif +#ifndef ELF64_ST_BIND +#define ELF64_ST_BIND(x) 0 /* FIXME */ +#endif +#endif /* HAVE_ELF64_R_INFO */ + + +static void +print_reloc_information_64(int section_no, Dwarf_Small * buf, + Dwarf_Unsigned size, Elf64_Xword type, + const char **scn_names, int scn_names_count) +{ + /* Include support for Elf64_Rel and Elf64_Rela */ + Dwarf_Unsigned add = 0; + Dwarf_Half rel_size = SHT_RELA == type ? + sizeof(Elf64_Rela) : sizeof(Elf64_Rel); + Dwarf_Unsigned off = 0; + + cout << endl; + cout << ((type == SHT_RELA)?sectnamesa[section_no]: + sectnames[section_no]) << ":" << endl;; + /* Print some headers and change the order for better reading */ + printf("Offset Addend %-26s Index Symbol Name\n","Reloc Type"); +#if HAVE_ELF64_GETEHDR + for (off = 0; off < size; off += rel_size) { +#if HAVE_ELF64_R_INFO + /* This works for the Elf64_Rel in linux */ + Elf64_Rel *p = (Elf64_Rel *) (buf + off); + string name; + if(sym_data ) { + size_t index = ELF64_R_SYM(p->r_info) - 1; + if(index < sym_data_entry_count) { + name = sym_data[index].name; + } + } else if (sym_data_64) { + size_t index = ELF64_R_SYM(p->r_info) - 1; + if(index < sym_data_64_entry_count) { + name = sym_data_64[index].name; + } + } + /* When the name is not available, use the + section name as a reference for the name.*/ + if (name.empty()) { + size_t index = ELF64_R_SYM(p->r_info) - 1; + if (index < sym_data_64_entry_count) { + SYM64 *sym_64 = &sym_data_64[index]; + if (sym_64->type == STT_SECTION && + sym_64->shndx < scn_names_count) { + name = scn_names[sym_64->shndx]; + } + } + } + if (name.empty()) { + name = "<no name>"; + } + + if (SHT_RELA == type) { + Elf64_Rela *pa = (Elf64_Rela *)p; + add = pa->r_addend; + } + + + cout << IToHex0N(p->r_offset,10); + cout << " " << IToHex0N(add,10); + cout << " " <<LeftAlign(26,get_reloc_type_names(ELF64_R_TYPE(p->r_info))); + cout << " " << BracketSurround(IToDec(ELF64_R_SYM(p->r_info),5)); + cout << " " << name; + cout << endl; +#else + /* sgi/mips -64 does not have r_info in the 64bit relocations, + but seperate fields, with 3 types, actually. Only one of + which prints here, as only one really used with dwarf */ + Elf64_Rel *p = (Elf64_Rel *) (buf + off); + string name; + if(sym_data ) { + size_t index = p->r_sym - 1; + if(index < sym_data_entry_count) { + name = sym_data[index].name; + } + } else if (sym_data_64) { + size_t index = p->r_sym - 1; + if(index < sym_data_64_entry_count) { + name = sym_data_64[index].name; + } + } + if (name.empty()) { + name = "<no name>"; + } + cout << IToHex0N(p->r_offset,10); + cout << " " << IToHex0N(add,10); + cout << " " << LeftAlign(26,get_reloc_type_names(ELF64_R_TYPE(p->r_info))); + cout << " " << BracketSurround(IToDec(ELF64_R_SYM(p->r_info),3)) + cout << " " << name; + cout << endl; +#endif + } +#endif /* HAVE_ELF64_GETEHDR */ +} + +static void +print_reloc_information_32(int section_no, Dwarf_Small * buf, + Dwarf_Unsigned size, Elf64_Xword type, + const char **scn_names, int scn_names_count) +{ +/* Include support for Elf32_Rel and Elf32_Rela */ + Dwarf_Unsigned add = 0; + Dwarf_Half rel_size = SHT_RELA == type ? + sizeof(Elf32_Rela) : sizeof(Elf32_Rel); + Dwarf_Unsigned off = 0; + + cout << endl; + cout << ((type == SHT_RELA)?sectnamesa[section_no]: + sectnames[section_no]) << ":" << endl; + printf("Offset Addend %-26s Index Symbol Name\n","Reloc Type"); + for (off = 0; off < size; off += rel_size) { + Elf32_Rel *p = (Elf32_Rel *) (buf + off); + string name; + if(sym_data) { + size_t index = ELF32_R_SYM(p->r_info) - 1; + if(index < sym_data_entry_count) { + name = sym_data[index].name; + } + } + /* When the name is not available, use the + section name as a reference for the name.*/ + if (name.empty()) { + size_t index = ELF32_R_SYM(p->r_info) - 1; + if(index < sym_data_entry_count) { + SYM *sym_32 = &sym_data[index]; + if (sym_32->type == STT_SECTION && + sym_32->shndx < scn_names_count) { + name = scn_names[sym_32->shndx]; + } + } + } + if (name.empty()) { + name = "<no name>"; + } + + if (SHT_RELA == type) { + Elf32_Rela *pa = (Elf32_Rela *)p; + add = pa->r_addend; + } + cout << IToHex0N(p->r_offset,10); + cout << " " << IToHex0N(add,10); + cout << " " << LeftAlign(26, + get_reloc_type_names(ELF32_R_TYPE(p->r_info))); + cout << " " << BracketSurround(IToDec(ELF32_R_SYM(p->r_info),5)); + cout << " " << name; + cout << endl; + } +} + +static SYM * +readsyms(Elf32_Sym * data, size_t num, Elf * elf, Elf32_Word link) +{ + SYM *s, *buf; + indx_type i; + + buf = (SYM *) calloc(num, sizeof(SYM)); + if (buf == NULL) { + return NULL; + } + s = buf; /* save pointer to head of array */ + for (i = 1; i < num; i++, data++, buf++) { + buf->indx = i; + buf->name = (char *) elf_strptr(elf, link, data->st_name); + buf->value = data->st_value; + buf->size = data->st_size; + buf->type = ELF32_ST_TYPE(data->st_info); + buf->bind = ELF32_ST_BIND(data->st_info); + buf->other = data->st_other; + buf->shndx = data->st_shndx; + } /* end for loop */ + return (s); +} + +static SYM64 * +read_64_syms(Elf64_Sym * data, size_t num, Elf * elf, Elf64_Word link) +{ +#ifdef HAVE_ELF64_GETEHDR + + SYM64 *s, *buf; + indx_type i; + + buf = (SYM64 *) calloc(num, sizeof(SYM64)); + if (buf == NULL) { + return NULL; + } + s = buf; /* save pointer to head of array */ + for (i = 1; i < num; i++, data++, buf++) { + buf->indx = i; + buf->name = (char *) elf_strptr(elf, link, data->st_name); + buf->value = data->st_value; + buf->size = data->st_size; + buf->type = ELF64_ST_TYPE(data->st_info); + buf->bind = ELF64_ST_BIND(data->st_info); + buf->other = data->st_other; + buf->shndx = data->st_shndx; + } /* end for loop */ + return (s); +#else + return 0; +#endif /* HAVE_ELF64_GETEHDR */ +} + +static void * +get_scndata(Elf_Scn * fd_scn, size_t * scn_size) +{ + Elf_Data *p_data; + + p_data = 0; + if ((p_data = elf_getdata(fd_scn, p_data)) == 0 || + p_data->d_size == 0) { + return NULL; + } + *scn_size = p_data->d_size; + return (p_data->d_buf); +} + +/* Cleanup of malloc space (some of the pointers will be 0 here) + so dwarfdump looks 'clean' to a malloc checker. +*/ +void +clean_up_syms_malloc_data() +{ + free(sym_data); + sym_data = 0; + free(sym_data_64); + sym_data_64 = 0; + sym_data_64_entry_count = 0; + sym_data_entry_count = 0; +} diff --git a/dwarfdump2/print_sections.cc b/dwarfdump2/print_sections.cc new file mode 100644 index 0000000..07cfb0e --- /dev/null +++ b/dwarfdump2/print_sections.cc @@ -0,0 +1,216 @@ +/* + 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 2008-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_sections.c,v 1.69 2006/04/17 00:09:56 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. +*/ + +// Contains functions that support printing. +// Actual section-print code is in other print_*.cc files. +#include "globals.h" +#include <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_frames.h" +#include "print_sections.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +bool dwarf_names_print_on_error = true; + + +/* If an offset is bad, libdwarf will notice it and + return an error. + If it does the error checking in + print_pubname_style_entry() + will be useless as we give up here on an error. + + This intended for checking pubnames-style call return + values (for all the pubnames-style interfaces). + + In at least one gigantic executable die_off turned out wrong. +*/ + + +void +deal_with_name_offset_err(Dwarf_Debug dbg, + const string &err_loc, + const string &name, + Dwarf_Unsigned die_off, + int nres, Dwarf_Error err) +{ + if (nres == DW_DLV_ERROR) { + Dwarf_Unsigned myerr = dwarf_errno(err); + if (myerr == DW_DLE_OFFSET_BAD) { + cout << "Error: bad offset "; + cout << err_loc; + cout << " "; + cout << name; + cout << die_off; + cout << " ("; + cout << IToHex0N(die_off,10); + cout << ")" << endl; + } + print_error(dbg, err_loc, nres, err); + } +} +/* The new (April 2005) dwarf_get_section_max_offsets() + in libdwarf returns all max-offsets, but we only + want one of those offsets. This function returns + the one we want from that set, + making functions needing this offset as readable as possible. + (avoiding code duplication). +*/ +Dwarf_Unsigned +get_info_max_offset(Dwarf_Debug dbg) +{ + Dwarf_Unsigned debug_info_size = 0; + Dwarf_Unsigned debug_abbrev_size = 0; + Dwarf_Unsigned debug_line_size = 0; + Dwarf_Unsigned debug_loc_size = 0; + Dwarf_Unsigned debug_aranges_size = 0; + Dwarf_Unsigned debug_macinfo_size = 0; + Dwarf_Unsigned debug_pubnames_size = 0; + Dwarf_Unsigned debug_str_size = 0; + Dwarf_Unsigned debug_frame_size = 0; + Dwarf_Unsigned debug_ranges_size = 0; + Dwarf_Unsigned debug_pubtypes_size = 0; + + dwarf_get_section_max_offsets(dbg, + &debug_info_size, + &debug_abbrev_size, + &debug_line_size, + &debug_loc_size, + &debug_aranges_size, + &debug_macinfo_size, + &debug_pubnames_size, + &debug_str_size, + &debug_frame_size, + &debug_ranges_size, + &debug_pubtypes_size); + return debug_info_size; +} + + +/* + decode ULEB +*/ +Dwarf_Unsigned +local_dwarf_decode_u_leb128(unsigned char *leb128, + unsigned int *leb128_length) +{ + unsigned char byte = 0; + Dwarf_Unsigned number = 0; + unsigned int shift = 0; + unsigned int byte_length = 1; + + byte = *leb128; + for (;;) { + number |= (byte & 0x7f) << shift; + shift += 7; + + if ((byte & 0x80) == 0) { + if (leb128_length != NULL) + *leb128_length = byte_length; + return (number); + } + + byte_length++; + byte = *(++leb128); + } +} + +#define BITSINBYTE 8 +Dwarf_Signed +local_dwarf_decode_s_leb128(unsigned char *leb128, + unsigned int *leb128_length) +{ + Dwarf_Signed number = 0; + Dwarf_Bool sign = 0; + Dwarf_Signed shift = 0; + unsigned char byte = *leb128; + Dwarf_Signed byte_length = 1; + + /* byte_length being the number of bytes of data absorbed so far in + turning the leb into a Dwarf_Signed. */ + + for (;;) { + sign = byte & 0x40; + number |= ((Dwarf_Signed) ((byte & 0x7f))) << shift; + shift += 7; + + if ((byte & 0x80) == 0) { + break; + } + ++leb128; + byte = *leb128; + byte_length++; + } + + if ((shift < sizeof(Dwarf_Signed) * BITSINBYTE) && sign) { + number |= -((Dwarf_Signed) 1 << shift); + } + + if (leb128_length != NULL) + *leb128_length = byte_length; + return (number); +} + + +/* Dumping a dwarf-expression as a byte stream. */ +void +dump_block(const string &prefix, char *data, Dwarf_Signed len) +{ + char *end_data = data + len; + char *cur = data; + int i = 0; + + cout << prefix; + for (; cur < end_data; ++cur, ++i) { + if (i > 0 && i % 4 == 0){ + cout << " "; + } + cout << IToHex02(*cur); + } +} + diff --git a/dwarfdump2/print_sections.h b/dwarfdump2/print_sections.h new file mode 100644 index 0000000..ccb6bbe --- /dev/null +++ b/dwarfdump2/print_sections.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-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 + + +*/ + + + +void deal_with_name_offset_err(Dwarf_Debug dbg, + const std::string &err_loc, + const std::string &name, + Dwarf_Unsigned die_off, + int nres, + Dwarf_Error err); + +Dwarf_Unsigned get_info_max_offset(Dwarf_Debug dbg); + +void print_pubname_style_entry(Dwarf_Debug dbg, + const std::string &line_title, + const std::string &name, + Dwarf_Unsigned die_off, + Dwarf_Unsigned cu_off, + Dwarf_Unsigned global_cu_off, + Dwarf_Unsigned maxoff); + + diff --git a/dwarfdump2/print_static_funcs.cc b/dwarfdump2/print_static_funcs.cc new file mode 100644 index 0000000..1231e7c --- /dev/null +++ b/dwarfdump2/print_static_funcs.cc @@ -0,0 +1,135 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* Get all the data in .debug_static_funcs + On error, this allows some dwarf memory leaks. +*/ +extern void +print_static_funcs(Dwarf_Debug dbg) +{ + Dwarf_Func *funcbuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + int gfres = 0; + + error_message_data.current_section_id = DEBUG_STATIC_FUNC; + if (!do_print_dwarf) { + return; + } + cout << endl; + cout << ".debug_static_func" << endl; + gfres = dwarf_get_funcs(dbg, &funcbuf, &count, &err); + if (gfres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_funcs", gfres, err); + } else if (gfres == DW_DLV_NO_ENTRY) { + /* no static funcs */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (i = 0; i < count; i++) { + int fnres; + int cures3; + Dwarf_Unsigned global_cu_off = 0; + char *name = 0; + + fnres = dwarf_func_name_offsets(funcbuf[i], &name, &die_off, + &cu_off, &err); + deal_with_name_offset_err(dbg, "dwarf_func_name_offsets", + name, die_off, fnres, err); + + cures3 = dwarf_func_cu_offset(funcbuf[i], &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_global_cu_offset", cures3, err); + } + + print_pubname_style_entry(dbg, + "static-func", name, die_off, + cu_off, global_cu_off, maxoff); + + + /* print associated die too? */ + if (check_pubname_attr) { + Dwarf_Bool has_attr; + int ares; + int dres; + Dwarf_Die die; + + /* get die at die_off */ + dres = dwarf_offdie(dbg, die_off, &die, &err); + if (dres != DW_DLV_OK) { + print_error(dbg, "dwarf_offdie", dres, err); + } + ares = dwarf_hasattr(die, DW_AT_external, &has_attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "hassattr on DW_AT_external", ares, + err); + } + DWARF_CHECK_COUNT(pubname_attr_result,1); + if (ares == DW_DLV_OK && has_attr) { + /* Should the value of flag be examined? */ + } else { + DWARF_CHECK_ERROR2(pubname_attr_result,name, + "pubname (in static funcs section) does not have DW_AT_external"); + } + dwarf_dealloc(dbg, die, DW_DLA_DIE); + } + } + dwarf_funcs_dealloc(dbg, funcbuf, count); + } +} /* print_static_funcs() */ + diff --git a/dwarfdump2/print_static_vars.cc b/dwarfdump2/print_static_vars.cc new file mode 100644 index 0000000..72f83ea --- /dev/null +++ b/dwarfdump2/print_static_vars.cc @@ -0,0 +1,106 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* get all the data in .debug_static_vars */ +extern void +print_static_vars(Dwarf_Debug dbg) +{ + Dwarf_Var *varbuf = NULL; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + Dwarf_Signed count = 0; + error_message_data.current_section_id = DEBUG_STATIC_VARS; + if (!do_print_dwarf) { + return; + } + + cout << endl; + cout << ".debug_static_vars" << endl; + int gvres = dwarf_get_vars(dbg, &varbuf, &count, &err); + if (gvres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_vars", gvres, err); + } else if (gvres == DW_DLV_NO_ENTRY) { + /* no static vars */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (Dwarf_Signed i = 0; i < count; i++) { + Dwarf_Off global_cu_off = 0; + char *namearg = 0; + + int vnres = dwarf_var_name_offsets(varbuf[i], + &namearg, &die_off, &cu_off, &err); + deal_with_name_offset_err(dbg, + "dwarf_var_name_offsets", + namearg, die_off, vnres, err); + string name = namearg; + + int cures3 = dwarf_var_cu_offset(varbuf[i], + &global_cu_off, &err); + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_global_cu_offset", cures3, err); + } + + print_pubname_style_entry(dbg, + "static-var", + name, die_off, cu_off, + global_cu_off, maxoff); + /* print associated die too? */ + } + dwarf_vars_dealloc(dbg, varbuf, count); + } +} /* print_static_vars */ + diff --git a/dwarfdump2/print_strings.cc b/dwarfdump2/print_strings.cc new file mode 100644 index 0000000..9c94206 --- /dev/null +++ b/dwarfdump2/print_strings.cc @@ -0,0 +1,88 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* print data in .debug_string */ +extern void +print_strings(Dwarf_Debug dbg) +{ + Dwarf_Signed length = 0; + char * name = 0; + Dwarf_Off offset = 0; + int sres = 0; + + error_message_data.current_section_id = DEBUG_STR; + cout << endl; + cout << ".debug_string" << endl; + while ((sres = dwarf_get_str(dbg, offset, &name, &length, &err)) + == DW_DLV_OK) { + if(display_offsets) { + cout << "name at offset " << IToHex0N(offset,10) << + ", length " << IToDec(length,4) << + " is " << "'" << name <<"'" << endl; + } else { + cout << "name: length " << IToDec(length,4) << + " is '" << name << "'" << endl; + } + offset += length + 1; + } + /* An inability to find the section is not necessarily + a real error, so do not report error unless we've + seen a real record. */ + if(sres == DW_DLV_ERROR && offset != 0) { + print_error(dbg, "dwarf_get_str failure", sres, err); + } +} + diff --git a/dwarfdump2/print_types.cc b/dwarfdump2/print_types.cc new file mode 100644 index 0000000..8595813 --- /dev/null +++ b/dwarfdump2/print_types.cc @@ -0,0 +1,142 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* get all the data in .debug_types */ +extern void +print_types(Dwarf_Debug dbg, enum type_type_e type_type) +{ + string section_name; + string offset_err_name; + string section_open_name; + string print_name_prefix; + int (*get_types) (Dwarf_Debug, Dwarf_Type **, Dwarf_Signed *, + Dwarf_Error *) = 0; + int (*get_offset) (Dwarf_Type, char **, Dwarf_Off *, Dwarf_Off *, + Dwarf_Error *) = 0; + int (*get_cu_offset) (Dwarf_Type, Dwarf_Off *, Dwarf_Error *) = + 0; + void (*dealloctype) (Dwarf_Debug, Dwarf_Type *, Dwarf_Signed) = + 0; + + if(!do_print_dwarf) { + return; + } + + if (type_type == DWARF_PUBTYPES) { + section_name = ".debug_pubtypes"; + offset_err_name = "dwarf_pubtype_name_offsets"; + section_open_name = "dwarf_get_pubtypes"; + print_name_prefix = "pubtype"; + get_types = dwarf_get_pubtypes; + get_offset = dwarf_pubtype_name_offsets; + get_cu_offset = dwarf_pubtype_cu_offset; + dealloctype = dwarf_pubtypes_dealloc; + } else { + /* SGI_TYPENAME */ + section_name = ".debug_typenames"; + offset_err_name = "dwarf_type_name_offsets"; + section_open_name = "dwarf_get_types"; + print_name_prefix = "type"; + get_types = dwarf_get_types; + get_offset = dwarf_type_name_offsets; + get_cu_offset = dwarf_type_cu_offset; + dealloctype = dwarf_types_dealloc; + } + + + + Dwarf_Signed count = 0; + Dwarf_Type *typebuf = NULL; + int gtres = get_types(dbg, &typebuf, &count, &err); + if (gtres == DW_DLV_ERROR) { + print_error(dbg, section_open_name, gtres, err); + } else if (gtres == DW_DLV_NO_ENTRY) { + /* no types */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + /* Before July 2005, the section name was printed + unconditionally, now only prints if non-empty section really + exists. */ + cout << endl; + cout << section_name << endl; + + for (Dwarf_Signed i = 0; i < count; i++) { + char *name = NULL; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + Dwarf_Off global_cu_off = 0; + + int tnres = + get_offset(typebuf[i], &name, &die_off, &cu_off, &err); + deal_with_name_offset_err(dbg, offset_err_name, name, + die_off, tnres, err); + + int cures3 = get_cu_offset(typebuf[i], &global_cu_off, &err); + + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_var_cu_offset", cures3, err); + } + print_pubname_style_entry(dbg, + print_name_prefix, + name, die_off, cu_off, + global_cu_off, maxoff); + + /* print associated die too? */ + } + dealloctype(dbg, typebuf, count); + } +} /* print_types() */ diff --git a/dwarfdump2/print_weaknames.cc b/dwarfdump2/print_weaknames.cc new file mode 100644 index 0000000..e73ae47 --- /dev/null +++ b/dwarfdump2/print_weaknames.cc @@ -0,0 +1,113 @@ +/* + 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 2008-2011 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_sections.c,v 1.69 2006/04/17 00:09:56 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 <vector> +#include "naming.h" +#include "dwconf.h" + +#include "print_sections.h" +#include "print_frames.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +/* Get all the data in .debug_weaknames */ +extern void +print_weaknames(Dwarf_Debug dbg) +{ + Dwarf_Weak *weaknamebuf = NULL; + Dwarf_Signed count = 0; + Dwarf_Signed i = 0; + Dwarf_Off die_off = 0; + Dwarf_Off cu_off = 0; + int wkres = 0; + + error_message_data.current_section_id = DEBUG_WEAKNAMES; + if (!do_print_dwarf) { + return; + } + cout << endl; + cout << ".debug_weaknames" << endl; + wkres = dwarf_get_weaks(dbg, &weaknamebuf, &count, &err); + if (wkres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_weaks", wkres, err); + } else if (wkres == DW_DLV_NO_ENTRY) { + /* no weaknames */ + } else { + Dwarf_Unsigned maxoff = get_info_max_offset(dbg); + + for (i = 0; i < count; i++) { + int tnres; + int cures3; + char *name = NULL; + + Dwarf_Unsigned global_cu_off = 0; + + tnres = dwarf_weak_name_offsets(weaknamebuf[i], + &name, &die_off, &cu_off, + &err); + deal_with_name_offset_err(dbg, + "dwarf_weak_name_offsets", + name, die_off, tnres, err); + + cures3 = dwarf_weak_cu_offset(weaknamebuf[i], + &global_cu_off, &err); + + if (cures3 != DW_DLV_OK) { + print_error(dbg, "dwarf_weakname_cu_offset", + cures3, err); + } + print_pubname_style_entry(dbg, + "weakname", + name, die_off, cu_off, + global_cu_off, maxoff); + + /* print associated die too? */ + } + dwarf_weaks_dealloc(dbg, weaknamebuf, count); + } +} /* print_weaknames() */ + diff --git a/dwarfdump2/srcfilesholder.h b/dwarfdump2/srcfilesholder.h new file mode 100644 index 0000000..0594c07 --- /dev/null +++ b/dwarfdump2/srcfilesholder.h @@ -0,0 +1,89 @@ +/* + Copyright (C) 2009-2011 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 + + +*/ + +#ifndef SRCFILESHOLDER_H +#define SRCFILESHOLDER_H +// Reference counting eliminates confusion and bugs +// when deciding when to do dealloc. +// It might be nice to store a vector of string here and +// dealloc the dwarf data on construction. +// But for now we store the libdwarf strings. +class SrcfilesHolder { +public: + SrcfilesHolder():dbg_(0),srcfiles_(0),cnt_(0),refcount_(new int(1)) { }; + SrcfilesHolder(Dwarf_Debug dbg, char **srcfiles, Dwarf_Signed cnt): + dbg_(dbg),srcfiles_(srcfiles),cnt_(cnt),refcount_(new int(1)) { }; + ~SrcfilesHolder() { + (*refcount_)--; + if( (*refcount_) == 0) { + delete refcount_; + if(srcfiles_) do_delete(); + } + }; + SrcfilesHolder(const SrcfilesHolder & d):dbg_(d.dbg_), + srcfiles_(d.srcfiles_),cnt_(d.cnt_), + refcount_(d.refcount_) { + (*refcount_)++; + }; + SrcfilesHolder & operator=(const SrcfilesHolder & d) { + if(this != &d) { + (*d.refcount_)++; + (*refcount_)--; + if( (*refcount_) == 0) { + delete refcount_; + if(srcfiles_) do_delete(); + } + refcount_ = d.refcount_; + srcfiles_ = d.srcfiles_; + cnt_ = d.cnt_; + dbg_ = d.dbg_; + } + return *this; + }; + Dwarf_Signed count() { return cnt_; }; + char ** srcfiles() { return srcfiles_; }; + Dwarf_Debug dbg() { return dbg_; }; +private: + void do_delete() { + for (Dwarf_Signed si = 0; si < cnt_; ++si) { + dwarf_dealloc(dbg_, srcfiles_[si], DW_DLA_STRING); + } + dwarf_dealloc(dbg_, srcfiles_, DW_DLA_LIST); + }; + Dwarf_Debug dbg_; + char **srcfiles_; + Dwarf_Signed cnt_; + int *refcount_; +}; +#endif // SRCFILESHOLDER_H diff --git a/dwarfdump2/strstrnocase.cc b/dwarfdump2/strstrnocase.cc new file mode 100755 index 0000000..7d68ba9 --- /dev/null +++ b/dwarfdump2/strstrnocase.cc @@ -0,0 +1,115 @@ +/* + Copyright (C) 2009-2011 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 + +*/ +/* The address of the Free Software Foundation is + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + + +/* +This tries to find the string 'contained' in the +string 'container'. it returns true if found, else false. +The comparisons are independent of case. + +Regrettably there is no generally accepted version that +does this job, though GNU Linux has strcasestr() which +does what we need. + +There is a public domain stristr(). But given that dwarfdump is GPL, +it would seem (IANAL) that we cannot mix public domain code +into the release. + +The software here is independently written and indeed trivial. + +The POSIX function tolower() is only properly defined on unsigned char, hence +the ugly casts. + +strstrnocase.cc + +*/ +#include <ctype.h> +#include <stdio.h> +#include <globals.h> + +bool +is_strstrnocase(const char * container, const char * contained) +{ + const unsigned char *ct = (const unsigned char *)container; + for( ; *ct; ++ct ) + { + const unsigned char * cntnd = (const unsigned char *)contained; + bool innerwrong = true; + for( ; *cntnd; ++cntnd,++ct) + { + unsigned char lct = tolower(*ct); + unsigned char tlc = tolower(*cntnd); + if(lct != tlc) { + innerwrong=true; + break; /* Go to outer loop */ + } + innerwrong=false; + } + if(!innerwrong) { + return true; + } + } + return false; +} + +#ifdef TEST +static void +test(const char *t1, const char *t2,int resexp) +{ + bool res = is_strstrnocase(t1,t2); + if (res == resexp) { + return; + } + printf("Error,mismatch %s and %s. Expected %d got %d\n", + t1,t2,resexp,res); +} + +int main() +{ + test("aaaaa","a",1); + test("aaaaa","b",0); + test("abaaba","ba",1); + test("abaabA","Ba",1); + test("a","ab",0); + test("b","c",0); + test("b","",0); + test("","c",0); + test("","",0); + test("aaaaa","aaaaaaaa",0); +} +#endif diff --git a/dwarfdump2/tag_attr.cc b/dwarfdump2/tag_attr.cc new file mode 100644 index 0000000..e4a633c --- /dev/null +++ b/dwarfdump2/tag_attr.cc @@ -0,0 +1,278 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-2011 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/tag_attr.c,v 1.8 2005/12/01 17:34:59 davea Exp $ */ +#include <dwarf.h> +#include <stdio.h> +#include <stdlib.h> /* For exit() declaration etc. */ +#include <errno.h> /* For errno declaration. */ +#include <unistd.h> /* For getopt. */ + +#include "globals.h" +#include "naming.h" +#include "common.h" +#include "tag_common.h" +using std::string; +using std::cerr; +using std::cout; +using std::endl; + +bool ellipsis = true; /* So we can use naming.cc */ + +/* Expected input format + +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +... + +No blank lines or commentary allowed, no symbols, just numbers. + + +*/ + +unsigned int tag_attr_combination_table[ATTR_TABLE_ROW_MAXIMUM][ATTR_TABLE_COLUMN_MAXIMUM]; + + +static const char *usage[] = { + "Usage: tag_attr_build <options>\n", + " -i input-table-path\n", + " -o output-table-path\n", + " -s (Generate standard attribute table)\n", + " -e (Generate extended attribute table (common extensions))\n", + "" +}; + +string input_name; +string output_name; +bool standard_flag = false; +bool extended_flag = false; + +/* process arguments */ +void +process_args(int argc,char *argv[]) +{ + int c = 0; + bool usage_error = false; + + while ((c = getopt(argc, const_cast<char **>(argv), "i:o:se")) != EOF) { + switch (c) { + case 'i': + input_name = optarg; + break; + case 'o': + output_name = optarg; + break; + case 'e': + extended_flag = true; + break; + case 's': + standard_flag = true; + break; + default: + usage_error = true; + break; + } + } + + if (usage_error || 1 == optind || optind != argc) { + print_usage_message(argv[0],usage); + exit(FAILED); + } +} + + + +int +main(int argc, char **argv) +{ + print_version_details(argv[0],false); + process_args(argc,argv); + print_args(argc,argv); + + if (input_name.empty()) { + cerr << "Input name required, not supplied." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + FILE *fileInp = fopen(input_name.c_str(),"r"); + if (!fileInp) { + cerr << "Invalid input filename, could not open '" << + input_name << "'." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + + + if (output_name.empty()) { + cerr << "Output name required, not supplied." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + FILE *fileOut = fopen(output_name.c_str(),"w"); + if (!fileOut) { + cerr << "Invalid output filename, could not open: '" << + output_name << "'." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + if ((standard_flag && extended_flag) || + (!standard_flag && !extended_flag)) { + cerr << "Invalid table type" << endl; + cerr << "Choose -e or -s ." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + + + unsigned table_rows = 0; + unsigned table_columns = 0; + if(standard_flag) { + table_rows = STD_ATTR_TABLE_ROWS; + table_columns = STD_ATTR_TABLE_COLUMNS; + } else { + table_rows = EXT_ATTR_TABLE_ROWS; + table_columns = EXT_ATTR_TABLE_COLS; + } + + unsigned int num = 0; + int input_eof = read_value(&num,fileInp); /* 0xffffffff */ + if (IS_EOF == input_eof) { + bad_line_input("Empty input file"); + } + if (num != MAGIC_TOKEN_VALUE) { + bad_line_input("Expected 0xffffffff"); + } + unsigned int current_row = 0; + while (!feof(stdin)) { + unsigned int tag; + unsigned int curcol = 0; + + input_eof = read_value(&tag,fileInp); + if (IS_EOF == input_eof) { + /* Reached normal eof */ + break; + } + if(standard_flag) { + if (tag >= table_rows ) { + bad_line_input("tag value exceeds standard table size"); + } + } else { + if(current_row >= table_rows) { + bad_line_input("too many extended table rows."); + } + tag_attr_combination_table[current_row][0] = tag; + } + + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly.."); + } + curcol = 1; + while (num != MAGIC_TOKEN_VALUE) { + if(standard_flag) { + unsigned idx = num / BITS_PER_WORD; + unsigned bit = num % BITS_PER_WORD; + + if (idx >= table_columns) { + bad_line_input + ("too many attributes: table incomplete."); + } + tag_attr_combination_table[tag][idx] |= (1 << bit); + } else { + if (curcol >= table_columns) { + bad_line_input("too many attributes: table incomplete."); + } + tag_attr_combination_table[current_row][curcol] = num; + curcol++; + + } + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly."); + } + } + ++current_row; + } + fprintf(fileOut,"/* Generated code, do not edit. */\n"); + fprintf(fileOut,"/* Generated on %s %s */\n",__DATE__,__TIME__); + if (standard_flag) { + fprintf(fileOut,"#define ATTR_TREE_ROW_COUNT %u\n\n",table_rows); + fprintf(fileOut,"#define ATTR_TREE_COLUMN_COUNT %u\n\n",table_columns); + fprintf(fileOut, + "static unsigned int tag_attr_combination_table" + "[ATTR_TREE_ROW_COUNT][ATTR_TREE_COLUMN_COUNT] = {\n"); + } + else { + fprintf(fileOut,"/* Common extensions */\n"); + fprintf(fileOut,"#define ATTR_TREE_EXT_ROW_COUNT %u\n\n",table_rows); + fprintf(fileOut,"#define ATTR_TREE_EXT_COLUMN_COUNT %d\n\n", + table_columns); + fprintf(fileOut, + "static unsigned int tag_attr_combination_ext_table" + "[ATTR_TREE_EXT_ROW_COUNT][ATTR_TREE_EXT_COLUMN_COUNT] = {\n"); + } + + for (unsigned int i = 0; i < table_rows; i++) { + bool printonerr = false; + if(standard_flag) { + fprintf(fileOut,"/* %d %-37s*/\n",i, + get_TAG_name(i,printonerr).c_str()); + } else { + fprintf(fileOut,"/* %u %-37s*/\n", + tag_attr_combination_table[i][0], + get_TAG_name( + tag_attr_combination_table[i][0],printonerr).c_str()); + } + fprintf(fileOut," { "); + for(unsigned j = 0; j < table_columns; ++j ) { + fprintf(fileOut,"0x%08x,",tag_attr_combination_table[i][j]); + } + fprintf(fileOut,"},\n"); + } + fprintf(fileOut,"};\n"); + return (0); +} +/* A fake so we can use dwarf_names.cc */ +void print_error (Dwarf_Debug dbg, const string &msg,int res, Dwarf_Error err) +{ +} + diff --git a/dwarfdump2/tag_attr.list b/dwarfdump2/tag_attr.list new file mode 100644 index 0000000..813ae18 --- /dev/null +++ b/dwarfdump2/tag_attr.list @@ -0,0 +1,880 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_attr.list,v 1.7 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* + list for semantic check of tag-attr relation. + + 0xffffffff is a "punctuation." The final line of this file + must be 0xffffffff. The next line after each 0xffffffff + (except the final line) is a tag. The lines after this line + before the next 0xffffffff are the attributes that can be given + to the tag." + + For example, + + 0xffffffff + DW_TAG_access_declaration + DW_AT_decl_column + DW_AT_decl_file + DW_AT_decl_line + DW_AT_accessibility + DW_AT_name + DW_AT_sibling + 0xffffffff + + means "only DW_AT_decl_column, DW_AT_decl_file, DW_AT_decl_line, + DW_AT_accessibility, DW_AT_name and DW_AT_sibling can be given to + DW_TAG_access_declaration." + + This file is applied to the preprocessor, thus any C comment and + preprocessor control line is available. +*/ + +0xffffffff +DW_TAG_access_declaration +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_name +DW_AT_sibling +0xffffffff +DW_TAG_array_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_bit_stride +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_ordering +DW_AT_sibling +DW_AT_specification +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_base_type +DW_AT_allocated +DW_AT_associated +DW_AT_binary_scale +DW_AT_bit_offset +DW_AT_bit_size +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_bit_offset +DW_AT_data_location +DW_AT_decimal_scale +DW_AT_decimal_sign +DW_AT_description +DW_AT_digit_count +DW_AT_encoding +DW_AT_endianity +DW_AT_name +DW_AT_name +DW_AT_picture_string +DW_AT_sibling +DW_AT_small +0xffffffff +DW_TAG_catch_block +DW_AT_abstract_origin +DW_AT_high_pc +DW_AT_low_pc +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +0xffffffff +DW_TAG_class_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_visibility +0xffffffff +DW_TAG_common_block +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_declaration +DW_AT_location +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_visibility +0xffffffff +DW_TAG_common_inclusion +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_common_reference +DW_AT_declaration +DW_AT_sibling +DW_AT_visibility +0xffffffff +DW_TAG_compile_unit +DW_AT_base_types +DW_AT_comp_dir +DW_AT_identifier_case +DW_AT_high_pc +DW_AT_language +DW_AT_low_pc +DW_AT_macro_info +DW_AT_main_subprogram +DW_AT_name +DW_AT_producer +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +DW_AT_stmt_list +DW_AT_use_UTF8 +DW_AT_entry_pc +0xffffffff +DW_TAG_condition +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_name +DW_AT_sibling +0xffffffff +DW_TAG_const_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_constant +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_const_value +DW_AT_declaration +DW_AT_description +DW_AT_endianity +DW_AT_external +DW_AT_linkage_name +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_dwarf_procedure +DW_AT_location +0xffffffff +DW_TAG_entry_point +DW_AT_address_class +DW_AT_description +DW_AT_linkage_name +DW_AT_low_pc +DW_AT_name +DW_AT_return_addr +DW_AT_segment +DW_AT_sibling +DW_AT_static_link +DW_AT_type +0xffffffff +DW_TAG_enumeration_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_bit_stride +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_byte_stride +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_enum_class +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_enumerator +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_const_value +DW_AT_description +DW_AT_name +DW_AT_sibling +0xffffffff +DW_TAG_file_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_formal_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_artificial +DW_AT_const_value +DW_AT_default_value +DW_AT_description +DW_AT_endianity +DW_AT_is_optional +DW_AT_location +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_type +DW_AT_variable_parameter +0xffffffff +DW_TAG_friend +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_friend +DW_AT_sibling +0xffffffff +DW_TAG_imported_declaration +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_description +DW_AT_import +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_imported_module +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_import +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_imported_unit +DW_AT_import +0xffffffff +DW_TAG_inheritance +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_data_member_location +DW_AT_sibling +DW_AT_type +DW_AT_virtuality +0xffffffff +DW_TAG_inlined_subroutine +DW_AT_abstract_origin +DW_AT_call_column +DW_AT_call_file +DW_AT_call_line +DW_AT_const_expr +DW_AT_entry_pc +DW_AT_high_pc +DW_AT_low_pc +DW_AT_ranges +DW_AT_return_addr +DW_AT_segment +DW_AT_sibling +DW_AT_start_scope +DW_AT_trampoline +0xffffffff +DW_TAG_interface_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_label +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_description +DW_AT_low_pc +DW_AT_name +DW_AT_segment +DW_AT_start_scope +DW_AT_sibling +0xffffffff +DW_TAG_lexical_block +DW_AT_abstract_origin +DW_AT_description +DW_AT_high_pc +DW_AT_low_pc +DW_AT_name +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +0xffffffff +DW_TAG_member +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_bit_offset +DW_AT_bit_size +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_bit_offset +DW_AT_data_member_location +DW_AT_declaration +DW_AT_description +DW_AT_mutable +DW_AT_name +DW_AT_sibling +DW_AT_type +DW_AT_visibility +DW_AT_artificial +0xffffffff +DW_TAG_module +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_declaration +DW_AT_description +DW_AT_entry_pc +DW_AT_high_pc +DW_AT_low_pc +DW_AT_name +DW_AT_priority +DW_AT_segment +DW_AT_sibling +DW_AT_specification +DW_AT_visibility +0xffffffff +DW_TAG_namelist +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_abstract_origin +DW_AT_declaration +DW_AT_name +DW_AT_sibling +DW_AT_visibility +0xffffffff +DW_TAG_namelist_item +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_namelist_item +DW_AT_sibling +0xffffffff +DW_TAG_namespace +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_description +DW_AT_extension +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +0xffffffff +DW_TAG_packed_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_partial_unit +DW_AT_base_types +DW_AT_comp_dir +DW_AT_description +DW_AT_identifier_case +DW_AT_high_pc +DW_AT_language +DW_AT_low_pc +DW_AT_macro_info +DW_AT_main_subprogram +DW_AT_name +DW_AT_producer +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +DW_AT_stmt_list +DW_AT_use_UTF8 +0xffffffff +DW_TAG_pointer_type +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_specification +DW_AT_type +/* Comment from 1993: + "Though DWARF spec doesn't refer to DW_AT_byte_size, it may well be + given to DW_TAG_pointer_type." + Comment 31 January 2009: + Discussed in the dwarf-workgroup mailing list Jan 5 2009, that + DW_AT_byte_size is allowed. +*/ +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 (if DW_AT_byte_size allowed) */ +0xffffffff +DW_TAG_ptr_to_member_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_containing_type +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_type +DW_AT_use_location +DW_AT_visibility +0xffffffff +DW_TAG_rvalue_reference_type +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_reference_type +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +/* Comment from 1993: + "Though DWARF spec doesn't refer to DW_AT_byte_size, it may well be + given to DW_TAG_pointer_type." + Comment 31 January 2009: + Discussed in the dwarf-workgroup mailing list Jan 5 2009, that + DW_AT_byte_size is allowed. +*/ +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +0xffffffff +DW_TAG_template_alias +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_restrict_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_set_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_start_scope +DW_AT_sibling +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_shared_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_count +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_string_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_start_scope +DW_AT_string_length +DW_AT_visibility +0xffffffff +DW_TAG_structure_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_containing_type +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_visibility +0xffffffff +DW_TAG_subprogram +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_address_class +DW_AT_artificial +DW_AT_calling_convention +DW_AT_containing_type +DW_AT_declaration +DW_AT_description +DW_AT_elemental +DW_AT_entry_pc +DW_AT_explicit +DW_AT_external +DW_AT_frame_base +DW_AT_high_pc +DW_AT_inline +DW_AT_linkage_name +DW_AT_low_pc +DW_AT_main_subprogram +DW_AT_name +DW_AT_object_pointer +DW_AT_prototyped +DW_AT_pure +DW_AT_ranges +DW_AT_recursive +DW_AT_return_addr +DW_AT_segment +DW_AT_sibling +DW_AT_specification +DW_AT_start_scope +DW_AT_static_link +DW_AT_trampoline +DW_AT_type +DW_AT_visibility +DW_AT_virtuality +DW_AT_vtable_elem_location +0xffffffff +DW_TAG_subrange_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_bit_stride +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_byte_stride +DW_AT_count +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_lower_bound +DW_AT_name +DW_AT_sibling +DW_AT_threads_scaled +DW_AT_type +DW_AT_upper_bound +DW_AT_visibility +0xffffffff +DW_TAG_subroutine_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_address_class +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_prototyped +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_template_type_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_template_value_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_const_value +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_thrown_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_try_block +DW_AT_abstract_origin +DW_AT_high_pc +DW_AT_low_pc +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +0xffffffff +DW_TAG_typedef +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_union_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_allocated +DW_AT_associated +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_data_location +DW_AT_declaration +DW_AT_description +DW_AT_name +DW_AT_sibling +DW_AT_signature +DW_AT_specification +DW_AT_start_scope +DW_AT_visibility +0xffffffff +DW_TAG_unspecified_parameters +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_artificial +DW_AT_sibling +0xffffffff +DW_TAG_unspecified_type +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_description +DW_AT_sibling +0xffffffff +DW_TAG_variable +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_abstract_origin +DW_AT_accessibility +DW_AT_byte_size +DW_AT_bit_size /* Allowed in DWARF4 */ +DW_AT_const_expr +DW_AT_const_value +DW_AT_declaration +DW_AT_description +DW_AT_endianity +DW_AT_external +DW_AT_linkage_name +DW_AT_location +DW_AT_name +DW_AT_segment +DW_AT_sibling +DW_AT_specification +DW_AT_start_scope +DW_AT_type +DW_AT_visibility +DW_AT_artificial +0xffffffff +DW_TAG_variant +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_abstract_origin +DW_AT_declaration +DW_AT_discr_list +DW_AT_discr_value +DW_AT_sibling +0xffffffff +DW_TAG_variant_part +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_accessibility +DW_AT_abstract_origin +DW_AT_declaration +DW_AT_discr +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_volatile_type +DW_AT_allocated +DW_AT_associated +DW_AT_data_location +DW_AT_name +DW_AT_sibling +DW_AT_type +0xffffffff +DW_TAG_with_stmt +DW_AT_accessibility +DW_AT_address_class +DW_AT_declaration +DW_AT_high_pc +DW_AT_location +DW_AT_low_pc +DW_AT_ranges +DW_AT_segment +DW_AT_sibling +DW_AT_type +DW_AT_visibility +0xffffffff +DW_TAG_type_unit +DW_AT_language +0xffffffff + diff --git a/dwarfdump2/tag_attr_ext.list b/dwarfdump2/tag_attr_ext.list new file mode 100644 index 0000000..ce6d8b0 --- /dev/null +++ b/dwarfdump2/tag_attr_ext.list @@ -0,0 +1,78 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_attr.list,v 1.7 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* list for semantic check of tag-attr relation. + See tag_attr.list for details. +*/ + +/* Common DWARF extensions */ + +0xffffffff +DW_TAG_member +DW_AT_GNU_guarded_by /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_pt_guarded_by /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_guarded /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_pt_guarded /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +0xffffffff +DW_TAG_array_type +DW_AT_GNU_vector +0xffffffff +DW_TAG_subprogram +DW_AT_MIPS_linkage_name /* Used by GNU, SGI-IRIX, and others. */ +DW_AT_MIPS_fde /* SGI-IRIX uses this */ +DW_AT_GNU_locks_excluded /* gcc.gnu.org/wiki/ThreadSafetyAnnotationsInDWARF */ +DW_AT_GNU_exclusive_locks_required +DW_AT_GNU_shared_locks_required +0xffffffff +DW_TAG_variable +DW_AT_MIPS_linkage_name /* Used by GNU, SGI-IRIX, and others. */ +DW_AT_GNU_guarded_by +DW_AT_GNU_pt_guarded_by +DW_AT_GNU_guarded +DW_AT_GNU_pt_guarded +0xffffffff +DW_TAG_GNU_template_template_parameter +DW_AT_decl_column +DW_AT_decl_file +DW_AT_decl_line +DW_AT_name +DW_AT_GNU_template_name +DW_AT_GNU_guarded_by /* GNU changed the name of 0x2108! */ +0xffffffff + diff --git a/dwarfdump2/tag_common.cc b/dwarfdump2/tag_common.cc new file mode 100644 index 0000000..6cdc738 --- /dev/null +++ b/dwarfdump2/tag_common.cc @@ -0,0 +1,150 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-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/tag_common.c,v 1.8 2008/01/23 09:47:59 davea Exp $ */ + +#include <dwarf.h> +#include <stdio.h> +#include <stdlib.h> /* For exit() declaration etc. */ +#include <errno.h> /* For errno declaration. */ +#include <ctype.h> /* For isspace() declaration */ +#include <string> +#include <iostream> + +#include "globals.h" +#include "naming.h" +#include "tag_common.h" +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +static int linecount = 0; +static char line_in[MAX_LINE_SIZE]; + + +void +bad_line_input(const std::string &msg) +{ + cerr << "tag_(tree,attr) table build failed " << + msg << ", line "<< linecount << ": \"" << line_in << "\"" << + endl; + exit(FAILED); +} + +void +trim_newline(char *line, int max) +{ + char *end = line + max - 1; + for (; *line && (line < end); ++line) { + if (*line == '\n') { + /* Found newline, drop it */ + *line = 0; + return; + } + } + return; +} + +/* Detect empty lines (and other lines we do not want to read) */ +bool +is_skippable_line(char *pLine) +{ + bool empty = true; + + if(pLine[0] == '#') { + // Preprocessor lines are of no interest. + return true; + } + if (pLine[0] == '}') { + // The } is from an 'extern "C"' and not interesting. + return true; + } + if(strncmp(&pLine[0],"extern \"C\"",10) == 0) { + // It is an 'extern "C"' and not interesting. + return true; + } + for (; *pLine && empty; ++pLine) { + empty = isspace(*pLine); + } + return empty; +} + +/* Reads a value from the text table. + Exits with non-zero status + if the table is erroneous in some way. +*/ +int +read_value(unsigned int *outval, FILE*file) +{ + char *res = 0; + unsigned long lval; + char *strout = 0; + bool bBlankLine = true; + + ++linecount; + *outval = 0; + + while (bBlankLine) { + res = fgets(line_in, sizeof(line_in), file); + if (res == 0) { + if (ferror(file)) { + cerr << "tag_attr: Error reading table, " << + linecount << " lines read" << endl; + exit(FAILED); + } + if (feof(file)) { + return IS_EOF; + } + /* impossible */ + cerr << "tag_attr: Impossible error reading table, " << + linecount << " lines read" << endl; + exit(FAILED); + } + bBlankLine = is_skippable_line(line_in); + } + trim_newline(line_in, sizeof(line_in)); + errno = 0; + lval = strtoul(line_in, &strout, 0); + + if (strout == line_in) { + bad_line_input("bad number input!"); + } + if (errno != 0) { + int myerr = errno; + cerr << "tag_attr errno " << myerr << endl; + bad_line_input("invalid number on line"); + } + *outval = (int) lval; + return NOT_EOF; +} diff --git a/dwarfdump2/tag_common.h b/dwarfdump2/tag_common.h new file mode 100644 index 0000000..d7e6d99 --- /dev/null +++ b/dwarfdump2/tag_common.h @@ -0,0 +1,125 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2010 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2009-2011 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/tag_common.h,v 1.8 2008/01/23 09:47:59 davea Exp $ */ + +#ifndef tag_common_INCLUDED +#define tag_common_INCLUDED + + + +/* The following is the magic token used to + distinguish real tags/attrs from group-delimiters. + Blank lines have been eliminated by an awk script. +*/ +#define MAGIC_TOKEN_VALUE 0xffffffff + +/* TAG_TREE.LIST Expected input format + +0xffffffff +value of a tag +value of a standard tag that may be a child of that tag +... +0xffffffff +value of a tag +value of a standard tag that may be a child of that tag +... +0xffffffff +... + +No blank lines or commentary allowed, no symbols, just numbers. + +*/ + +/* TAG_ATTR.LIST Expected input format + +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +value of a tag +value of a standard attribute that follows that tag +... +0xffffffff +... + +No blank lines or commentary allowed, no symbols, just numbers. + +*/ + +/* We don't need really long lines: the input file is simple. */ +#define MAX_LINE_SIZE 1000 + +/* 1 more than the highest number in the DW_TAG defines, + this is for standard TAGs. Number of rows. */ +#define STD_TAG_TABLE_ROWS 0x44 +/* Enough entries to have a bit for each standard legal tag. */ +#define STD_TAG_TABLE_COLUMNS 7 + +/* TAG tree common extension maximums. */ +#define EXT_TAG_TABLE_ROWS 7 +#define EXT_TAG_TABLE_COLS 7 + +/* The following 2 used in tag_tree.c only. */ +#define TAG_TABLE_ROW_MAXIMUM STD_TAG_TABLE_ROWS +#define TAG_TABLE_COLUMN_MAXIMUM EXT_TAG_TABLE_COLS + + + +/* Number of attributes columns per tag. The array is bit fields, + BITS_PER_WORD fields per word. Dense and quick to inspect */ +#define COUNT_ATTRIBUTE_STD 7 + +#define STD_ATTR_TABLE_ROWS STD_TAG_TABLE_ROWS +#define STD_ATTR_TABLE_COLUMNS 7 +/* tag/attr tree common extension maximums. */ +#define EXT_ATTR_TABLE_ROWS 7 +#define EXT_ATTR_TABLE_COLS 7 + +/* The following 2 used in tag_attr.c only. */ +#define ATTR_TABLE_ROW_MAXIMUM STD_ATTR_TABLE_ROWS +#define ATTR_TABLE_COLUMN_MAXIMUM EXT_ATTR_TABLE_COLS + +/* Bits per 'int' to mark legal attrs. */ +#define BITS_PER_WORD 32 + +#define IS_EOF 1 +#define NOT_EOF 0 + +extern void bad_line_input(const std::string &msg); +extern void trim_newline(std::string &line, int max); +extern bool is_blank_line(const std::string &pLine); +extern int read_value(unsigned int *outval,FILE *f); + +#endif /* tag_common_INCLUDED */ diff --git a/dwarfdump2/tag_tree.cc b/dwarfdump2/tag_tree.cc new file mode 100644 index 0000000..93ea464 --- /dev/null +++ b/dwarfdump2/tag_tree.cc @@ -0,0 +1,282 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2009-2010 SN Systems Ltd. All rights reserved. + Portions Copyright 2009-2011 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/tag_tree.c,v 1.8 2005/12/01 17:34:59 davea Exp $ */ +#include <dwarf.h> +#include <stdio.h> +#include <stdlib.h> /* For exit() declaration etc. */ +#include <errno.h> /* For errno declaration. */ +#include <unistd.h> /* For getopt. */ + +#include "globals.h" +#include "naming.h" +#include "common.h" +#include "tag_common.h" +using std::cout; +using std::cerr; +using std::endl; +using std::string; + +unsigned int tag_tree_combination_table[TAG_TABLE_ROW_MAXIMUM][TAG_TABLE_COLUMN_MAXIMUM]; + +bool ellipsis = false; /* So we can use dwarf_names.c */ + +/* Expected input format + +0xffffffff +value of a tag +value of a standard tag that may be a child ofthat tag +... +0xffffffff +value of a tag +value of a standard tag that may be a child ofthat tag +... +0xffffffff +... + +No commentary allowed, no symbols, just numbers. +Blank lines are allowed and are dropped. + +*/ + +static const char *usage[] = { + "Usage: tag_tree_build <options>\n", + "options:\t-t\tGenerate Tags table\n", + " -i Input-file-path\n", + " -o Output-table-path\n", + " -e (Want Extended table (common extensions))\n", + " -s (Want Standard table)\n", + "" +}; + +static std::string input_name; +static std::string output_name; +bool extended_flag = false; +bool standard_flag = false; + +static void +process_args(int argc, char *argv[]) +{ + int c = 0; + bool usage_error = false; + + while ((c = getopt(argc, argv, "i:o:es")) != EOF) { + switch (c) { + case 'i': + input_name = optarg; + break; + case 'o': + output_name = optarg; + break; + case 'e': + extended_flag = true; + break; + case 's': + standard_flag = true; + break; + default: + usage_error = true; + break; + } + } + + if (usage_error || 1 == optind || optind != argc) { + print_usage_message(argv[0],usage); + exit(FAILED); + } +} + + + +int +main(int argc, char **argv) +{ + + + print_version_details(argv[0],false); + process_args(argc,argv); + print_args(argc,argv); + + if (input_name.empty() ) { + cerr << "Input name required, not supplied." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + FILE *fileInp = fopen(input_name.c_str(),"r"); + if (!fileInp) { + cerr << "Invalid input filename, could not open '" << + input_name << "'" << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + + + if (output_name.empty() ) { + cerr << "Output name required, not supplied." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + FILE *fileOut = fopen(output_name.c_str(),"w"); + if (!fileOut) { + cerr << "Invalid output filename, could not open: '" << + output_name << "'" << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + if ((standard_flag && extended_flag) || (!standard_flag && !extended_flag)) { + cerr <<"Invalid table type" << endl; + cerr << "Choose -e or -s ." << endl; + print_usage_message(argv[0],usage); + exit(FAILED); + } + unsigned int table_rows = 0; + unsigned int table_columns = 0; + if(standard_flag) { + table_rows = STD_TAG_TABLE_ROWS; + table_columns = STD_TAG_TABLE_COLUMNS; + } else { + table_rows = EXT_TAG_TABLE_ROWS; + table_columns = EXT_TAG_TABLE_COLS; + } + + unsigned int num = 0; + int input_eof = read_value(&num,fileInp); /* 0xffffffff */ + if (IS_EOF == input_eof) { + bad_line_input("Empty input file"); + } + if (num != MAGIC_TOKEN_VALUE) { + bad_line_input("Expected 0xffffffff"); + } + + unsigned int current_row = 0; + while (!feof(stdin)) { + unsigned int tag = 0; + unsigned int nTagLoc = 0; + + input_eof = read_value(&tag,fileInp); + if (IS_EOF == input_eof) { + /* Reached normal eof */ + break; + } + if(standard_flag) { + if (tag >= table_rows ) { + bad_line_input("tag value exceeds standard table size"); + } + } else { + if(current_row >= table_rows) { + bad_line_input("too many extended table rows."); + } + tag_tree_combination_table[current_row][0] = tag; + } + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly.."); + } + nTagLoc = 1; + while (num != 0xffffffff) { + if(standard_flag) { + unsigned idx = num / BITS_PER_WORD; + unsigned bit = num % BITS_PER_WORD; + + if (idx >= table_columns) { + cout << "Want column " << idx << ", have only " << + table_columns << endl; + bad_line_input("too many TAGs: table incomplete."); + } + tag_tree_combination_table[tag][idx] |= (1 << bit); + } else { + if(nTagLoc >= table_columns) { + cout << "Attempting to use column " << nTagLoc << + ", max is " << table_columns << endl; + bad_line_input("too many subTAGs, table incomplete."); + } + tag_tree_combination_table[current_row][nTagLoc] = num; + nTagLoc++; + } + input_eof = read_value(&num,fileInp); + if (IS_EOF == input_eof) { + bad_line_input("Not terminated correctly."); + } + } + ++current_row; /* for extended table */ + } + fprintf(fileOut,"/* Generated code, do not edit. */\n"); + fprintf(fileOut,"/* Generated on %s %s */\n",__DATE__,__TIME__); + if (standard_flag) { + fprintf(fileOut,"#define TAG_TREE_COLUMN_COUNT %d\n\n",table_columns); + fprintf(fileOut,"#define TAG_TREE_ROW_COUNT %d\n\n",table_rows); + fprintf(fileOut, + "static unsigned int tag_tree_combination_table" + "[TAG_TREE_ROW_COUNT][TAG_TREE_COLUMN_COUNT] = {\n"); + } else { + fprintf(fileOut,"#define TAG_TREE_EXT_COLUMN_COUNT %d\n\n", + table_columns); + fprintf(fileOut,"#define TAG_TREE_EXT_ROW_COUNT %d\n\n",table_rows); + fprintf(fileOut,"/* Common extensions */\n"); + fprintf(fileOut, + "static unsigned int tag_tree_combination_ext_table" + "[TAG_TREE_EXT_ROW_COUNT][TAG_TREE_EXT_COLUMN_COUNT] = {\n"); + } + + for (unsigned i = 0; i < table_rows; i++) { + bool printonerr=false; + if (standard_flag) { + fprintf(fileOut,"/* %d %-37s*/\n",i, + get_TAG_name(i,printonerr).c_str()); + } else { + fprintf(fileOut,"/* %u %-37s*/\n", + tag_tree_combination_table[i][0], + get_TAG_name( + tag_tree_combination_table[i][0],printonerr).c_str()); + } + fprintf(fileOut," { "); + for(unsigned j = 0; j < table_columns; ++j ) { + fprintf(fileOut,"0x%08x,",tag_tree_combination_table[i][j]); + } + fprintf(fileOut,"},\n"); + + } + fprintf(fileOut,"\n#define MAX_CHECKED_TAG_ID 0x%2x\n",STD_TAG_TABLE_ROWS); + fprintf(fileOut,"};\n"); + fclose(fileInp); + fclose(fileOut); + return (0); +} + +/* A fake so we can use dwarf_names.c */ +void print_error (Dwarf_Debug dbg, const string& msg,int res, Dwarf_Error err) +{ +} + diff --git a/dwarfdump2/tag_tree.list b/dwarfdump2/tag_tree.list new file mode 100644 index 0000000..ebad794 --- /dev/null +++ b/dwarfdump2/tag_tree.list @@ -0,0 +1,486 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_tree.list,v 1.6 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* + list for semantic check of tag-tree. + + 0xffffffff is a "punctuation." The final line of this file + must be 0xffffffff. The next line after each 0xffffffff + (except the final line) stands for "parent-tag." The lines + after this line before the next 0xffffffff are the tags that + can be children of the "parent-tag." + + For example, + + 0xffffffff + DW_TAG_array_type + DW_TAG_subrange_type + DW_TAG_enumeration_type + 0xffffffff + + means "only DW_TAG_subrange_type and DW_TAG_enumeration_type can + be children of DW_TAG_array_type. + + This file is applied to the preprocessor, thus any C comment and + preprocessor control line is available. +*/ + +0xffffffff +DW_TAG_access_declaration +0xffffffff +DW_TAG_array_type +DW_TAG_subrange_type +DW_TAG_enumeration_type +0xffffffff +DW_TAG_base_type +0xffffffff +DW_TAG_catch_block +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +0xffffffff +DW_TAG_class_type +DW_TAG_member +DW_TAG_inheritance +DW_TAG_access_declaration +DW_TAG_friend +DW_TAG_ptr_to_member_type +DW_TAG_subprogram +DW_TAG_template_type_parameter /* template instantiations */ +DW_TAG_template_value_parameter /* template instantiations */ +DW_TAG_typedef +DW_TAG_base_type +DW_TAG_pointer_type +DW_TAG_union_type +DW_TAG_const_type +DW_TAG_class_type /* Nested classes */ +DW_TAG_structure_type /* Nested structures */ +DW_TAG_enumeration_type /* Nested enums */ +DW_TAG_imported_declaration +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_common_block +DW_TAG_variable +0xffffffff +DW_TAG_common_inclusion +0xffffffff +DW_TAG_compile_unit +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_namespace +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_imported_module +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_type_unit +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_namespace +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_imported_module +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_condition /* COBOL */ +DW_TAG_constant +DW_TAG_subrange_type +0xffffffff +DW_TAG_const_type +0xffffffff +DW_TAG_constant +0xffffffff +DW_TAG_dwarf_procedure +0xffffffff +DW_TAG_entry_point +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_common_inclusion +0xffffffff +DW_TAG_enumeration_type +DW_TAG_enumerator +0xffffffff +DW_TAG_enumerator +0xffffffff +DW_TAG_file_type +0xffffffff +DW_TAG_formal_parameter +0xffffffff +DW_TAG_friend +0xffffffff +DW_TAG_imported_declaration +0xffffffff +DW_TAG_imported_module +0xffffffff +DW_TAG_imported_unit +0xffffffff +DW_TAG_inheritance +0xffffffff +DW_TAG_inlined_subroutine +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_lexical_block +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_inlined_subroutine +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +0xffffffff +DW_TAG_interface_type +DW_TAG_member +DW_TAG_subprogram +0xffffffff +DW_TAG_label +0xffffffff +DW_TAG_lexical_block +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_inlined_subroutine +DW_TAG_lexical_block +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_formal_parameter +0xffffffff +DW_TAG_member +0xffffffff +DW_TAG_module +0xffffffff +DW_TAG_namelist +DW_TAG_namelist_item +0xffffffff +DW_TAG_namelist_item +0xffffffff +DW_TAG_namespace +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_namespace /* Allow a nested namespace */ +DW_TAG_imported_module /* Allow imported module */ +0xffffffff +DW_TAG_packed_type +0xffffffff +DW_TAG_partial_unit +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_imported_declaration +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_common_block +DW_TAG_inlined_subroutine +DW_TAG_module +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +0xffffffff +DW_TAG_pointer_type +DW_TAG_rvalue_reference_type +DW_TAG_reference_type +DW_TAG_restrict_type +DW_TAG_ptr_to_member_type +0xffffffff +DW_TAG_ptr_to_member_type +DW_TAG_rvalue_reference_type +DW_TAG_reference_type +DW_TAG_pointer_type +DW_TAG_restrict_type +0xffffffff +DW_TAG_reference_type +DW_TAG_rvalue_reference_type +DW_TAG_reference_type +DW_TAG_pointer_type +DW_TAG_restrict_type +DW_TAG_ptr_to_member_type +0xffffffff +DW_TAG_rvalue_reference_type +DW_TAG_pointer_type +DW_TAG_restrict_type +DW_TAG_ptr_to_member_type +DW_TAG_reference_type +0xffffffff +DW_TAG_restrict_type +DW_TAG_pointer_type +DW_TAG_ptr_to_member_type +DW_TAG_rvalue_reference_type +0xffffffff +DW_TAG_set_type +0xffffffff +DW_TAG_shared_type +0xffffffff +DW_TAG_string_type +0xffffffff +DW_TAG_structure_type +DW_TAG_member +DW_TAG_inheritance +DW_TAG_access_declaration +DW_TAG_friend +DW_TAG_ptr_to_member_type +DW_TAG_variant_part +DW_TAG_subprogram +DW_TAG_template_type_parameter /* template instantiations */ +DW_TAG_template_value_parameter /* template instantiations */ +DW_TAG_typedef +DW_TAG_base_type +DW_TAG_pointer_type +DW_TAG_union_type +DW_TAG_const_type +DW_TAG_structure_type /* nested structures */ +DW_TAG_enumeration_type /* nested enums */ +DW_TAG_class_type /* nested classes */ +DW_TAG_imported_declaration /* References to namespaces */ +DW_TAG_template_alias /* C++ 2010 template alias */ +0xffffffff +DW_TAG_subprogram +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +DW_TAG_thrown_type +DW_TAG_template_type_parameter +DW_TAG_template_value_parameter +DW_TAG_common_inclusion +DW_TAG_common_block +DW_TAG_array_type +DW_TAG_class_type +DW_TAG_enumeration_type +DW_TAG_pointer_type +DW_TAG_reference_type +DW_TAG_string_type +DW_TAG_lexical_block +DW_TAG_structure_type +DW_TAG_subroutine_type +DW_TAG_typedef +DW_TAG_union_type +DW_TAG_inlined_subroutine +DW_TAG_ptr_to_member_type +DW_TAG_set_type +DW_TAG_subrange_type +DW_TAG_base_type +DW_TAG_const_type +DW_TAG_constant +DW_TAG_file_type +DW_TAG_namelist +DW_TAG_packed_type +DW_TAG_subprogram +DW_TAG_variable +DW_TAG_volatile_type +DW_TAG_label +DW_TAG_imported_module /* References to namespaces */ +DW_TAG_imported_declaration /* References to namespaces */ +0xffffffff +DW_TAG_subrange_type +0xffffffff +DW_TAG_subroutine_type +DW_TAG_formal_parameter +DW_TAG_unspecified_parameters +0xffffffff +DW_TAG_template_type_parameter +0xffffffff +DW_TAG_template_value_parameter +0xffffffff +DW_TAG_thrown_type +0xffffffff +DW_TAG_try_block +0xffffffff +DW_TAG_typedef +0xffffffff +DW_TAG_union_type +DW_TAG_friend +DW_TAG_member +DW_TAG_class_type /* Nested classes */ +DW_TAG_enumeration_type /* Nested enums */ +DW_TAG_structure_type /* Nested structures */ +DW_TAG_typedef /* Nested typedef */ +DW_TAG_subprogram +DW_TAG_template_type_parameter /* template instantiations */ +DW_TAG_template_value_parameter /* template instantiations */ +0xffffffff +DW_TAG_template_alias +DW_TAG_template_type_parameter +DW_TAG_template_value_parameter +0xffffffff +DW_TAG_unspecified_parameters +0xffffffff +DW_TAG_unspecified_type +0xffffffff +DW_TAG_variable +0xffffffff +DW_TAG_variant +DW_TAG_variant_part +0xffffffff +DW_TAG_variant_part +0xffffffff +DW_TAG_volatile_type +0xffffffff +DW_TAG_with_stmt +0xffffffff diff --git a/dwarfdump2/tag_tree_ext.list b/dwarfdump2/tag_tree_ext.list new file mode 100644 index 0000000..e671373 --- /dev/null +++ b/dwarfdump2/tag_tree_ext.list @@ -0,0 +1,63 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2009-2010 SN Systems Ltd. All rights reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + 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/tag_attr.list,v 1.7 2005/12/01 17:34:59 davea Exp $ +*/ +#include <dwarf.h> + +/* list for semantic check of tag-tree relation. + See tag_tree.list for details. + +*/ + +/* Common DWARF extensions */ + +0xffffffff +DW_TAG_structure_type +DW_TAG_variable /* GNU gcc usage. */ +0xffffffff +DW_TAG_class_type +DW_TAG_variable /* GNU gcc usage. */ +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff +DW_TAG_structure_type +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff +DW_TAG_subprogram +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff +DW_TAG_union_type +DW_TAG_GNU_template_template_parameter /* template instantiations */ +0xffffffff diff --git a/dwarfdump2/uri.cc b/dwarfdump2/uri.cc new file mode 100644 index 0000000..545bad7 --- /dev/null +++ b/dwarfdump2/uri.cc @@ -0,0 +1,477 @@ +/* + Copyright 2011 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 + +*/ + +/* 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 <iostream> //* for error and debug output. +#include <string> +#include "uri.h" +#include <stdio.h> +#include <ctype.h> +using std::string; + + +/* dwarfdump_ctype table. See dwarfdump/uritablebuild.c */ +static char dwarfdump_ctype_table[256] = { +0, /* NUL 0x00 */ +0, /* control 0x01 */ +0, /* control 0x02 */ +0, /* control 0x03 */ +0, /* control 0x04 */ +0, /* control 0x05 */ +0, /* control 0x06 */ +0, /* control 0x07 */ +0, /* control 0x08 */ +0, /* whitespace 0x09 */ +0, /* whitespace 0x0a */ +0, /* whitespace 0x0b */ +0, /* whitespace 0x0c */ +0, /* whitespace 0x0d */ +0, /* control 0x0e */ +0, /* control 0x0f */ +0, /* control 0x10 */ +0, /* control 0x11 */ +0, /* control 0x12 */ +0, /* control 0x13 */ +0, /* control 0x14 */ +0, /* control 0x15 */ +0, /* control 0x16 */ +0, /* control 0x17 */ +0, /* control 0x18 */ +0, /* control 0x19 */ +0, /* control 0x1a */ +0, /* control 0x1b */ +0, /* control 0x1c */ +0, /* control 0x1d */ +0, /* control 0x1e */ +0, /* control 0x1f */ +1, /* ' ' 0x20 */ +1, /* '!' 0x21 */ +0, /* '"' 0x22 */ +1, /* '#' 0x23 */ +1, /* '$' 0x24 */ +0, /* '%' 0x25 */ +1, /* '&' 0x26 */ +0, /* ''' 0x27 */ +1, /* '(' 0x28 */ +1, /* ')' 0x29 */ +1, /* '*' 0x2a */ +1, /* '+' 0x2b */ +1, /* ',' 0x2c */ +1, /* '-' 0x2d */ +1, /* '.' 0x2e */ +1, /* '/' 0x2f */ +1, /* '0' 0x30 */ +1, /* '1' 0x31 */ +1, /* '2' 0x32 */ +1, /* '3' 0x33 */ +1, /* '4' 0x34 */ +1, /* '5' 0x35 */ +1, /* '6' 0x36 */ +1, /* '7' 0x37 */ +1, /* '8' 0x38 */ +1, /* '9' 0x39 */ +1, /* ':' 0x3a */ +0, /* ';' 0x3b */ +1, /* '<' 0x3c */ +1, /* '=' 0x3d */ +1, /* '>' 0x3e */ +1, /* '?' 0x3f */ +1, /* '@' 0x40 */ +1, /* 'A' 0x41 */ +1, /* 'B' 0x42 */ +1, /* 'C' 0x43 */ +1, /* 'D' 0x44 */ +1, /* 'E' 0x45 */ +1, /* 'F' 0x46 */ +1, /* 'G' 0x47 */ +1, /* 'H' 0x48 */ +1, /* 'I' 0x49 */ +1, /* 'J' 0x4a */ +1, /* 'K' 0x4b */ +1, /* 'L' 0x4c */ +1, /* 'M' 0x4d */ +1, /* 'N' 0x4e */ +1, /* 'O' 0x4f */ +1, /* 'P' 0x50 */ +1, /* 'Q' 0x51 */ +1, /* 'R' 0x52 */ +1, /* 'S' 0x53 */ +1, /* 'T' 0x54 */ +1, /* 'U' 0x55 */ +1, /* 'V' 0x56 */ +1, /* 'W' 0x57 */ +1, /* 'X' 0x58 */ +1, /* 'Y' 0x59 */ +1, /* 'Z' 0x5a */ +1, /* '[' 0x5b */ +1, /* '\' 0x5c */ +1, /* ']' 0x5d */ +1, /* '^' 0x5e */ +1, /* '_' 0x5f */ +0, /* '`' 0x60 */ +1, /* 'a' 0x61 */ +1, /* 'b' 0x62 */ +1, /* 'c' 0x63 */ +1, /* 'd' 0x64 */ +1, /* 'e' 0x65 */ +1, /* 'f' 0x66 */ +1, /* 'g' 0x67 */ +1, /* 'h' 0x68 */ +1, /* 'i' 0x69 */ +1, /* 'j' 0x6a */ +1, /* 'k' 0x6b */ +1, /* 'l' 0x6c */ +1, /* 'm' 0x6d */ +1, /* 'n' 0x6e */ +1, /* 'o' 0x6f */ +1, /* 'p' 0x70 */ +1, /* 'q' 0x71 */ +1, /* 'r' 0x72 */ +1, /* 's' 0x73 */ +1, /* 't' 0x74 */ +1, /* 'u' 0x75 */ +1, /* 'v' 0x76 */ +1, /* 'w' 0x77 */ +1, /* 'x' 0x78 */ +1, /* 'y' 0x79 */ +1, /* 'z' 0x7a */ +1, /* '{' 0x7b */ +1, /* '|' 0x7c */ +1, /* '}' 0x7d */ +1, /* '~' 0x7e */ +0, /* DEL 0x7f */ +1, /* 0x80 */ +1, /* 0x81 */ +1, /* 0x82 */ +1, /* 0x83 */ +1, /* 0x84 */ +1, /* 0x85 */ +1, /* 0x86 */ +1, /* 0x87 */ +1, /* 0x88 */ +1, /* 0x89 */ +1, /* 0x8a */ +1, /* 0x8b */ +1, /* 0x8c */ +1, /* 0x8d */ +1, /* 0x8e */ +1, /* 0x8f */ +1, /* 0x90 */ +1, /* 0x91 */ +1, /* 0x92 */ +1, /* 0x93 */ +1, /* 0x94 */ +1, /* 0x95 */ +1, /* 0x96 */ +1, /* 0x97 */ +1, /* 0x98 */ +1, /* 0x99 */ +1, /* 0x9a */ +1, /* 0x9b */ +1, /* 0x9c */ +1, /* 0x9d */ +1, /* 0x9e */ +1, /* 0x9f */ +0, /* other: 0xa0 */ +1, /* 0xa1 */ +1, /* 0xa2 */ +1, /* 0xa3 */ +1, /* 0xa4 */ +1, /* 0xa5 */ +1, /* 0xa6 */ +1, /* 0xa7 */ +1, /* 0xa8 */ +1, /* 0xa9 */ +1, /* 0xaa */ +1, /* 0xab */ +1, /* 0xac */ +1, /* 0xad */ +1, /* 0xae */ +1, /* 0xaf */ +1, /* 0xb0 */ +1, /* 0xb1 */ +1, /* 0xb2 */ +1, /* 0xb3 */ +1, /* 0xb4 */ +1, /* 0xb5 */ +1, /* 0xb6 */ +1, /* 0xb7 */ +1, /* 0xb8 */ +1, /* 0xb9 */ +1, /* 0xba */ +1, /* 0xbb */ +1, /* 0xbc */ +1, /* 0xbd */ +1, /* 0xbe */ +1, /* 0xbf */ +1, /* 0xc0 */ +1, /* 0xc1 */ +1, /* 0xc2 */ +1, /* 0xc3 */ +1, /* 0xc4 */ +1, /* 0xc5 */ +1, /* 0xc6 */ +1, /* 0xc7 */ +1, /* 0xc8 */ +1, /* 0xc9 */ +1, /* 0xca */ +1, /* 0xcb */ +1, /* 0xcc */ +1, /* 0xcd */ +1, /* 0xce */ +1, /* 0xcf */ +1, /* 0xd0 */ +1, /* 0xd1 */ +1, /* 0xd2 */ +1, /* 0xd3 */ +1, /* 0xd4 */ +1, /* 0xd5 */ +1, /* 0xd6 */ +1, /* 0xd7 */ +1, /* 0xd8 */ +1, /* 0xd9 */ +1, /* 0xda */ +1, /* 0xdb */ +1, /* 0xdc */ +1, /* 0xdd */ +1, /* 0xde */ +1, /* 0xdf */ +1, /* 0xe0 */ +1, /* 0xe1 */ +1, /* 0xe2 */ +1, /* 0xe3 */ +1, /* 0xe4 */ +1, /* 0xe5 */ +1, /* 0xe6 */ +1, /* 0xe7 */ +1, /* 0xe8 */ +1, /* 0xe9 */ +1, /* 0xea */ +1, /* 0xeb */ +1, /* 0xec */ +1, /* 0xed */ +1, /* 0xee */ +1, /* 0xef */ +1, /* 0xf0 */ +1, /* 0xf1 */ +1, /* 0xf2 */ +1, /* 0xf3 */ +1, /* 0xf4 */ +1, /* 0xf5 */ +1, /* 0xf6 */ +1, /* 0xf7 */ +1, /* 0xf8 */ +1, /* 0xf9 */ +1, /* 0xfa */ +1, /* 0xfb */ +1, /* 0xfc */ +1, /* 0xfd */ +1, /* 0xfe */ +0, /* other: 0xff */ +}; +static char * +xchar(int c, char *buf, int size) +{ + snprintf(buf, size,"%%%02x",c); + return buf; +} + +/* Translate dangerous and some other characters to safe + %xx form. +*/ +void +translate_to_uri(const string &s, string &out) +{ + const char *cp = s.c_str(); + for( ; *cp; ++cp) { + int c = 0xff & (unsigned char)*cp; + if(dwarfdump_ctype_table[c]) { + out.push_back((char)c); + } else { + char buf[8]; + string b = xchar(c,buf,sizeof(buf)); + out.append(b); + } + } +} + +/* This is not very efficient, but it is seldom called. */ +static char +hexdig(char c) +{ + char ochar = 0; + if(c >= 0 && c <= '9') { + ochar = (c - '0'); + return ochar; + } + if(c >= 'a' && c <= 'f') { + ochar = (c - 'a')+10; + return ochar; + } + if(c >= 'A' && c <= 'F') { + ochar = (c - 'A')+10; + return ochar; + } + // We have an input botch here. + fprintf(stderr,"Translating from uri: " + "A supposed hexadecimal input character is " + "not 0-9 or a-f or A-F, it is (shown as hex here): %x\n",c); + return ochar; +} + +static char tohex(char c1, char c2) +{ + char out = (hexdig(c1) << 4) | hexdig(c2); + return out; +} + +static int +hexpairtochar(const char *cp, char *myochar) +{ + char ochar = 0; + int olen = 0; + char c = cp[0]; + if(c) { + char c2 = cp[1]; + if(c2) { + ochar = tohex(c,c2); + olen = 2; + } else { + std::cerr << "Translating from uri: " + "A supposed hexadecimal input character pair " + "runs off the end of the input after 1 hex digit."<< + std::endl; + /* botched input. */ + ochar = c; + olen = 1; + } + } else { + /* botched input. */ + std::cerr << "Translating from uri: " + "A supposed hexadecimal input character pair " + "runs off the end of the input." << std::endl; + ochar = '%'; + olen = 0; + } + *myochar = ochar; + return olen; +} +void +translate_from_uri(const std::string & input, string &out) +{ + const char *cp = input.c_str(); + for(; *cp; ++cp) { + char c = *cp; + if(c == '%') { + char c2 = cp[1]; + // hexpairtochar deals with c2 being NUL. + if ( c2 == '%') { + out.push_back(c); + ++cp; + continue; + } + int increment = hexpairtochar(cp+1,&c); + out.push_back(c); + cp += increment; + continue; + } + out.push_back(c); + } +} + +#ifdef TEST + +unsigned errcnt = 0; +static void +mytestfrom(const std::string & in,const std::string & expected,int testnum) +{ + string out; + translate_from_uri(in, out); + if(expected != out) { + printf(" Fail test %d expected \"%s\" got \"%s\"\n", + testnum,expected.c_str(),out.c_str()); + ++errcnt; + } +} + +static void +mytest(const std::string & in,const std::string & expected,int testnum) +{ + string out; + translate_to_uri(in.c_str(), out); + if(expected != out) { + printf(" Fail test %d expected \"%s\" got \"%s\"\n", + testnum,expected.c_str(),out.c_str()); + ++errcnt; + } +} + + +int +main() +{ + /* We no longer translate space to %20, that + turns out not to help all that much. */ + mytest("aaa","aaa",1); + mytest(" bc"," bc",2); + mytest(";bc","%3bbc",3); + mytest(" bc\n"," bc%0a",4); + mytest(";bc\n","%3bbc%0a",5); + mytest(" bc\r"," bc%0d",6); + mytest(";bc\r","%3bbc%0d",7); + mytest(" \x01"," %01",8); + mytest(";\x01","%3b%01",9); + mytestfrom("abc","abc",10); + mytestfrom("a%20bc","a bc",11); + mytestfrom("a%%20bc","a%20bc",12); + mytestfrom("a%%%20bc","a% bc",13); + mytestfrom("a%%%%20bc","a%%20bc",14); + mytestfrom("a%20","a ",15); + /* The following is mistaken input. */ + mytestfrom("a%2","a2",16); + mytestfrom("a%","a%",17); + mytest("%bc","%25bc",18); + + if(errcnt) { + printf("uri errcount ",errcnt); + } + return errcnt? 1:0; +} +#endif + diff --git a/dwarfdump2/uri.h b/dwarfdump2/uri.h new file mode 100644 index 0000000..397a6c5 --- /dev/null +++ b/dwarfdump2/uri.h @@ -0,0 +1,37 @@ +/* + Copyright 2011 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 + +*/ + + +void translate_to_uri(const std::string &inname, std::string &out); +void translate_from_uri(const std::string &input, std::string &out); + diff --git a/dwarfexample/ChangeLog b/dwarfexample/ChangeLog new file mode 100644 index 0000000..e635b2f --- /dev/null +++ b/dwarfexample/ChangeLog @@ -0,0 +1,5 @@ +2011-06-04 DavidAnderson <davea42@earthlink.net> + * frame1.c, simplereader.c: Altered indentation to + multiples of 4 spaces, no tabs. No substantive change. +2011-01-13 DavidAnderson <davea42@earthlink.net> + * New year starts. diff --git a/dwarfexample/ChangeLog2009 b/dwarfexample/ChangeLog2009 new file mode 100644 index 0000000..e65d29b --- /dev/null +++ b/dwarfexample/ChangeLog2009 @@ -0,0 +1,8 @@ +August 7, 2009 David Anderson <davea42@earthlink.net> + * frame1.c: This is a new example that uses frame functions. +July 21, 2009 David Anderson <davea42@earthlink.net> + * simplereader.c: After cur_die = sib_die; nothing was printing + cur_die, so added a print call after the assignment. +July 8, 2009 David Anderson <davea42@earthlink.net> + * Makefile: New trivial Makefile to build the example. + * simplereader.c: New trivial example using libdwarf. diff --git a/dwarfexample/ChangeLog2010 b/dwarfexample/ChangeLog2010 new file mode 100644 index 0000000..76ebe69 --- /dev/null +++ b/dwarfexample/ChangeLog2010 @@ -0,0 +1,11 @@ +April 26, 2010 David Anderson <davea42@earthlink.net> + * simplereader.c: Now prints all TAGs regardless of + whether a DIE has a DW_AT_name attribute. All names + print an "" pair so it's easy to recognize empty names + and names with embedded spaces. +March 31, 2010 David Anderson <davea42@earthlink.net> + * simplereader.c: Added a new option --names which + shows additional detail on getting attributes and source + file information. +January 3, 2010 David Anderson <davea42@earthlink.net> + * frame1.c, simplereader.c: Update copyright year. diff --git a/dwarfexample/Makefile b/dwarfexample/Makefile new file mode 100644 index 0000000..0fb18d2 --- /dev/null +++ b/dwarfexample/Makefile @@ -0,0 +1,18 @@ + + +LIBDIR= -L../libdwarf +LIBS= -ldwarf -lelf +CFLAGS= -Wall -I../libdwarf + +all: simplereader frame1 + +simplereader: simplereader.c + $(CC) $(CFLAGS) simplereader.c -o simplereader $(LIBDIR) $(LIBS) +frame1: frame1.c + $(CC) $(CFLAGS) frame1.c -o frame1 $(LIBDIR) $(LIBS) + +clean: + rm -f simplereader.o + rm -f simplereader + rm -f frame1 + rm -f frame1.o diff --git a/dwarfexample/NEWS b/dwarfexample/NEWS new file mode 100644 index 0000000..c9ad467 --- /dev/null +++ b/dwarfexample/NEWS @@ -0,0 +1,6 @@ +July 21, 2009 + Roni Simonian noticed a call to print_die_data(dbg,cur_die,in_level); + was missing so not all DIEs would print. Good Catch! +July 8, 2009 + Created a sample libdwarf consumer. Using BSD license so + anyone can use it. And a trivial Makefile. diff --git a/dwarfexample/frame1.c b/dwarfexample/frame1.c new file mode 100644 index 0000000..80d3430 --- /dev/null +++ b/dwarfexample/frame1.c @@ -0,0 +1,408 @@ +/* + Copyright (c) 2009-2010 David Anderson. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the example nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY David Anderson ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL David Anderson BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ +/* simplereader.c + This is an example of code reading dwarf .debug_frame. + It is kept as simple as possible to expose essential features. + It does not do all possible error reporting or error handling. + + It specifically calls dwarf_expand_frame_instructions() + to verify that works without crashing! + + To use, try + make + ./frame1 frame1 +*/ +#include <sys/types.h> /* For open() */ +#include <sys/stat.h> /* For open() */ +#include <fcntl.h> /* For open() */ +#include <stdlib.h> /* For exit() */ +#include <unistd.h> /* For close() */ +#include <string.h> /* For strcmp* */ +#include <stdio.h> +#include <errno.h> +#include "dwarf.h" +#include "libdwarf.h" + + +static void read_frame_data(Dwarf_Debug dbg); +static void print_fde_instrs(Dwarf_Debug dbg, Dwarf_Fde fde, + int fdenum, Dwarf_Error *error); +static void print_regtable(Dwarf_Fde fde,Dwarf_Regtable3 *tab3,int oldrulecount, + Dwarf_Debug dbg,Dwarf_Error *error); +static void +print_cie_instrs(Dwarf_Debug dbg,Dwarf_Cie cie,Dwarf_Error *error); + + +#define UNDEF_VAL 2000 +#define SAME_VAL 2001 +#define CFA_VAL 2002 + + +int +main(int argc, char **argv) +{ + + Dwarf_Debug dbg = 0; + int fd = -1; + const char *filepath = "<stdin>"; + int res = DW_DLV_ERROR; + Dwarf_Error error; + Dwarf_Handler errhand = 0; + Dwarf_Ptr errarg = 0; + int regtabrulecount = 0; + + if(argc < 2) { + fd = 0; /* stdin */ + } else { + filepath = argv[1]; + fd = open(filepath,O_RDONLY); + } + if(fd < 0) { + printf("Failure attempting to open %s\n",filepath); + } + res = dwarf_init(fd,DW_DLC_READ,errhand,errarg, &dbg,&error); + if(res != DW_DLV_OK) { + printf("Giving up, dwarf_init failed, cannot do DWARF processing\n"); + exit(1); + } + /* Do this setting after init before any real operations. + These return the old values, but here we do not + need to know the old values. The sizes and + values here are higher than most ABIs and entirely + arbitrary. + + The setting of initial_value to + the same as undefined-value (the other possible choice being + same-value) is arbitrary, different ABIs do differ, and + you have to know which is right. */ + regtabrulecount=1999; + dwarf_set_frame_undefined_value(dbg, UNDEF_VAL); + dwarf_set_frame_rule_initial_value(dbg, UNDEF_VAL); + dwarf_set_frame_same_value(dbg,SAME_VAL); + dwarf_set_frame_cfa_value(dbg,CFA_VAL); + dwarf_set_frame_rule_table_size(dbg,regtabrulecount); + + read_frame_data(dbg); + res = dwarf_finish(dbg,&error); + if(res != DW_DLV_OK) { + printf("dwarf_finish failed!\n"); + } + close(fd); + return 0; +} + +static void +read_frame_data(Dwarf_Debug dbg) +{ + Dwarf_Error error; + Dwarf_Signed cie_element_count = 0; + Dwarf_Signed fde_element_count = 0; + Dwarf_Cie *cie_data = 0; + Dwarf_Fde *fde_data = 0; + int res = DW_DLV_ERROR; + Dwarf_Signed fdenum = 0; + + + res = dwarf_get_fde_list(dbg,&cie_data,&cie_element_count, + &fde_data,&fde_element_count,&error); + if(res == DW_DLV_NO_ENTRY) { + printf("No frame data present "); + exit(0); + } + if( res == DW_DLV_ERROR) { + printf("Error reading frame data "); + exit(1); + } + printf( "%" DW_PR_DSd " cies present. " + "%" DW_PR_DSd " fdes present. \n", + cie_element_count,fde_element_count); + /*if(fdenum >= fde_element_count) { + printf("Want fde %d but only %" DW_PR_DSd " present\n",fdenum, + fde_element_count); + exit(1); + }*/ + + for(fdenum = 0; fdenum < fde_element_count; ++fdenum) { + Dwarf_Cie cie = 0; + printf("Print cie of fde %" DW_PR_DSd "\n",fdenum); + res = dwarf_get_cie_of_fde(fde_data[fdenum],&cie,&error); + if(res != DW_DLV_OK) { + printf("Error accessing fdenum %" DW_PR_DSd + " to get its cie\n",fdenum); + exit(1); + } + print_cie_instrs(dbg,cie,&error); + printf("Print fde %" DW_PR_DSd "\n",fdenum); + print_fde_instrs(dbg,fde_data[fdenum],fdenum,&error); + } + + /* Done with the data. */ + dwarf_fde_cie_list_dealloc(dbg,cie_data,cie_element_count, + fde_data, fde_element_count); + return; +} +static void +print_cie_instrs(Dwarf_Debug dbg,Dwarf_Cie cie,Dwarf_Error *error) +{ + int res = DW_DLV_ERROR; + Dwarf_Unsigned bytes_in_cie = 0; + Dwarf_Small version = 0; + char *augmentation = 0; + Dwarf_Unsigned code_alignment_factor = 0; + Dwarf_Signed data_alignment_factor = 0; + Dwarf_Half return_address_register_rule = 0; + Dwarf_Ptr instrp = 0; + Dwarf_Unsigned instr_len = 0; + + res = dwarf_get_cie_info(cie,&bytes_in_cie, + &version, &augmentation, &code_alignment_factor, + &data_alignment_factor, &return_address_register_rule, + &instrp,&instr_len,error); + if(res != DW_DLV_OK) { + printf("Unable to get cie info!\n"); + exit(1); + } +} + +static void +print_frame_instrs(Dwarf_Debug dbg,Dwarf_Frame_Op *frame_op_list, + Dwarf_Signed frame_op_count) +{ + Dwarf_Signed i = 0; + printf("Base op. Ext op. Reg. Offset. Instr-offset.\n"); + for(i = 0; i < frame_op_count; ++i) { + printf("[%" DW_PR_DSd "]", i); + printf(" %d. ", frame_op_list[i].fp_base_op); + printf(" %d. ", frame_op_list[i].fp_extended_op); + printf(" %" DW_PR_DSd ". ", frame_op_list[i].fp_offset); + printf(" 0x%" DW_PR_DUx ". ", frame_op_list[i].fp_instr_offset); + printf("\n"); + } +} + +static void +print_fde_instrs(Dwarf_Debug dbg, + Dwarf_Fde fde,int fdenum, Dwarf_Error *error) +{ + int res; + Dwarf_Addr lowpc = 0; + Dwarf_Unsigned func_length = 0; + Dwarf_Ptr fde_bytes; + Dwarf_Unsigned fde_byte_length = 0; + Dwarf_Off cie_offset = 0; + Dwarf_Signed cie_index = 0; + Dwarf_Off fde_offset = 0; + Dwarf_Addr arbitrary_addr = 0; + Dwarf_Addr actual_pc = 0; + Dwarf_Regtable3 tab3; + int oldrulecount = 0; + Dwarf_Ptr outinstrs = 0; + Dwarf_Unsigned instrslen = 0; + Dwarf_Frame_Op * frame_op_list = 0; + Dwarf_Signed frame_op_count = 0; + Dwarf_Cie cie = 0; + + + res = dwarf_get_fde_range(fde,&lowpc,&func_length,&fde_bytes, + &fde_byte_length,&cie_offset,&cie_index,&fde_offset,error); + if(res != DW_DLV_OK) { + printf("Problem getting fde range \n"); + exit(1); + } + + arbitrary_addr = lowpc + (func_length/2); + printf("function low pc 0x%" DW_PR_DUx + " and length 0x%" DW_PR_DUx + " and addr we choose 0x%" DW_PR_DUx + "\n", + lowpc,func_length,arbitrary_addr); + + /* 1 is arbitrary. We are winding up getting the + rule count here while leaving things unchanged. */ + oldrulecount = dwarf_set_frame_rule_table_size(dbg,1); + dwarf_set_frame_rule_table_size(dbg,oldrulecount); + + tab3.rt3_reg_table_size = oldrulecount; + tab3.rt3_rules = (struct Dwarf_Regtable_Entry3_s *) malloc( + sizeof(struct Dwarf_Regtable_Entry3_s)* oldrulecount); + if (!tab3.rt3_rules) { + printf("Unable to malloc for %d rules\n",oldrulecount); + exit(1); + } + + res = dwarf_get_fde_info_for_all_regs3(fde,arbitrary_addr , + &tab3,&actual_pc,error); + + if(res != DW_DLV_OK) { + printf("dwarf_get_fde_info_for_all_regs3 failed!\n"); + exit(1); + } + print_regtable(fde,&tab3,oldrulecount,dbg,error); + + res = dwarf_get_fde_instr_bytes(fde,&outinstrs,&instrslen,error); + if(res != DW_DLV_OK) { + printf("dwarf_get_fde_instr_bytes failed!\n"); + exit(1); + } + res = dwarf_get_cie_of_fde(fde,&cie,error); + if(res != DW_DLV_OK) { + printf("Error getting cie from fde\n"); + exit(1); + } + + res = dwarf_expand_frame_instructions(cie, + outinstrs,instrslen,&frame_op_list, + &frame_op_count,error); + if(res != DW_DLV_OK) { + printf("dwarf_expand_frame_instructions failed!\n"); + exit(1); + } + printf("Frame op count: %" DW_PR_DUu "\n",frame_op_count); + print_frame_instrs(dbg,frame_op_list,frame_op_count); + + dwarf_dealloc(dbg,frame_op_list, DW_DLA_FRAME_BLOCK); + free(tab3.rt3_rules); +} + +static void +print_reg(int r) +{ + switch(r) { + case SAME_VAL: + printf(" %d SAME_VAL ",r); + break; + case UNDEF_VAL: + printf(" %d UNDEF_VAL ",r); + break; + case CFA_VAL: + printf(" %d (CFA) ",r); + break; + default: + printf(" r%d ",r); + break; + } +} + +static void +print_one_regentry(const char *prefix,Dwarf_Fde fde,Dwarf_Debug dbg, + int oldrulecount,struct Dwarf_Regtable_Entry3_s *entry, + Dwarf_Error * error) +{ + int is_cfa = !strcmp("cfa",prefix); + printf("%s ",prefix); + printf("type: %d %s ", + entry->dw_value_type, + (entry->dw_value_type == DW_EXPR_OFFSET)? "DW_EXPR_OFFSET": + (entry->dw_value_type == DW_EXPR_VAL_OFFSET)? "DW_EXPR_VAL_OFFSET": + (entry->dw_value_type == DW_EXPR_EXPRESSION)? "DW_EXPR_EXPRESSION": + (entry->dw_value_type == DW_EXPR_VAL_EXPRESSION)? + "DW_EXPR_VAL_EXPRESSION": + "Unknown"); + switch(entry->dw_value_type) { + case DW_EXPR_OFFSET: + print_reg(entry->dw_regnum); + printf(" offset_rel? %d ",entry->dw_offset_relevant); + if(entry->dw_offset_relevant) { + printf(" offset %" DW_PR_DSd " " , + entry->dw_offset_or_block_len); + if(is_cfa) { + printf("defines cfa value"); + } else { + printf("address of value is CFA plus signed offset"); + } + if(!is_cfa && entry->dw_regnum != CFA_VAL) { + printf(" compiler botch, regnum != CFA_VAL"); + } + } else { + printf("value in register"); + } + break; + case DW_EXPR_VAL_OFFSET: + print_reg(entry->dw_regnum); + printf(" offset %" DW_PR_DSd " " , + entry->dw_offset_or_block_len); + if(is_cfa) { + printf("does this make sense? No?"); + } else { + printf("value at CFA plus signed offset"); + } + if(!is_cfa && entry->dw_regnum != CFA_VAL) { + printf(" compiler botch, regnum != CFA_VAL"); + } + break; + case DW_EXPR_EXPRESSION: + print_reg(entry->dw_regnum); + printf(" offset_rel? %d ",entry->dw_offset_relevant); + printf(" offset %" DW_PR_DSd " " , + entry->dw_offset_or_block_len); + printf("Block ptr set? %s ",entry->dw_block_ptr?"yes":"no"); + printf(" Value is at address given by expr val "); + /* printf(" block-ptr 0x%" DW_PR_DUx " ", + (Dwarf_Unsigned)entry->dw_block_ptr); */ + break; + case DW_EXPR_VAL_EXPRESSION: + printf(" expression byte len %" DW_PR_DSd " " , + entry->dw_offset_or_block_len); + printf("Block ptr set? %s ",entry->dw_block_ptr?"yes":"no"); + printf(" Value is expr val "); + if(!entry->dw_block_ptr) { + printf("Compiler botch. "); + } + /* printf(" block-ptr 0x%" DW_PR_DUx " ", + (Dwarf_Unsigned)entry->dw_block_ptr); */ + break; + } + printf("\n"); +} + +static void +print_regtable(Dwarf_Fde fde,Dwarf_Regtable3 *tab3,int oldrulecount, + Dwarf_Debug dbg,Dwarf_Error *error) +{ + int r; + /* We won't print too much. A bit arbitrary. */ + int max = 10; + if(max > tab3->rt3_reg_table_size) { + max = tab3->rt3_reg_table_size; + } + print_one_regentry("cfa",fde,dbg,oldrulecount,&tab3->rt3_cfa_rule, + error); + + for(r = 0; r < max; r++) { + char rn[30]; + snprintf(rn,sizeof(rn),"reg %d",r); + print_one_regentry(rn, fde,dbg,oldrulecount,tab3->rt3_rules+r, + error); + } + + +} + + + + diff --git a/dwarfexample/simplereader.c b/dwarfexample/simplereader.c new file mode 100644 index 0000000..da21b65 --- /dev/null +++ b/dwarfexample/simplereader.c @@ -0,0 +1,384 @@ +/* + Copyright (c) 2009-2010 David Anderson. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the example nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY David Anderson ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL David Anderson BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ +/* simplereader.c + This is an example of code reading dwarf .debug_info. + It is kept as simple as possible to expose essential features. + It does not do all possible error reporting or error handling. + + The --names + option adds some extra printing. + + To use, try + make + ./simplereader simplereader +*/ +#include <sys/types.h> /* For open() */ +#include <sys/stat.h> /* For open() */ +#include <fcntl.h> /* For open() */ +#include <stdlib.h> /* For exit() */ +#include <unistd.h> /* For close() */ +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "dwarf.h" +#include "libdwarf.h" + +struct srcfilesdata { + char ** srcfiles; + Dwarf_Signed srcfilescount; + int srcfilesres; +}; + +static void read_cu_list(Dwarf_Debug dbg); +static void print_die_data(Dwarf_Debug dbg, Dwarf_Die print_me,int level, + struct srcfilesdata *sf); +static void get_die_and_siblings(Dwarf_Debug dbg, Dwarf_Die in_die,int in_level, + struct srcfilesdata *sf); +static void resetsrcfiles(Dwarf_Debug dbg,struct srcfilesdata *sf); + +static int namesoptionon = 0; + +int +main(int argc, char **argv) +{ + + Dwarf_Debug dbg = 0; + int fd = -1; + const char *filepath = "<stdin>"; + int res = DW_DLV_ERROR; + Dwarf_Error error; + Dwarf_Handler errhand = 0; + Dwarf_Ptr errarg = 0; + + if(argc < 2) { + fd = 0; /* stdin */ + } else { + int i = 0; + for(i = 1; i < (argc-1) ; ++i) { + if(strcmp(argv[i],"--names") == 0) { + namesoptionon=1; + } else { + printf("Unknown argument \"%s\" ignored\n",argv[i]); + } + } + filepath = argv[i]; + fd = open(filepath,O_RDONLY); + } + if(argc > 2) { + } + if(fd < 0) { + printf("Failure attempting to open \"%s\"\n",filepath); + } + res = dwarf_init(fd,DW_DLC_READ,errhand,errarg, &dbg,&error); + if(res != DW_DLV_OK) { + printf("Giving up, cannot do DWARF processing\n"); + exit(1); + } + + read_cu_list(dbg); + res = dwarf_finish(dbg,&error); + if(res != DW_DLV_OK) { + printf("dwarf_finish failed!\n"); + } + close(fd); + return 0; +} + +static void +read_cu_list(Dwarf_Debug dbg) +{ + Dwarf_Unsigned cu_header_length = 0; + Dwarf_Half version_stamp = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half address_size = 0; + Dwarf_Unsigned next_cu_header = 0; + Dwarf_Error error; + int cu_number = 0; + + for(;;++cu_number) { + struct srcfilesdata sf; + sf.srcfilesres = DW_DLV_ERROR; + sf.srcfiles = 0; + sf.srcfilescount = 0; + Dwarf_Die no_die = 0; + Dwarf_Die cu_die = 0; + int res = DW_DLV_ERROR; + res = dwarf_next_cu_header(dbg,&cu_header_length, + &version_stamp, &abbrev_offset, &address_size, + &next_cu_header, &error); + if(res == DW_DLV_ERROR) { + printf("Error in dwarf_next_cu_header\n"); + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + /* Done. */ + return; + } + /* The CU will have a single sibling, a cu_die. */ + res = dwarf_siblingof(dbg,no_die,&cu_die,&error); + if(res == DW_DLV_ERROR) { + printf("Error in dwarf_siblingof on CU die \n"); + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + /* Impossible case. */ + printf("no entry! in dwarf_siblingof on CU die \n"); + exit(1); + } + get_die_and_siblings(dbg,cu_die,0,&sf); + dwarf_dealloc(dbg,cu_die,DW_DLA_DIE); + resetsrcfiles(dbg,&sf); + } +} + +static void +get_die_and_siblings(Dwarf_Debug dbg, Dwarf_Die in_die,int in_level, + struct srcfilesdata *sf) +{ + int res = DW_DLV_ERROR; + Dwarf_Die cur_die=in_die; + Dwarf_Die child = 0; + Dwarf_Error error; + + print_die_data(dbg,in_die,in_level,sf); + + for(;;) { + Dwarf_Die sib_die = 0; + res = dwarf_child(cur_die,&child,&error); + if(res == DW_DLV_ERROR) { + printf("Error in dwarf_child , level %d \n",in_level); + exit(1); + } + if(res == DW_DLV_OK) { + get_die_and_siblings(dbg,child,in_level+1,sf); + } + /* res == DW_DLV_NO_ENTRY */ + res = dwarf_siblingof(dbg,cur_die,&sib_die,&error); + if(res == DW_DLV_ERROR) { + printf("Error in dwarf_siblingof , level %d \n",in_level); + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + /* Done at this level. */ + break; + } + /* res == DW_DLV_OK */ + if(cur_die != in_die) { + dwarf_dealloc(dbg,cur_die,DW_DLA_DIE); + } + cur_die = sib_die; + print_die_data(dbg,cur_die,in_level,sf); + } + return; +} +static void +get_addr(Dwarf_Attribute attr,Dwarf_Addr *val) +{ + Dwarf_Error error = 0; + int res; + Dwarf_Addr uval = 0; + res = dwarf_formaddr(attr,&uval,&error); + if(res == DW_DLV_OK) { + *val = uval; + return; + } + return; +} +static void +get_number(Dwarf_Attribute attr,Dwarf_Unsigned *val) +{ + Dwarf_Error error = 0; + int res; + Dwarf_Signed sval = 0; + Dwarf_Unsigned uval = 0; + res = dwarf_formudata(attr,&uval,&error); + if(res == DW_DLV_OK) { + *val = uval; + return; + } + res = dwarf_formsdata(attr,&sval,&error); + if(res == DW_DLV_OK) { + *val = sval; + return; + } + return; +} +static void +print_subprog(Dwarf_Debug dbg,Dwarf_Die die, int level, + struct srcfilesdata *sf) +{ + int res; + Dwarf_Error error = 0; + Dwarf_Attribute *attrbuf = 0; + Dwarf_Addr lowpc = 0; + Dwarf_Addr highpc = 0; + Dwarf_Signed attrcount = 0; + Dwarf_Unsigned i; + Dwarf_Unsigned filenum = 0; + Dwarf_Unsigned linenum = 0; + char *filename = 0; + res = dwarf_attrlist(die,&attrbuf,&attrcount,&error); + if(res != DW_DLV_OK) { + return; + } + for(i = 0; i < attrcount ; ++i) { + Dwarf_Half aform; + res = dwarf_whatattr(attrbuf[i],&aform,&error); + if(res == DW_DLV_OK) { + if(aform == DW_AT_decl_file) { + get_number(attrbuf[i],&filenum); + if((filenum > 0) && (sf->srcfilescount > (filenum-1))) { + filename = sf->srcfiles[filenum-1]; + } + } + if(aform == DW_AT_decl_line) { + get_number(attrbuf[i],&linenum); + } + if(aform == DW_AT_low_pc) { + get_addr(attrbuf[i],&lowpc); + } + if(aform == DW_AT_high_pc) { + get_addr(attrbuf[i],&highpc); + } + } + dwarf_dealloc(dbg,attrbuf[i],DW_DLA_ATTR); + } + if(filenum || linenum) { + printf("<%3d> file: %" DW_PR_DUu " %s line %" + DW_PR_DUu "\n",level,filenum,filename?filename:"",linenum); + } + if(lowpc) { + printf("<%3d> low_pc : 0x%" DW_PR_DUx "\n", + level, (Dwarf_Unsigned)lowpc); + } + if(highpc) { + printf("<%3d> high_pc: 0x%" DW_PR_DUx "\n", + level, (Dwarf_Unsigned)highpc); + } + dwarf_dealloc(dbg,attrbuf,DW_DLA_LIST); +} + +static void +print_comp_dir(Dwarf_Debug dbg,Dwarf_Die die,int level, struct srcfilesdata *sf) +{ + int res; + Dwarf_Error error = 0; + Dwarf_Attribute *attrbuf = 0; + Dwarf_Signed attrcount = 0; + Dwarf_Unsigned i; + res = dwarf_attrlist(die,&attrbuf,&attrcount,&error); + if(res != DW_DLV_OK) { + return; + } + sf->srcfilesres = dwarf_srcfiles(die,&sf->srcfiles,&sf->srcfilescount, + &error); + for(i = 0; i < attrcount ; ++i) { + Dwarf_Half aform; + res = dwarf_whatattr(attrbuf[i],&aform,&error); + if(res == DW_DLV_OK) { + if(aform == DW_AT_comp_dir) { + char *name = 0; + res = dwarf_formstring(attrbuf[i],&name,&error); + if(res == DW_DLV_OK) { + printf( "<%3d> compilation directory : \"%s\"\n", + level,name); + } + } + if(aform == DW_AT_stmt_list) { + /* Offset of stmt list for this CU in .debug_line */ + } + } + dwarf_dealloc(dbg,attrbuf[i],DW_DLA_ATTR); + } + dwarf_dealloc(dbg,attrbuf,DW_DLA_LIST); +} + +static void +resetsrcfiles(Dwarf_Debug dbg,struct srcfilesdata *sf) +{ + Dwarf_Signed sri = 0; + for (sri = 0; sri < sf->srcfilescount; ++sri) { + dwarf_dealloc(dbg, sf->srcfiles[sri], DW_DLA_STRING); + } + dwarf_dealloc(dbg, sf->srcfiles, DW_DLA_LIST); + sf->srcfilesres = DW_DLV_ERROR; + sf->srcfiles = 0; + sf->srcfilescount = 0; +} + +static void +print_die_data(Dwarf_Debug dbg, Dwarf_Die print_me,int level, + struct srcfilesdata *sf) +{ + char *name = 0; + Dwarf_Error error = 0; + Dwarf_Half tag = 0; + const char *tagname = 0; + int localname = 0; + + int res = dwarf_diename(print_me,&name,&error); + + if(res == DW_DLV_ERROR) { + printf("Error in dwarf_diename , level %d \n",level); + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + name = "<no DW_AT_name attr>"; + localname = 1; + } + res = dwarf_tag(print_me,&tag,&error); + if(res != DW_DLV_OK) { + printf("Error in dwarf_tag , level %d \n",level); + exit(1); + } + res = dwarf_get_TAG_name(tag,&tagname); + if(res != DW_DLV_OK) { + printf("Error in dwarf_get_TAG_name , level %d \n",level); + exit(1); + } + if(namesoptionon) { + if( tag == DW_TAG_subprogram) { + printf( "<%3d> subprogram : \"%s\"\n",level,name); + print_subprog(dbg,print_me,level,sf); + } else if (tag == DW_TAG_compile_unit || + tag == DW_TAG_partial_unit || + tag == DW_TAG_type_unit) { + + resetsrcfiles(dbg,sf); + printf( "<%3d> source file : \"%s\"\n",level,name); + print_comp_dir(dbg,print_me,level,sf); + } + } else { + printf("<%d> tag: %d %s name: \"%s\"\n",level,tag,tagname,name); + } + if(!localname) { + dwarf_dealloc(dbg,name,DW_DLA_STRING); + } +} + + + diff --git a/dwarfgen/COPYING b/dwarfgen/COPYING new file mode 100644 index 0000000..e6e8795 --- /dev/null +++ b/dwarfgen/COPYING @@ -0,0 +1,30 @@ +Files here are copyrighted by David Anderson +(and possibly others, see the copyright notices in individual +files) by the GPL version 2. +A typical notice is: + + Copyright (C) 2010 David Anderson. + + 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. + + 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. + + +See GPL.txt in this directory for an original copy of the GPL version 2. +(GPL.txt contains an obsolete address for the Free Software Foundation, +51 Franklin Street is the correct address.) + +David Anderson is at +libdwarf-list -at- earthlink =dot= net + +280 Bella Vista Drive +Hillsborough, California 94010 +USA. diff --git a/dwarfgen/ChangeLog b/dwarfgen/ChangeLog new file mode 100644 index 0000000..f8eea52 --- /dev/null +++ b/dwarfgen/ChangeLog @@ -0,0 +1,6 @@ +2011-04-10 DavidAnderson <davea42@earthlink.net> + * config.h.in: Add HAVE_INTPTR_T + * configure.in: Test for intptr_t + * configure: Regenerated + * irepattrtodbg.cc: Add typedef and test for INTPTR_T + diff --git a/dwarfgen/GPL.txt b/dwarfgen/GPL.txt new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/dwarfgen/GPL.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/dwarfgen/Makefile.in b/dwarfgen/Makefile.in new file mode 100644 index 0000000..8998f3d --- /dev/null +++ b/dwarfgen/Makefile.in @@ -0,0 +1,89 @@ +# +# Makefile.in uses very simple make rules. +# There are no restrictions on copying this file. +# + +# Standard Makefile.in stuff: +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +mandir = $(exec_prefix)/share/man +man1dir = $(mandir)/man1 + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +DATAROOT = @datarootdir@ +SHELL = /bin/sh +CXX = @CXX@ +AR = @AR@ +#ARFLAGS = @ARFLAGS@ +RM = rm +RANLIB = @RANLIB@ +DEFS = @DEFS@ +LIBS = @LIBS@ -L ../libdwarf -ldwarf -lelf +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libdwarf +CXXFLAGS = @CXXFLAGS@ $(INCLUDES) +LDFLAGS = @LDFLAGS@ $(LIBS) + + +DIRINC = $(srcdir)/../libdwarf +INSTALL = cp + +binprefix = + +DGOBJECTS = \ + createirepformfrombinary.o \ + createirepfrombinary.o \ + dwarfgen.o \ + irepattrtodbg.o \ + ireptodbg.o + +HEADERS = \ + createirepfrombinary.h\ + general.h \ + irepattrtodbg.h \ + irepdie.h \ + irepframe.h \ + irepform.h \ + irepmacro.h \ + irepresentation.h \ + ireptodbg.h \ + strtabdata.h + +all: dwarfgen + +default: $(TARGETS) + +dwarfgen: $(HEADERS) $(DGOBJECTS) + $(CXX) $(CXXFLAGS) -o $@ $(DGOBJECTS) $(LDFLAGS) + +test: + +install: all + $(INSTALL) $(srcdir)/dwarfgen.conf $(libdir)/dwarfgen.conf + $(INSTALL) $(srcdir)/dwarfgen.1 $(man1dir)/dwarfgen.1 + $(INSTALL) dwarfgen $(bindir)/dwarfgen + +clean: + -rm -f *.o dwarfgen + +uninstall: + -rm -f $(libdir)/dwarfgen.conf + -rm -f $(man1dir)/dwarfgen.1 + -rm -f $(bindir)/dwarfgen + +distclean: clean + -rm -f config.log config.h config.cache config.status + rm -rf autom4te.cache + rm -f Makefile + +shar: + @echo "shar not set up." + +dist: + @echo "dist not set up." diff --git a/dwarfgen/README b/dwarfgen/README new file mode 100644 index 0000000..f1d4814 --- /dev/null +++ b/dwarfgen/README @@ -0,0 +1,20 @@ + +David Anderson, September 20, 2010 + +The dwarfgen application is intended as both a vehicle +for testing dwarf-generation by libdwarf and as an example +of how one uses libdwarf to generate DWARF. +In addition, it should be useful as a test vehicle for +evaluating future changes to the DWARF standard. + +It is necessary as a test-vehicle so that the libdwarf +producer code can be updated to allow more recent features +of DWARF to be supported while trying to guarantee current +producer code users are correctly supported. + +By default dwarfgen produces a fake a.out. By that we mean +that no relocation sections are written. Instead, relocations +are processed directly by dwarfgen. +Perhaps at some point a more a.out-like output will be optionally +supported. + diff --git a/dwarfgen/config.h.in b/dwarfgen/config.h.in new file mode 100644 index 0000000..75d2f40 --- /dev/null +++ b/dwarfgen/config.h.in @@ -0,0 +1,85 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if you have the <elf.h> header file. */ +#undef HAVE_ELF_H + +/* Define to 1 if you have the <getopt.h> header file. */ +#undef HAVE_GETOPT_H + +/* Define 1 if intptr_t defined in C99 stdint.h */ +#undef HAVE_INTPTR_T + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <libelf.h> header file. */ +#undef HAVE_LIBELF_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the <sgidefs.h> header file. */ +#undef HAVE_SGIDEFS_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define 1 if __uint32_t is in sgidefs.h. */ +#undef HAVE___UINT32_T_IN_SGIDEFS_H + +/* Define 1 if is in sgidefs.h. */ +#undef HAVE___UINT64_T_IN_SGIDEFS_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif diff --git a/dwarfgen/configure b/dwarfgen/configure new file mode 100755 index 0000000..2e26d1b --- /dev/null +++ b/dwarfgen/configure @@ -0,0 +1,5445 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.68. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="dwarfgen.cc" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +AR +RANLIB +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +EGREP +GREP +CPP +ac_ct_CXX +CXXFLAGS +CXX +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.68 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.68. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if ${ac_cv_prog_gcc_traditional+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgtty.h> +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <termio.h> +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + +for ac_header in elf.h getopt.h libelf.h sgidefs.h sys/types.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint32_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint64_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint64_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint32_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdint.h> +int +main () +{ +intptr_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_INTPTR_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint64_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint64_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.68. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.68, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/dwarfgen/configure.in b/dwarfgen/configure.in new file mode 100644 index 0000000..d7bb8cd --- /dev/null +++ b/dwarfgen/configure.in @@ -0,0 +1,41 @@ +dnl This is input to autoconf, producing a configure script. +AC_INIT(dwarfgen.cc) +AC_CONFIG_HEADER(config.h) + +AC_PROG_CC +AC_PROG_CXX +AC_C_BIGENDIAN +AC_GCC_TRADITIONAL +AC_PROG_INSTALL +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(AR, ar) + +AC_CHECK_HEADERS(elf.h getopt.h libelf.h sgidefs.h sys/types.h) + +dnl Attempt to determine if it is really IRIX/SGI or 'other'. +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint32_t p; p = 27;] , + AC_DEFINE(HAVE___UINT32_T_IN_SGIDEFS_H,1, + [Define 1 if __uint32_t is in sgidefs.h.])) +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint64_t p; p = 27;] , + AC_DEFINE(HAVE___UINT64_T_IN_SGIDEFS_H,1, + [Define 1 if __uint64_t is in sgidefs.h.])) +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint64_t p; p = 27;] , + AC_DEFINE(HAVE___UINT64_T_IN_SGIDEFS_H,1, + [Define 1 if is in sgidefs.h.])) +dnl the existence of sgidefs.h does not prove it's truly SGI, nor +dnl prove that __uint32_t or __uint64_t is defined therein. +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint32_t p; p = 27;] , + AC_DEFINE(HAVE___UINT32_T_IN_SGIDEFS_H,1, + [Define 1 if __uint32_t is in sgidefs.h.])) +AC_TRY_COMPILE([#include <stdint.h>],[intptr_t p; p = 27;] , + AC_DEFINE(HAVE_INTPTR_T,1, + [Define 1 if intptr_t defined in C99 stdint.h])) +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint64_t p; p = 27;] , + AC_DEFINE(HAVE___UINT64_T_IN_SGIDEFS_H,1, + [Define 1 if __uint64_t is in sgidefs.h.])) +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint64_t p; p = 27;] , + AC_DEFINE(HAVE___UINT64_T_IN_SGIDEFS_H,1, + [Define 1 if is in sgidefs.h.])) + + +AC_OUTPUT(Makefile) diff --git a/dwarfgen/createirepformfrombinary.cc b/dwarfgen/createirepformfrombinary.cc new file mode 100644 index 0000000..f9381cf --- /dev/null +++ b/dwarfgen/createirepformfrombinary.cc @@ -0,0 +1,357 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ +// createirepfrombinary.cc +// Reads an object and inserts its dwarf data into +// an object intended to hold all the dwarf data. + +#include "config.h" +#include <unistd.h> +#include <stdlib.h> // for exit +#include <iostream> +#include <string> +#include <list> +#include <vector> +#include <string.h> // For memset etc +#include <sys/stat.h> //open +#include <fcntl.h> //open +#include "elf.h" +#include "gelf.h" +#include "strtabdata.h" +#include "dwarf.h" +#include "libdwarf.h" +#include "irepresentation.h" +#include "createirepfrombinary.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +using std::vector; +using std::list; + +// THis should instantiated only locally, not with 'new'. +// It should not bt copied. +class IRFormInterface { +public: + IRFormInterface(Dwarf_Debug dbg, + Dwarf_Attribute attr,IRCUdata &cudata,IRAttr & irattr): + dbg_(dbg),attr_(attr),cudata_(cudata),irattr_(irattr) {}; + // Do not free anything we did not create here. + ~IRFormInterface() {}; + Dwarf_Debug dbg_; + Dwarf_Attribute attr_; + IRCUdata &cudata_; + IRAttr &irattr_; +private: + + // Do not instantiate. + IRFormInterface(); + IRFormInterface& operator= (const IRFormInterface &ir); + +}; + + +IRForm *formFactory(Dwarf_Debug dbg, + Dwarf_Attribute attr,IRCUdata &cudata,IRAttr & irattr) +{ + Dwarf_Error err = 0; + IRFormInterface interface(dbg,attr,cudata,irattr); + enum Dwarf_Form_Class cl = irattr.getFormClass(); + switch(cl) { + case DW_FORM_CLASS_UNKNOWN: + break; + case DW_FORM_CLASS_ADDRESS: + { + IRFormAddress *f = new IRFormAddress(&interface); + // FIXME: do we need to do anything about the symbol here? + return f; + } + break; + case DW_FORM_CLASS_BLOCK: + { + IRFormBlock *f = new IRFormBlock(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_CONSTANT: + { + IRFormConstant *f = new IRFormConstant(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_EXPRLOC: + { + IRFormExprloc *f = new IRFormExprloc(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_FLAG: + { + IRFormFlag *f = new IRFormFlag(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_LINEPTR: + { + IRFormLinePtr *f = new IRFormLinePtr(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_LOCLISTPTR: + { + IRFormLoclistPtr *f = new IRFormLoclistPtr(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_MACPTR: + { + IRFormMacPtr *f = new IRFormMacPtr(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_RANGELISTPTR: + { + IRFormRangelistPtr *f = new IRFormRangelistPtr(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_REFERENCE: + { + IRFormReference *f = new IRFormReference(&interface); + //FIXME + return f; + } + break; + case DW_FORM_CLASS_STRING: + { + IRFormString *f = new IRFormString(&interface); + return f; + } + break; + case DW_FORM_CLASS_FRAMEPTR: /* SGI/IRIX extension. */ + { + IRFormFramePtr *f = new IRFormFramePtr(&interface); + //FIXME + return f; + } + break; + default: + break; + } + return new IRFormUnknown(); +} + +IRFormAddress::IRFormAddress(IRFormInterface * interface) +{ + Dwarf_Addr val = 0; + Dwarf_Error error = 0; + int res = dwarf_formaddr(interface->attr_,&val, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read flag value. Impossible error.\n" << endl; + exit(1); + } + // FIXME do we need to do anything about the symbol here? + address_ = val; +} +IRFormBlock::IRFormBlock(IRFormInterface * interface) +{ + Dwarf_Block *blockptr = 0; + Dwarf_Error error = 0; + int res = dwarf_formblock(interface->attr_,&blockptr, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read flag value. Impossible error.\n" << endl; + exit(1); + } + insertBlock(blockptr); + dwarf_dealloc(interface->dbg_,blockptr,DW_DLA_BLOCK); +} +IRFormConstant::IRFormConstant(IRFormInterface * interface) +{ + enum Signedness oursign = SIGN_NOT_SET; + Dwarf_Unsigned uval = 0; + Dwarf_Signed sval = 0; + Dwarf_Error error = 0; + int ress = dwarf_formsdata(interface->attr_, &sval,&error); + int resu = dwarf_formudata(interface->attr_, &uval,&error); + if(resu == DW_DLV_OK ) { + if(ress == DW_DLV_OK) { + oursign = SIGN_UNKNOWN; + } else { + oursign = UNSIGNED; + sval = static_cast<Dwarf_Signed>(uval); + } + } else { + if(ress == DW_DLV_OK) { + oursign = SIGNED; + uval = static_cast<Dwarf_Unsigned>(sval); + } else { + cerr << "Unable to read constant value. Impossible error.\n" + << endl; + exit(1); + } + } + setValues(sval, uval, oursign); +} +IRFormExprloc::IRFormExprloc(IRFormInterface * interface) +{ + Dwarf_Unsigned len = 0; + Dwarf_Ptr data = 0; + Dwarf_Error error = 0; + int res = dwarf_formexprloc(interface->attr_,&len, &data, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read flag value. Impossible error.\n" << endl; + exit(1); + } + insertBlock(len,data); +} +IRFormFlag::IRFormFlag(IRFormInterface * interface) +{ + Dwarf_Bool flagval = 0; + Dwarf_Error error = 0; + int res = dwarf_formflag(interface->attr_,&flagval, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read flag value. Impossible error.\n" << endl; + exit(1); + } +} + +// We are simply assuming (here) that the value is a global offset +// to some section or other. +// Calling code ensures that is true. +// +static Dwarf_Unsigned +get_section_offset(IRFormInterface * interface) +{ + Dwarf_Unsigned uval = 0; + Dwarf_Signed sval = 0; + Dwarf_Error error = 0; + Dwarf_Off sectionoffset = 0; + int resu = 0; + // The following allows more sorts of value than + // we really want to allow here, but that is + // harmless, we believe. + int resgf = dwarf_global_formref(interface->attr_, + §ionoffset, &error); + if(resgf == DW_DLV_OK ) { + return sectionoffset; + } + resu = dwarf_formudata(interface->attr_, &uval,&error); + if(resu != DW_DLV_OK ) { + int ress = dwarf_formsdata(interface->attr_, &sval,&error); + if(ress == DW_DLV_OK) { + uval = static_cast<Dwarf_Unsigned>(sval); + } else { + cerr << "Unable to read constant offset value. Impossible error.\n" + << endl; + exit(1); + } + } + return uval; +} +IRFormLoclistPtr::IRFormLoclistPtr(IRFormInterface * interface) +{ + Dwarf_Unsigned uval = get_section_offset(interface); + setOffset(uval); +} +IRFormLinePtr::IRFormLinePtr(IRFormInterface * interface) +{ + Dwarf_Unsigned uval = get_section_offset(interface); + setOffset(uval); +} +IRFormMacPtr::IRFormMacPtr(IRFormInterface * interface) +{ + Dwarf_Unsigned uval = get_section_offset(interface); + setOffset(uval); +} +IRFormRangelistPtr::IRFormRangelistPtr(IRFormInterface * interface) +{ + Dwarf_Unsigned uval = get_section_offset(interface); + setOffset(uval); +} +IRFormFramePtr::IRFormFramePtr(IRFormInterface * interface) +{ + Dwarf_Unsigned uval = get_section_offset(interface); + setOffset(uval); +} + +// This is a .debug_info to .debug_info (or .debug_types to .debug_types) +// reference. +IRFormReference::IRFormReference(IRFormInterface * interface) +{ + Dwarf_Off val = 0; + Dwarf_Error error = 0; + Dwarf_Half form = interface->irattr_.getFinalForm(); + if(form == DW_FORM_ref_sig8) { + Dwarf_Sig8 val8; + int res = dwarf_formsig8(interface->attr_,&val8, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read sig8 reference. Impossible error.\n" << endl; + exit(1); + } + setSignature(&val8); + return; + } + if(form == DW_FORM_ref_addr) { + int res = dwarf_global_formref(interface->attr_,&val, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read reference. Impossible error.\n" << endl; + exit(1); + } + setOffset(val); + return; + } + // Otherwise it is (if a correct FORM for a .debug_info reference) + // a local CU offset, and we record it as such.. + int res = dwarf_formref(interface->attr_,&val, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read reference. Impossible error.\n" << endl; + exit(1); + } + setCUOffset(val); +} + +// Global static data used to initialized a sig8 reliably. +static Dwarf_Sig8 zero_sig8; +// Initialization helper function. +void +IRFormReference::initSig8() +{ + typeSig8_ = zero_sig8; +} + +IRFormString::IRFormString(IRFormInterface * interface) +{ + char *str = 0; + Dwarf_Error error = 0; + int res = dwarf_formstring(interface->attr_,&str, &error); + if(res != DW_DLV_OK) { + cerr << "Unable to read string. Impossible error.\n" << endl; + exit(1); + } + setString(str); +} + + + diff --git a/dwarfgen/createirepfrombinary.cc b/dwarfgen/createirepfrombinary.cc new file mode 100644 index 0000000..193e35d --- /dev/null +++ b/dwarfgen/createirepfrombinary.cc @@ -0,0 +1,608 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// createirepfrombinary.cc + +// Reads an object and inserts its dwarf data into +// an object intended to hold all the dwarf data. + +#include "config.h" +#include <unistd.h> +#include <stdlib.h> // for exit +#include <iostream> +#include <string> +#include <list> +#include <vector> +#include <string.h> // For memset etc +#include <sys/stat.h> //open +#include <fcntl.h> //open +#include "elf.h" +#include "gelf.h" +#include "strtabdata.h" +#include "dwarf.h" +#include "libdwarf.h" +#include "irepresentation.h" +#include "createirepfrombinary.h" +#include "general.h" // For IToHex() + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +using std::vector; +using std::list; + +static void readFrameDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep); +static void readMacroDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep); +static void readCUDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep); + +class DbgInAutoCloser { +public: + DbgInAutoCloser(Dwarf_Debug dbg,int fd): dbg_(dbg),fd_(fd) {}; + ~DbgInAutoCloser() { + Dwarf_Error err = 0; + dwarf_finish(dbg_,&err); + close(fd_); + }; +private: + Dwarf_Debug dbg_; + int fd_; +}; + + +void +createIrepFromBinary(const std::string &infile, + IRepresentation & irep) +{ + Dwarf_Debug dbg = 0; + Dwarf_Error err; + int fd = open(infile.c_str(),O_RDONLY, 0); + if(fd < 0 ) { + cerr << "Unable to open " << infile << + " for reading." << endl; + exit(1); + } + // All reader error handling is via the err argument. + int res = dwarf_init(fd,DW_DLC_READ, + 0, + 0, + &dbg, + &err); + if(res != DW_DLV_OK) { + close(fd); + cerr << "Error init-ing " << infile << + " for reading." << endl; + exit(1); + } + + DbgInAutoCloser closer(dbg,fd); + + readFrameDataFromBinary(dbg,irep); + readCUDataFromBinary(dbg,irep); + readMacroDataFromBinary(dbg,irep); + + return; +} + +static void +readFrameDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep) +{ + Dwarf_Error err = 0; + Dwarf_Cie * cie_data = 0; + Dwarf_Signed cie_count = 0; + Dwarf_Fde * fde_data = 0; + Dwarf_Signed fde_count = 0; + int res = dwarf_get_fde_list(dbg, + &cie_data, + &cie_count, + &fde_data, + &fde_count, + &err); + if(res == DW_DLV_NO_ENTRY) { + // No frame data. + return; + } + if(res == DW_DLV_ERROR) { + cerr << "Error reading frame data " << endl; + exit(1); + } + + for(Dwarf_Signed i =0; i < cie_count; ++i) { + Dwarf_Unsigned bytes_in_cie = 0; + Dwarf_Small version = 0; + char * augmentation = 0; + Dwarf_Unsigned code_alignment_factor = 0; + Dwarf_Signed data_alignment_factor = 0; + Dwarf_Half return_address_register_rule = 0; + Dwarf_Ptr initial_instructions = 0; + Dwarf_Unsigned initial_instructions_length = 0; + res = dwarf_get_cie_info(cie_data[i], &bytes_in_cie, + &version,&augmentation, &code_alignment_factor, + &data_alignment_factor,&return_address_register_rule, + &initial_instructions,&initial_instructions_length, + &err); + if(res != DW_DLV_OK) { + cerr << "Error reading frame data cie index " << i << endl; + exit(1); + } + // Index in cie_data must match index in ciedata_, here + // correct by construction. + IRCie cie(bytes_in_cie,version,augmentation,code_alignment_factor, + data_alignment_factor,return_address_register_rule, + initial_instructions,initial_instructions_length); + irep.framedata().insert_cie(cie); + } + for(Dwarf_Signed i =0; i < fde_count; ++i) { + Dwarf_Addr low_pc = 0; + Dwarf_Unsigned func_length = 0; + Dwarf_Ptr fde_bytes = 0; + Dwarf_Unsigned fde_byte_length = 0; + Dwarf_Off cie_offset = 0; + Dwarf_Signed cie_index = 0; + Dwarf_Off fde_offset = 0; + res = dwarf_get_fde_range(fde_data[i], &low_pc, + &func_length,&fde_bytes, &fde_byte_length, + &cie_offset,&cie_index, + &fde_offset, + &err); + if(res != DW_DLV_OK) { + cerr << "Error reading frame data fde index " << i << endl; + exit(1); + } + IRFde fde(low_pc,func_length,fde_bytes,fde_byte_length, + cie_offset, cie_index,fde_offset); + Dwarf_Ptr instr_in = 0; + Dwarf_Unsigned instr_len = 0; + res = dwarf_get_fde_instr_bytes(fde_data[i], + &instr_in, &instr_len, &err); + if(res != DW_DLV_OK) { + cerr << "Error reading frame data fde instructions " << i << endl; + exit(1); + } + fde.get_fde_instrs_into_ir(instr_in,instr_len); + irep.framedata().insert_fde(fde); + } + dwarf_fde_cie_list_dealloc(dbg,cie_data,cie_count, + fde_data,fde_count); +} + + +static void +readCUMacroDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep, + Dwarf_Unsigned macrodataoffset,IRCUdata &cu) +{ + // Arbitrary, but way too high to be real! + // Probably should be lower. + Dwarf_Unsigned maxcount = 1000000000; + Dwarf_Error error; + Dwarf_Signed mcount=0; + Dwarf_Macro_Details *md = 0; + int res = dwarf_get_macro_details(dbg,macrodataoffset, + maxcount, &mcount, &md, &error); + if(res == DW_DLV_OK) { + IRMacro ¯odata = irep.macrodata(); + vector<IRMacroRecord> mvec = macrodata.getMacroVec(); + mvec.reserve(mcount); + Dwarf_Unsigned dieoffset = cu.baseDie().getGlobalOffset(); + Dwarf_Macro_Details *mdp = md; + for(int i = 0; i < mcount; ++i, mdp++ ) { + IRMacroRecord i(dieoffset,mdp->dmd_offset, + mdp->dmd_type, mdp->dmd_lineno, + mdp->dmd_fileindex, mdp->dmd_macro?mdp->dmd_macro:""); + mvec.push_back(i); + } + } + dwarf_dealloc(dbg, md, DW_DLA_STRING); +} + +void +get_basic_attr_data_one_attr(Dwarf_Debug dbg, + Dwarf_Attribute attr,IRCUdata &cudata,IRAttr & irattr) +{ + Dwarf_Error error; + Dwarf_Half attrnum = 0; + Dwarf_Half dirform = 0; + Dwarf_Half indirform = 0; + int res = dwarf_whatattr(attr,&attrnum,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get attr number " << endl; + exit(1); + } + res = dwarf_whatform(attr,&dirform,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get attr form " << endl; + exit(1); + } + + res = dwarf_whatform_direct(attr,&indirform,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get attr direct form " << endl; + exit(1); + } + irattr.setBaseData(attrnum,dirform,indirform); + enum Dwarf_Form_Class cl = dwarf_get_form_class( + cudata.getVersionStamp(), attrnum, + cudata.getOffsetSize(), dirform); + irattr.setFormClass(cl); + if (cl == DW_FORM_CLASS_UNKNOWN) { + cerr << "Unable to figure out form class. ver " << + cudata.getVersionStamp() << + " attrnum " << attrnum << + " offsetsize " << cudata.getOffsetSize() << + " formnum " << dirform << endl; + return; + } + irattr.setFormData(formFactory(dbg,attr,cudata,irattr)); +} +void +get_basic_die_data(Dwarf_Debug dbg,Dwarf_Die indie,IRDie &irdie) +{ + Dwarf_Half tagval = 0; + Dwarf_Error error = 0; + int res = dwarf_tag(indie,&tagval,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get die tag "<< endl; + exit(1); + } + Dwarf_Off goff = 0; + res = dwarf_dieoffset(indie,&goff,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get die offset "<< endl; + exit(1); + } + Dwarf_Off localoff = 0; + res = dwarf_die_CU_offset(indie,&localoff,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get cu die offset "<< endl; + exit(1); + } + irdie.setBaseData(tagval,goff,localoff); +} + + +static void +get_attrs_of_die(Dwarf_Die in_die,IRDie &irdie, + IRCUdata &data, IRepresentation &irep, + Dwarf_Debug dbg) +{ + Dwarf_Error error = 0; + Dwarf_Attribute *atlist = 0; + Dwarf_Signed atcnt = 0; + std::list<IRAttr> &attrlist = irdie.getAttributes(); + int res = dwarf_attrlist(in_die, &atlist,&atcnt,&error); + if(res == DW_DLV_NO_ENTRY) { + return; + } + if(res == DW_DLV_ERROR) { + cerr << "dwarf_attrlist failed " << endl; + exit(1); + } + for (Dwarf_Signed i = 0; i < atcnt; ++i) { + Dwarf_Attribute attr = atlist[i]; + IRAttr irattr; + get_basic_attr_data_one_attr(dbg,attr,data,irattr); + attrlist.push_back(irattr); + + } + dwarf_dealloc(dbg,atlist, DW_DLA_LIST); +} + +// Invariant: IRDie and IRCUdata is in the irep tree, +// not local record references to local scopes. +static void +get_children_of_die(Dwarf_Die in_die,IRDie&irdie, + IRCUdata &ircudata, + IRepresentation &irep, + Dwarf_Debug dbg) +{ + Dwarf_Die curchilddie = 0; + Dwarf_Error error = 0; + int res = dwarf_child(in_die,&curchilddie,&error); + if(res == DW_DLV_NO_ENTRY) { + return; + } + if(res == DW_DLV_ERROR) { + cerr << "dwarf_child failed " << endl; + exit(1); + } + //std::list<IRDie> & childlist = irdie.getChildren(); + int childcount = 0; + for(;;) { + IRDie child; + get_basic_die_data(dbg,curchilddie,child); + get_attrs_of_die(curchilddie,child,ircudata,irep,dbg); + irdie.addChild(child); + IRDie &lastchild = irdie.lastChild(); + + get_children_of_die(curchilddie,lastchild,ircudata,irep,dbg); + ++childcount; + + Dwarf_Die tchild = 0; + res = dwarf_siblingof(dbg,curchilddie,&tchild,&error); + if(res == DW_DLV_NO_ENTRY) { + break; + } + if(res == DW_DLV_ERROR) { + cerr << "dwarf_siblingof failed " << endl; + exit(1); + } + dwarf_dealloc(dbg,curchilddie,DW_DLA_DIE); + curchilddie = tchild; + } + dwarf_dealloc(dbg,curchilddie,DW_DLA_DIE); +} + +static void +get_linedata_of_cu_die(Dwarf_Die in_die,IRDie&irdie, + IRCUdata &ircudata, + IRepresentation &irep, + Dwarf_Debug dbg) +{ + Dwarf_Error error = 0; + char **srcfiles = 0; + Dwarf_Signed srccount = 0; + IRCULineData&culinesdata = ircudata.getCULines(); + int res = dwarf_srcfiles(in_die,&srcfiles, &srccount,&error); + if(res == DW_DLV_ERROR) { + cerr << "dwarf_srcfiles failed " << endl; + exit(1); + } else if (res == DW_DLV_NO_ENTRY) { + // No data. + return; + } + + std::vector<IRCUSrcfile> &srcs = culinesdata.get_cu_srcfiles(); + for (Dwarf_Signed i = 0; i < srccount; ++i) { + IRCUSrcfile S(srcfiles[i]); + srcs.push_back(S); + /* use srcfiles[i] */ + dwarf_dealloc(dbg, srcfiles[i], DW_DLA_STRING); + } + dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST); + + Dwarf_Line * linebuf = 0; + Dwarf_Signed linecnt = 0; + int res2 = dwarf_srclines(in_die,&linebuf,&linecnt, &error); + if(res == DW_DLV_ERROR) { + cerr << "dwarf_srclines failed " << endl; + exit(1); + } else if (res == DW_DLV_NO_ENTRY) { + // No data. + cerr << "dwarf_srclines failed NO_ENTRY, crazy " + "since srcfiles worked" << endl; + exit(1); + } + + std::vector<IRCULine> &lines = culinesdata.get_cu_lines(); + for(Dwarf_Signed j = 0; j < linecnt ; ++j ) { + Dwarf_Line li = linebuf[j]; + int lres; + + Dwarf_Addr address = 0; + lres = dwarf_lineaddr(li,&address,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineaddr failed. " << endl; + exit(1); + } + Dwarf_Bool is_addr_set = 0; + lres = dwarf_line_is_addr_set(li,&is_addr_set,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_line_is_addr_set failed. " << endl; + exit(1); + } + Dwarf_Unsigned fileno = 0; + lres = dwarf_line_srcfileno(li,&fileno,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_srcfileno failed. " << endl; + exit(1); + } + Dwarf_Unsigned lineno = 0; + lres = dwarf_lineno(li,&lineno,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineno failed. " << endl; + exit(1); + } + Dwarf_Unsigned lineoff = 0; + lres = dwarf_lineoff_b(li,&lineoff,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineoff failed. " << endl; + exit(1); + } + char *linesrctmp = 0; + lres = dwarf_linesrc(li,&linesrctmp,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_linesrc failed. " << endl; + exit(1); + } + // libdwarf is trying to generate a full path, + // the string here is that generated data, not + // simply the 'file' path represented by the + // file number (fileno). + std::string linesrc(linesrctmp); + + + Dwarf_Bool is_stmt = 0; + lres = dwarf_linebeginstatement(li,&is_stmt,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_linebeginstatement failed. " << endl; + exit(1); + } + + Dwarf_Bool basic_block = 0; + lres = dwarf_lineblock(li,&basic_block,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineblock failed. " << endl; + exit(1); + } + + Dwarf_Bool end_sequence = 0; + lres = dwarf_lineendsequence(li,&end_sequence,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineendsequence failed. " << endl; + exit(1); + } + + Dwarf_Bool prologue_end = 0; + Dwarf_Bool epilogue_begin = 0; + Dwarf_Unsigned isa = 0; + Dwarf_Unsigned discriminator = 0; + lres = dwarf_prologue_end_etc(li,&prologue_end, + &epilogue_begin,&isa,&discriminator,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_prologue_end_etc failed. " << endl; + exit(1); + } + + IRCULine L(address, + is_addr_set, + fileno, + lineno, + lineoff, + linesrc, + is_stmt, + basic_block, + end_sequence, + prologue_end,epilogue_begin, + isa,discriminator); + lines.push_back(L); + } + dwarf_srclines_dealloc(dbg, linebuf, linecnt); +} + +static bool +getToplevelOffsetAttr(Dwarf_Die cu_die,Dwarf_Half attrnumber, + Dwarf_Unsigned &offset_out) +{ + Dwarf_Error error = 0; + Dwarf_Off offset = 0; + Dwarf_Attribute attr = 0; + int res = dwarf_attr(cu_die,attrnumber,&attr, &error); + bool foundit = false; + Dwarf_Off sectoff = 0; + if(res == DW_DLV_OK) { + Dwarf_Signed sval = 0; + Dwarf_Unsigned uval = 0; + res = dwarf_global_formref(attr,&offset,&error); + if(res == DW_DLV_OK) { + foundit = true; + offset_out = offset; + } + } + return foundit; +} + +// We record the .debug_info info for each CU found +// To start with we restrict attention to very few DIEs and +// attributes, but intend to get all eventually. +static void +readCUDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep) +{ + Dwarf_Error error; + int cu_number = 0; + std::list<IRCUdata> &culist = irep.infodata().getCUData(); + + for(;;++cu_number) { + Dwarf_Unsigned cu_header_length = 0; + Dwarf_Half version_stamp = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half address_size = 0; + Dwarf_Unsigned next_cu_header = 0; + Dwarf_Half offset_size = 0; + Dwarf_Half extension_size = 0; + Dwarf_Die no_die = 0; + Dwarf_Die cu_die = 0; + int res = DW_DLV_ERROR; + res = dwarf_next_cu_header_b(dbg,&cu_header_length, + &version_stamp, &abbrev_offset, &address_size, + &offset_size, &extension_size, + &next_cu_header, &error); + if(res == DW_DLV_ERROR) { + cerr <<"Error in dwarf_next_cu_header"<< endl; + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + /* Done. */ + return; + } + IRCUdata cudata(cu_header_length,version_stamp, + abbrev_offset,address_size, offset_size, + extension_size,next_cu_header); + + // The CU will have a single sibling (well, it is + // not exactly a sibling, but close enough), a cu_die. + res = dwarf_siblingof(dbg,no_die,&cu_die,&error); + if(res == DW_DLV_ERROR) { + cerr <<"Error in dwarf_siblingof on CU die "<< endl; + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + /* Impossible case. */ + cerr <<"no Entry! in dwarf_siblingof on CU die "<< endl; + exit(1); + } + Dwarf_Off macrooffset = 0; + bool foundmsect = getToplevelOffsetAttr(cu_die,DW_AT_macro_info, + macrooffset); + Dwarf_Off linesoffset = 0; + bool foundlines = getToplevelOffsetAttr(cu_die,DW_AT_stmt_list, + linesoffset); + Dwarf_Off dieoff = 0; + res = dwarf_dieoffset(cu_die,&dieoff,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get cu die offset for macro infomation "<< endl; + exit(1); + } + if(foundmsect) { + cudata.setMacroData(macrooffset,dieoff); + } + if(foundlines) { + cudata.setLineData(linesoffset,dieoff); + } + culist.push_back(cudata); + IRCUdata & treecu = irep.infodata().lastCU(); + IRDie &cuirdie = treecu.baseDie(); + get_basic_die_data(dbg,cu_die,cuirdie); + get_attrs_of_die(cu_die,cuirdie,treecu,irep,dbg); + get_children_of_die(cu_die,cuirdie,treecu,irep,dbg); + get_linedata_of_cu_die(cu_die,cuirdie,treecu,irep,dbg); + dwarf_dealloc(dbg,cu_die,DW_DLA_DIE); + } + // If we want pointers from child to parent now is the time + // we can construct them. +} + +// We read thru the CU headers and the CU die to find +// the macro info for each CU (if any). +// We record the CU macro info for each CU found (using +// the value of the DW_AT_macro_info attribute, if any). +static void +readMacroDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep) +{ + + list<IRCUdata> &cudata = irep.infodata().getCUData(); + list<IRCUdata>::iterator it = cudata.begin(); + int ct = 0; + for( ; it != cudata.end(); ++it,++ct) { + Dwarf_Unsigned macrooffset = 0; + Dwarf_Unsigned cudieoffset = 0; + bool foundmsect = it->hasMacroData(¯ooffset,&cudieoffset); + if(foundmsect) { + readCUMacroDataFromBinary(dbg, irep, macrooffset,*it); + } + } +} + diff --git a/dwarfgen/createirepfrombinary.h b/dwarfgen/createirepfrombinary.h new file mode 100644 index 0000000..32d7d04 --- /dev/null +++ b/dwarfgen/createirepfrombinary.h @@ -0,0 +1,22 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// createirepfrombinary.h + + +void createIrepFromBinary(const std::string &infile, + IRepresentation & irep); diff --git a/dwarfgen/dwarfgen.1 b/dwarfgen/dwarfgen.1 new file mode 100644 index 0000000..dd90cbb --- /dev/null +++ b/dwarfgen/dwarfgen.1 @@ -0,0 +1,10 @@ +.TH DWARFGEN +.SH NAME +dwarfgen \- Generate example DWARF data. +.SH SYNOPSIS +.B dwarfgen +.SH DESCRIPTION +The +.B dwarfgen +command creates DWARF sections as requested by specific options. +The command is under development as of January 2010. diff --git a/dwarfgen/dwarfgen.cc b/dwarfgen/dwarfgen.cc new file mode 100755 index 0000000..1eae4a4 --- /dev/null +++ b/dwarfgen/dwarfgen.cc @@ -0,0 +1,666 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ +// dwarfgen.cc +// +// Using some information source, create a tree of dwarf +// information (speaking of a DIE tree). +// Turn the die tree into dwarfdata using libdwarf producer +// and write the resulting data in an object file. +// It is a bit inconsistent in error handling just to +// demonstrate the various possibilities using the producer +// library. +// +// dwarfgen [-t def|obj|txt] [-o outpath] [-c cunum] path + +// where -t means what sort of input to read +// def means predefined (no input is read, the output +// is based on some canned setups built into dwarfgen). +// 'path' is ignored in this case. This is the default. +// +// obj means 'path' is required, it is the object file to +// read (the dwarf sections are duplicated in the output file) +// +// txt means 'path' is required, path must contain plain text +// (in a form rather like output by dwarfdump) +// that defines the dwarf that is to be output. +// +// where -o means specify the pathname of the output object. If not +// supplied testout.o is used as the default output path. +// where -c supplies a CU number of the obj input to output +// because the dwarf producer wants just one CU. +// Default is -1 which won't match anything. + +#include "config.h" +#include <unistd.h> +#include <stdlib.h> // for exit +#include <iostream> +#include <sstream> +#include <iomanip> +#include <string> +#include <list> +#include <vector> +#include <string.h> // For memset etc +#include <sys/stat.h> //open +#include <fcntl.h> //open +#include "general.h" +#include "elf.h" +#include "gelf.h" +#include "strtabdata.h" +#include "dwarf.h" +#include "libdwarf.h" +#include "irepresentation.h" +#include "ireptodbg.h" +#include "createirepfrombinary.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +using std::vector; + +static void write_object_file(Dwarf_P_Debug dbg, IRepresentation &irep); +static void write_text_section(Elf * elf); +static void write_generated_dbg(Dwarf_P_Debug dbg,Elf * elf, + IRepresentation &irep); + +static string outfile("testout.o"); +static string infile; +static enum WhichInputSource { OptNone, OptReadText,OptReadBin,OptPredefined} + whichinput(OptPredefined); + + +// This is a global so thet CallbackFunc can get to it +// If we used the dwarf_producer_init_c() user_data pointer +// creatively we would not need a global. +static IRepresentation Irep; + +static Elf * elf = 0; +static Elf32_Ehdr * ehp = 0; +static strtabdata secstrtab; + +// loff_t is signed for some reason (strange) but we make offsets unsigned. +#define LOFFTODWUNS(x) ( (Dwarf_Unsigned)(x)) + +class SectionFromDwarf { +public: + std::string name_; + Dwarf_Unsigned section_name_itself_; + ElfSymIndex section_name_symidx_; + int size_; + Dwarf_Unsigned type_; + Dwarf_Unsigned flags_; + Dwarf_Unsigned link_; + Dwarf_Unsigned info_; +private: + ElfSectIndex elf_sect_index_; + Dwarf_Unsigned lengthWrittenToElf_; +public: + Dwarf_Unsigned getNextOffset() { return lengthWrittenToElf_; } + void setNextOffset(Dwarf_Unsigned v) { lengthWrittenToElf_ = v; } + + unsigned getSectionNameSymidx() { + return section_name_symidx_.getSymIndex(); }; + SectionFromDwarf():section_name_itself_(0), + section_name_symidx_(0), + size_(0),type_(0),flags_(0), + link_(0), info_(0), elf_sect_index_(0), + lengthWrittenToElf_(0) {} ; + ~SectionFromDwarf() {}; + void setSectIndex(ElfSectIndex v) { elf_sect_index_ = v;} + ElfSectIndex getSectIndex() const { return elf_sect_index_;} + SectionFromDwarf(const std::string&name, + int size,Dwarf_Unsigned type,Dwarf_Unsigned flags, + Dwarf_Unsigned link, Dwarf_Unsigned info): + name_(name), + size_(size),type_(type),flags_(flags), + link_(link), info_(info), elf_sect_index_(0), + lengthWrittenToElf_(0) { + // Now create section name string section. + section_name_itself_ = secstrtab.addString(name.c_str()); + ElfSymbols& es = Irep.getElfSymbols(); + // Now creat a symbol for the section name. + // (which has its own string table) + section_name_symidx_ = es.addElfSymbol(0,name); + } ; +}; + +vector<SectionFromDwarf> dwsectab; + +static ElfSectIndex create_dw_elf(SectionFromDwarf &ds); + +static SectionFromDwarf & FindMySection(const ElfSectIndex & elf_section_index) +{ + for(unsigned i =0; i < dwsectab.size(); ++i) { + if(elf_section_index.getSectIndex() != + dwsectab[i].getSectIndex().getSectIndex()) { + continue; + } + return dwsectab[i]; + } + cerr << "Unable to find my dw sec data for elf section " << + elf_section_index.getSectIndex() << endl; + exit(1); +} + +static unsigned +createnamestr(unsigned strtabstroff) +{ + Elf_Scn * strscn =elf_newscn(elf); + if(!strscn) { + cerr << "Unable to elf_newscn() on " << outfile << endl; + exit(1); + } + Elf_Data* shstr =elf_newdata(strscn); + if(!shstr) { + cerr << "Unable to elf_newdata() on " << outfile << endl; + exit(1); + } + shstr->d_buf = secstrtab.exposedata(); + shstr->d_type = ELF_T_BYTE; + shstr->d_size = secstrtab.exposelen(); + shstr->d_off = 0; + shstr->d_align = 1; + shstr->d_version = EV_CURRENT; + + Elf32_Shdr * strshdr = elf32_getshdr(strscn); + if(!strshdr) { + cerr << "Unable to elf_getshdr() on " << outfile << endl; + exit(1); + } + strshdr->sh_name = strtabstroff; + strshdr->sh_type= SHT_STRTAB; + strshdr->sh_flags = SHF_STRINGS; + strshdr->sh_addr = 0; + strshdr->sh_offset = 0; + strshdr->sh_size = 0; + strshdr->sh_link = 0; + strshdr->sh_info = 0; + strshdr->sh_addralign = 1; + strshdr->sh_entsize = 0; + return elf_ndxscn(strscn); +} + + +// This functional interface is defined by libdwarf. +int CallbackFunc( + char* name, + int size, + Dwarf_Unsigned type, + Dwarf_Unsigned flags, + Dwarf_Unsigned link, + Dwarf_Unsigned info, + Dwarf_Unsigned* sect_name_symbol_index, + void * user_data, + int* error) +{ + // Create an elf section. + // If the data is relocations, we suppress the generation + // of a section when we intend to do the relocations + // ourself (quite normal for dwarfgen but would + // be really surprising for a normal compiler + // back end using the producer code). + + // The section name appears both in the section strings .shstrtab and + // in the elf symtab .symtab and its strings .strtab. + + if (0 == strncmp(name,".rel",4)) { + // It is relocation, create no section! + return 0; + } + SectionFromDwarf ds(name,size,type,flags,link,info) ; + *sect_name_symbol_index = ds.getSectionNameSymidx(); + ElfSectIndex createdsec = create_dw_elf(ds); + + // Do all the data creation before pushing (copying) ds onto dwsectab! + dwsectab.push_back(ds); + return createdsec.getSectIndex(); +} + +static ElfSectIndex +create_dw_elf(SectionFromDwarf &ds) +{ + Elf_Scn * scn =elf_newscn(elf); + if(!scn) { + cerr << "Unable to elf_newscn() on " << ds.name_ << endl; + exit(1); + } + Elf32_Shdr * shdr = elf32_getshdr(scn); + if(!shdr) { + cerr << "Unable to elf_getshdr() on " << ds.name_ << endl; + exit(1); + } + shdr->sh_name = ds.section_name_itself_; + shdr->sh_type = ds.type_; + shdr->sh_flags = ds.flags_; + shdr->sh_addr = 0; + shdr->sh_offset = 0; + shdr->sh_size = ds.size_; + shdr->sh_link = ds.link_; + shdr->sh_info = ds.info_; + shdr->sh_addralign = 1; + shdr->sh_entsize = 0; + ElfSectIndex si(elf_ndxscn(scn)); + ds.setSectIndex(si); + return si; +} + +// Default error handler of libdwarf producer code. +void ErrorHandler(Dwarf_Error err,Dwarf_Ptr errarg) +{ + // FIXME do better error handling + cerr <<"Giving up, encountered an error" << endl; + exit(1); +} + + +static void +setinput(enum WhichInputSource *src, + const string &type, + bool *pathreq) +{ + if(type == "txt") { + *src = OptReadText; + *pathreq = true; + return; + } else if (type == "obj") { + *src = OptReadBin; + *pathreq = true; + return; + } else if (type == "def") { + *src = OptPredefined; + *pathreq = false; + return; + } + cout << "Giving up, only txt obj or def accepted after -t" << endl; + exit(1); +} + +int +main(int argc, char **argv) +{ + + + int opt; + bool pathrequired(false); + long cu_of_input_we_output = -1; + while((opt=getopt(argc,argv,"o:t:c:")) != -1) { + switch(opt) { + case 'c': + // At present we can only create a single + // cu in the output of the libdwarf producer. + cu_of_input_we_output = atoi(optarg); + break; + case 't': + setinput(&whichinput,optarg,&pathrequired); + break; + case 'o': + outfile = optarg; + break; + case '?': + cerr << "Invalid quest? option input " << endl; + exit(1); + + default: + cerr << "Invalid option input " << endl; + exit(1); + } + } + if ( (optind >= argc) && pathrequired) { + cerr << "Expected argument after options! Giving up." << endl; + exit(EXIT_FAILURE); + } + + if(pathrequired) { + infile = argv[optind]; + } + + if(whichinput == OptReadBin) { + createIrepFromBinary(infile,Irep); + } else if (whichinput == OptReadText) { + cerr << "text read not supported yet" << endl; + exit(EXIT_FAILURE); + } else if (whichinput == OptPredefined) { + cerr << "predefined not supported yet" << endl; + exit(EXIT_FAILURE); + } else { + cerr << "Impossible: unknown input style." << endl; + exit(EXIT_FAILURE); + } + + // Example will return error value thru 'err' pointer + // and return DW_DLV_BADADDR if there is an error. + int ptrsize = DW_DLC_SIZE_32; + Dwarf_Ptr errarg = 0; + Dwarf_Error err = 0; + // We use DW_DLC_SYMBOLIC_RELOCATIONS so we can + // read the relocations and do our own relocating. + // See calls of dwarf_get_relocation_info(). + Dwarf_P_Debug dbg = dwarf_producer_init_c( + DW_DLC_WRITE|ptrsize|DW_DLC_SYMBOLIC_RELOCATIONS, + CallbackFunc, + 0, + errarg, + 0, /* we are not using user_data, so pass in 0 */ + &err); + if(dbg == reinterpret_cast<Dwarf_P_Debug>(DW_DLV_BADADDR)) { + cerr << "Failed init_b" << endl; + exit(EXIT_FAILURE); + } + + transform_irep_to_dbg(dbg,Irep,cu_of_input_we_output); + + write_object_file(dbg,Irep); + // Example calls ErrorHandler if there is an error + // (which does not return, see above) + // so no need to test for error. + dwarf_producer_finish( dbg, 0); + + return 0; +} + +static void +write_object_file(Dwarf_P_Debug dbg, IRepresentation &irep) +{ + int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + int fd = open(outfile.c_str(),O_WRONLY|O_CREAT|O_TRUNC, mode); + if(fd < 0 ) { + cerr << "Unable to open " << outfile << + " for writing." << endl; + exit(1); + } + + if(elf_version(EV_CURRENT) == EV_NONE) { + cerr << "Bad elf_version" << endl; + exit(1); + } + + Elf_Cmd cmd = ELF_C_WRITE; + elf = elf_begin(fd,cmd,0); + if(!elf) { + cerr << "Unable to elf_begin() on " << outfile << endl; + exit(1); + } + ehp = elf32_newehdr(elf); + if(!ehp) { + cerr << "Unable to elf_newehdr() on " << outfile << endl; + exit(1); + } + ehp->e_ident[EI_MAG0] = ELFMAG0; + ehp->e_ident[EI_MAG1] = ELFMAG1; + ehp->e_ident[EI_MAG2] = ELFMAG2; + ehp->e_ident[EI_MAG3] = ELFMAG3; + ehp->e_ident[EI_CLASS] = ELFCLASS32; + ehp->e_ident[EI_DATA] = ELFDATA2LSB; + ehp->e_ident[EI_VERSION] = EV_CURRENT; + ehp->e_machine = EM_386; + ehp->e_type = ET_EXEC; + ehp->e_version = EV_CURRENT; + + unsigned strtabstroff = secstrtab.addString(".shstrtab"); + + // an object section with fake .text data (just as an example). + write_text_section(elf); + + write_generated_dbg(dbg,elf,Irep); + + // Now create section name string section. + unsigned shstrindex = createnamestr(strtabstroff); + ehp->e_shstrndx = shstrindex; + + off_t ures = elf_update(elf,cmd); + if(ures == (off_t)(-1LL)) { + cerr << "Unable to elf_update() on " << outfile << endl; + int eer = elf_errno(); + cerr << "Error is " << eer << " " << elf_errmsg(eer) << endl; + exit(1); + } + cout << " output image size in bytes " << ures << endl; + + elf_end(elf); + close(fd); +} + + +// an object section with fake .text data (just as an example). +static void +write_text_section(Elf * elf) +{ + unsigned osecnameoff = secstrtab.addString(".text"); + Elf_Scn * scn1 =elf_newscn(elf); + if(!scn1) { + cerr << "Unable to elf_newscn() on " << outfile << endl; + exit(1); + } + + Elf_Data* ed1 =elf_newdata(scn1); + if(!ed1) { + cerr << "Unable to elf_newdata() on " << outfile << endl; + exit(1); + } + const char *d = "data in section"; + ed1->d_buf = (void *)d; + ed1->d_type = ELF_T_BYTE; + ed1->d_size = strlen(d) +1; + ed1->d_off = 0; + ed1->d_align = 4; + ed1->d_version = EV_CURRENT; + Elf32_Shdr * shdr1 = elf32_getshdr(scn1); + if(!shdr1) { + cerr << "Unable to elf_getshdr() on " << outfile << endl; + exit(1); + } + shdr1->sh_name = osecnameoff; + shdr1->sh_type= SHT_PROGBITS; + shdr1->sh_flags = 0; + shdr1->sh_addr = 0; + shdr1->sh_offset = 0; + shdr1->sh_size = 0; + shdr1->sh_link = 0; + shdr1->sh_info = 0; + shdr1->sh_addralign = 1; + shdr1->sh_entsize = 0; +} +static void +InsertDataIntoElf(Dwarf_Signed d,Dwarf_P_Debug dbg,Elf *elf) +{ + Dwarf_Signed elf_section_index = 0; + Dwarf_Unsigned length = 0; + Dwarf_Ptr bytes = dwarf_get_section_bytes(dbg,d, + &elf_section_index,&length,0); + + Elf_Scn *scn = elf_getscn(elf,elf_section_index); + if(!scn) { + cerr << "Unable to elf_getscn on disk transform # " << d << endl; + exit(1); + } + + ElfSectIndex si(elf_section_index); + SectionFromDwarf & sfd = FindMySection(si); + + Elf_Data* ed =elf_newdata(scn); + if(!ed) { + cerr << "elf_newdata died on transformed index " << d << endl; + exit(1); + } + ed->d_buf = bytes; + ed->d_type = ELF_T_BYTE; + ed->d_size = length; + ed->d_off = sfd.getNextOffset(); + sfd.setNextOffset(ed->d_off + length); + ed->d_align = 1; + ed->d_version = EV_CURRENT; + cout << "Inserted " << length << " bytes into elf section index " << + elf_section_index << endl; +} + +#if 0 +static string +printable_rel_type(unsigned char reltype) +{ + enum Dwarf_Rel_Type t = (enum Dwarf_Rel_Type)reltype; + switch(t) { + case dwarf_drt_none: + return "dwarf_drt_none"; + case dwarf_drt_data_reloc: + return "dwarf_drt_data_reloc"; + case dwarf_drt_segment_rel: + return "dwarf_drt_segment_rel"; + case dwarf_drt_first_of_length_pair: + return "dwarf_drt_first_of_length_pair"; + case dwarf_drt_second_of_length_pair: + return "dwarf_drt_second_of_length_pair"; + default: + break; + } + return "drt-unknown (impossible case)"; +} +#endif + +static Dwarf_Unsigned +FindSymbolValue(ElfSymIndex symi,IRepresentation &irep) +{ + ElfSymbols & syms = irep.getElfSymbols(); + ElfSymbol & es = syms.getElfSymbol(symi); + Dwarf_Unsigned symv = es.getSymbolValue(); + return symv; +} + +static void +bitreplace(char *buf, Dwarf_Unsigned newval, + size_t newvalsize,int length) +{ + if(length == 4) { + uint32_t my4 = newval; + uint32_t * p = reinterpret_cast<uint32_t *>(buf ); + uint32_t oldval = *p; + *p = oldval + my4; + } else if (length == 8) { + uint64_t my8 = newval; + uint64_t * p = reinterpret_cast<uint64_t *>(buf ); + uint64_t oldval = *p; + *p = oldval + my8; + } else { + cerr << " Relocation is length " << length << + " which we do not yet handle." << endl; + exit(1); + } +} + +// This remembers nothing, so is dreadfully slow. +static char * +findelfbuf(Elf *elf,Elf_Scn *scn,Dwarf_Unsigned offset, unsigned length) +{ + Elf_Data * edbase = 0; + Elf_Data * ed = elf_getdata(scn,edbase); + unsigned bct = 0; + for (;ed; ed = elf_getdata(scn,ed)) { + bct++; + if(offset >= LOFFTODWUNS(ed->d_off + ed->d_size) ) { + continue; + } + if(offset < LOFFTODWUNS(ed->d_off)) { + cerr << " Relocation at offset " << + offset << " cannot be accomplished, no buffer. " + << endl; + exit(1); + } + Dwarf_Unsigned localoff = offset - ed->d_off; + if((localoff + length) > ed->d_size) { + cerr << " Relocation at offset " << + offset << " cannot be accomplished, size mismatch. " + << endl; + exit(1); + } + char *lclptr = reinterpret_cast<char *>(ed->d_buf) + localoff; + return lclptr; + } + cerr << " Relocation at offset " << offset << + " cannot be accomplished, past end of buffers" << endl; + return 0; + +} + +static void +write_generated_dbg(Dwarf_P_Debug dbg,Elf * elf,IRepresentation &irep) +{ + Dwarf_Error err = 0; + Dwarf_Signed sectioncount = + dwarf_transform_to_disk_form(dbg,0); + + Dwarf_Signed d = 0; + for(d = 0; d < sectioncount ; ++d) { + InsertDataIntoElf(d,dbg,elf); + } + + // Since we are emitting in final form sometimes, we may + // do relocation processing here or we may + // instead emit relocation records into the object file. + // The following is for DW_DLC_SYMBOLIC_RELOCATIONS. + Dwarf_Unsigned reloc_sections_count = 0; + int drd_version = 0; + int res = dwarf_get_relocation_info_count(dbg,&reloc_sections_count, + &drd_version,&err); + if( res != DW_DLV_OK) { + cerr << "Error getting relocation info count." << endl; + exit(1); + + } + cout << "Relocations sections count= " << reloc_sections_count << + " relversion=" << drd_version << endl; + for( Dwarf_Unsigned ct = 0; ct < reloc_sections_count ; ++ct) { + // elf_section_index is the elf index of the relocations + // themselves. + Dwarf_Signed elf_section_index = 0; + // elf_section_index_link is the elf index of the section + // the relocations apply to. + Dwarf_Signed elf_section_index_link = 0; + // relocation_buffer_count is the number of relocations + // of this section. + Dwarf_Unsigned relocation_buffer_count = 0; + Dwarf_Relocation_Data reld; + res = dwarf_get_relocation_info(dbg,&elf_section_index, + &elf_section_index_link, + &relocation_buffer_count, + &reld,&err); + if (res != DW_DLV_OK) { + cerr << "Error getting relocation record " << + ct << "." << endl; + exit(1); + } + ElfSectIndex si(elf_section_index_link); + cout << "Relocs for sec " << ct << " elf-sec=" << elf_section_index << + " link=" << elf_section_index_link << + " bufct=" << relocation_buffer_count << endl; + Elf_Scn *scn = elf_getscn(elf,si.getSectIndex()); + if(!scn) { + cerr << "Unable to elf_getscn # " << si.getSectIndex() << endl; + exit(1); + } + + for (Dwarf_Unsigned r = 0; r < relocation_buffer_count; ++r) { + Dwarf_Relocation_Data rec = reld+r; + ElfSymIndex symi(rec->drd_symbol_index); + Dwarf_Unsigned newval = FindSymbolValue(symi,irep); + char *buf_to_update = findelfbuf(elf,scn, + rec->drd_offset,rec->drd_length); + if(buf_to_update) { + bitreplace(buf_to_update, newval,sizeof(newval), + rec->drd_length); + } + } + } +} diff --git a/dwarfgen/general.h b/dwarfgen/general.h new file mode 100644 index 0000000..4212092 --- /dev/null +++ b/dwarfgen/general.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ +// general.h +// The following needed in code using this. +//#include <sstream> +//#include <iomanip> // iomanip for setw etc + +#include <sstream> +#include <iomanip> + +template <typename T > +std::string IToHex(T v,unsigned l=0) +{ + if(v == 0) { + // For a zero value, ostringstream does not insert 0x. + // So we do zeroes here. + std::string out = "0x0"; + if(l > 3) { + out.append(l-3,'0'); + } + return out; + } + std::ostringstream s; + s.setf(std::ios::hex,std::ios::basefield); + s.setf(std::ios::showbase); + if (l > 0) { + s << std::setw(l); + } + s << v ; + return s.str(); +}; + +template <typename T> +std::string BldName(const std::string & prefix, T v) +{ + std::ostringstream s; + s << prefix; + s << v; + return s.str(); +} + diff --git a/dwarfgen/install.sh b/dwarfgen/install.sh new file mode 100755 index 0000000..0ff4b6a --- /dev/null +++ b/dwarfgen/install.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/dwarfgen/irepattrtodbg.cc b/dwarfgen/irepattrtodbg.cc new file mode 100644 index 0000000..c2f41ed --- /dev/null +++ b/dwarfgen/irepattrtodbg.cc @@ -0,0 +1,221 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// irepattrtodbg.cc + +#include "config.h" +#include <unistd.h> +#include <stdlib.h> // for exit +#include <iostream> +#include <sstream> // For BldName +#include <iomanip> // iomanp for setw etc +#include <string> +#include <list> +#include <vector> +#include <string.h> // For memset etc +#include <sys/stat.h> //open +#include <fcntl.h> //open +#include "general.h" +#include "elf.h" +#include "gelf.h" +#include "strtabdata.h" +#include "dwarf.h" +#include "libdwarf.h" +#include "irepresentation.h" +#include "ireptodbg.h" +#include "irepattrtodbg.h" + +#ifdef HAVE_INTPTR_T +#include <stdint.h> +typedef intptr_t myintfromp; // intptr_t is from C99. +#else +// We want an integer that is big enough for a pointer so the +// pointer return value from the libdwarf producer can be +// tested for -1. Ugly overloading of integer and pointer in libdwarf. +// We just hope it will compile for you. +typedef long myintfromp; +#endif + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +using std::vector; +using std::list; + +static Dwarf_Error error; +static unsigned fakeaddrnum; + +// We are not going to 'validate' the FORM for this Attribute. +// or this Die. We just assume that what we are handed is +// what we are to produce. We do test the attribute +// at times, partly to ensure we use as many of the dwarf_add_AT* +// functions as possible. + +// Correctness/appropriateness must be evaluated elsewhere. + +void +AddAttrToDie(Dwarf_P_Debug dbg, + IRepresentation & Irep, + Dwarf_P_Die outdie,IRDie & irdie,IRAttr &irattr) +{ + int attrnum = irattr.getAttrNum(); + enum Dwarf_Form_Class formclass = irattr.getFormClass(); + // IRForm is an abstract base class. + IRForm *form = irattr.getFormData(); + + switch(formclass) { + case DW_FORM_CLASS_UNKNOWN: + cerr << "ERROR Impossible DW_FORM_CLASS_UNKNOWN, attrnum " + <<attrnum << cerr; + break; + case DW_FORM_CLASS_ADDRESS: + { + IRFormAddress *f = dynamic_cast<IRFormAddress *>(form); + if (!f) { + cerr << "ERROR Impossible DW_FORM_CLASS_ADDRESS cast fails, attrnum " + <<attrnum << cerr; + break; + } + // FIXME: do better creating a symbol: try to match original + // or specified input. + Dwarf_Addr addr = f->getAddress(); + + string symname = BldName("addrsym",fakeaddrnum++); + Dwarf_Addr pcval = addr; + + ElfSymbols& es = Irep.getElfSymbols(); + ElfSymIndex esi = es.addElfSymbol(pcval,symname); + Dwarf_Unsigned sym_index = esi.getSymIndex(); + + // FIXME: we should allow for DW_FORM_indirect here. + // Relocation later will fix value. + Dwarf_P_Attribute a = dwarf_add_AT_targ_address(dbg, + outdie,attrnum,0,sym_index,&error); + if( reinterpret_cast<myintfromp>(a) == DW_DLV_BADADDR) { + cerr << "ERROR dwarf_add_AT_targ_address fails, attrnum " + <<attrnum << cerr; + + } + } + break; + case DW_FORM_CLASS_BLOCK: + { + //FIXME + } + break; + case DW_FORM_CLASS_CONSTANT: + { + //FIXME + } + break; + case DW_FORM_CLASS_EXPRLOC: + { + //FIXME + } + break; + case DW_FORM_CLASS_FLAG: + { + IRFormFlag *f = dynamic_cast<IRFormFlag *>(form); + if (!f) { + cerr << "ERROR Impossible DW_FORM_CLASS_FLAG cast fails, attrnum " + <<attrnum << cerr; + break; + } + // FIXME: handle indirect form (libdwarf needs feature). + // FIXME: handle implicit flag (libdwarf needs feature). + // FIXME: rel type ok? + Dwarf_P_Attribute a = + dwarf_add_AT_flag(dbg,outdie,attrnum,f->getFlagVal(),&error); + if( reinterpret_cast<myintfromp>(a) == DW_DLV_BADADDR) { + cerr << "ERROR dwarf_add_AT_flag fails, attrnum " + <<attrnum << cerr; + } + } + break; + case DW_FORM_CLASS_LINEPTR: + { + //FIXME + } + break; + case DW_FORM_CLASS_LOCLISTPTR: + { + //FIXME + } + break; + case DW_FORM_CLASS_MACPTR: + { + //FIXME + } + break; + case DW_FORM_CLASS_RANGELISTPTR: + { + //FIXME + } + break; + case DW_FORM_CLASS_REFERENCE: + break; + case DW_FORM_CLASS_STRING: + { + IRFormString *f = dynamic_cast<IRFormString *>(form); + if (!f) { + cerr << "ERROR Impossible DW_FORM_CLASS_STRING cast fails, attrnum " + <<attrnum << cerr; + break; + } + Dwarf_P_Attribute a = 0; + // We know libdwarf does not change the string. Historical mistake + // not making it a const char * argument. + // Ugly cast. + // FIXME: handle indirect form (libdwarf needs feature). + // FIXME: rel type ok? + char *mystr = const_cast<char *>(f->getString().c_str()); + switch(attrnum) { + case DW_AT_name: + a = dwarf_add_AT_name(outdie,mystr,&error); + break; + case DW_AT_producer: + a = dwarf_add_AT_producer(outdie,mystr,&error); + break; + case DW_AT_comp_dir: + a = dwarf_add_AT_comp_dir(outdie,mystr,&error); + break; + default: + a = dwarf_add_AT_string(dbg,outdie,attrnum,mystr, + &error); + break; + } + if( reinterpret_cast<myintfromp>(a) == DW_DLV_BADADDR) { + cerr << "ERROR dwarf_add_AT_string fails, attrnum " + <<attrnum << cerr; + } + } + break; + case DW_FORM_CLASS_FRAMEPTR: // SGI/MIPS/IRIX only. + { + //FIXME + } + break; + default: + cerr << "ERROR Impossible DW_FORM_CLASS "<< + static_cast<int>(formclass) + <<attrnum << cerr; + //FIXME + } + return; +} + diff --git a/dwarfgen/irepattrtodbg.h b/dwarfgen/irepattrtodbg.h new file mode 100644 index 0000000..963c123 --- /dev/null +++ b/dwarfgen/irepattrtodbg.h @@ -0,0 +1,26 @@ +#ifndef IREPATTRTODBG_H +#define IREPATTRTODBG_H +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// irepattrtodbg.h + +void AddAttrToDie(Dwarf_P_Debug dbg, + IRepresentation & Irep, + Dwarf_P_Die outdie,IRDie & irdie,IRAttr &irattr); + +#endif /* IREPATTRTODBG_H */ diff --git a/dwarfgen/irepdie.h b/dwarfgen/irepdie.h new file mode 100644 index 0000000..2a0732a --- /dev/null +++ b/dwarfgen/irepdie.h @@ -0,0 +1,228 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + + +// +// irepdie.h +// +// +class IRCUdata; + +class IRAttr { +public: + IRAttr():attr_(0),directform_(0),indirectform_(0), + formclass_(DW_FORM_CLASS_UNKNOWN),formdata_(0) { + }; + IRAttr(Dwarf_Half attr,Dwarf_Half dirform, Dwarf_Half indirform): + attr_(attr),directform_(dirform),indirectform_(indirform), + formclass_(DW_FORM_CLASS_UNKNOWN),formdata_(0) { + }; + IRAttr(const IRAttr &r) { + attr_ = r.attr_; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + if(r.formdata_) { + formdata_ = r.formdata_->clone(); + } else { + formdata_ = 0; + } + }; + ~IRAttr() { delete formdata_; }; + IRAttr & operator=( const IRAttr &r) { + if(this == &r) { + return *this; + } + attr_ = r.attr_; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + if(r.formdata_) { + formdata_ = r.formdata_->clone(); + } else { + formdata_ = 0; + } + return *this; + } + void setBaseData(Dwarf_Half attr, Dwarf_Half dirform, + Dwarf_Half indirform){ + attr_ = attr; + directform_ = dirform; + indirectform_ = indirform; + }; + void setFormClass(enum Dwarf_Form_Class cl) { + formclass_ = cl; + }; + enum Dwarf_Form_Class getFormClass() const {return formclass_; }; + void setFormData(IRForm *f) { formdata_ = f; }; + Dwarf_Half getFinalForm() const { return indirectform_; }; + Dwarf_Half getDirectForm() const { return directform_; }; + Dwarf_Half getAttrNum() const { return attr_; }; + IRForm * getFormData() { return formdata_;}; +private: + Dwarf_Half attr_; + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + IRForm *formdata_; +}; + +class IRDie { +public: + IRDie():tag_(0),globalOffset_(0), cuRelativeOffset_(0) {}; + ~IRDie() {}; + void addChild(const IRDie & newdie ) { + children_.push_back(newdie); + }; + std::string getName() { + std::list<IRAttr>::iterator it = attrs_.begin(); + for( ; it != attrs_.end() ; ++it) { + if (it->getAttrNum() == DW_AT_name) { + IRForm *f = it->getFormData(); + const IRFormString * isv = + dynamic_cast<const IRFormString *>(f); + if(isv) { + return isv->getString(); + } + } + } + return ""; + }; + std::list<IRAttr> & getAttributes() {return attrs_; }; + std::list<IRDie> & getChildren() {return children_; }; + bool hasNewestChild(IRDie **lastch) { size_t N = children_.size(); + if(N < 1) { + return false; + } + *lastch = &children_.back(); + return true; + }; + // lastChild will throw if no child exists. + IRDie &lastChild() { return children_.back(); }; + void setBaseData(Dwarf_Half tag,Dwarf_Unsigned goff, + Dwarf_Unsigned cuoff) { + tag_ = tag; + globalOffset_=goff; + cuRelativeOffset_ = cuoff; + }; + Dwarf_Unsigned getGlobalOffset() const { return globalOffset_;}; + unsigned getTag() {return tag_; } + +private: + std::list<IRDie> children_; + std::list<IRAttr> attrs_; + unsigned tag_; + Dwarf_Unsigned globalOffset_; + Dwarf_Unsigned cuRelativeOffset_; +}; + +class IRCUdata { +public: + IRCUdata(): + cu_header_length_(0), + abbrev_offset_(0), + next_cu_header_offset_(0), + version_stamp_(0), + address_size_(0), + length_size_(0), + extension_size_(0), + has_macrodata_(false), + macrodata_offset_(0), + has_linedata_(false), + linedata_offset_(0), + cudie_offset_(0) + {}; + IRCUdata(Dwarf_Unsigned len,Dwarf_Half version, + Dwarf_Unsigned abbrev_offset, + Dwarf_Half addr_size, + Dwarf_Half length_size, + Dwarf_Half extension_size, + Dwarf_Unsigned next_cu_header): + cu_header_length_(len), + abbrev_offset_(abbrev_offset), + next_cu_header_offset_(addr_size), + version_stamp_(version), + address_size_(addr_size), + length_size_(length_size), + extension_size_(extension_size), + has_macrodata_(false), + macrodata_offset_(0), + has_linedata_(false), + linedata_offset_(0), + cudie_offset_(0) {}; + ~IRCUdata() { }; + bool hasMacroData(Dwarf_Unsigned *offset_out,Dwarf_Unsigned *cudie_off) { + *offset_out = macrodata_offset_; + *cudie_off = cudie_offset_; + return has_macrodata_; + } + bool hasLineData(Dwarf_Unsigned *offset_out,Dwarf_Unsigned *cudie_off) { + *offset_out = linedata_offset_; + *cudie_off = cudie_offset_; + return has_linedata_; + } + void setMacroData(Dwarf_Unsigned offset,Dwarf_Unsigned cudieoff) { + has_macrodata_ = true; + macrodata_offset_ = offset; + cudie_offset_ = cudieoff; + }; + void setLineData(Dwarf_Unsigned offset,Dwarf_Unsigned cudieoff) { + has_linedata_ = true; + linedata_offset_ = offset; + cudie_offset_ = cudieoff; + }; + IRDie & baseDie() { return cudie_; }; + Dwarf_Half getVersionStamp() { return version_stamp_; }; + Dwarf_Half getOffsetSize() { return length_size_; }; + IRCULineData & getCULines() { return cu_lines_; }; + std::string getCUName() { + return cudie_.getName(); + } + +private: + Dwarf_Unsigned cu_header_length_; + Dwarf_Unsigned abbrev_offset_; + Dwarf_Unsigned next_cu_header_offset_; + Dwarf_Half version_stamp_; + Dwarf_Half address_size_; + Dwarf_Half length_size_; + Dwarf_Half extension_size_; + bool has_macrodata_; + Dwarf_Unsigned macrodata_offset_; + bool has_linedata_; + Dwarf_Unsigned linedata_offset_; + Dwarf_Unsigned cudie_offset_; + IRCULineData cu_lines_; + + // If true, is 32bit dwarf,else 64bit. Gives the size of a reference. + bool dwarf32bit_; + + IRDie cudie_; +}; + +class IRDInfo { +public: + IRDInfo() {}; + ~IRDInfo() {}; + IRCUdata &lastCU() { return cudata_.back(); } + std::list<IRCUdata>& getCUData() {return cudata_; }; +private: + std::list<IRCUdata> cudata_; +}; + diff --git a/dwarfgen/irepform.h b/dwarfgen/irepform.h new file mode 100644 index 0000000..2388ea6 --- /dev/null +++ b/dwarfgen/irepform.h @@ -0,0 +1,592 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + + +// +// irepform.h +// +// +class IRCUdata; +class IRAttr; +class IRFormInterface; + +// An Abstract class. +class IRForm { +public: + //virtual void emitvalue() = 0; + //IRForm & operator=(const IRForm &r); + virtual IRForm * clone() const =0; + virtual ~IRForm() {}; + IRForm() {}; + virtual enum Dwarf_Form_Class getFormClass() const = 0; +private: +}; + +class IRFormUnknown : public IRForm { +public: + IRFormUnknown(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_UNKNOWN) + {} + ~IRFormUnknown() {}; + IRFormUnknown(IRFormInterface *); + IRFormUnknown(const IRFormUnknown &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + } + virtual IRFormUnknown * clone() const { + return new IRFormUnknown(*this); + } + IRFormUnknown & operator=(const IRFormUnknown &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + }; + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; +}; +// An address class entry refers to some part +// (normally a loadable) section of the object file. +// Not to DWARF info. Typically into .text or .data for example. +// We therefore want a section number and offset (generally useless for us) +// or preferably an elf symbol as that has a value +// and an elf section number. +// We often/usually know neither here so we do not even try. +// Later we will make one up if we have to. +class IRFormAddress : public IRForm { +public: + IRFormAddress(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_ADDRESS), + address_(0) + {}; + IRFormAddress(IRFormInterface *); + ~IRFormAddress() {}; + IRFormAddress & operator=(const IRFormAddress &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + address_ = r.address_; + }; + IRFormAddress(const IRFormAddress &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + address_ = r.address_; + } + virtual IRFormAddress * clone() const { + return new IRFormAddress(*this); + }; + Dwarf_Addr getAddress() { return address_;}; + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + void setAddress(Dwarf_Addr addr) { address_ = addr; }; + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + Dwarf_Addr address_; +}; +class IRFormBlock : public IRForm { +public: + IRFormBlock(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_BLOCK), + fromloclist_(0),sectionoffset_(0) + {} + IRFormBlock(IRFormInterface *); + ~IRFormBlock() {}; + IRFormBlock & operator=(const IRFormBlock &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + blockdata_ = r.blockdata_; + fromloclist_ = r.fromloclist_; + sectionoffset_ = r.sectionoffset_; + }; + IRFormBlock(const IRFormBlock &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + blockdata_ = r.blockdata_; + fromloclist_ = r.fromloclist_; + sectionoffset_ = r.sectionoffset_; + } + virtual IRFormBlock * clone() const { + return new IRFormBlock(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + std::vector<char> blockdata_; + Dwarf_Small fromloclist_; + Dwarf_Unsigned sectionoffset_; + + void insertBlock(Dwarf_Block *bl) { + char *d = static_cast<char *>(bl->bl_data); + Dwarf_Unsigned len = bl->bl_len; + blockdata_.clear(); + blockdata_.insert(blockdata_.end(),d+0,d+len); + fromloclist_ = bl->bl_from_loclist; + sectionoffset_ = bl->bl_section_offset; + }; +}; +class IRFormConstant : public IRForm { +public: + IRFormConstant(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_CONSTANT), + signedness_(SIGN_NOT_SET), + uval_(0), sval_(0) + {} + IRFormConstant(IRFormInterface *); + ~IRFormConstant() {}; + IRFormConstant & operator=(const IRFormConstant &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + signedness_ = r.signedness_; + uval_ = r.uval_; + sval_ = r.sval_; + }; + IRFormConstant(const IRFormConstant &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + signedness_ = r.signedness_; + uval_ = r.uval_; + sval_ = r.sval_; + } + virtual IRFormConstant * clone() const { + return new IRFormConstant(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + // Starts at SIGN_NOT_SET. + // SIGN_UNKNOWN means it was a DW_FORM_data* of some + // kind so we do not really know. + enum Signedness {SIGN_NOT_SET,SIGN_UNKNOWN,UNSIGNED, SIGNED }; + enum Signedness signedness_; + // Both uval_ and sval_ are always set to the same bits. + Dwarf_Unsigned uval_; + Dwarf_Signed sval_; + + void setValues(Dwarf_Signed sval, Dwarf_Unsigned uval, + enum Signedness s) { + signedness_ = s; + uval_ = uval; + sval_ = sval; + } +}; + +class IRFormExprloc : public IRForm { +public: + IRFormExprloc(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_EXPRLOC) + {}; + IRFormExprloc(IRFormInterface *); + ~IRFormExprloc() {}; + IRFormExprloc & operator=(const IRFormExprloc &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + exprlocdata_ = r.exprlocdata_; + }; + IRFormExprloc(const IRFormExprloc &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + exprlocdata_ = r.exprlocdata_; + + } + virtual IRFormExprloc * clone() const { + return new IRFormExprloc(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + std::vector<char> exprlocdata_; + void insertBlock(Dwarf_Unsigned len, Dwarf_Ptr data) { + char *d = static_cast<char *>(data); + exprlocdata_.clear(); + exprlocdata_.insert(exprlocdata_.end(),d+0,d+len); + }; +}; + + +class IRFormFlag : public IRForm { +public: + IRFormFlag(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_FLAG), + flagval_(0) + {}; + IRFormFlag(IRFormInterface*); + ~IRFormFlag() {}; + IRFormFlag & operator=(const IRFormFlag &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + flagval_ = r.flagval_; + }; + IRFormFlag(const IRFormFlag &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + flagval_ = r.flagval_; + } + virtual IRFormFlag * clone() const { + return new IRFormFlag(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; + Dwarf_Bool getFlagVal() { return flagval_; } +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + Dwarf_Bool flagval_; +}; + + +class IRFormLinePtr : public IRForm { +public: + IRFormLinePtr(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_LINEPTR), + debug_line_offset_(0) + {}; + IRFormLinePtr(IRFormInterface *); + ~IRFormLinePtr() {}; + IRFormLinePtr & operator=(const IRFormLinePtr &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + debug_line_offset_ = r.debug_line_offset_; + }; + IRFormLinePtr(const IRFormLinePtr &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + debug_line_offset_ = r.debug_line_offset_; + } + virtual IRFormLinePtr * clone() const { + return new IRFormLinePtr(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + Dwarf_Off debug_line_offset_; + + void setOffset(Dwarf_Unsigned uval) { + debug_line_offset_ = uval; + }; +}; + + +class IRFormLoclistPtr : public IRForm { +public: + IRFormLoclistPtr(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_LOCLISTPTR), + loclist_offset_(0) + {}; + IRFormLoclistPtr(IRFormInterface *); + ~IRFormLoclistPtr() {}; + IRFormLoclistPtr & operator=(const IRFormLoclistPtr &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + loclist_offset_ = r.loclist_offset_; + }; + IRFormLoclistPtr(const IRFormLoclistPtr &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + loclist_offset_ = r.loclist_offset_; + } + virtual IRFormLoclistPtr * clone() const { + return new IRFormLoclistPtr(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + Dwarf_Off loclist_offset_; + + void setOffset(Dwarf_Unsigned uval) { + loclist_offset_ = uval; + }; +}; + + +class IRFormMacPtr : public IRForm { +public: + IRFormMacPtr(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_MACPTR), + macro_offset_(0) + {}; + IRFormMacPtr(IRFormInterface *); + ~IRFormMacPtr() {}; + IRFormMacPtr & operator=(const IRFormMacPtr &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + macro_offset_ = r.macro_offset_; + }; + IRFormMacPtr(const IRFormMacPtr &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + macro_offset_ = r.macro_offset_; + } + virtual IRFormMacPtr * clone() const { + return new IRFormMacPtr(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + Dwarf_Off macro_offset_; + + void setOffset(Dwarf_Unsigned uval) { + macro_offset_ = uval; + }; +}; + + +class IRFormRangelistPtr : public IRForm { +public: + IRFormRangelistPtr(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_RANGELISTPTR), + rangelist_offset_(0) + {}; + IRFormRangelistPtr(IRFormInterface *); + ~IRFormRangelistPtr() {}; + IRFormRangelistPtr & operator=(const IRFormRangelistPtr &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + rangelist_offset_ = r.rangelist_offset_; + }; + IRFormRangelistPtr(const IRFormRangelistPtr &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + rangelist_offset_ = r.rangelist_offset_; + } + virtual IRFormRangelistPtr * clone() const { + return new IRFormRangelistPtr(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + Dwarf_Off rangelist_offset_; + + void setOffset(Dwarf_Unsigned uval) { + rangelist_offset_ = uval; + }; +}; + +class IRFormFramePtr : public IRForm { +public: + IRFormFramePtr(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_FRAMEPTR), + frame_offset_(0) + {}; + IRFormFramePtr(IRFormInterface *); + ~IRFormFramePtr() {}; + IRFormFramePtr & operator=(const IRFormFramePtr &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + frame_offset_ = r.frame_offset_; + }; + IRFormFramePtr(const IRFormFramePtr &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + frame_offset_ = r.frame_offset_; + } + virtual IRFormFramePtr * clone() const { + return new IRFormFramePtr(*this); + } + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + Dwarf_Off frame_offset_; + + void setOffset(Dwarf_Unsigned uval) { + frame_offset_ = uval; + }; +}; + + + +class IRFormReference : public IRForm { +public: + IRFormReference(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_REFERENCE), + reftype_(RT_NONE), + globalOffset_(0),cuRelativeOffset_(0) + {initSig8();}; + IRFormReference(IRFormInterface *); + ~IRFormReference() {}; + IRFormReference & operator=(const IRFormReference &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + reftype_ = r.reftype_; + globalOffset_ = r.globalOffset_; + cuRelativeOffset_ = r.cuRelativeOffset_; + typeSig8_ = r.typeSig8_; + }; + IRFormReference(const IRFormReference &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + reftype_ = r.reftype_; + globalOffset_ = r.globalOffset_; + cuRelativeOffset_ = r.cuRelativeOffset_; + typeSig8_ = r.typeSig8_; + } + virtual IRFormReference * clone() const { + return new IRFormReference(*this); + } + void setOffset(Dwarf_Off off) { globalOffset_ = off; + reftype_ = RT_GLOBAL;}; + void setCUOffset(Dwarf_Off off) { cuRelativeOffset_= off; + reftype_ = RT_CUREL;}; + void setSignature(Dwarf_Sig8 * sig) { typeSig8_ = *sig; + reftype_ = RT_SIG;}; + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + void initSig8(); + + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + enum RefType { RT_NONE,RT_GLOBAL, RT_CUREL,RT_SIG }; + enum RefType reftype_; + Dwarf_Off globalOffset_; + Dwarf_Off cuRelativeOffset_; + Dwarf_Sig8 typeSig8_; +}; + + +class IRFormString: public IRForm { +public: + IRFormString(): + directform_(0), indirectform_(0), + formclass_(DW_FORM_CLASS_STRING), + strpoffset_(0) {}; + ~IRFormString() {}; + IRFormString(IRFormInterface *); + IRFormString(const IRFormString &r) { + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + formdata_= r.formdata_; + strpoffset_= r.strpoffset_; + } + virtual IRFormString * clone() const { + return new IRFormString(*this); + } + IRFormString & operator=(const IRFormString &r) { + if(this == &r) return *this; + directform_ = r.directform_; + indirectform_ = r.indirectform_; + formclass_ = r.formclass_; + formdata_ = r.formdata_; + strpoffset_ = r.strpoffset_; + }; + void setString(const char *s) {formdata_ = s; }; + const std::string & getString() const {return formdata_; }; + enum Dwarf_Form_Class getFormClass() const { return formclass_; }; +private: + Dwarf_Half directform_; + // In most cases directform == indirect form. + // Otherwise, directform == DW_FORM_indirect. + Dwarf_Half indirectform_; + enum Dwarf_Form_Class formclass_; + std::string formdata_; + Dwarf_Unsigned strpoffset_; +}; + + +// Factory Method. +IRForm *formFactory(Dwarf_Debug dbg, Dwarf_Attribute attr, + IRCUdata &cudata,IRAttr & irattr); + diff --git a/dwarfgen/irepframe.h b/dwarfgen/irepframe.h new file mode 100644 index 0000000..3f598f8 --- /dev/null +++ b/dwarfgen/irepframe.h @@ -0,0 +1,154 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// +// irepframe.h +// + +class IRCie { +public: + IRCie(): cie_byte_length_(0), version_(0), + code_alignment_factor_(1), + data_alignment_factor_(1), + return_address_register_rule_(0) + {}; + IRCie(Dwarf_Unsigned length, Dwarf_Unsigned version, + const std::string &augmentation, Dwarf_Unsigned code_align, + Dwarf_Signed data_align, Dwarf_Half return_reg_rule, + const void * init_instrs, Dwarf_Unsigned instrs_len): + cie_byte_length_(length), version_(version), + augmentation_(augmentation), code_alignment_factor_(code_align), + data_alignment_factor_(data_align), + return_address_register_rule_(return_reg_rule) + { + const Dwarf_Small *x = + reinterpret_cast<const Dwarf_Small *>(init_instrs); + for(Dwarf_Unsigned i = 0; i < instrs_len; ++i) { + initial_instructions_.push_back(x[i]); + } + } + void insert_fde_index(unsigned i) { fde_index_.push_back(i); }; + ~IRCie() {}; + void get_basic_cie_data(Dwarf_Unsigned * version, + std::string * aug, + Dwarf_Unsigned * code_align, + Dwarf_Signed * data_align, + Dwarf_Half * ret_addr_reg) { + *version = version_; + *aug = augmentation_; + *code_align = code_alignment_factor_; + *data_align = data_alignment_factor_; + *ret_addr_reg = return_address_register_rule_; + } + void get_init_instructions(Dwarf_Unsigned *len, + void **bytes) { + *len = initial_instructions_.size(); + *bytes = reinterpret_cast<void *>(&initial_instructions_[0]); + }; + +private: + // Byte length 0 if not known yet. + Dwarf_Unsigned cie_byte_length_; + Dwarf_Unsigned version_; + std::string augmentation_; + Dwarf_Unsigned code_alignment_factor_; + Dwarf_Signed data_alignment_factor_; + Dwarf_Half return_address_register_rule_; + std::vector<Dwarf_Small> initial_instructions_; + // fde_index is the array of indexes into fdedata_ + // that are fdes used by this cie. + std::vector<unsigned> fde_index_; +}; +class IRFde { +public: + IRFde(): low_pc_(0), func_length_(0), + cie_offset_(0), cie_index_(-1), + fde_offset_(0) {}; + IRFde(Dwarf_Addr low_pc,Dwarf_Unsigned func_length, + Dwarf_Ptr fde_bytes, Dwarf_Unsigned fde_length, + Dwarf_Off cie_offset,Dwarf_Signed cie_index, + Dwarf_Off fde_offset): low_pc_(low_pc), func_length_(func_length), + cie_offset_(cie_offset), cie_index_(cie_index), + fde_offset_(fde_offset) { + const Dwarf_Small *x = + reinterpret_cast<const Dwarf_Small *>(fde_bytes); + for(Dwarf_Unsigned i = 0; i < fde_length; ++i) { + fde_bytes_.push_back(x[i]); + } + }; + ~IRFde() {}; + Dwarf_Signed cie_index() { return cie_index_; }; + void get_fde_base_data(Dwarf_Addr *lowpc, Dwarf_Unsigned * funclen, + Dwarf_Signed *cie_index_input) { + *lowpc = low_pc_; + *funclen = func_length_; + *cie_index_input = cie_index_; + }; + void get_fde_instrs_into_ir(Dwarf_Ptr ip,Dwarf_Unsigned len ) { + const Dwarf_Small *x = + reinterpret_cast<const Dwarf_Small *>(ip); + for(Dwarf_Unsigned i = 0; i < len; ++i) { + fde_instrs_.push_back(x[i]); + } + }; + + void get_fde_instructions(Dwarf_Unsigned *len, + void **bytes) { + *len = fde_instrs_.size(); + *bytes = reinterpret_cast<void *>(&fde_instrs_[0]); + }; + void fde_instrs () { + }; + +private: + Dwarf_Addr low_pc_; + Dwarf_Unsigned func_length_; + // fde_bytes_ may be empty if content bytes not yet created. + std::vector<Dwarf_Small> fde_bytes_; + + std::vector<Dwarf_Small> fde_instrs_; + // cie_offset may be 0 if not known yet. + Dwarf_Off cie_offset_; + // cie_index is the index in ciedata_ of + // the applicable CIE. Begins with index 0. + Dwarf_Signed cie_index_; + // fde_offset may be 0 if not yet known. + Dwarf_Off fde_offset_; +}; + +class IRFrame { +public: + IRFrame() {}; + ~IRFrame() {}; + void insert_cie(IRCie &cie) { + ciedata_.push_back(cie); + } + void insert_fde(IRFde &fdedata) { + fdedata_.push_back(fdedata); + unsigned findex = fdedata_.size() -1; + Dwarf_Signed cindex = fdedata.cie_index(); + if( cindex != -1) { + IRCie & mycie = ciedata_[cindex]; + mycie.insert_fde_index(findex); + } + } + std::vector<IRCie> &get_cie_vec() { return ciedata_; }; + std::vector<IRFde> &get_fde_vec() { return fdedata_; }; +private: + std::vector<IRCie> ciedata_; + std::vector<IRFde> fdedata_; +}; diff --git a/dwarfgen/irepline.h b/dwarfgen/irepline.h new file mode 100644 index 0000000..88c3e07 --- /dev/null +++ b/dwarfgen/irepline.h @@ -0,0 +1,101 @@ +#ifndef IREPLINE_H +#define IREPLINE_H +/* + Copyright (C) 2011 David Anderson. + + 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. + + 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. + +*/ + +// +// irepline.h +// + +class IRCULine { +public: + IRCULine(Dwarf_Addr addr,Dwarf_Bool isset, + Dwarf_Unsigned fileno, + Dwarf_Unsigned lineno, + Dwarf_Unsigned linecol, + const std::string & linename, + Dwarf_Bool is_stmt, + Dwarf_Bool bb, + Dwarf_Bool endseq, + Dwarf_Bool prol_end, + Dwarf_Bool epil_beg, + Dwarf_Unsigned isa, + Dwarf_Unsigned discrim): + address_(addr), + isaddrset_(isset), + srcfileno_(fileno), + lineno_(lineno), + linecol_(linecol), + linesrc_(linename), + is_stmt_(is_stmt), + basic_block_(bb), + end_sequence_(endseq), + prologue_end_(prol_end), + epilogue_begin_(epil_beg), + isa_(isa), + discriminator_(discrim) + {}; + const std::string &getpath() { return linesrc_; }; + Dwarf_Addr getaddr() { return address_;}; + bool getaddrset() { return isaddrset_;}; + bool getendsequence() { return end_sequence_; }; + Dwarf_Unsigned getlineno() { return lineno_; }; + Dwarf_Unsigned getlinecol() { return linecol_; }; + bool getisstmt() { return is_stmt_; }; + bool getisblock() { return basic_block_; }; + bool getepiloguebegin() { return epilogue_begin_; }; + bool getprologueend() { return prologue_end_; }; + Dwarf_Unsigned getisa() { return isa_; }; + Dwarf_Unsigned getdiscriminator() { return discriminator_; }; + ~IRCULine() {}; +private: + + // Names taken from the DWARF4 std. document, sec 6.2.2. + Dwarf_Addr address_; + bool isaddrset_; + Dwarf_Unsigned srcfileno_; + Dwarf_Unsigned lineno_; + Dwarf_Signed linecol_; // aka lineoff + std::string linesrc_; // Name for the file, constructed by libdwarf. + bool is_stmt_; + bool basic_block_; + bool end_sequence_; + bool prologue_end_; + bool epilogue_begin_; + int isa_; + int discriminator_; +}; +class IRCUSrcfile { +public: + IRCUSrcfile(std::string file): cusrcfile_(file) {}; + ~IRCUSrcfile() {}; + std::string &getfilepath() {return cusrcfile_;}; +private: + std::string cusrcfile_; +}; + +class IRCULineData { +public: + IRCULineData() {}; + ~IRCULineData() {}; + std::vector<IRCULine> &get_cu_lines() { return culinedata_; }; + std::vector<IRCUSrcfile> &get_cu_srcfiles() { return cusrcfiledata_; }; +private: + std::vector<IRCUSrcfile> cusrcfiledata_; + std::vector<IRCULine> culinedata_; +}; +#endif // IREPLINE_H diff --git a/dwarfgen/irepmacro.h b/dwarfgen/irepmacro.h new file mode 100644 index 0000000..103772e --- /dev/null +++ b/dwarfgen/irepmacro.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// +// irepmacro.h +// + +class IRMacroRecord { +public: + IRMacroRecord() {}; + ~IRMacroRecord() {}; + IRMacroRecord(Dwarf_Off cuDieOffset,Dwarf_Off offset,Dwarf_Small type, + Dwarf_Signed lineno, Dwarf_Signed lineindex, + const std::string ¯o):cuDieOffset_(cuDieOffset), + offset_(offset), + type_(type),lineno_(lineno),lineindex_(lineindex), + macro_(macro) {}; +private: + Dwarf_Off cuDieOffset_; + Dwarf_Off offset_; + Dwarf_Small type_; + Dwarf_Signed lineno_; + Dwarf_Signed lineindex_; + std::string macro_; +}; +class IRMacro { +public: + IRMacro() {}; + ~IRMacro() {}; + std::vector<IRMacroRecord> &getMacroVec() { return macrorec_; }; +private: + std::vector<IRMacroRecord> macrorec_; +}; diff --git a/dwarfgen/irepresentation.h b/dwarfgen/irepresentation.h new file mode 100644 index 0000000..3718c71 --- /dev/null +++ b/dwarfgen/irepresentation.h @@ -0,0 +1,135 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// +// irepresentation.h +// The internal (to dwarfgen) representation of debug information. +// All the various components (info, frame, etc) +// will be stored here in an internal-to-dwarfgen form. +// +// +#include "irepform.h" +#include "irepline.h" +#include "irepdie.h" +#include "irepmacro.h" +#include "irepframe.h" +#include "strtabdata.h" + +// The elf symbols are used to tie relocations to values. +// We do relocations ourselves in dwarfgen so the data is not needed +// once the dwarf .debug_* sections created in elf. +// We don't write the symbols out as an elf section. +// The position in the vector of symbols is the 'elf symbol index' +// we create. +// Symbol 0 is 'no symbol'. +// Symbol 1 is .text +class ElfSymbol { +public: + ElfSymbol():symbolValue_(0), + nameIndex_(0) {}; + ElfSymbol(Dwarf_Unsigned val, const std::string&name, strtabdata&stab): + symbolValue_(val),name_(name) { + nameIndex_ = stab.addString(name); + }; + ~ElfSymbol() {}; + Dwarf_Unsigned getSymbolValue() const { return symbolValue_;} +private: + Dwarf_Unsigned symbolValue_; + std::string name_; + // The offset in the string table. + unsigned nameIndex_; +}; + +class ElfSectIndex { +public: + ElfSectIndex():elfsect_(0) {}; + ~ElfSectIndex() {}; + ElfSectIndex(unsigned v):elfsect_(v) {}; + unsigned getSectIndex() const { return elfsect_; } + void setSectIndex(unsigned v) { elfsect_ = v; } +private: + unsigned elfsect_; +}; + + +class ElfSymIndex { +public: + ElfSymIndex():elfsym_(0) {}; + ~ElfSymIndex() {}; + ElfSymIndex(unsigned v):elfsym_(v) {}; + unsigned getSymIndex() const { return elfsym_; } + void setSymIndex(unsigned v) { elfsym_ = v; } +private: + unsigned elfsym_; +}; + +class ElfSymbols { +public: + ElfSymbols() { + // The initial symbol is 'no symbol'. + std::string emptyname(""); + elfSymbols_.push_back(ElfSymbol(0,emptyname,symstrtab_)); + + // We arbitrarily make this symbol .text now, though + // not needed yet. + std::string textname(".text"); + elfSymbols_.push_back(ElfSymbol(0,textname,symstrtab_)); + baseTextAddressSymbol_.setSymIndex(elfSymbols_.size()-1); + } + ~ElfSymbols() {}; + ElfSymIndex getBaseTextSymbol() const {return baseTextAddressSymbol_;}; + ElfSymIndex addElfSymbol(Dwarf_Unsigned val, const std::string&name) { + elfSymbols_.push_back(ElfSymbol(val,name,symstrtab_)); + ElfSymIndex indx(elfSymbols_.size()-1); + return indx; + + }; + ElfSymbol & getElfSymbol(ElfSymIndex symi) { + size_t i = symi.getSymIndex(); + if (i >= elfSymbols_.size()) { + std::cerr << "Error, sym index " << i << " to big for symtab size " << elfSymbols_.size() << std::endl; + exit(1); + } + return elfSymbols_[i]; + } +private: + std::vector<ElfSymbol> elfSymbols_; + strtabdata symstrtab_; + ElfSymIndex baseTextAddressSymbol_; +}; + + +class IRepresentation { +public: + IRepresentation() {}; + ~IRepresentation(){}; + IRFrame &framedata() { return framedata_; }; + IRMacro ¯odata() { return macrodata_; }; + IRDInfo &infodata() { return debuginfodata_; }; + ElfSymbols &getElfSymbols() { return elfSymbols_;}; + unsigned getBaseTextSymbol() { + return elfSymbols_.getBaseTextSymbol().getSymIndex();}; +private: + // The Elf symbols data to use for relocations + ElfSymbols elfSymbols_; + + IRFrame framedata_; + IRMacro macrodata_; + + // Line data is inside IRDInfo. + IRDInfo debuginfodata_; +}; diff --git a/dwarfgen/ireptodbg.cc b/dwarfgen/ireptodbg.cc new file mode 100644 index 0000000..bc56e36 --- /dev/null +++ b/dwarfgen/ireptodbg.cc @@ -0,0 +1,371 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + +// ireptodbg.cc + +#include "config.h" +#include <unistd.h> +#include <stdlib.h> // for exit +#include <iostream> +#include <string> +#include <list> +#include <map> +#include <vector> +#include <string.h> // For memset etc +#include <sys/stat.h> //open +#include <fcntl.h> //open +#include "elf.h" +#include "gelf.h" +#include "strtabdata.h" +#include "dwarf.h" +#include "libdwarf.h" +#include "irepresentation.h" +#include "ireptodbg.h" +#include "irepattrtodbg.h" +#include "general.h" + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +using std::vector; +using std::map; +using std::list; + +static Dwarf_Error error; + +typedef std::map<std::string,unsigned> pathToUnsignedType; + +static Dwarf_P_Die +HandleOneDieAndChildren(Dwarf_P_Debug dbg, + IRepresentation & Irep, + IRDie &inDie, unsigned level) +{ + list<IRDie>& children = inDie.getChildren(); + // We create our target DIE first so we can link + // children to it, but add no content yet. + Dwarf_P_Die ourdie = dwarf_new_die(dbg,inDie.getTag(),NULL,NULL, + NULL,NULL,&error); + if (reinterpret_cast<int>(ourdie) == DW_DLV_BADADDR) { + cerr << "Die creation failure. "<< endl; + exit(1); + } + + Dwarf_P_Die lastch = 0; + for ( list<IRDie>::iterator it = children.begin(); + it != children.end(); + it++) { + IRDie & ch = *it; + Dwarf_P_Die chp = HandleOneDieAndChildren(dbg,Irep,ch,level+1); + Dwarf_P_Die res = 0; + if(lastch) { + // Link to right of earlier sibling. + res = dwarf_die_link(chp,NULL,NULL,lastch,NULL,&error); + } else { + // Link as first child. + res = dwarf_die_link(chp,ourdie,NULL,NULL, NULL,&error); + } + // Bad cast here, FIXME + if (reinterpret_cast<int>(res) == DW_DLV_BADADDR) { + cerr << "Die link failure. "<< endl; + exit(1); + } + lastch = chp; + } + list<IRAttr>& attrs = inDie.getAttributes(); + // Now we add attributes (content), if any, to the 'ourdie'. + for (list<IRAttr>::iterator it = attrs.begin(); + it != attrs.end(); + it++) { + IRAttr & attr = *it; + AddAttrToDie(dbg,Irep,ourdie,inDie,attr); + } + return ourdie; +} + +static void +HandleLineData(Dwarf_P_Debug dbg,IRepresentation & Irep, IRCUdata&cu) +{ + Dwarf_Error error = 0; + // We refer to files by fileno, this builds an index. + pathToUnsignedType pathmap; + + IRCULineData& ld = cu.getCULines(); + std::vector<IRCULine> & cu_lines = ld.get_cu_lines(); + //std::vector<IRCUSrcfile> &cu_srcfiles = ld.get_cu_srcfiles(); + if(cu_lines.empty()) { + // No lines data to emit, do nothing. + return; + } + // To start with, we are doing a trivial generation here. + // To be refined 'soon'. FIXME + // Initially we don't worry about dwarf_add_directory_decl(). + + bool firstline = true; + bool addrsetincu = false; + for(unsigned k = 0; k < cu_lines.size(); ++k) { + IRCULine &li = cu_lines[k]; + const std::string&path = li.getpath(); + unsigned pathindex = 0; + pathToUnsignedType::const_iterator it = pathmap.find(path); + if(it == pathmap.end()) { + Dwarf_Error error = 0; + Dwarf_Unsigned idx = dwarf_add_file_decl( + dbg,const_cast<char *>(path.c_str()), + 0,0,0,&error); + if(idx == DW_DLV_NOCOUNT) { + cerr << "Error from dwarf_add_file_decl() on " << + path << endl; + exit(1); + } + pathindex = idx; + pathmap[path] = pathindex; + } else { + pathindex = it->second; + } + Dwarf_Addr a = li.getaddr(); + bool addrsetinline = li.getaddrset(); + bool endsequence = li.getendsequence(); + if(firstline || !addrsetincu) { + // We fake an elf sym index here. + Dwarf_Unsigned elfsymidx = 0; + if(firstline && !addrsetinline) { + cerr << "Error building line, first entry not addr set" << + endl; + exit(1); + } + Dwarf_Unsigned res = dwarf_lne_set_address(dbg, + a,elfsymidx,&error); + if(res == DW_DLV_NOCOUNT) { + cerr << "Error building line, dwarf_lne_set_address" << + endl; + exit(1); + } + addrsetincu = true; + firstline = false; + } else if( endsequence) { + Dwarf_Unsigned esres = dwarf_lne_end_sequence(dbg, + a,&error); + if(esres == DW_DLV_NOCOUNT) { + cerr << "Error building line, dwarf_lne_end_sequence" << + endl; + exit(1); + } + addrsetincu = false; + continue; + } + Dwarf_Signed linecol = li.getlinecol(); + // It's really the code address or (when in a proper compiler) + // a section or function offset. + // libdwarf subtracts the code_offset from the address passed + // this way or from dwarf_lne_set_address() and writes a small + // offset in a DW_LNS_advance_pc instruction. + Dwarf_Addr code_offset = a; + Dwarf_Unsigned lineno = li.getlineno(); + Dwarf_Bool isstmt = li.getisstmt()?1:0; + Dwarf_Bool isblock = li.getisblock()?1:0; + Dwarf_Bool isepiloguebegin = li.getepiloguebegin()?1:0; + Dwarf_Bool isprologueend = li.getprologueend()?1:0; + Dwarf_Unsigned isa = li.getisa(); + Dwarf_Unsigned discriminator = li.getdiscriminator(); + Dwarf_Unsigned lires = dwarf_add_line_entry_b(dbg, + pathindex, + code_offset, + lineno, + linecol, + isstmt, + isblock, + isepiloguebegin, + isprologueend, + isa, + discriminator, + &error); + if(lires == DW_DLV_NOCOUNT) { + cerr << "Error building line, dwarf_add_line_entry" << + endl; + exit(1); + } + } + if(addrsetincu) { + cerr << "CU Lines did not end in an end_sequence!" << endl; + } +} +// This emits the DIEs for a single CU and possibly line data +// associated with the CU. +// The DIEs form a graph (which can be created and linked together +// in any order) and which is emitted in tree preorder as +// defined by the DWARF spec. +// +static void +emitOneCU( Dwarf_P_Debug dbg,IRepresentation & Irep, IRCUdata&cu, + int cu_of_input_we_output) +{ + // We descend the the tree, creating DIEs and linking + // them in as we return back up the tree of recursing + // on IRDie children. + Dwarf_Error error; + + IRDie & basedie = cu.baseDie(); + Dwarf_P_Die cudie = HandleOneDieAndChildren(dbg,Irep,basedie,0); + + // Add base die to debug, this is the CU die. + // This is not a good design as DWARF3/4 have + // requirements of multiple CUs in a single creation, + // which cannot be handled yet. + Dwarf_Unsigned res = dwarf_add_die_to_debug(dbg,cudie,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to add_die_to_debug " << endl; + exit(1); + } + + HandleLineData(dbg,Irep,cu); +} +// .debug_info creation. +// Also creates .debug_line +static void +transform_debug_info(Dwarf_P_Debug dbg, + IRepresentation & irep,int cu_of_input_we_output) +{ + int cu_number = 0; + std::list<IRCUdata> &culist = irep.infodata().getCUData(); + // For now, just one CU we write (as spoken by Yoda). + + for ( list<IRCUdata>::iterator it = culist.begin(); + it != culist.end(); + it++,cu_number++) { + if(cu_number == cu_of_input_we_output) { + IRCUdata & primecu = *it; + emitOneCU(dbg,irep,primecu,cu_of_input_we_output); + break; + } + } +} +static void +transform_cie_fde(Dwarf_P_Debug dbg, + IRepresentation & Irep,int cu_of_input_we_output) +{ + Dwarf_Error err = 0; + std::vector<IRCie> &cie_vec = Irep.framedata().get_cie_vec(); + std::vector<IRFde> &fde_vec = Irep.framedata().get_fde_vec(); + + for(size_t i = 0; i < cie_vec.size(); ++i) { + IRCie &ciein = cie_vec[i]; + Dwarf_Unsigned version = 0; + string aug; + Dwarf_Unsigned code_align = 0; + Dwarf_Signed data_align = 0; + Dwarf_Half ret_addr_reg = -1; + void * bytes = 0; + Dwarf_Unsigned bytes_len; + ciein.get_basic_cie_data(&version, &aug, + &code_align, &data_align, &ret_addr_reg); + ciein.get_init_instructions(&bytes_len,&bytes); + // version implied: FIXME, need to let user code set output + // frame version. + char *str = const_cast<char *>(aug.c_str()); + Dwarf_Signed out_cie_index = + dwarf_add_frame_cie(dbg, str, + code_align, data_align, ret_addr_reg, + bytes,bytes_len, + &err); + if(out_cie_index == DW_DLV_NOCOUNT) { + cerr << "Error creating cie from input cie " << i << endl; + exit(1); + } + vector<int> fdeindex; + // This inner loop is C*F so a bit slow. + for(size_t j = 0; j < fde_vec.size(); ++j) { + IRFde &fdein = fde_vec[j]; + Dwarf_Unsigned code_len = 0; + Dwarf_Addr code_virt_addr = 0; + Dwarf_Signed cie_input_index = 0; + fdein.get_fde_base_data(&code_virt_addr, + &code_len, &cie_input_index); + if(cie_input_index != i) { + // Wrong cie, ignore this fde right now. + continue; + } + + + Dwarf_P_Fde fdeout = dwarf_new_fde(dbg,&err); + if(reinterpret_cast<Dwarf_Addr>(fdeout) == DW_DLV_BADADDR) { + cerr << "Error creating new fde " << j << endl; + exit(1); + } + Dwarf_Unsigned ilen = 0; + void *instrs = 0; + fdein.get_fde_instructions(&ilen, &instrs); + + int res = dwarf_insert_fde_inst_bytes(dbg, + fdeout, ilen, instrs,&err); + if(res != DW_DLV_OK) { + cerr << "Error inserting frame instr block " << j << endl; + exit(1); + } + + Dwarf_P_Die irix_die = 0; + Dwarf_Signed irix_table_offset = 0; + Dwarf_Unsigned irix_excep_sym = 0; + Dwarf_Unsigned code_virt_addr_symidx = + Irep.getBaseTextSymbol(); + Dwarf_Unsigned fde_index = dwarf_add_frame_info( + dbg, fdeout,irix_die, + out_cie_index, code_virt_addr, + code_len,code_virt_addr_symidx, + irix_table_offset,irix_excep_sym, + &err); + if(fde_index == DW_DLV_BADADDR) { + cerr << "Error creating new fde " << j << endl; + exit(1); + } + } + } +} + +static void +transform_macro_info(Dwarf_P_Debug dbg, + IRepresentation & Irep,int cu_of_input_we_output) +{ + IRMacro ¯odata = Irep.macrodata(); + std::vector<IRMacroRecord> ¯ov = macrodata.getMacroVec(); + for(size_t m = 0; m < macrov.size() ; m++ ) { + // FIXME: we need to coordinate with generated + // CUs . + cout << "FIXME: macros not really output yet " << + m << " " << + macrov.size() << endl; + } + Dwarf_Unsigned reloc_count = 0; + int drd_version = 0; + int res = dwarf_get_relocation_info_count(dbg,&reloc_count, + &drd_version,&error); + if( res != DW_DLV_OK) { + cerr << "Error getting relocation info count." << endl; + exit(1); + + } + for( Dwarf_Unsigned ct = 0; ct < reloc_count ; ++ct) { + } +} +void +transform_irep_to_dbg(Dwarf_P_Debug dbg, + IRepresentation & Irep,int cu_of_input_we_output) +{ + transform_debug_info(dbg,Irep,cu_of_input_we_output); + transform_cie_fde(dbg,Irep,cu_of_input_we_output); + transform_macro_info(dbg,Irep,cu_of_input_we_output); +} diff --git a/dwarfgen/ireptodbg.h b/dwarfgen/ireptodbg.h new file mode 100644 index 0000000..ae1088c --- /dev/null +++ b/dwarfgen/ireptodbg.h @@ -0,0 +1,24 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + + + +// ireptodbg.h + + +void transform_irep_to_dbg(Dwarf_P_Debug dbg, IRepresentation & Irep, + int cu_of_input_we_output); diff --git a/dwarfgen/strtabdata.h b/dwarfgen/strtabdata.h new file mode 100755 index 0000000..d005055 --- /dev/null +++ b/dwarfgen/strtabdata.h @@ -0,0 +1,65 @@ +#ifndef STRTABDATA_H +#define STRTABDATA_H +/* + Copyright (C) 2010-2011 David Anderson. + + 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. + + 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. + +*/ + + +// strtabdata.h +// Creates a string table in a way consistent with +// elf string tables. The zero index is a null byte always. + +class strtabdata { +public: + strtabdata(): data_(new char[1000]), + datalen_(1000), nexttouse_(0) { data_[0] = 0; nexttouse_ = 1;}; + ~strtabdata() { delete[]data_; }; + unsigned addString(const std::string & newstr) { + // The 1 is for the terminating null byte. + unsigned nsz = newstr.size() +1; + unsigned needed = nexttouse_ + nsz; + if (needed >= datalen_) { + unsigned baseincr = nsz; + unsigned altincr = datalen_*2; + if(altincr> baseincr) { + baseincr = altincr; + } + unsigned newsize = datalen_ + baseincr; + char *newdata = new char [newsize]; + memcpy(newdata, data_, nexttouse_); + delete [] data_; + data_ = newdata; + datalen_ = newsize; + } + memcpy(data_ + nexttouse_, newstr.c_str(),nsz); + unsigned newstrindex = nexttouse_; + nexttouse_ += nsz; + return newstrindex; + }; + void *exposedata() {return (void *)data_;}; + unsigned exposelen() const {return nexttouse_;}; +private: + char * data_; + + // datalen_ is the size in bytes pointed to by data_ . + unsigned datalen_; + + // nexttouse_ is the index of the next (unused) byte in + // data_ , so it is also the amount of space in data_ that + // is in use. + unsigned nexttouse_; +}; +#endif /* STRTABDATA_H */ diff --git a/libdwarf/CHANGES b/libdwarf/CHANGES new file mode 100644 index 0000000..88fbcd8 --- /dev/null +++ b/libdwarf/CHANGES @@ -0,0 +1,102 @@ + + +------------------------------------------------------------- +April 14, 2000 davea@sgi.com +Corrected minor bugs in production of 32bit dwarf with +64 bit pointers. Fixed omissions in legal +DIE children of a DIE. Make small changes in +description of regster output in frame information +access. + +------------------------------------------------------------- +Mar 7, 2000 davea@sgi.com +Corrected line table reading so it will handle +reading an object with a diffent number of standard +op codes than at libdwarf compile time. +This was possible all along, but libdwarf did +not do it right. + +------------------------------------------------------------- +Dec 8, 1999 davea@sgi.com +Changed nearly all files. +Adding the capability to read and produce +the new, accepted by committee, but not +released-publically 64bit extension proposal +dwarf data. +This allows dwarf compilation units +with 64bit section offsets and 32bit +sections offsets to be mixed. +So that offsets can grow very large with +64-bit pointer applications (though 64bit pointers +and 64bit offsets are not the same notion). + +In addition, removed all the contents (or nearly all) +of the dwarf_funcs.c dwarf_weaks.c dwarf_vars.c, +and dwarf_types.c, as the data format is identical +to dwarf globals (pubnames) and there is no need +to duplicate all that code. + +All these sections whose contents were gutted are things that +are formatted exactly like pubnames, and all are sgi +extensions. Now the implementation uses pubnames code +(dwarf_global.c) to do the work for all the pubnames-like +sections. + +The (minor, IMO) difference is that in case of an incorrect +dwarf file (leading to libdwarf being unable to process +something in one of the sgi-specific pubnames-like sections) +the dwarf error string may reference pubnames when weaks, +static functions, static variables, or global typenames are +actually the problem. This is fixable, however the price would +appear to be that even globals would need to call a helper +function (to pass in the correct error return). Right now the +dwarf_weaks.c calls the dwarf_global.c function, for example, +with no extra arguments indicating the true section involved. +(Other approaches keeping the original error codes exist. +Producing the code uniquely via macros seems unappealing. +Inline functions would be ok though. This version does not +inline the functions we are talking about, such as +dwarf_global_name_offsets() when called from +dwarf_type_name_offsets().) + +Since these extra sections are SGI only and only really used by +SGI's workshop product, and the performance hit is small, the +extra function calls in reading each seem acceptable. + + +------------------------------------------------------------- +Sep 29,1999 davea@sgi.com +Changed many files, so that it is easy to switch +from 32bit-offset-only (like cygnus +and dwarf2 v 2.0.0) to sgi/mips 64 bit dwarf. +See NEWS for more info on 32bit-offset. + + +------------------------------------------------------------- +Since Oct 95 and before May, 1996 + +Added the function dwarf_get_cie_of_fde() which makes it possible +to remember a single fde/cie set out of a block usefully. + +Enhanced doc of dwarf_bitoffset() + +Added new function dwarf_global_formref() so all reference +forms can be retrieved. + +Fixed bug in retrieving array bounds: was failing to sign extend +formsdata. + +Added function dwarf_get_fde_info_for_all_regs(), which makes +retrieval of the complete set of registers (as needed by +debuggers and exception handlers) effectively N times faster +than getting them one a time where N is the number of registers. + +Added support for exception table handling (really just support +for a reference to an exception table for c++ exceptions). + +Fixed a bug where useless extra space (several megabytes) +were malloc'ed for the abbreviations table by the libdwarf +consumer code. + +davea@sgi.com +------------------------------------------------------------- diff --git a/libdwarf/CODINGSTYLE b/libdwarf/CODINGSTYLE new file mode 100644 index 0000000..3dd7601 --- /dev/null +++ b/libdwarf/CODINGSTYLE @@ -0,0 +1,61 @@ +This document is a brief description of the main +coding style conventions in libdwarf. Many of them +will be obvious from the code, but over time some +accidental diffences crept in. + + +Code should be indented in multiples of 4 spaces, and +tabs should not be used to indent the source code. +Use the dicheck program to check indenting. + + +dwarf.h and libdwarf.h must have all arguments commented +out as these are public headers. Because a prototype like +int dwarf_example_prototype(Dwarf_Debug foo); +would be made unusable by a legitimate +preprocessor definition +such as #define foo + + +The struct naming convention is 'struct Camel_Caps_s' for the +struct and 'Camel_Caps' for any typedef for the struct. +Admittedly having both camel caps +and an underbar is an unusual convention, but it is +the way the coding was begun in the early 1990's and +we should remain consistent now. + +All user-referenceable data and functions +and user_visible types should begin with DW_ or +dwarf_. Non-static libdwarf global data and functions +should begin with _dwarf (a somewhat questionable +approach, but workable). + +Function names should be all lower case with underbars +for readability. + +There should never be static data in any function. +Nor should there ever be static data outside of libdwarf +functions. libdwarf can be called from multiple threads +(but only from one thread per Dwarf_Debug) and multiple +Dwarf_Debug objects can be open at one time. +Instead place such data per-dbg into the Dwarf_Debug structure +in dwarf_opaque.h. Similarly for the producer code. + +Function-local variables should be lower-case with +underbars for readability. It's ok for a small loop +with counters to use single letter names like i or k or m. + +structure members should have a struct-specific +2-character prefix to the name (followed by +an underbar). That makes it much +easier to grep for uses of members. + +Try to keep lines under 80 characters in length. + +Ensure every if() has {} to enclose the actions. + +Use libdwarf.h types for all the data objects you define, +though sometimes an 'unsigned' or 'int' or 'size_t' is +ok in restricted circumstances. Dwarf_Unsigned Dwarf_Signed +are the preferred integer types for general use. + +------------ diff --git a/libdwarf/COPYING b/libdwarf/COPYING new file mode 100644 index 0000000..eb621ce --- /dev/null +++ b/libdwarf/COPYING @@ -0,0 +1,37 @@ + + +The files: + libdwarf.h + dwarf.h + and all the .h and .c files in this implementation of + libdwarf are copyrighted according to the file + LIBDWARFCOPYRIGHT (which mentions the LGPL version 2.1). + The full text of the LGPL 2.1 is provided in LGPL.txt + + +The dwarf documentation: + dwarf.v2.mm and its postscript form and its + indexes are copyright Unix International (UI is now defunct). + One presumes XOPEN owns the copyright now. In any case copying + and revision without fee is permitted (see the + copyright in the document). + +The libdwarf documentation: + libdwarf2.1.mm + is based on material submitted to the UI PLSIG as proposed + interfaces for dwarf, but completely rewritten. + Copyright ownership is therefore SGI (but see the document for details) + and it seems clear that the intent was there was to be free + copying with no fees. + + libdwarf2p.1.mm + is documentation of a set of interfaces + (not part of the UI PLSIG proposals) + and the document was written from scratch at SGI. + Copyright ownership is therefore SGI (but see the document for details) + and it seems clear that the intent was there was to be free + copying with no fees. + +$Source: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/libdwarf/RCS/COPYING,v $ +$Revision: 1.2 $ +$Date: 2001/01/16 17:08:36 $ diff --git a/libdwarf/ChangeLog b/libdwarf/ChangeLog new file mode 100644 index 0000000..247cf9f --- /dev/null +++ b/libdwarf/ChangeLog @@ -0,0 +1,9 @@ +2012-04-04 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: A pointer "*" was right next to + a "/*" so a space introduced between them for clarity. + Fixed comments on DW_DLC_SIZE_64 and DW_DLC_SIZE_32. + * dwarf_die_deliv.c: Two local variables were declared in the + middle of code, accidentally creating C99 dependencies. + Both trivially fixed with no change in logic. +2012-01-01 DavidAnderson <davea42@earthlink.net> + * A new year starts. diff --git a/libdwarf/ChangeLog2006 b/libdwarf/ChangeLog2006 new file mode 100644 index 0000000..02009d6 --- /dev/null +++ b/libdwarf/ChangeLog2006 @@ -0,0 +1,835 @@ +2006-12-05 David Anderson <davea@sgi.com> + * dwarf_error.c, libdwarf.h: added + DW_DLE_FRAME_REGISTER_COUNT_MISMATCH. + * dwarf_frame.c (_dwarf_exec_frame_instr): removed references + to compile-time constants for register table size. Now uses + run-time-chosen sizes. Now uses heap for reg table instead + of stack. Now uses SIMPLE_ERROR_RETURN macro to simplify + the code. +2006-11-08 David Anderson <davea@sgi.com> + * pro_expr.c (dwarf_add_expr_gen): DW_OP_deref_size, + DW_OP_xderef_size, and DW_OP_pick were incorrect, missing + & operator. Would coredump. Thanks to Alan Chambers for mentioning + the coredump. +2006-09-26 David Anderson <davea@sgi.com> + * dwarf_die_deliv.c (dwarf_offdie): Now returns the + correct die (worked before, almost always, but worked by accident). + Thanks to Mattias Lindblad for supplying a test case. +2006-09-01 David Anderson <davea@sgi.com> + * libdwarf2.1.mm (dwarf_loclist_n): Minor refinement + of the description. + * libdwarf2.1.ps: regenerated +2006-08-31 David Anderson <davea@sgi.com> + * libdwarf2.1.mm (dwarf_loclist_n): A location expression + sets ld_lopc to 0, ld_hipc to all-bits-on, and this + is now documented. + * libdwarf2.1.ps: regenerated +2006-06-14 David Anderson <davea@sgi.com> + * dwarf_opaque.h dwarf_frame.h dwarf_frame.c + dwarf_init_finish.c dwarf_frame2.c: Corrected handling + of eh_frame zP encoding. + Thanks to Cristi Vlasceanu for noticing it was broken. + * Makefile.in: remove libdwarf.so in 'clean' rule. + Thanks to Cristi Vlasceanu for noticing it was missing. +2006-04-28 David Anderson <davea@sgi.com> + * dwarf_frame.c: Changed local variable type to + avoid compiler warning. +2006-04-21 David Anderson <davea@sgi.com> + * dwarf_frame.c: Initialized local to 0, wrong value. + Thanks to Cristi Vlasceanu for noticing. +2006-04-18 David Anderson <davea@sgi.com> + * All *.c: Ran indent so all c files follow a standard look. +2006-04-16 David Anderson <davea@sgi.com> + * dwarf.h: Remove #if 0 around some #defines, it is ok to + leave the defines visible (the defines are HP extensions). + * libdwarf.h: Add new dwarf3 interface to frames. + (which actually is also a better interface to dwarf2 info, + not strictly for dwarf3). + * dwarf_alloc.c: Add 'constructor/destructor' pointers + to the initialization table so we can handle a more + flexible (dwarf3) frame interface.Call the functions + at the appropriate times. + * dwarf_frame.c: Using macro FDE_NULL_CHECKS_AND_SET_DBG + reduce duplicate coding.Internal code now handles dwarf2 + and dwarf3 and interfaces to exported interfaces appropriately. + * dwarf_frame.h: Alter internal struct to handle frames more flexibly. + * dwarf_frame2.c: Remove unused local variable. + * dwarf_init_finish.c: Add initialization of new Dwarf_Debug + struct entries allowing handling + of run-time-config of frame info. + * dwarf_loc.c: Add DWARF3 operators, such as DW_OP_call4. + * dwarf_opaque.h: Declaration of new Dwarf_Debug struct + entries allowing handling of run-time-config of frame info. + * pro_expr.c: Add entries allowing creation of DWARF3 DW_OP + such as call2. + * pro_section.c: Change crucial code handling section lengths, + using a macro BEGIN_LEN_SIZE to clarify and correct a few places. +2006-03-31 David Anderson <davea@sgi.com> + * libdwarf.h: Added dwarf_get_fde_info_for_cfa_reg3() prototype + preparing for dwarf3 frame interface. + * dwarf_frame.c: Now uses separate rule, not DW_FRAME_CFA_COL, + to record CFA. + * dwarf_frame.h: Add commentary on frame access. +2006-03-30 David Anderson <davea@sgi.com> + * Makefile.in configure.in: Adding --enable-shared --enable-nonshared + --disable-shared and --disable-nonshared. + * configure: regenerated with 2.59 autoconf. + * README: Added explanation on changing dwarf.h libdwarf.h. +2006-03-29 David Anderson <davea@sgi.com> + * dwarf_print_lines.c dwarf_sort_line.c: Clean up initialization + code for line table reading. When returning rules table + data to caller ensure fully filled out yet no overrun + (handling case where rules table sizes not defined identically + by caller and library). + * dwarf.h: New commentary on ABI/register-number issues. + * libdwarf.h: New commentary on ABI/register-number issues. +2006-03-26 David Anderson <davea@sgi.com> + * dwarf_line.c: file_entry_count local was not initialized. + Initialized some locals at declaration. + Thanks to Mikael Vidstedt for noticing. +2006-03-23 David Anderson <davea@sgi.com> + * dwarf_error.c: added error strings for codes 200,201 + * dwarf_line.c dwarf_line.h dwarf_print_lines.c dwarf_sort_line.c: Moved + line prefix reading to a common routine, filling in a new internal + struct to make it simple. Removed much duplicate code. + Added more support for dwarf3 line table standard opcodes. + Now prints details (with -v -v) of standard opcodes it + does not understand (if any present). +2006-03-13 David Anderson <davea@sgi.com> + * dwarf.h: add ALTIUM #defines (extensions to dwarf) + * libdwarf.h: Alter arguments to new + functions dwarf_get_fde_augmentation_data() and + dwarf_get_cie_augmentation_data() used by GNU eh_frame. + * dwarf_frame.h: Add new fields so we can handle GNU eh_frame. + * dwarf_frame.c: Remove erroneous load_sections calls (wrong for eh_frame + data) and correct the new dwarf_get_fde_augmentation_data() and + dwarf_get_cie_augmentation_data() implementation. + * dwarf_frame2.c: Implement support for GNU eh_frame. + * dwarf_line.h: Correct handling of DWARF3 opcode base check. + * dwarf_line.c: Add new macro use to get DWARF3 opcode base handling correct. + * dwarf_print_lines.c: Add new macro use to get DWARF3 opcode base handling correct. + * dwarf_sort_lines.c: Add new macro use to get DWARF3 opcode base handling correct. +2006-03-08 David Anderson <davea@sgi.com> + * dwarf_frame2.c: ensure local variables initialized + to avoid coredump. +2006-03-08 David Anderson <davea@sgi.com> + * dwarf_die_deliv.c: Remove Richard Stukey's -1 and + replace with a simpler more complete fix. +2006-03-07 David Anderson <davea@sgi.com> + * Makefile.in: Add dwarf_line2.c dwarf_frame3.c to files to build. + * dwarf_addr_finder.c: Add comments about file purpose. + * dwarf_frame.c: Move IRIX specific function out of this file. + * dwarf_frame3.c: Move IRIX specific function to this new file. + * dwarf_frame.h: Add interface declaration. + * dwarf_line.c: Move IRIX specific function out of this file. + * dwarf_line2.c: Move IRIX specific function to this new file. + * dwarf_line.h: Add interface declaration. + * dwarf_frame2.c: Altered comments so indent handles them better, + ran indent. + +2006-03-07 David Anderson <davea@sgi.com> + * dwarf_die_deliv.c (dwarf_siblingof): -1 to point to end of cu, + not one-past-end. With thanks to Richard Stuckey. + * libdwarf2.1.mm: document existing function dwarf_get_fde_exception_info() + * dwarf_frame.h: Add new internal interfaces. + * dwarf_frame.c: Remove cie/fde reader to dwarf_frame2.c. + * dwarf_frame2.c: Contains heavily refactored cie/fde reader, + preparing for eh_frame support and avoids some searching + in fde creation. Removes duplicated code into new + internal functions. + * Makefile.in: Adding comment about flag for malloc_checking + code. Add dwarf_frame2.c to source list. + * libdwarf.h: added declarations for eh_frame information, though + these are not yet supported. + * dwarf.h: Added defines for eh_frame information, though these + are not yet used. +2006-02-23 David Anderson <davea@sgi.com> + * dwarf_line.h dwarf_line.c: added dwarf_line_srcfileno() + to complement dwarf_lineno. + * libdwarf2.1.mm: document dwarf_line_srcfileno(). + +2005-11-25 David Anderson <davea@sgi.com> + * dwarf.h: Now matches 2005 DWARF3 public review document. + +2005-11-08 David Anderson <davea@sgi.com> + * dwarf_alloc.c, dwarf_init_finish.c, dwarf_sort_line.c, malloc_check.c: + remove malloc.h include, it is not needed, stdlib.h suffices. + +2005-10-24 David Anderson <davea@sgi.com> + * dwarf.h: Updated to match DWARF3 public review document. + +2005-10-03 David Anderson <davea@sgi.com> + * dwarf_alloc.c: Change some entries to BASE_ALLOC. + * dwarf_global.h: Add argument to interface so we do not + universally use DW_DLA_GLOBAL, but cater to compatibility. + * dwarf_funcs.c, dwarf_global.c, dwarf_weaks.c, + dwarf_funcs.c, dwarf_types.c: Restored use of DW_DLA_* + instead of universally using DW_DLA_GLOBAL. + * dwarf_pubtypes.c: added comments about DW_DLA_GLOBAL use. +2005-08-01 David Anderson <davea@sgi.com> + * malloc_check.c: Moved the #ifdef WANT_LIBBDWARF_MALLOC_CHECK + down after #includes so the test is meaningful. +2005-07-15 David Anderson <davea@sgi.com> + * libdwarf.h: New DW_DLA codes and full .debug_types support added. + new dealloc functions declared. + * Makefile.in: Add dwarf_pubtypes.o (.debug_pubtypes support). + * dwarf_abbrev.c: Add dealloc() calls where needed. + * dwarf_alloc.c: Add dwarf_malloc_check calls, rename and + update _DW_RESERVE to DW_RESERVE, make hash table declaration + in array more readable. Add optional final dealloc loop. + * dwarf_alloc.h: Increase the index array to add .debug_pubtypes + support. + * dwarf_base_types.h: Increase the index array to add .debug_pubtypes + support. + * dwarf_die_deliv.c: Add dealloc calls to get full dealloc. + * dwarf_error.c: Document new error codes for .debug_pubtypes. + * dwarf_init_finish.c: Add .debug_pubtypes support, add + dwarf_malloc_check_complete() call for alloc checking. + * dwarf_form.c: Document dwarf_formstring() use. + * dwarf_frame.c: Add dwarf_fde_cie_list_dealloc() for + complete dealloc. + * dwarf_global.h: Add _dwarf_internal_globals_dealloc + declaration for libdwarf-internal use. + * dwarf_global.c dwarf_funcs.c dwarf_types.c dwarf_vars.c + dwarf_weaks.c: Add new dealloc public routines for + complete dealloc and add .debug_pubtypes support. + * dwarf_pubtypes.c: Support for .debug_pubtypes. + * dwarf_malloc_check.h dwarf_malloc_check.c : New checking + for complete accurate dealloc (off by default). + * dwarf_opaque.h: Add internal .debug_pubtypes support. + * libdwarf2.1.mm: Document new dealloc code, correct + dwarf_formstring documentation. + +2005-07-14 David Anderson <davea@sgi.com> + * dwarf_line.c: Added dwarf_srclines_dealloc and call it + for dwarf_srclines output. Does complete deallocation, + unlike previous method, which was incomplete deallocation. + Thanks to Alan Alexander for pointing out there was + incomplete deallocation. + * dwarf_print_lines.c: remove references and allocation + of line_context. Memory was leaking due to unreferenced + variable. + * libdwarf2.1.mm: Document new dwarf_srclines_dealloc() + deallocation routine for dwarf_srclines(). + +2005-07-13 David Anderson <davea@sgi.com> + * dwarf_init_finish.c (dwarf_init): if _dwarf_setup() fails, + free elf resources with elf_end() call. + Thanks to Cristi Vlasceanu for pointing out that a memory + leak existed here. + +2005-06-13 David Anderson <davea@sgi.com> + * dwarf_frame.c (_dwarf_exec_frame_instr): Corrected test + so that .o files (pre-relocation) are less likely to generate + DW_DLE_DF_NEW_LOC_LESS_OLD_LOC error. Renamed local variable + for better readability. +2005-04-13 David Anderson <davea@sgi.com> + * dwarf_error.c: Error codes 194 and 195 were missing + strings, added them to table. + * dwarf_frame.c: Check for newer gcc .eh_frame + augmentation strings and avoid trying to handle these + for now. + * dwarf_global.c: Add an error check for + pubnames-style sections for bad offset. + * dwarf_init_finish.c: Add dwarf_get_section_max_offsets() + to allow clients to do additional error checking. + This code will have to change again, so leaving it + undocumented. As written it's not useful for COMDAT + style DWARF sections. + * libdwarf.h: Added prototype for dwarf_get_section_max_offsets(). + +2005-03-31 David Anderson <davea@sgi.com> + * mips_extensions.mm: Documented the libexc/.debug_funcnames + dependency and the 64bit-offset DWARF extension. + * mips_extensions.ps: Regenerated. + +2005-03-21 David Anderson <davea@sgi.com> + * dwarf_line.c: Added commentary. + * libdwarf2.1.mm: Documented dwarf_lineendsequence() better. + * libdwarf2.1.ps: Regenerated. + * libdwarf.h: Added DW_DLE_FRAME_AUGMENTATION_UNKNOWN as + error code 195. + * dwarf_init_finish.c: Corrected comment spelling. + * dwarf_frame.h dwarf_frame.c: Added handling for + much (but not all) of gcc 3.3 gcc 3.4 .eh_frame + 'z' augmentation. Gives error on attempting + to get z augmentation data since such is not + completely handled. + +2005-03-18 David Anderson <davea@sgi.com> + * dwarf_frame.h dwarf_frame.c: The gcc .eh_frame + info did not print correctly so we now access the + correct section data so it prints. Still no support + for dwarf3 frame operators. + * dwarf_macro.c: Detect end-of-macros properly + (stopped too soon before). + +2005-02-14 David Anderson <davea@sgi.com> + * pro_incl.h: Added #elif defined(HAVE_LIBELF_H) + enabling build on a platform missing normal elf.h. + +2005-02-11 David Anderson <davea@sgi.com> + * dwarf_base_types.h: Added DW_CIE_VERSION3 define. + * dwarf_die_deliv.c: Allowed CURRENT_VERSION_STAMP3. + * dwarf_frame.c: Allowed DW_CIE_VERSION3. + * dwarf_frame.h: Define DW_DEBUG_FRAME_VERSION3. + * dwarf_line.c: Allow CURRENT_VERSION_STAMP3. + * dwarf_line.h: Add lc_version_number to line structure. + * dwarf_opaque.h: Add CURRENT_VERSION_STAMP3 and comment showing + version numbers (DWARF3 vs DWARF2) by DWARF section. + +2004-11-21 David Anderson <davea@sgi.com> + * configure.in libdwarfdefs.h: Now tests more precisely for __uint32_t + and __uint64_t (previous test was not sufficient for debian/mips). + Regenerated configure config.h.in. + +2004-10-28 David Anderson <davea@sgi.com> + * LIBDWARFCOPYRIGHT Makefile.in NEWS config.h dwarf_abbrev.c + dwarf_abbrev.h dwarf_addr_finder.c dwarf_alloc.c dwarf_alloc.h + dwarf_arange.c dwarf_arange.h dwarf_base_types.h dwarf_die_deliv.c + dwarf_die_deliv.h dwarf_error.c dwarf_error.h dwarf_form.c + dwarf_frame.c dwarf_frame.h dwarf_funcs.c dwarf_funcs.h + dwarf_global.c dwarf_global.h dwarf_incl.h dwarf_init_finish.c + dwarf_leb.c dwarf_line.c dwarf_line.h dwarf_loc.c dwarf_loc.h + dwarf_macro.c dwarf_macro.h dwarf_opaque.h dwarf_print_lines.c + dwarf_query.c dwarf_sort_line.c dwarf_string.c dwarf_stubs.c + dwarf_types.c dwarf_types.h dwarf_util.c dwarf_util.h + dwarf_vars.c dwarf_vars.h dwarf_weaks.c dwarf_weaks.h + libdwarfdefs.h pro_alloc.c pro_alloc.h pro_arange.c pro_arange.h + pro_die.c pro_die.h pro_encode_nm.c pro_encode_nm.h pro_error.c + pro_error.h pro_expr.c pro_expr.h pro_finish.c pro_forms.c + pro_frame.c pro_frame.h pro_funcs.c pro_funcs.h pro_incl.h + pro_init.c pro_line.c pro_line.h pro_macinfo.c pro_macinfo.h + pro_opaque.h pro_pubnames.c pro_pubnames.h pro_reloc.c + pro_reloc.h pro_reloc_stream.c pro_reloc_stream.h pro_reloc_symbolic.c + pro_reloc_symbolic.h pro_section.c pro_section.h pro_types.c + pro_types.h pro_util.c pro_util.h pro_vars.c pro_vars.h + pro_weaks.c pro_weaks.h: Copyright update with + 2004 and new SGI official address. + +2004-10-26 David Anderson <davea@sgi.com> + * acconfig.h: removed. Was old style autoconf usage. + * configure.in: Updated AC_DEFINE usage, adding args 2 & 3. + * config.guess: Updated. timestamp='2004-06-11'. + * config.sub: Updated. timestamp='2004-03-12'. + * configure config.h.in: regenerated with autoconf 2.58. + +2004-06-09 David Anderson <davea@sgi.com> + * dwarf_frame.c (_dwarf_exec_frame_instr): + Was not setting ru_offset to 1 in DW_CFA_def_cfa_offset + case, now it does. + +2004-02-24 David Anderson <davea@sgi.com> + * dwarf_frame.c (_dwarf_exec_frame_instr): + DW_CFA_def_cfa_register case, was setting offset, which + is incorrect. Thanks to Tom Hughes <thh@cyberscience.com> + for pointing this out. + +2004-02-03 David Anderson <davea@sgi.com> + * dwarf_util.h: DECODE_LEB128_UWORD DECODE_LEB128_SWORD + were simply wrong if Dwarf_Word or + Dwarf_Sword longer than 4 bytes. Upper bits left random. + Large values not extracted correctly. + +2004-01-15 David Anderson <davea@sgi.com> + * dwarf_alloc.c pro_alloc.c pro_init.c: changing BSD-ish bzero() + to posix-standard memset() calls. + * configure.in: remove bstring.h test, add alloca.h test. + No longer useing bzero, some environments have alloca + in malloc.h, no alloca.h. If neither exist + it's up to you to deal with it. + * dwarf_line.c dwarf_print_lines.c dwarf_sort_line.c: Test + HAVE_ALLOCA_H + * configure config.h.in: regenerated + +2003-12-31 David Anderson <davea@sgi.com> + * dwarf_init_finish.c: added #error to detect and describe + absence of libelf.h. + * README: Added mention of libelf.h requirement, minor + cleanout of obsolete comments, added configure example. + * Makefile.in: Removed bogus LIBS line, updated copyright date. + * acconfig.h: Updated copyright date. + * config.guess config.sub: new versions from automake-1.6. + * config.h.in configure: Regenerated. + +2003-12-15 David Anderson <davea@sgi.com> + * dwarf_init_finish.c (_dwarf_setup): test for (section_size) + was wrong for eh_frame section. Changed this one to + (section_size == 0) so it is like all the others testing + section_size. Thanks to David Mosberger + for pointing out this inconsistency. + +2003-12-08 David Anderson <davea@sgi.com> + * dwarf_line.h: reference in comment to li_dbg meant to + refer to li_offset. Corrected and amplified comment. + +2003-10-06 David Anderson <davea@sgi.com> + * dwarf_abbrev.c dwarf_die_deliv.c dwarf_form.c dwarf_loc.c + dwarf_util.c: applied indent(1). + +2003-10-02 David Anderson <davea@sgi.com> + * dwarf_loc.c: Implemented dwarf_get_loclist_entry(), + implemented new dwarf_loclist_n() fully implementing + loclist support. + * dwarf_stubs.c: removed dwarf_get_loclist_entry stub. + * libdwarf2.1.mm: Documented dwarf_loclist_n() and + updated documentation on dwarf_loclist(). + +2003-09-29 David Anderson <davea@sgi.com> + * dwarf_abbrev.c: Ensure the .debug_abbrev section is loaded. + * dwarf_arange.c dwarf_global.c: Recent dwarf committee + discussions have revealed we were wrong in not allowing + padding in aranges. + * dwarf_die_deliv.c dwarf_query.c: handle DW_FORM_indirect. + * dwarf_form.c: Add dwarf_whatform_direct() so folks + can report on DW_FORM_indirect use. + Fill in new Dwarf_Locdesc fields. + * dwarf_loc.c: Handle .debug_loc partially. + Fill in new Dwarf_Locdesc fields. + Load .debug_loc if not present and if it's needed. + * dwarf_opaque.h: Added ar_attribute_form_direct field + so we can report DW_FORM_indirect + in libdwarf-using code (where such wants to). + * dwarf_util.c: Don't confuse DW_FORM_indirect uleb length + with other lengths. + * libdwarf2.1.mm: Document new function dwarf_whatform_direct() + Not needed by ordinary clients, just for clients + wanting to print certain debug info. + +2003-04-15 Brian Ford <ford@vss.fsi.com> + * configure.in (AC_C_BIGENDIAN): Move after AC_PROG_CC so a proper + working compiler is used for the test. + +2003-01-21 David Anderson <davea@sgi.com> + * dwarf_die_deliv.c (dwarf_next_cu_header, dwarf_offdie): + Add calls to dwarf_load_object() to load .debug_info, + .debug_abbrev + * dwarf_init_finish.c (_dwarf_setup): Remove calls to + dwarf_load_object for .debug_info, .debug_abbrev sections. + * dwarf_opaque.h: Add new fields to Dwarf_Debug so + we don't need to pre-load .debug_info, .debug_abbrev + * dwarf_util.h: Fix READ_AREA_LENGTH macro so it uses + only length itself to determine which format the + length is. + +2003-01-14 David Anderson <davea@sgi.com> + * dwarf_loc.c: Made comment at head of dwarf_loclist() + a bit clearer. + +2002-11-22 Tom Hughes <thh@cyberscience.com> + * dwarf_macro.c: Corrected bugs in macro-info functions. + +2002-10-29 David Anderson <davea@sgi.com> + * dwarf_init_finish.c: The libelf_sgi mods + left a HAVE_ELF64_GETSHDR ifdef in the wrong place + so folks without Elf64 could not build. Fixed. + +2002-10-21 David Anderson <davea@sgi.com> + * dwarf_form.c: the form_ref functions were failing to + add in cc_extension_size when checking for offset + legality. Thanks to Kelly O'Hair <kelly.ohair@sun.com> + for pointing out the 4 places this was wrong. + Used cu_context local pointer to avoid numerous + double indirections. + +2002-08-14 David Anderson <davea@sgi.com> + * dwarf_string.c (dwarf_get_str): Return + DW_DLV_NO_ENTRY when offset is just at the end of the + sections, making it possible to use dwarf_get_str + to print the section independently. + * libdwarf2.1.mm, libdwarf2.1.ps: Document the + revised dwarf_get_str interface (which was not + fully thought thru before). + * dwarf_line.c (dwarf_srcfiles): Avoid core dump + when DW_AT_comp_dir absent (it's not required). + + +2002-07-31 David Anderson <davea@sgi.com> + * pro_types.c (_dwarf_transform_simplename_to_disk): correct + generation of .debug_info size field. + Thanks to Kelly O'Hair <kelly.ohair@sun.com> for pointing out + the bug. + +2002-05-23 Daniel Gohman <gohmandj@sgi.com> + * dwarf_init_finish.c: Add support for using SGI's + ELF library as an alternative to using AT&T-style + libelf. + Add a new function _dwarf_load_section to handle + loading of sections. + * dwarf_opaque.h: Add entries to Dwarf_Debug_s to + store section indicies. + * most consumer files: Load sections on demand so + that unneeded sections don't get loaded. + * dwarf_init_finish.c: Fixed an incorrect check for + duplicate .eh_frame sections. + +2002-04-25 Kelly O'Hair <kelly.ohair@sun.com> + * pro_section.c (_dwarf_pro_generate_debuginfo): add + required dwarf2 sec 7.5.3 trailing null byte + to .debug_abbrev per compilation-unit. + +2002-03-31 David Anderson <davea@sgi.com> + * dwarf_abbref.c (dwarf_get_abbrev): change + DW_DLE_DEBUG_ABBREV_NULL to DW_DLE_DWARF_ABBREV_NULL. + Former was wrong code. + * libdwarf2.1.mm: correct argument reference, returned_abbrev + not returned_fde in dwarf_get_abbrev discussion. + +2002-03-07 David Anderson <davea@sgi.com> + * libdwarf.h: added struct Elf declaration + to reduce dependency on header include ordering. + +2002-02-11 David Anderson <davea@sgi.com> + * libdwarf2.1.mm libdwarf2.1.ps: + dwarf_offdie can return DW_DLV_NO_ENTRY and that + is now documented. + * dwarf_loc.c: if the length of a location description + is zero that is ok, not an error. dwarf2 sec 2.4.1. + +2002-01-10 David Anderson <davea@sgi.com> + * dwarf_opaque.h, dwarf_init_finish.c: if libdwarf does + the elf_begin() it must also do the elf_end() to + avoid a memory leak, and now does this correctly. + +2002-01-10 David Anderson <davea@sgi.com> + * dwarf_init_finish.c: Using a variable to + hold ELF_C_READ_MMAP. Really motivated by + code not added to this source. + * dwarf_die_deliv.c: Added comments, moved + a couple variables to local scope from function scope. + + * dwarf.h: Added some #defines which were specified in the Dwarf + 2.1 Dwarf draft 5 (now called dwarf 3 draft 5). + +2001-09-18 David Anderson davea@sgi.com + * all files: applied gnu indent with + -bad -bap -nbbo -br -ce -brs + -l72 -lc72 -hnl -nprs + -fca -i4 -lp -psl -npcs + Code should use this set in libdwarf. + + +2001-08-21 "kelly o'hair" <kelly.ohair@eng.sun.com> + * pro_section.c: If one called dwarf_add_file_decl() + or dwarf_add_directory_decl() but never added a line, + .debug_line was not produced. This was a mistake, + as if any file or directory was provided .debug_line + should be produced. + +2001-08-06 davea@sgi.com + * libdwarf2.1.mm: documented dwarf_dealloc rules + more clearly. (.ps updated too) + * mips_extensions.mm: documented the way SGI + gets frame stack pointer out of debug_frame. + (.ps updated too) + +2001-06-14 davea@sgi.com + * dwarf_leb.c: changed around where bytes counted in + _dwarf_decode_s_leb128 so it's easier to tell it is correct. + And removed one loop completely: it was + an early attempt at performance improvement and + is no longer relevant. + + * dwarf_global.c: added new + dwarf_get_cu_die_offset_given_cu_header_offset function + to get CU die offset (as the long name says). + A variety of functions return cu-header-offsets, so + this is useful at times. + Used locals to reduce the number of indirections + and make things easier to follow. + + * dwarf_arange.c: added new dwarf_get_arange_cu_header_offset + function so dwarfdump could print the cu header offset + (which appears in the arange headers). + + * libdwarf2.1.mm: documented the above new functions. + +2001-06-07 davea@sgi.com + * dwarf_leb.c: shift operator was not being applied + to full size of Dwarf_Signed/Unsigned for 64bit + Dwarf_Signed/Unsigned (ILP32 compile) so + large numbers not decoded if signed. + * pro_encode_nm.c: added {} in a couple if/else + for 'clarity' and to make inserting debug printf easier. + * pro_expr.c: Added comments explaining why possible + compiler (gcc) warnings are ok, the result is safe. + +2001-05-30 davea@sgi.com + * pro_reloc_stream.c: Wrote Set_REL32_info and + Set_REL64_info macros + from generic ELF abi documents to make use acceptable + when IRIX elfaccess.h is not available. + +2001-05-30 "kelly o'hair" <kelly.ohair@eng.sun.com> + * Makefile.in: was missing pro_macinfo.o + pro_encode_nm.o dwarf_macro.o from the OBJS list. + +2001-05-22 davea@sgi.com + * dwarf_frame.c, pro_expr.c: Added comments on why + casts are safe in spite of gcc warnings (4 places total). + +2001-05-18 Dan Gritter <dgritter@us.ibm.com> + * dwarf_loc.c DW_OP_bregx operands are unsigned + reg num followed by signed offset. + +2001-04-11 David Anderson <davea@sgi.com> + * dwarf_die_deliv.c: check for 0 abbreviation code + and return a 'no entry' return value when found. + (normal dwarf2, 0 means no DIE, the end of some set of DIEs.) + +2001-01-16 David Anderson <davea@sgi.com> + + * pro_die.c: set ar_reloc_len field + in all cases. + +2000-12-14 David Anderson <davea@sgi.com> + + * dwarf_frame.h: clarified some comments. + +2000-12-14 Ulrich Drepper <drepper@cygnus.com> + + * dwarf_line.c: Now sets DW_LNE_end_sequence to + default_is_stmt, the correct value, not is_stmt. + + +2000 Aug 24 davea@sgi.com + dwarf_error.c: a dwarf_init() failure resulted in this + using a static Dwarf_Error struct. And dwarf_dealloc + did not deal properly with that. + dwarf_alloc.c dwarf_alloc.h: these had DYNAMIC_CHUNK protected code + which was never used. Deleted the unused code. Added a small + comment (hopefully useful) to dwarf_alloc.h. + + And now deals correctly with a null dbg on + DW_DLA_ERROR due to failed + dwarf_init() call (or due to other error in calling + libdwarf that results in libdwarf not knowing the dbg, + a likely far more common case) and frees the memory. + This used to result in chaos (depending on your + luck...). + +2000 Aug 23 davea@sgi.com + libdwarf2.1.mm, ps. Failed to mention that dwarf_finish() + has to be accompanied by elf_end() if dwarf_init() was used + to initialize libdwarf to truly release all stuff. + Added text to dwarf_finish() describing how to do that. +2000 April 14 davea@sgi.com + + dwarf_abbrev.c - 1.22 + - When it is a null abbrev entry, return it correctly so it can be + printed (meaning fill out all the return-parameters so the caller can + do the right thing). + + dwarf_init_finish.c - 1.48 + - For most sections, simply having an empty section (present but empty) + is just fine. There is no reason to register an error in such a case. + + Copyright has changed. See LIBDWARFCOPYRIGHT and NEWS + + dwarfdump/print_die.c - 1.42 + - Explain what combo checker is doing and make it more maintainable (and fix bug which would not be hit, but was real enough). + + dwarfdump/tag_tree.list - 1.2 + - Add valid parent/child relationships so checker does not report valid + entries as bogus. + + dwarf_form.c - 1.26 + - Correct dwarf reader to use appropriate size, not de_length_size. This is part of the handling of the new dwarf2 64bit facilities. I + overlooked this small aspect before in one place + dwarf_query.c - 1.48 + - Use correct size, not de_length_size. For offset size. + libdwarf2.1.mm - 1.41 + - Tried to make frame register output args meaning clearer + libdwarf2.1.ps - 1.19 + - Tried to make frame register output args meaning clearer + pro_forms.c - 1.33 + - Get ref4, not ref8 when generating 32bit dwarf per original dwarf2 + spec. even if pointer size is 64 bits. + pro_init.c - 1.18 + - Get ref4, not ref8 when generating 32bit dwarf per original dwarf2 + spec. even if pointer size is 64 bits. + + +davea@sgi.com + + +2000 March 7 +dwarf_line.c - 1.48 +dwarf_line.h - 1.16 +dwarf_print_lines.c - 1.10 +dwarf_sort_line.c - 1.8 + - Now handles opcode_base of line section to be other than that at + compile time of libdwarf. +Important as the dwarf2 committee is adding a new standard opcode +davea@sgi.com + +2000 Feb 24 +pro_forms.c 1.31 ar_next field not always zeroed before. +Could lead to infinite loop in the producer code. +Now the field is always zeroed. + +Makefile.in - 1.3 Jason Merrill <jason@cygnus.com> + provided fix so gcc will work on libdwarf +print_sections.c - 1.54 - casts to avoid warnings + +davea@sgi.com + + +1999 Dec 14 +acconfig.h - 1.3 +config.h.in - 1.5 +configure - 1.4 +configure.in - 1.5 + - HAVE_DWARF2_99_EXTENSION HAVE_OLD_DWARF2_32BIT_OFFSET + refinements added. +CHANGES - 1.3 +Makefile.base - 1.98 +NEWS - 1.5 +config.h - 1.4 +config.h.in - 1.4 +configure.in - 1.4 +dwarf_alloc.c - 1.36 +dwarf_arange.c - 1.19 +dwarf_arange.h - 1.6 +dwarf_die_deliv.c - 1.51 +dwarf_frame.c - 1.62 +dwarf_frame.h - 1.23 +dwarf_funcs.c - 1.10 +dwarf_funcs.h - 1.3 +dwarf_global.c - 1.21 +dwarf_global.h - 1.7 +dwarf_init_finish.c - 1.45 +dwarf_line.c - 1.44 +dwarf_opaque.h - 1.52 +dwarf_print_lines.c - 1.8 +dwarf_query.c - 1.45 +dwarf_types.c - 1.10 +dwarf_types.h - 1.3 +dwarf_util.c - 1.40 +dwarf_util.h - 1.22 +dwarf_vars.c - 1.11 +dwarf_vars.h - 1.3 +dwarf_weaks.c - 1.10 +dwarf_weaks.h - 1.3 +libdwarf2.1.mm - 1.40 +libdwarf2.1.ps - 1.18 +pro_arange.c - 1.15 +pro_die.c - 1.23 +pro_frame.c - 1.29 +pro_init.c - 1.15 +pro_macinfo.c - 1.7 +pro_opaque.h - 1.14 +pro_pubnames.c - 1.18 +pro_reloc_stream.c - 1.5 +pro_section.c - 1.70 +pro_section.h - 1.16 +pro_types.c - 1.12 + - Allowing generation of correct dwarf2 with the 1999 64bit dwarf + extension, and reading all forms of dwarf2 compatibly (all 32/64bit + dwarf2 section forms). + +This adds the ability to consume and produce both sgi 64bit +and the new dwarf2 committee-approved 64bit dwarf extension. +As a result of the new dwarf2 stuff , a producer (compiler) +can mix 32 and 64bit dwarf (for a 64bit object) and the +linker will work seamlessly. (as long as section sizes don't +get over 2GBytes). + +And the producer is easily configured to produce mips/sgi style +64bit dwarf or the new form of 64bit dwarf. + +This also eliminates a fair amount of rather silly duplicated code. +davea@sgi.com + + +1999 Nov 4 + +pro_section.c - 1.69 + - A pointer size entity had an offset-size value used at one place. +davea@sgi.com + +1999 Sep 30 +dwarf_arange.c - 1.18 + - Changed // comment to /* */. // failed to compile + with C89 compiler... +davea@sgi.com + + +1999 Sep 29 +Changed all the producer code +substantially to allow generating assembler code +for the dwarf2 (rather similar to what gcc does) +allowing symbolic relocations. +MIPS output still generates the binary form. +davea@sgi.com + + + +1999 Aug 20 +Stan Shebs (shebs@cygnus.com) pointed out that the pro_util.h +use of R_MIPS* was a problem compiling on Sun. +Since the producer code is not really used at present except for +MIPS/sgi, I've added #ifndefs to pro_util.h which provide zero values +when <elf.h> does not provide the macros. +When anyone needs the producer code to actually *work* for non-MIPS +something better will have to be done. + +This has no effect on those simply compiling libdwarf for +use by dwarfdump. +davea@sgi.com + +1999 July 21 +Changed the READ_UNALAGNED macro to call a function +depending on endianness of the host and the object being read. +So all the dwarf_* source changed in a trivial way. +Added support for printing egcs eh_frame section. +Added a local memcpy-like function to do the cross-endian +thing where applicable (called by READ_UNALIGNED macro). +Because the .eh_frame section +after linking can have some zeroed out bytes at the +end of the CIE/FDE data the code looking for CIEs and FDEs +now assumes a zero CIE/FDE length means it has reached +the end of the CIE/FDE data. +davea@sgi.com + + +1999 June 14 + Fred Fish fnf@ninemoons.com contributed + autoconf'ing of the libdwarf and dwarfdump source. + + + mips_extensions.* Documented additional old errors + in the Dwarf Version 2 spec. + + The ChangeLog before this is incomplete. + +------------------------------------------------------------- +Since Oct 95 and before May, 1996 davea@sgi.com David Anderson + +Added the function dwarf_get_cie_of_fde() which makes it possible +to remember a single fde/cie set out of a block usefully. + +Enhanced doc of dwarf_bitoffset() + +Added new function dwarf_global_formref() so all reference +forms can be retrieved. + +Fixed bug in retrieving array bounds: was failing to sign extend +formsdata. + +Added function dwarf_get_fde_info_for_all_regs(), which makes +retrieval of the complete set of registers (as needed by +debuggers and exception handlers) effectively N times faster +than getting them one a time where N is the number of registers. + +Added support for exception table handling (really just support +for a reference to an exception table for c++ exceptions). + +Fixed a bug where useless extra space (several megabytes) +were malloc'ed for the abbreviations table by the libdwarf +consumer code. + +------------------------------------------------------------- +June 10, 1999 + Changelog started. +------------------------------------------------------------- diff --git a/libdwarf/ChangeLog2007 b/libdwarf/ChangeLog2007 new file mode 100644 index 0000000..6de48a5 --- /dev/null +++ b/libdwarf/ChangeLog2007 @@ -0,0 +1,217 @@ +2007-12-09 DavidAnderson <davea42@earthlink.net> + * dwarf_sort_line.c dwarf_print_lines.c darf_frame.c: Forgot + to commit yesterday. + Today's commit includes renaming _dwarf_fde_section_offset + _dwarf_cie_section_offset, _dwarf_print_lines, _dwarf_ld_sort_lines + to dwarf_* name while retaining support for the now obsolete + _dwarf_* form. +2007-12-08 DavidAnderson <davea42@earthlink.net> + * config.h.in, configure.in: Latest linux libelf.h requires + _GNU_SOURCE to get off64_t defined so dwarfdump compiles. + Only define _GNU_SOURCE if libelf.h defines off64_t. + Regenerated configure. + * config.guess, config.sub: Updated to 2.61 + * acconfig.h: Deleted, removing autoconf complaint. +2007-11-14 David Anderson <davea42@earthlink.net> + * dwarf_frame2.c (gnu_aug_encodings): Now allows 'S' augmentation + character in eh_frame. +2007-10-16 David Anderson <davea42@earthlink.net> + * dwarf_alloc.c: Reformat a comment. + * dwarf_die_deliv.c (dwarf_siblingof): When there is no trailing + null-DIE in the section, ensure we don't test the contents + of a byte past section end. + * dwarf_frame.c: Changed spelling of a local variable + so it is easier to grep for and to read. + * dwarf_macro.c (free_macro_stack): Was free()ing memory that + _dwarf_get_alloc() had supplied, which could lead to core dump. + Fixed potential memory leaks (said leaks only possible with an + error in the macro data, not with valid macro section + data). +2007-10-15 David Anderson <davea42@earthlink.net> + * dwarf_alloc.c: The code supporting the special build + flag DWARF_SIMPLE_MALLOC + was broken and could coredump libdwarf + (which did not affect normal use of libdwarf). + * dwarf_opaque.h: Remove the field de_simple_malloc_current + as it is no longer used. + +2007-09-04 David Anderson <davea42@earthlink.net> + * pro_forms.c: Add commentary relating to the + recent DWARF4 DW_AT_high_pc change. + Correct FSF address. + * libdwarf2p.1.mm: Document dwarf_add_AT_dataref() + and dwarf_add_AT_ref_address(). + * libdwarf2p.1.pdf: Regenerate. + * dwarf.h: Update FSF address. + * dwarf_opaque.h: Add DWARF4 entry (version stamp). + Update FSF address. + * dwarf_die_deliv.c: Add check for .debug_info version 4 + (version stamp). Update FSF address. + * libdwarf.h pro_macinfo.h pro_line.h dwarf_incl.h + pro_alloc.h pro_section.h libdwarfdefs.h pro_util.h + dwarf_vars.h dwarf_funcs.h pro_error.h dwarf_alloc.h pro_arange.h + dwarf_arange.h pro_die.h dwarf_global.h pro_expr.h + pro_reloc_stream.h pro_incl.h pro_encode_nm.h + dwarf_line.h pro_frame.h pro_opaque.h dwarf_error.h + dwarf_base_types.h dwarf_abbrev.h pro_types.h pro_reloc_symbolic.h + dwarf_weaks.h dwarf_util.h dwarf_loc.h malloc_check.h + dwarf_die_deliv.h acconfig.h dwarf_frame.h dwarf_macro.h + pro_reloc.h dwarf_types.h + pro_funcs.c Makefile.in pro_forms.c pro_line.c + dwarf_print_lines.c pro_alloc.c pro_init.c dwarf_addr_finder.c + pro_section.c dwarf_form.c dwarf_query.c dwarf_vars.c + dwarf_pubtypes.c dwarf_frame3.c dwarf_funcs.c pro_error.c + pro_arange.c dwarf_alloc.c dwarf_arange.c pro_die.c + dwarf_sort_line.c dwarf_global.c dwarf_init_finish.c pro_weaks.c + pro_pubnames.c pro_expr.c pro_reloc_stream.c pro_finish.c + pro_encode_nm.c dwarf_line.c pro_frame.c dwarf_error.c + dwarf_abbrev.c pro_types.c dwarf_leb.c pro_reloc_symbolic.c + dwarf_string.c pro_vars.c dwarf_line2.c dwarf_weaks.c + dwarf_frame2.c dwarf_util.c dwarf_loc.c LIBDWARFCOPYRIGHT + malloc_check.c dwarf_die_deliv.c dwarf_frame.c dwarf_stubs.c + dwarf_macro.c pro_reloc.c dwarf_types.c pro_macinfo.c: + Update FSF address. +2007-07-26 David Anderson <davea42@earthlink.net> + * pro_frame.c: Added commentary about some missing DWARF3 support. + * dwarf_srclines_dealloc.c: File unused, now deleted. +2007-07-04 David Anderson <davea42@earthlink.net> + * libdwarf.h: dwarf_get_loclist_entry() is implemented, + removed the erroneous 'unimplemented' comment. + * libdwarf2.1.mm: Improved the dwarf_get_loclist_entry() + documentation. + * libdwarf2.1.pdf: regenerated + * dwarf_loclist_entry.c: Removed from distribution, the + source has nothing of interest. + +2007-07-03 David Anderson <davea42@earthlink.net> + * libdwarf.h: Add declaration of dwarf_loclist_from_expr(); + * dwarf_loc.c: Implement dwarf_loclist_from_expr() and add + sign-extension macro calls to case DW_OP_const4s numbers. + Removed unused local variables. + * dwarf_form.c: Removed unused local variables. + * libdwarf2.1.mm: Document dwarf_loclist_from_expr(). + * libdwarf2.1.pdf: Regenerated. +2007-07-01 David Anderson <davea42@earthlink.net> + * dwarf_frame2.c: Add commentary. + * dwarf_frame.c: Add in block_len for DW_CFA_val_expression + so libdwarf does not get confused by this frame expression + operator. Thanks to Cristian Vlasceanu for providing + a test case. +2007-06-29 David Anderson <davea42@earthlink.net> + * README: added a note that a few warnings about conversions + from pointer to integer are normal at libdwarf compile time. +2007-05-25 David Anderson <davea42@earthlink.net> + * dwarf_frame2.c (_dwarf_get_fde_list_internal): + Correct cie-list-creation so it adds to the tail of the list. + gcc 4.1.2 generates cie-use in an order the code did + not properly handle. +2007-05-08 David Anderson <davea42@earthlink.net> + * Makefile.in: Now generates pdf files. + * mips_extensions.mm: The only changes were to eliminate + unsupported macro (.PM) and to try to get correct output + from groff. No technical content change intended. + The pdf/postscript output remains a little odd though. + * libdwarf2.1.mm: Remove troff comment line. +2007-04-18 Chris Quenelle <chris.quenelle@sun.com> + * dwarf_addr_finder.c: repaired comment + * dwarf_form.c: add support for DW_AT_SUN_func_offsets + * pro_alloc.c: add memory block tracking to find and fix + lingering allocations. This is more important for very large + and intensive compiles. + * pro_die.c: Implement "markers" which are a generic way to + do things like relocations. You can set a marker on any + die, and when dwarf is produced in binary form, you get back + a list of your markers with the offset of each one in the binary + output. This is used by the Sun compilers to implement die + references that span compile unit blocks. (I may remove this, + it might be unused code related to partial_units and comdat + support) + * pro_die.c: Also check for loops in the die relationships so + that if you add a child twice, or other errors, you won't get + an infinite loop or a crash. Also start passing a DBG structure + to all allocation calls to help with memory block tracking. + * pro_expr.c: Add a public function to "reset" an expr. This + allows the same expr object to be reused over and over to save + memory if you're creating many many expressions for a location list. + * pro_finish.c: Free any left over blocks when the user calls + dwarf_producer_finish. + * pro_forms.c: More support for compressed integer blocks. Modify + error diagnostics so that user-defined attributes can be any type. + Add support for dwarf_add_AT_ref_address which is just like + dwarf_add_AT_address, only it produces a DW_FORM_ref_addr instead + of DW_FORM_addr. This is needed for cross-CU die pointers. + * pro_incl.h: add macros to control the spelling of relocation types. + * pro_init.c: use new macros to control reloc types + * pro_line.h: correct minimum instruction length on x86 + * pro_opaque.h: add support for markers (see above) and also ability + have libdwarf tell the caller where the string constants are so + that they can be recorded as strings in case the binary output of libdwarf + needs to be converted back into assembly. That's what + Dwarf_P_Per_Sect_String_Attrs is about. + Remove de_mem_list as it is never used. + * pro_reloc_stream.c: repair prototype and comment for + _dwarf_pro_reloc_name_stream64, and use relocation type macros. + * pro_section.c: support for markers (see above) and for tracking + inline string attributes. Add code to sort the attributes so that + abbreviation table entries will be reduced. Change treatment of + DW_FORM_ref_addr to be more correct. Some support for packing + in the middle of sections, this will probably be removed. + Also pass DBg structure to more allocations. + * pro_util.h: relocation type values can't be zero. +2007-04-10 David Anderson <davea42@earthlink.net + * dwarf_print_lines.c pro_section.c dwarf_query.c + dwarf_alloc.c dwarf_arange.c dwarf_sort_line.c + dwarf_global.c dwarf_line.c dwarf_abbrev.c + dwarf_frame2.c dwarf_util.c dwarf_loc.c dwarf_util.h + dwarf_die_deliv.c dwarf_frame.c dwarf_macro.c: Additions + to source for year 2007 now fit in with pre-existing + copyright wording. Effectively no change. + * dwarf_srclines_dealloc.c: Now has the (always-intended) SGI + LGPL copyright wording. +2007-04-09 David Anderson <davea42@earthlink.net + * dwarf_error.h: Add DW_DLE_LINK_LOOP error code (Sun). + * libdwarf.h: Add DW_DLE_LINK_LOOP error code (Sun). + * dwarf.h: Incorporate Sun extensions. Thanks to + Chris Quenelle at Sun Microsystems. +2007-04-06 David Anderson <davea42@earthlink.net + * dwarf_sort_line.c (_dwarf_update_line_sec): initialize + Dwarf_Debug_s struct. Thanks to Chris Quenelle of Sun Microsystems. + Also initialize other local variables. +2007-04-02 David Anderson <davea42@earthlink.net + * dwarf_form.c (dwarf_formsdata, dwarf_formudata): Use + Dwarf_sfixed in dwarf_formsdata, document need for casts, + Use Dwarf_Signed as type for READ_UNALIGNED macro use. + The only real correction here is for a 64bit long compiled + libdwarf reading 32bit dwarf_formsdata FORM_data4. + * dwarf_base_types.h: Now Dwarf_sfixed64 and Dwarf_ufixed64 + are properly declared (so they are usable). +2007-03-11 David Anderson <davea42@earthlink.net + * Makefile.in: use groff to produce postscript. + * libdwarf2.1.mm libdwarf2.1.ps libdwarf2p.1.mm + libdwarf2p.1.ps: Clean up the introduction and history. + Add a non-restrictive copyright notice. +2007-02-23 David Anderson <davea42@earthlink.net + * dwarf_util.h: now the macros use do{} while(0) + * pro_forms.c dwarf_print_lines.c pro_section.c dwarf_query.c + dwarf_arange.c dwarf_sort_line.c dwarf_global.c dwarf_line.c + dwarf_abbrev.c dwarf_frame2.c dwarf_util.c dwarf_loc.c + dwarf_die_deliv.c dwarf_frame.c: Now have ; + after all dwarf_util.h macros. Also added local variable + initializations (compiler noticed). + * dwarf_macro.c: was missing include of <stdlib.h> for free() + declaration. + * dwarf_print_lines.c pro_section.c dwarf_query.c dwarf_alloc.c + dwarf_arange.c dwarf_sort_line.c dwarf_global.c dwarf_line.c + dwarf_abbrev.c dwarf_srclines_dealloc.c dwarf_frame2.c + dwarf_util.c dwarf_loc.c dwarf_die_deliv.c dwarf_frame.c + dwarf_macro.c: indent run with standard libdwarf options. + +2007-02-20 David Anderson <davea42@earthlink.net + * dwarf_macro.c (dwarf_get_macro_details): Now call + dwarf_free_macro_stack() at every return so no data + is leaked and there is no longer any global data + (restoring thread safety). +2007-02-09 David Anderson <davea42@earthlink.net + * dwarf_line.c (dwarf_srclines): Added in calls + to dwarf_free_line_table_prefix() which were omitted + by accident. Thanks to Cristian Vlasceanu for noticing. diff --git a/libdwarf/ChangeLog2008 b/libdwarf/ChangeLog2008 new file mode 100644 index 0000000..1867b40 --- /dev/null +++ b/libdwarf/ChangeLog2008 @@ -0,0 +1,263 @@ +2008-12-29 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Add support for .debug_ranges with + dwarf_get_ranges() and dwarf_ranges_dealloc(). + * dwarf_init_finish.c: Add support for .debug_ranges. + * dwarf_base_types.h: Add support for .debug_ranges functions. + * dwarf_alloc.c, dwarf_alloc.h: Add support for .debug_ranges + alloc/dealloc. + * dwarf_opaque.h: Add support for .debug_ranges. + * libdwarf2.1.mm: Documented dwarf_get_ranges() and + dwarf_ranges_dealloc() (rev 1.72). + * libdwarf2.1.pdf: Regenerated. +2008-12-09 DavidAnderson <davea42@earthlink.net> + * dwarf_alloc.c: Remove useless comments and + tweak a few comments. +2008-12-08 DavidAnderson <davea42@earthlink.net> + * dwarf_opaque.h: Add di_abbrev_code field to record + a DIE abbreviation value so consumers can report it. + * libdwarf.h: Add dwarf_die_abbrev_code() interface. + * dwarf_query.c: Add dwarf_die_abbrev_code() interface. + * dwarf_die_deliv.c: Set di_abbrev_code for consumers. + * libdwarf2.1.mm: Documented dwarf_die_abbrev_code(). + * libdwarf2.1.pdf: Regenerated. + * pro_util.h: Removed gratuitous tabs. Used a space instead. +2008-12-07 DavidAnderson <davea42@earthlink.net> + * dwarf.h: Entered DWARF4 defines known so far. + * dwarf_opaque.h: Updated dwarf 4 section-version comment + with the latest info. +2008-12-07 DavidAnderson <davea42@earthlink.net> + * dwarf_original_elf_init.c: Delete unused local variables. + * pro_forms.c: Delete unused local variables and initialize + local variables at definition. + * dwarf_pubtypes.c, dwarf_line.c: Delete accidental + duplicated /* comment-start. + * malloc_check.c: In the 'do nothing' case, create + an extern declaration to eliminate a compiler warning. +2008-11-19 DavidAnderson <davea42@earthlink.net> + * dwarf_die_deliv.c: Handle the case where DW_AT_sibling + uses DW_FORM_ref_addr. + * dwarf_util.c: Add a comment about DW_FORM_ref_addr. + * dwarf_opaque.h: Add a comment about CU fields, + comment out an unused CU header field. + * dwarf_query.c: Added dwarf_die_CU_offset_range() + so dwarfdump can check for additional errors. + * dwarf_form.c: Clarifying a comment. + * dwarf_print_lines.c: Add additional print detail on + line table headers (used by dwarfdump). + * libdwarf2.1.mm: Documenting the new function + dwarf_die_CU_offset_range(). + * libdwarf2.1.pdf: Regenerated. + * libdwarf.h: Added dwarf_die_CU_offset_range() interface + declaration. +2008-10-13 DavidAnderson <davea42@earthlink.net> + * dwarf_frame2.c: Removed last use of DW_FRAME_LAST_REG_NUM: + use dbg->de_frame_reg_rules_entry_count instead. +2008-09-30 DavidAnderson <davea42@earthlink.net> + * dwarf_print_lines.c: Print corrected warning + about bogus prologue length. + * dwarf_line.c: Work around bogus prologue length + compiler bug. + * dwarf_line.h: Rename arguments. +2008-09-29 DavidAnderson <davea42@earthlink.net> + * libdwarf2.1.mm: Documented requirement that + dwarf_get_fde_n() dwarf_get_fde_at_pc() pass a + pointer to an fde table that contains at least 1 entry. + * libdwarf2.1.pdf: regenerated. + * dwarf_opaque.h: Add new fields for cie/fde specific + fields for eh. + * dwarf_frame2.c: Initialize the new Dwarf_debug and + Dwarf_Fde fields. + * dwarf_frame.c: Access the new Dwarf_Fde fields. + * dwarf_frame.h: Define a new Dwarf_Fde field so we + keep eh and non-eh distinct. + +2008-09-29 DavidAnderson <davea42@earthlink.net> + * All .c files: Mechanically removed tab characters with + the expand tool. +2008-09-29 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: DW_DLE_LINE_SET_ADDR_ERROR no longer used. + The tests which generated it were bogus. + * dwarf_print_lines.c: Print a warning if there are any + apparently wasted bytes after the line prologue and before + the line table instructions. Match the new prologue reading + function prototype. + * dwarf_sort_line.c: Match the new prologue reading function + prototype. + * dwarf_line.c: Modify the prologue reading function so + it correctly finds the beginning of instructions even + when there are 'wasted' bytes after the prologue. + Drop bogus tests for minimum-instruction-size + matching the ABI pointer size. Removing the tests removed + all uses of DW_DLE_LINE_SET_ADDR_ERROR. + * dwarf_line.h: Modify the prototype for the prologue reading + function so it is possible for a caller to know about the + possibly wasted bytes after a prologue. +2008-09-02 DavidAnderson <davea42@earthlink.net> + * dwarf_init_finish.c (_dwarf_setup): Delete unused local + variable 'section_error'. +2008-08-14 DavidAnderson <davea42@earthlink.net> + * libdwarf2p.1.mm: Make it clearer that dwarf_get_pubnames, dwarf_get_varnames, + etc return a result across all compilation units (an entire section), + not just for a single compilation unit. Document version 1.68. + * libdwarf2p.1.pdf: Regenerated. +2008-08-08 DavidAnderson <davea42@earthlink.net> + * libdwarf2p.1.mm: Removed some long time + spelling mistakes: no technical change in content. + Document version 1.67. + * libdwarf2p.1.pdf: Regenerated. +2008-08-05 DavidAnderson <davea42@earthlink.net> + * libdwarf.h, dwarf_error.c: DW_DLA_PUBTYPE_CONTEXT was a mistake, + DW_DLE_PUBTYPE_CONTEXT was intended and is now the spelling (neither + is used). + * dwarf_pubtypes.c dwarf_vars.c dwarf_funcs.c dwarf_global.c dwarf_weaks.c: + tabs removed and previous strange formatting generated by a tool + removed (4 space indent per level now present). + +2008-08-05 DavidAnderson <davea42@earthlink.net> + * libdwarf2.1.mm: There were numerous places the apostrophe + was used incorrectly, thru is now spelled through, + and a few other small typographical errors were corrected. + The document revision id printed is now 1.67. + There is no technical change in content. + * libdwarf2.1.pdf: Regenerated. +2008-06-17 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Add DW_DLE_STRP_OFFSET_BAD error code. + * dwarf_form.c: Add runtime check for strp offset. + * dwarf_error.c: Add DW_DLE_STRP_OFFSET_BAD error code string. + * dwarf_init_finish.c, dwarf_opaque.h, dwarf_elf_access.h: Remove + CR characters that crept in. +2008-06-13 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Remove __SGI_FAST_LIBELF + dwarf_original_elf_init.c: Remove __SGI_FAST_LIBELF + and fix some indentation botches. + * dwarf_init_finish.c: Fix typo in variable name introduced + a few days ago. + * dwarf_elf_access.c: Remove __SGI_FAST_LIBELF + and fix some indentation botches. + +2008-05-20 DavidAnderson <davea42@earthlink.net> + * dwarf_init_finish.c: Expand tabs to spaces. +2008-05-20 DavidAnderson <davea42@earthlink.net> + * dwarf_init_finish.c(dwarf_object_init): When there is no + DWARF information return DW_DLV_NO_ENTRY gracefully. + Thanks to Carlos Alberto Enciso for pointing out + the bug. +2008-04-12 DavidAnderson <davea42@earthlink.net> + * pro_section.c: Initialize local variables to zero. + Change leading tabs to spaces. + * pro_reloc_stream.c: Initialize local variables to zero. + Change leading tabs to spaces. + * pro_reloc.c: Initialize local variables to zero. + Change leading tabs to spaces. +2008-04-04 DavidAnderson <davea42@earthlink.net> + * dwarf_base_types.h: Removed unused macro definition. + * dwarf_util.c: Altered abbreviations hash table for a small + performance improvement and space saving. + * dwarf_util.h: Changed declaration for space saving in dwarf + abbreviations table. +2008-04-04 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: A trivial change to make a declaration look better. + * dwarf_abbrev.h: We record tags in more than 16 bits now just in case + we encounter such a thing (increased ab_tag field size), though + we should not find such. + * dwarf_abbrev.c: Adding a comment about the dwarf TAG value. + * dwarf_util.c: Initialize local variables at declaration for safety. + Removed truncation of some values: internally record more bits. + Rewrote handling of the abbrev table as the old one did not scale + to large numbers of abbreviations (things got very slow). + * dwarf_util.h: Now has a larger field size in the argument to + _dwarf_get_abbrev_for_code (not quite necessary but not harmful). + * dwarf_die_deliv.c: Initializing local variables at declaration and + removing truncation of bits from some uleb values. + * dwarf_die_deliv.h: Increased size of ab_code field. + * dwarf_opaque.h: Added a comment about abbreviations. + * dwarf_base_types.h: Revised to match addition of new + allocation table entry. + * dwarf_alloc.h: Document macro definitions and increase one to + match new table size. + * dwarf_alloc.c: Arrange handling of new DW_DLA_HASH_TABLE_ENTRY + (most of the work done in dwarf_util.c). +2008-02-27 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Fixed minor typo in latest libdwarf.h that gcc did not + complain about. Noted by Josh Fuhs. +2008-02-26 DavidAnderson <davea42@earthlink.net> + * dwarf_alloc.h: Add comment giving placement of DWARF_SIMPLE_MALLOC. + * pro_opaque.h: Remove de_access field, it is never used. + * libdwarf.h: Add new data structures to allow reading of + non-Elf object files. + * dwarf_original_elf_init.c: dwarf_init(), dwarf_elf_init() + moved here from dwarf_init_finish.c. + * Makefile.in: Build new source files dwarf_original_elf_init.c + and dwarf_elf_access.c. + * dwarf_init_finish.c: All dependencies on libelf and elf + have been removed. + * dwarf_opaque.h: The elf related info is removed and Dwarf_Debug_s + now contains a new structure (from libdwarf.h) to hide object + information. + * dwarf_elf_access.c: All the Elf-using code is now in this + source file and elf details are kept in a struct defined and + used here. Non-libelf and non-elf object access code would + write a new source file with their own details using this + as an example. + * dwarf_elf_access.h: Prototypes for calling between + dwarf_original_elf_init.c and dwarf_elf_access.c. +2008-02-18 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Declare new object-access functions and structures. + * dwarf_original_elf_init.c: Traditional dwarf_init() and dwarf_elf_init() + are moved to this new source file. + * Makefile.in: Add new source files. + * dwarf_init_finish.c: Now uses the function pointers, not + libelf specific fields or ifdefs. + * pro_opaque.h: Remove de_access field, it is unused. + * dwarf_opaque.h: New fields for new object-access functions. + * dwarf_elf_access.c: New implementation details for elf access functions + moved here from dwarf_init_finish.c. + * dwarf_elf_access.h: New function interface so dwarf_elf_access.c + and dwarf_original_elf_init.c can communicate. +2008-02-08 DavidAnderson <davea42@earthlink.net> + * dwarf_print_lines.c: Added commentary to clarify that + dwarf_print_lines() and _dwarf_print_lines are intentionally + identical. Initialized local variables so they are alll + visibly set to some sensible value. +2008-02-07 DavidAnderson <davea42@earthlink.net> + * dwarf_frame.c (_dwarf_fde_section_offset): A typo + in the last release made this an infinite loop. + A one character change fixed it. Thanks to Carlos Alberto + Enciso for noticing the bug. +2008-02-04 DavidAnderson <davea42@earthlink.net> + * dwarf_incl.h, pro_incl.h: Moved #include of dwarf.h before libdwarf.h + * pro_forms.c: Some newer attributes are now handled. + * dwarf_print_lines.c: Removed unused #include. + * dwarf_sort_line.c: Removed alloca use in favor of + malloc and removed the alloca #include. + * dwarf_line.c: Removed unused #include. + * dwarf_line2.c: Removed unused #include. + +2008-02-04 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Fix commentary mistakes. +2008-02-02 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Add DW_DLC_OFFSET_SIZE_64 for run-time + selection of DWARF3 64bit extension producer offset generation. + * libdwarf2p.1.mm: Document DW_DLC_OFFSET_SIZE_64. + * pro_init.c (dwarf_producer_init): Now standard DWARF3 is the default. + * configure.in: Add --enable-dwarf-format-sgi-irix for those + wanting IRIX offset-style DWARF2. Add --enable-dwarf-format-strict-32bit + for those wanting strictly 32bit offsets. + Otherwise default to generating 64bit offsets from the producer code, + but allow the DWARF3 extended 64bit offsets if the flag + DW_DLC_OFFSET_SIZE_64 is turned on in the call to dwarf_producer_init(). + * config.h.in: Provide undefs for the offset macros. + +2008-01-25 DavidAnderson <davea42@earthlink.net> + * pro_die.c: Changed leading tabs to spaces. +2008-01-23 DavidAnderson <davea42@earthlink.net> + * pro_die.c: Using di_last_child field dwarf_die_link + goes from O(N) to O(1) in adding a child. + Thanks to Daniel Gollub for the suggestion. + An omission in linking left/right children is fixed. + Changed some leading TABs to spaces. + * pro_opaque.h: Add di_last_child field. +2008-01-14 DavidAnderson <davea42@earthlink.net> + * libdwarf2p.1.mm: Added missing backslash to correct formatting + error. Thanks to Daniel Golub for pointing out the ommission. + * libdwarf2.p1.pdf: Regenerated. diff --git a/libdwarf/ChangeLog2009 b/libdwarf/ChangeLog2009 new file mode 100644 index 0000000..a62bc0f --- /dev/null +++ b/libdwarf/ChangeLog2009 @@ -0,0 +1,348 @@ +2009-12-30 DavidAnderson <davea42@earthlink.net> + * configure: Regenerated with autoconf 2.64. + * config.guess, config.sub: Delete these. + * configure.in, README: The --enable-nonshared + option was coded incorrectly. The configure + options are --enable-shared and --disable-nonshared + work correctly. Options --disable-shared and --enable-nonshared work + correctly as well (these are the default values). +2009-12-29 DavidAnderson <davea42@earthlink.net> + * gennames.c: Add cast to int in printf so that the printf with * + as the field width sees an int, not size_t. + * Makefile.in: Add depenencies for libdwarf.so to match + libdwarf.a +2009-12-26 DavidAnderson <davea42@earthlink.net> + * libdwarf.h, pro_section.c, pro_reloc_symbolic.c: Reformatted + a few lines that were badly formatted. + Initialized local variables where a few were not initialized + (this did not affect correctness, just readability). +2009-11-27 DavidAnderson <davea42@earthlink.net> + * dwarf_form.c: Was an incorrect implemenation of + the reading of DW_FORM_sec_offset. + * libdwarf2.1.mm: Improved the documentation on reading DW_FORM_sec_offset. + See dwarf_global_formref() documentation. + * libdwarf2.1.pdf: Regenerate. +2009-11-27 DavidAnderson <davea42@earthlink.net> + * libdwarf.h, dwarf_form.c, dwarf_query.c: Adding + new form-class for the old DW_AT_MIPS_fde + SGI/IRIX extension (offset into .debug_frame). +2009-11-27 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Added dwarf_formexprloc() and a new + error code for it. + * dwarf_query.c: The new dwarf_get_form_class() + function had a typo for the address class. + * dwarf_form.c: dwarf_formexprloc() added so one can read + DW_FORM_exprloc location expressions. + * dwarf_error.c: New error added for dwarf_formexprloc(). + * libdwarf2.1.mm: Document dwarf_formexprloc(). + * libdwarf2.1.pdf: Regenerate. +2009-11-27 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Defines typedef Dwarf_Sig8 and + the new function dwarf_formsig8(). + * dwarf_error.c: Now deals with the latest + error codes, including a new one for dwarf_formsig8(). + * libdwarf2.1.mm: Document dwarf_formsig8(). + * libdwarf2.1.pdf: Regenerate. +2009-11-24 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Added enum dwarf_form_class_e and + dwarf_get_form_class() so clients have a simple + way to get the form-class mentioned in the DWARF + specification. + * dwarf_query.c: Implemented dwarf_get_form_class(). + * dwarf_die_deliv.c: Added dwarf_next_cu_header_b() + function as more useful than dwarf_next_cu_header(). + * dwarf_opaque.h: Added commentary about CU record. + * dwarf_elf_access.c: Added commentary about the CU header + data. + * libdwarf2.1.mm: Document dwarf_next_cu_header_b() + and suggest users convert to it. + Document dwarf_get_form_class(). Rev 1.84 + * libdwarf2.1.pdf: Regenerate. +2009-11-23 DavidAnderson <davea42@earthlink.net> + * dwarf_line.c: file_name_is_full_path() did not + allow for lower case in Windows root path + detection (with --enable-windowspath at configure + time). Now it does. +2009-11-17 DavidAnderson <davea42@earthlink.net> + * gennames.c: Check the return value from fgets(). + * dwarf_form.c, dwarf_util.c: Handle DW_FORM_sec_offset, new in DWARF4. + * libdwarf2.1.mm: Add comment to macro example to clarify its + limitation (it cannot always work). + * libdwarf2.1.pdf: Regenerate. +2009-09-30 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Added dwarf_insert_fde_inst_bytes() + to simplify copying an fde. Added dwarf_get_cie_index() + to provide a direct specific way to get a cie index for an fde. + * libdwarf2.1.mm: Minor reformatting to make things easier to read. + This is revision 1.82. Documented the new function + dwarf_get_cie_index(). + * libdwarf2.1.pdf: Regenerated. + * dwarf.h: Corrected typo, DW_CFA_cfa_offset_extended_sf is + really spelled DW_CFA_offset_extended_sf. + Added final new attributes, tag, language. + * pro_alloc.c: Reformatting a comment so the line is not so long. + * libdwarf2p.1.mm: Clarified that some arguments in fde + creation are MIPS/IRIX only (other targets should just pass 0). + This is revision 1.27. Document the new function + dwarf_insert_fde_inst_bytes(). + * libdwarf2p.1.pdf: Regenerated. + * config.h.in: Added HAVE_WINDOWS_PATH. + * configure.in: Added --enable-windowspath to set + HAVE_WINDOWS_PATH. + * configure: Regenerated. + * pro_section.c: Now allows use of a block of fde instructions + from dwarf_insert_fde_inst_bytes(). Some indentation fixed too. + * dwarf_line.c: Added detection of Windows full path if + HAVE_WINDOWS_PATH defined at library build time. + * pro_frame.c: Now handles dwarf3 CFA operations (but not the + expression operands yet). Removed some duplicated code in + a switch statement. Fixed commentary typos. + Created new function dwarf_insert_fde_inst_bytes(). + * pro_frame.h: Added fields to support dwarf_insert_fde_inst_bytes(). + * dwarf_arange.c: dwarf_get_arange_cu_header_offset() was + failing to load .debug_info, so a legitimate use of the function + might crash a client. + * dwarf_frame2.c: If there are CIE records but no FDEs this + is not considered a 'NO ENTRY' case. It is strange + but not a formal error and we might want to access the orphan + CIE records (to print them when debugging a compiler, for example). + * README: Documented --enable-windowspath. + * dwarf_frame.c: Adding dwarf_get_cie_index() convenience function. +2009-09-09 DavidAnderson <davea42@earthlink.net> + * libdwarf2p.1.mm: Improved the discussion of + dwarf_transform_to_disk_form. + * libdwarf2p.1.pdf: Regenerated. +2009-08-12 DavidAnderson <davea42@earthlink.net> + * pro_section.c: The Dwarf_Die argument to fde creation + functions is really optional (NULL is ok) and only used + for an IRIX/MIPS extension. So the code now allows + a NULL Dwarf_Die argument for these functions. + * libdwarf2p.1.mm: Rev 1.24, 11 Aug 2009 now documents + the argument as NULL for most users. + * libdwarf2p.1.pdf: Regenerated Rev 1.24, 11 Aug 2009. +2009-08-07 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Added to Dwarf_Regtable_Entry_s + and Dwarf_Regtable_Entry_s comments. + * libdwarf2.1.mm: Revised dwarf_set_frame_rule_table_size() + description, making it a bit more complete. + * libdwarf2.1.pdf: Regenerated, rev 1.81, 07 August 2009. +2009-08-05 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Interface to dwarf_expand_frame_instructions() + changed, the original could not really work right. + * libdwarf2.1.mm: Documented revised dwarf_expand_frame_instructions(). + * libdwarf2.1.pdf: Regenerated, rev 1.80, 05 August 2009. + * dwarf_frame.c: Fixed dwarf_expand_frame_instructions(); +2009-08-05 DavidAnderson <davea42@earthlink.net> + * gennames.c: Change include from getopt.h to unistd.h + so the code is more universally compilable. +2009-07-24 DavidAnderson <davea42@earthlink.net> + * dwarf_frame.c: Change debug printf to use libdwarf.h DW_PR macros + instead of %d. +2009-07-20 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Added DW_DLE_NO_ELF64_SUPPORT. + * dwarf_elf_access.c: If one has no Elf64 libelf support at build time + and runtime one finds an Elf64 object then we return + an error (DW_DLE_NO_ELF64_SUPPORT). Pretending we could handle + the elf64 was a bug. + * dwarf_error.c: Adding strings for new error codes. + * dwarf_elf_access.c: Add error code argument. + * dwarf_elf_access.h: Add error code argument. + * dwarf_original_elf_init.c: Report the correct error code instead + of a generic code. + +2009-07-16 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Add an error message define relating to rela relocations. + * dwarf_alloc.c: Add code to free malloc space (related + to rela relocations). + * config.h.in: Add ifdef for Sun host machines so rela processing + does not segv. + * dwarf_opaque.h: Add a flag to the section data to note that we malloced + space when rela relocations are involved. + * dwarf_elf_access.c: Refine is_32bit_abs_reloc() and + is_64bit_abs_reloc() for easier debugging. + Add malloc call when doing rela processing + as some host libelf libraries make some libelf data areas read-only + (Solaris and Irix for example). The malloc space avoids getting + a segv. +2009-07-13 DavidAnderson <davea42@earthlink.net> + * dwarf_elf_access.c: some cases had = where == was + needed in the reloc switch code. +2009-07-05 DavidAnderson <davea42@earthlink.net> + * dwarf_opaque.h: New data for .rela and unify section data + information. The changes will require consumers supporting + non-elf-objects to make small (hopefully simple) changes. + * dwarf_init_finish.c: Note existence of .rela sections. + * pro_forms.c: Explicitly allow DW_AT_const_value, + DW_AT_entry_pc, DW_AT_call_file, DW_AT_call_line. + * dwarf_ranges.c: Use simplified _dwarf_load_section() interface. + Change an accidental C++ style // comment to oldstyle C comment. + * dwarf_print_lines.c, dwarf_form.c, dwarf_query.c, + dwarf_vars.c, dwarf_pubtypes.c, dwarf_frame3.c, dwarf_funcs.c, + dwarf_arange.c, dwarf_global.c, dwarf_init_finish.c, + dwarf_line.c, dwarf_opaque.h, dwarf_string.c, dwarf_weaks.c + dwarf_util.c, dwarf_loc.c, dwarf_frame.c, dwarf_macro.c, + dwarf_types.c: Use simplified _dwarf_load_section() interface. + +2009-07-05 DavidAnderson <davea42@earthlink.net> + * dwarf_init_finish.c: Unified some common code into + a new local function , reducing file by 60 lines. + * dwarf_init_finish.c: Has long checked the wrong field + for duplicate debug_info and debug_abbrev. Fixed. + Also noted SGI IRIX only sections by adding comments. +2009-07-04 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Adding new function dwarf_CU_dieoffset_given_die(), + and comments on dwarf_get_cu_die_offset_given_cu_header_offset(); + * libdwarf2.1.mm: documenting dwarf_CU_dieoffset_given_die(). + * libdwarf2.1.pdf: Regenerated. + * dwarf_opaque.h: New structure Dwarf_Section_s consolidates + section information into one struct per section with + index and size so we remove many Dwarf_Debug_s fields. + * dwarf_print_lines.c, dwarf_form.c, dwarf_query.c, dwarf_vars.c, + dwarf_pubtypes.c, dwarf_frame3.c, dwarf_funcs.c, + dwarf_alloc.c, dwarf_arange.c, dwarf_init_finish.c , + dwarf_ranges.c, dwarf_line.c, dwarf_abbrev.c, dwarf_string.c, + dwarf_weaks.c, dwarf_frame2.c, dwarf_util.c, dwarf_loc.c, + dwarf_die_deliv.c, dwarf_frame.c, dwarf_macro.c, dwarf_types.c, + Reflect Dwarf_Section_s addition using its fields. + Simplify years list of SGI copyright using y-y replacing comma list. + Minor reformatting for consistency with 4-space indentation. + Initialize uninitialized local variables at declaration. + * dwarf_addr_finder.c, dwarf_print_lines.c: Initialize 'res' + local variables at declaration to DW_DLV_ERROR. + * dwarf_global.c: Add dwarf_CU_dieoffset_given_die(). + Reflect Dwarf_Section_s addition using its fields. + Simplify years list of SGI copyright using y-y replacing comma list. + Minor reformatting for consistency with 4-space indentation. + Initialize uninitialized local variables at declaration. +2009-06-06 DavidAnderson <davea42@earthlink.net> + * configure.in: The new option --enable_namestable + switches build time to generate a runtime binary search + in the dwarf_get_TAG_name() etc functions instead of the + default switch statement (for the rare case one knows a + compiler generates poor switch code). + * configure: regenerated. + * libdwarf.h: Correct format mistakes and omissions in + the Dwarf_Regtable_Entry3_s comments. + Add prototypes for dwarf_get_TAG_name() and the related + new functions. + * dwarf_frame.c: Add {} to clarify some 'if' ranges. + Remove code updating the DW_FRAME_CFA_COL row when finishing + up establishing the current frame table. The code should never + have been there. Fixed some indentation of function + formal parameters. Removed use of DW_FRAME_CFA_COL + and use de_frame_cfa_col_number instead. + In dwarf_get_fde_info_for_reg (the older interface) + correctly return the cfa table column in the 'old style'. + * gennames.c: Copied from dwarfdump.c (with changes). + This generates dwarf_names.c so that libdwarf has + functions like dwarf_get_TAG_name() which returns + functions like dwarf_get_TAG_name() which returns + the tag as a string (through a pointer argument). + * dwarf.h: The first word of a comment is now capitalized (1 place). + * common.c: New, used by gennames.c. + * common.h: New, used by gennames.c + * Makefile.in: Now contains changes which build and run + gennames and create dwarf_names.o (which is part + of libdwarf). + * libdwarf2.1.mm: Document the new libdwarf functions. + * libdwarf2.1.pdf: Regenerated as rev 1.76, 6 June 2009. +2009-06-05 DavidAnderson <davea42@earthlink.net> + * dwarf.h: added new DWARF4 attribute (etc) defines. +2009-05-10 DavidAnderson <davea42@earthlink.net> + * dwarf_frame.c: Remove use of DW_FRAME_UNDEFINED_VAL in + favor of the value in the dbg structure. + Adding comments about the meaning of an error case. +2009-05-07 DavidAnderson <davea42@earthlink.net> + * Makefile.in: Ensure temp files all get deleted. +2009-05-04 DavidAnderson <davea42@earthlink.net> + * dwarf_die_deliv.c: Update _dwarf_get_size_of_val() + call (with its new address_size argument). + * dwarf_frame.c: Use the new ci_address_size instead + of de_pointer_size. + * dwarf_frame.h: Added ci_address_size to cie + in preparation for this value in DWARF4. + * dwarf_util.h: Adding address_size functions + and arguments declarations so address_size can vary by CU. + * dwarf_util.c: Adding address_size functions + and arguments so address_size can vary by CU. + * dwarf_loc.c: Adding function dwarf_loclist_from_expr_a() + as a version with an address size argument. + * dwarf_frame2.c: Now initializes new ci_address_size field. + * dwarf_line.c: Now uses address size for CU instead of + default de_pointer_size. + * dwarf_ranges.c: File left out of svn before. + Implements dwarf_get_ranges() and dwarf_get_ranges_a(), + the latter is new with address size passed in via a DIE pointer. + * dwarf_arange.c: Added commentary. Removed erroneous + insistence that every aranges group have the same + address_size as the main elf object. + * dwarf_query.c: Adding address size to internal calls. + * dwarf_print_lines.c: Added '(file number is %d)' + to -l -v -v -v output as the + file number and traditional C zero-origin index index of a + line table header are not the same value + (see DWARF3 documentation, the end of section 6.2.5.3). + * libdwarf2.1.mm: Documented dwarf_loclist_from_expr_a() + and dwarf_get_ranges_a(). + * libdwarf2.1.pdf: Regenerated. + * libdwarf.h: Add commentary. + Add dwarf_loclist_from_expr_a() and + dwarf_get_ranges_a() interfaces so address_size passed in. +2009-04-04 DavidAnderson <davea42@earthlink.net> + * libdwarf.h, dwarf_frame.c: Added dwarf_set_frame_cfa_value(). + Added dwarf_set_frame_rule_initial_value() as proper + spelling of dwarf_set_frame_rule_inital_value(), keeping + the old spelling for compatibility. + * libdwarf2.1.mm: Documented Added dwarf_set_frame_cfa_value(), + corrected spelling to dwarf_set_frame_rule_initial_value(). + * libdwarf2.1.pdf: Regenerated. + * dwarf_opaque.h: Added field de_frame_cfa_col_number so that + we do not need to use magic macros at execution time. + * dwarf_init_finish.c: Now sets de_frame_cfa_col_number, + de_frame_same_value_number, and de_frame_undefined_value_number. +2009-02-02 DavidAnderson <davea42@earthlink.net> + * dwarf.h: Added dwarf extensions reported by + John Bishop. +2009-03-30 DavidAnderson <davea42@earthlink.net> + * dwarf.h: Added dwarf extensions reported + on the dwarf-workgroup mailing list by John DelSignore. +2009-03-19 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Expanded comments. + * dwarf_die_deliv.c: Expanded comments. +2009-03-16 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Fixed several instances of + inconsistent indentation. Documented arguments + to dwarf_uncompress_integer_block(). +2009-02-17 DavidAnderson <davea42@earthlink.net> + * dwarf_print_lines.c,dwarf_line.c,dwarf_frame.c: C99-isms + of // comments and declarations-in-code do not belong in + libdwarf. +2009-02-14 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Add support for compile-time definition + of the format for Dwarf_Unsigned types. + Using macros for DW_PR_DUx etc. + * dwarf_print_lines.c: Use the DW_PR_DUx macros. + * configure.in: Define --enable-nonstandardprintf + * config.h.in: new #undef HAVE_NONSTANDARD_PRINTF_64_FORMAT + * configure: Regenerated. + * config.guess, config.sub: Latest version from GNU. + * dwarf_line.c: Use the DW_PR_DUx macros. + * dwarf_frame2.c: Use the DW_PR_DUx macros. + * README: document --enable-nonstandardprintf + +2009-02-13 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Added argument to dwarf_print_lines() + for better error reporting. Added dwarf_check_lineheader() + which allows some error reporting when not calling dwarf_print_lines(). + * dwarf_print_lines.c: Implements dwarf_check_lineheader() now. + * dwarf_sort_line.c: Match up with new arguments to + dwarf_read_line_table_prefix(). + * dwarf_line.c: Implement new arguments to + dwarf_read_line_table_prefix() for better error reporting. + Allow erroneous ARM-compiler line table header to be used. + * dwarf_line.h: Adding new argument to dwarf_read_line_table_prefix + so we can report back on minor errors in the line table prefix. +2009-01-31 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Corrected DW_DLE_LAST. + * dwarf_frame.c: Remove accidental use of C99 mid-block + variable definition. diff --git a/libdwarf/ChangeLog2010 b/libdwarf/ChangeLog2010 new file mode 100644 index 0000000..844254b --- /dev/null +++ b/libdwarf/ChangeLog2010 @@ -0,0 +1,175 @@ +2010-10-13 DavidAnderson <davea42@earthlink.net> + * dwarf.h: Added DW_LANG_Go as 0x0015 per discussion on + mailing list. +2010-09-29 DavidAnderson <davea42@earthlink.net> + * README: Document that there is no install target and + update some of the old references to postscript to refer + to pdf. + * Makefile.in: A dummy install target provided though it + gets ignored by make. +2010-09-20 DavidAnderson <davea42@earthlink.net> + * libdwarf/libdwarf.h: Added commentary about markers. + * libdwarf/libdwarf2p.1.mm: Documented the marker calls. + * libdwarf/libdwarf2p.1.pdf: Regeenerated, ver 1.29. +2010-06-30 DavidAnderson <davea42@earthlink.net> + * dwarf.h: Add DW_ISA_ARM values for DW_LNS_set_isa. +2010-06-01 DavidAnderson <davea42@earthlink.net> + * README: Document issues with building on MacOSX and + how to deal with them. + * Makefile.in: Added comment about ar -s for MacOSX users. + * dwarf.h: Added comment about the gap in FORM number use + just before 0x20. +2010-03-30 DavidAnderson <davea42@earthlink.net> + * dwarf_frame2.c: Tightned up a harmless error + message string and deleted an unused local variable. + * dwarf_harmless.c: Detected more errors in the implementation + and fixed them. + * dwarf_elf_access.c: If EM_MIPS not defined, define it to 8, + the standard value for EM_MIPS. + Refine the rela relocations code for MIPS 64 BE vs LE. + * dwarf_arange.h: Added new fields to properly represent + segments in aranges as documented in DWARF4. + * dwarf_arange.c: dwarf_get_aranges was thinking + an entry with 0,0 (end of a set) was the end of the aranges + for a CU. But that is not guaranteed by the DWARF standards, + there can be multiple sets in one CU, see the standard, + section 7.20 (DWARF2,3,4). + Created local function, removing lots of duplicated code. + Added some support for DWARF4 segment value in tuples. + Added dwarf_get_arange_info_b() so all DWARF4 information + can be retrieved by client code. + * libdwarf.h: Aded new interface dwarf_get_arange_info_b(), +2010-03-28 DavidAnderson <davea42@earthlink.net> + * libdwarf.h: Adding dwarf_get_harmless_error_list(), + dwarf_insert_harmless_error(), and + dwarf_set_harmless_error_list_size() functions. + Some errors that are detectable are not sufficient + to warrant rejecting an object or refusing to process it. + * dwarf_harmless.c: Implementing + the harmless error functions. + * dwarf_harmless.h: Declaration of the libdwarf_internal + dwarf_harmless_init and dwarf_harmless_cleanout functions. + * dwarf_error.c: Added DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE + error string. + * dwarf_util.h: Clarify some comments on READ_AREA_LENGTH + macro. + * dwarf_opaque.h: Add structure and field to record + harmless errors for a dbg. + * dwarf_frame.h: Add commentary. Change ci_length from + Dwarf_Word to Dwarf_Unsigned for consistency with other such + length fields. + * Makefile.in: Add dwarf_harmless.o to the list of objects. + * dwarf_alloc.c: Add call to dwarf_harmless_cleanout() on + close of a dbg. + * dwarf_init_finish.c: Add call to dwarf_harmless_init + to initialize the fields for recording harmless errors. + * dwarf_frame2.c: Add handling of Arm "armcc+" augmentation + string. Create validate_length() local function to check + that the fde/cie length matches the requirements of the + specification, implementing the + DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE test (a harmless error). + Removed an earlier formally incorrect test. + * libdwarf2.1.mm: Documented the harmless error calls. + The version is now 1.90. + * libdwarf2.1.pdf: Regenerated as 1.90. +2010-02-14 DavidAnderson <davea42@earthlink.net> + * dwarf.h: Add GNU template defines. + * libdwarf.h: Add new error code DW_DLE_NOT_REF_FORM for + the DWARF 4 case where DW_FORM_data4/8 no longer + valid global reference forms. + * libdwarf2.1.mm: Document the manner that DW_OP_implicit_value + is returned as a location description set. + * libdwarf2.1.pdf: Regenerate. Rev 1.89. + * dwarf_error.c: Add two new DW_DLE error strings. + * dwarf_frame.h: define DW_DEBUG_FRAME_VERSION4 for + DWARF4 support. Add address size and segment size fields + to the internal CIE structure. + * dwarf_query.c: The form-class code was not correct, + DWARF4 has DW_FORM_sec_offset, not DWARF3. + Some places did not use the CU context address size + when reading an address. + * dwarf_form.c: Use the CU-context address size + instead of the overall object address/offset size. + Initialize all local variables at the point of declaration. + Refine some commentary. + Use the CU version number to guide processing of some FORMs. + * dwarf_print_lines.c, dwarf_query.c: Use the CU-context + address size instead of the overall object address/offset size. + Handle DW_LNE user extensions as well as possible. + * dwarf_arange.c: Delete some erroneous code (already ifdefd out) + as the address size need not match the de_pointer_size. + If segment-selector non-zero, read it properly. + DWARF2 and DWARF3 left this documented in an incorrect + and unusable fashion (DWARF4 documents it properly). + * dwarf_die_deliv.c: Delete erroneous code (previously ifdefd out) + as the address size need not match the de_pointer_size. + * dwarf_sort_line.c, dwarf_line.c: Deal with DW_DLE extended + line operations past those defined by the standard + (such as user-defined operations). + * dwarf_line.h: For user-defined line extended operations, provide + a sanity check of DW_LNE_LEN_MAX. + * dwarf_base_types.h: Add DW_CIE_VERSION4 for DWARF4. + Add other defines so each defined version number (sections + differ) has a name for the relevant section. + * dwarf_frame2.c: Add address size to argument lists so the proper + CIE address size (a new field in DWARF4 CIEs) are honored. + Also read the new DWARF4 segment_size field. + Use the address size instead of the object-derived de_pointer_size. + * dwarf_util.c: Return address_size instead of de_pointer_size. + * dwarf_loc.c: DWARF4 uses DW_FORM_sec_offset, not + DW_FORM_data4 or DW_FORM_data8 when specifying offsets to + other sections. Add DWARF4 DW_OP_implicit_value and + DW_OP_stack_value. + * dwarf_frame.c: Initialize a local variable at the point + of declaration. +2010-02-04 DavidAnderson <davea42@earthlink.net> + * libdwarf2.1.mm: Fix a spelling error. + * libdwarf2.1.mm: Regenerate. Rev 1.88. +2010-02-01 DavidAnderson <davea42@earthlink.net> + * dwarf_frame.c: The DW_CFA_remember_state and DW_CFA_restore_state + operations were not recording/restoring the cfa_rule, now they do. +2010-01-27 DavidAnderson <davea42@earthlink.net> + * dwarf_form.c: form_refsig8() had an uninitialized + local variable. +2010-01-25 DavidAnderson <davea42@earthlink.net> + * libdwarf2.1.mm: Rev 1.87. Improved the discussion + of frame information. + * libdwarf2.1.pdf: regenerated. +2010-01-25 DavidAnderson <davea42@earthlink.net> + * pro_opaque.h, pro_init.c, pro_section.c, + pro_reloc_stream.c, pro_reloc_symbolic.c: Rename the function + pointer members de_func and de_func_b to + de_callback_func and de_callback_func_b respectively. +2010-01-17 DavidAnderson <davea42@earthlink.net> + * dwarf.h, libdwarf.h: Updated commentary about frame interfaces. + * libdwarf2.1.mm: New descriptions of DW_FRAME_CFA_COL + and DW_FRAME_CFA_COL3. Document rev 1.86 . + * libdwarf2.1.pdf: Regenerated. + * libdwarf2p.1.mm: Fixed a couple of typos. Rev 1.28. + * libdwarf2p.1.pdf: Regenerated. + * configure.in: Added support for configure + --enable-oldframcol. + * config.h.in: Added support for configure + --enable-oldframcol. + * dwarf_init_finish.c: Added support for configure + --enable-oldframecol (see DW_FRAME_CFA_COL and + DW_FRAME_CFA_COL3). By default the frame column + is now DW_FRAME_CFA_COL3. --enable-oldframecol + changes the default to DW_FRAME_CFA_COL. + * configure: Regenerated. + * dwarf_opaque.h: Added one blank line and deleted + one, hopefully aiding clarity. + * dwarf_frame.c: Added commentary about the frame + interfaces to emphasize the newer ones. +2010-01-13 DavidAnderson <davea42@earthlink.net> + * dwarf_print_lines.c: Changed 'include files count' + to 'files count'. +2010-01-04 DavidAnderson <davea42@earthlink.net> + * pro_section.c, pro_opaque.h: A pretty-print tool + generated some odd formatting (long ago) and there + were silly blank lines present as well. This makes things more + readable. +2010-01-03 DavidAnderson <davea42@earthlink.net> + * common.h, common.c: Remove <cr> line end characters. + Update copyright for 2010. + * All other files: Update copyright year. diff --git a/libdwarf/LGPL.txt b/libdwarf/LGPL.txt new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/libdwarf/LGPL.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/libdwarf/LIBDWARFCOPYRIGHT b/libdwarf/LIBDWARFCOPYRIGHT new file mode 100644 index 0000000..a6d75ec --- /dev/null +++ b/libdwarf/LIBDWARFCOPYRIGHT @@ -0,0 +1,30 @@ + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 diff --git a/libdwarf/Makefile.in b/libdwarf/Makefile.in new file mode 100644 index 0000000..a2f3f0c --- /dev/null +++ b/libdwarf/Makefile.in @@ -0,0 +1,227 @@ +# +# +# Copyright (C) 2000,2003,2004,2006 Silicon Graphics, Inc. All Rights Reserved. +# Portions Copyright (C) 2010 David B Anderson. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, +# USA. + +# +# 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 +# +# + +# +# Makefile for libdwarf +# This is made very simple so it should work with +# any 'make'. +# + +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +SHELL = /bin/sh +CC = @CC@ +AR = @AR@ +# For use with BSD ar (MacOSX ar) edit the ARFLAGS to be -s +#ARFLAGS = @ARFLAGS@ +RM = rm +RANLIB = @RANLIB@ +DEFS = @DEFS@ +LIBS = @LIBS@ +INCLUDES = -I. -I$(srcdir) +dwfpic = @dwfpic@ +CFLAGS = $(PREINCS) @CFLAGS@ $(INCLUDES) $(dwfpic) $(POSTINCS) +# For more checking add -DWANT_LIBBDWARF_MALLOC_CHECK=1 to CFLAGS +LDFLAGS = $(PRELIBS) @LDFLAGS@ $(POSTLIBS) + + +BUILD_BASE = . + +OBJS= dwarf_abbrev.o \ + dwarf_alloc.o \ + dwarf_arange.o \ + dwarf_die_deliv.o \ + dwarf_elf_access.o \ + dwarf_error.o \ + dwarf_form.o \ + dwarf_frame.o \ + dwarf_frame2.o \ + dwarf_frame3.o \ + dwarf_funcs.o \ + dwarf_global.o \ + dwarf_harmless.o \ + dwarf_init_finish.o \ + dwarf_line.o \ + dwarf_line2.o \ + dwarf_loc.o \ + dwarf_original_elf_init.o \ + dwarf_query.o \ + dwarf_string.o \ + dwarf_stubs.o \ + dwarf_pubtypes.o \ + dwarf_types.o \ + dwarf_util.o \ + dwarf_leb.o \ + dwarf_ranges.o \ + dwarf_vars.o \ + dwarf_weaks.o \ + dwarf_addr_finder.o \ + dwarf_sort_line.o \ + dwarf_print_lines.o \ + dwarf_macro.o \ + malloc_check.o \ + pro_alloc.o \ + pro_arange.o \ + pro_die.o \ + pro_encode_nm.o \ + pro_error.o \ + pro_expr.o \ + pro_finish.o \ + pro_forms.o \ + pro_funcs.o \ + pro_frame.o \ + pro_init.o \ + pro_line.o \ + pro_reloc.o \ + pro_reloc_stream.o \ + pro_reloc_symbolic.o \ + pro_pubnames.o \ + pro_section.o \ + pro_types.o \ + pro_vars.o \ + pro_macinfo.o \ + pro_weaks.o + + +all: @build_shared@ @build_nonshared@ + +libdwarf.a: dwarf_names.h dwarf_names.c $(OBJS) dwarf_names.o + $(AR) $(ARFLAGS) $@ $(OBJS) dwarf_names.o + +libdwarf.so: dwarf_names.h dwarf_names.c $(OBJS) dwarf_names.o + $(CC) $(CFLAGS) -shared $(OBJS) dwarf_names.o -o $@ + +none: + echo "do nothing" +common.o: $(srcdir)/common.c $(srcdir)/common.h + $(CC) $(CFLAGS) -c $(srcdir)/common.c +gennames: $(srcdir)/gennames.c $(srcdir)/dwarf.h common.o + $(CC) $(CFLAGS) $(srcdir)/gennames.c common.o $(LDFLAGS) -o gennames +dwarf_names.c dwarf_names.h: gennames $(srcdir)/dwarf.h + rm -f dwarf_names.h dwarf_names.c + ./gennames @dwarf_namestable@ -i $(srcdir) -o . + + +# +# The following are very SGI-centric +# psroff is just a troff formatter. +# the .mm files are in ATT/USL/USG mm form. +# Calling it pdfbld or bldpdf is arbitrary, so allow both. + +docbld:pdfbld +bldpdf: pdfbld +pdfbld: libdwarf2.1.pdf libdwarf2p.1.pdf dwarf.v2.pdf index.v2.pdf mips_extensions.pdf +#Oriented to using gsroff now. +TROFF=/usr/bin/groff +TROFFDEV="-T ps" +TROFFDEV= +PSTOPDF=/usr/bin/ps2pdf +# pr expands tabs to spaces: this avoids problems with tab +# interpretation + +# The warning about 'cant break line' is a too-long line used +# in the table of contents. +# Ignore the warning (and those like it). +libdwarf2.1.pdf: $(BUILD_BASE)/libdwarf2.1.mm + -pr -t -e $(BUILD_BASE)/libdwarf2.1.mm \ + | tbl | $(TROFF) $(TROFFDEV) -mm >libdwarf2.1.ps + $(PSTOPDF) libdwarf2.1.ps libdwarf2.1.pdf + +libdwarf2p.1.pdf: $(BUILD_BASE)/libdwarf2p.1.mm + -pr -t -e $(BUILD_BASE)/libdwarf2p.1.mm \ + | tbl | $(TROFF) $(TROFFDEV) -mm >libdwarf2p.1.ps + $(PSTOPDF) libdwarf2p.1.ps libdwarf2p.1.pdf + +# At present, the newIndex is not usable: we have no tools +# to build a new index page at the moment. + +dwarf.v2.pdf: $(BUILD_BASE)/dwarf.v2.mm + -pic $(BUILD_BASE)/dwarf.v2.mm \ + | tbl | $(TROFF) $(TROFFDEV) -mm >dwarf.v2.ps 2> newIndex + $(PSTOPDF) dwarf.v2.ps dwarf.v2.pdf + +# the index is only useful till the document changes: it is +# not autmatically correct. It was prepared by tools internal +# to USL/Novell + +index.v2.pdf: index.v2.mm + -pic index.v2.mm | tbl | $(TROFF) $(TROFFDEV) -mm >index.v2.ps + $(PSTOPDF) index.v2.ps index.v2.pdf + + +mips_extensions.pdf: mips_extensions.mm + -pr $(TROFFDEV) -e mips_extensions.mm | tbl | \ + $(TROFF) $(TROFFDEV) -mm >mips_extensions.ps + $(PSTOPDF) mips_extensions.ps mips_extensions.pdf + +clean: + rm -f *.o libdwarf.a + rm -f libdwarf.so + rm -f libdwarf2.1.ps + rm -f newIndex + rm -f dwarf.v2.ps + rm -f index.v2.ps + rm -f mips_extensions.ps + rm -f libdwarf2p.1.ps + rm -f gennames + rm -f junk + rm -f ALL + rm -f gennames + rm -f dwarf_names_enum.h dwarf_names_new.h dwarf_names.c dwarf_names.h + +install: all + echo "No install provided, see comments in the README" + +distclean: clean + rm -f config.status config.log config.cache config.h + rm -rf autom4te.cache + rm -f Makefile + + +shar: + @echo "shar not set up yet" +dist: + @echo "dist not set up yet" diff --git a/libdwarf/NEWS b/libdwarf/NEWS new file mode 100644 index 0000000..4aa6176 --- /dev/null +++ b/libdwarf/NEWS @@ -0,0 +1,406 @@ +December 13, 2011 + dwarf_lineoff() is now deprecated, dwarf_lineoff_b() is + strongly recommended instead. + dwarf_add_line_entry() does not have all the line fields + needed for generating DWARF3/4, use dwarf_add_line_entry_b() instead. + Generation of DWARF3/4 is not yet functional, this new function + is a first step. +October 29, 2011 + Added support for reading .debug_types (type unit) data. +October 26,2011 + Revised the Makefile.in and README to make building libdwarf + easier to accomplish with unusual locations of libelf headers + or other headers or libraries. +June 04,2011 + Non-Elf objects could be used with libdwarf, but + no one has contributed non-elf-reading code for libdwarf + and a crucial detail was not documented so those writing + such object-reading code have not done it entirely correctly. + Fundamentally such code must treat a section index of 0 as + a real but empty section with no name (an empty name). + dwarf_elf_access.c and dwarf_elf_init_finish.c have some comments + on this point now. +March 29,2011 + All the code changed a lot because indentations were all over + the map, now they are consistent. + Additions were made to DWARF4 support. + Now we use dicheck (a new open source application) to check indentation. + Library users will not see any change, all interfaces remain + as before. +January 12,2010 + A libdwarf user has noticed that the April 4, 2009 + consumer function changes introduced + a problem: the default CFA column was DW_FRAME_CFA_COL + even when a newer DWARF3 consumer frame interface like + dwarf_get_fde_info_for_all_regs3() is used. The + libdwarf2.1.pdf documentation + stated the default should be DW_FRAME_CFA_COL3 in that case. + + The introduction of a caller-specified frame-column + function (dwarf_set_frame_cfa_value()) + in that April 4, 2009 release was flawed in that it failed + to match the documentation. + + Now the default frame column is DW_FRAME_CFA_COL3 unless + the configure option --enable-oldframecol + is used at libdwarf build time. + If you are using libdwarf old frame consumer interfaces + dwarf_get_fde_info_for_reg(), dwarf_get_fde_info_for_cfa_reg(), + and dwarf_get_fde_info_for_all_regs() and want unchanged operation + then please configure libdwarf with --enable-oldframecol . + or add the call dwarf_set_frame_cfa_value(dbg,DW_FRAME_CFA_COL) + after calling a libdwarf initialization function. + It is impossible to configure a single libdwarf.a so that + it transparently defaults to both DW_FRAME_CFA_COL + and DW_FRAME_CFA_COL3. + + A call such as dwarf_set_frame_cfa_value(dbg,DW_FRAME_CFA_COL3) + or dwarf_set_frame_cfa_value(dbg,DW_FRAME_CFA_COL) + (or some other name/value of your choosing) + following the dwarf_init() call gives your application + full control of the frame cfa column independent of the libdwarf + configure option. See the libdwarf2.1.pdf documentation for details. + We strongly recommend that you use dwarf_set_frame_cfa_value() + to avoid a configure-time dependency. + +July 7, 2009 + Implemented support for elf 'rela' relocations so libdwarf and dwarfdump + can read *nix .o files with such relocations reasonably, + at least for some machines + (see dwarf_elf_access.c for EM_ in 'case' statements.) + This changes the binary access for non-Elf object users (folks + who have coded there own non-Elf access routines do reference + internals of dwarf_opaque.h), but the new data can be left zero + and the rest of the code should work fine. + dwarf_opaque.h gathers section data in Dwarf_Section_s structs + which simplifies the code in dwarf_init_finish.c and clarifies + what fields are section related. +July 4, 2009 + When something erroneous is detected in a die + information about the CU context may be of interest. + So we added dwarf_CU_dieoffset_given_die(), a function which allows + clients to find the relevant CU die for any die. + The consumer can use normal attribute access functions to + print information about that CU die (and the erroneous die, + of course). See the libdwarf consumer document for more + information. +April 27, 2009 + Interface additions: dwarf_loclist_from_expr_a() and + dwarf_get_ranges_a() are new interfaces like + dwarf_loclist_from_expr() and dwarf_get_ranges() respectively, + but with arguments allowing + full support for different CIEs + in an executable having different address-sizes + (and their compilation unit DIEs if .debug_info is present). + dwarf_get_loclist_entry() does not support + differing address sizes per CIE/CU. +April 4, 2009 + Added new functions dwarf_set_frame_cfa_value() + dwarf_set_frame_same_value(), and + dwarf_set_frame_undefined_value(). These are essential + for ABIs where the real register numbers exceed 1033 + (such as ppc). Failing to use these leads to + frame instructions DW_CFA_undefined and + DW_CFA_same_value emitting values that cannot be + interpreted correctly by a libdwarf consumer. + See dwarfdump for examples of use. +Feb 14, 2009 + Added configure option --enable-nonstandardprintf + which makes it easy to get printf of Dwarf_Unsigned (etc) + types correct even for non-standard compilers. +Dec 30, 2008 + Added interfaces for getting and printing the .debug_ranges + data. +Dec 8, 2008 + Record the abbreviation 'code' (index) in each DIE. + Making it possible for a pretty-printer to print the + abbreviation code. +Sep 30, 2008 + Phil Mucci provided an a.out test chase which demonstrates a bug + in 64bit DWARF2 output by gcc. Now libdwarf works around this + and with -v -v -v -v prints a warning. +Sep 29, 2008 + Thanks to Phil Mucci for providing a little-endian 64bit + test object file that exposed a problem when there are 'extra' bytes + (possibly unused) after a line table prologue header and before the + line table itself. This releases fixes the bug. + + Thanks to Matthew Legendre for pointing out that we were sharing + de_fde_count for eh and non-eh and that could cause erroneous + error returns in a couple of functions. + These counts are now separate. +April 9, 2008 + libdwarf would behave badly if one compilation unit had more than 64K + abbreviations: It was both very slow dealing with abbreviations and would + get mixed up and error-off. Increased the size of some internal variables + and rewrote abbreviation lookup. +February 18, 2008 + It is now possible to write one's own access to objects, making it possible + to use a different library than libelf or even read a completely + different object format than ELF. + See dwarf_object_init() and see the new source files + dwarf_original_elf_init.c and dwarf_elf_access.c for example + code using the new function-pointer approach as it's implementation. + Thanks to Josh Fuhs for doing the design and 99% of the work to make + this happen. +February 2, 2008 + Now pro_init() defaults to standard DWARF3 generated offset sizes. + But if a new flag DW_DLC_OFFSET_SIZE_64 or'd into flags passed to + dwarf_produser_init() or dwarf_producer_init_b, + the DWARF3 extended offset size is generated (if the address size + is 64 bit). + The new configure option --enable-dwarf-format-strict-32bit + forces pro_init() to always cause 32bit offset dwarf generation. + The new configure option --enable-dwarf-format-sgi-irix forces + the old SGI IRIX 64bit offset generation for 64bit pointer size objects. + + This is intended to simplify standard DWARF3 generation with + the now-normal use of 32bit DWARF offsets for both 32 and 64 + bit pointer objects. + + It does require that anyone wanting SGI IRIX dwarf generation + with its non-standard offsets for 64bit objects use the new + --enable-dwarf-format-sgi-irix configure time option. + + This has no effect on dwarf reader code. It affects code calling + the libdwarf producer interfaces. + +December 8, 2007 + Had to add an ugly configure conditional as libelf has + unconditional use of off64_t in recent libelf.h +July 3, 2007 + A new interface function, dwarf_loclist_from_expr(), + allows easy extraction of dwarf expression bytes from + expressions in frame data. +May 8, 2007 + Now documents released as .mm and .pdf (no longer as .ps). +May 7, 2007 + Incorporates Sun Microsystems extensions to dwarf.h and + to the consumer and producer libraries. The changes + include corrections so the producer library cleans up it's memory + use on a call to dwarf_producer_finish(dbg). + Thanks to Chris Quenelle of Sun for these contributions. + +March 20, 2007 + nroff/troff and the AT&T -mm package are not widely available, + so now the Makefile refers to groff, which works quite nicely. + +February 20, 2007 + Documented libdwarf thread safety in README. + Fixed memory leak in dwarf macro reading code. + Removed use of static data in dwarf macro + reading code: now uses stack/heap (for + thread safety). + +February 9, 2007 + Maintenance of libdwarf is now outside SGI + as David Anderson has left SGI. + +March 29, 2006 + The March 27, 2006 version accomodates DWARF3. + Some people have been using the library without + altering dwarf.h, libdwarf.h to accomodate + large numbers of registers. This exposed a bug + (an off-by-one error) but also makes it clear + additional documentation is needed. So + in libdwarf large new comments near 'TARGET DEPENDENCY' + attempt to explain better. +Oct 03, 2005 + The July version had an incompatible interface: old + dealloc code did not always work right. The incompatibility + is now fixed and the new features remain. + +July 15, 2005 + New optional alloc-check code optionally checks all + allocated memory is freed (malloc_check.h malloc_check.c) + Various new dealloc routines written as the previous approach + of letting client code do detailed dealloc turned out not + to dealloc all memory. + To get the new checking you must manually change a line + in malloc_check.h and rebuild libdwarf. + + +Mar 31, 2005 + Documented the libexc.so/.debug_funcnames + dependency and the 64bit-offset DWARF extension in + mips_extentions.{mm,ps}. + +Mar 21, 2005 + gcc 3.3 and 3.4 .eh_frame 'z' augmentations are not handled + correctly, so libdwarf gives an error when attempting to + print such. gcc 2 'eh' augmentation is simpler and + prints correctly. (.eh_frame is a GNU section, + not DWARF2/3, and what is recorded in .eh_frame is not + specified by DWARF2/3, though .eh_frame does resemble + DWARF2/3 .debug_frame). + + +Oct 28, 2004 + Updated contact address in copyright: SGI moved 1/4 mile + in 2003 to a new address: 1500 Crittenden Lane. + + Documented additional vendor extensions. + +Oct 27, 2004 + Added known vendor extensions to dwarf2/3 to dwarf.h + HP, GNU, PGI and UPC extensions are now recorded. + Recorded vendor extensions from Concurrent. + +Feb 3, 2004 + If 'Dwarf_Word' is 64 bits, two macros reading leb numbers + fail to initialize upper bits of the values read. + First noticed with bogus line numbers printing from dwarfdump. + Now we use already-existing functions, avoiding the problem. + +Oct 02, 2003 + Support .debug_loc section fully. + +Sept 29, 2003 + Support DW_FORM_indirect properly. + Supports loclists in part (but not multiple loclist entries yet). + Support 'padding bytes' at end of .debug_arange and + .debug_pubnames and .debug_pubtypes per CU + (recent dwarf committee email made it clear this is appropriate). + +May 23, 2002 + Libdwarf now asks for sections only when they are + used, so that unneeded sections aren't loaded. + Support for using SGI's ELF library as an alternative to + using AT&T libelf-style has been added (the SGI ELF + library is presently only available internally to SGI). + +Jan 10, 2002 + Fixed memory leak in dwarf_finish(). + +Aug 21, 2001 + If one called dwarf_add_file_decl() + or dwarf_add_directory_decl() but never added a line, + .debug_line was not produced. This was a mistake, + as if any file or directory was provided .debug_line + should be produced. Now it is produced. + +June 14, 2001 + Given a cu header offset, it was not easy to derive the + CU header DIE offset. Created the new + function dwarf_get_cu_die_offset_given_cu_header_offset() + do get the CU header DIE offset. + Added the function dwarf_get_arange_cu_header_offset() + so the cu header offset could be retrieved from .debug_aranges + information. + +June 07, 2001 + Major bug in dwarf_leb.c decoding large integers + (Dwarf_Signed 64 bit where library is compiled in ILP32) + found and fixed. + +May 21, 2001 + Some small fixes have been found by various folks, + so it seems time to prepare a new source release. + See ChangeLog for details. + +April 15, 2000 + The libdwarf copyright has changed to + version 2.1 of the GNU Lesser General Public License. + Anyone holding a version of libdwarf that was published + before this new copyright is allowed to use + the copyright published in that earlier libdwarf source + on the earlier source + or to use + this new copyright on the earlier source, + at their option. + + +December 08, 1999 + The dwarf committee has adopted the offset-extension + proposal. This allows compatibly emitting + dwarf with 64bit offsets. + + The dwarf reader now automatically figures out which is in use. + The dwarf writer configures itself at the time the + writer initialization routine is called, though + the writer is restricted, at libdwarf + compile time, to one of + mips/sgi pure 32/pure 64 offsets/pointers. + + 32bit offsets only (per dwarf 2.0.0 and cygnus) + + 32bit offsets with extension to 64bit offsets + allowed (the offset-extension newly passed). + + In addition, a great deal of duplicate code + for the sgi .debug_weaknames, .debug_funcnames, + .debug_varnames and .debug_typenames sections has + been removed: a single set of functions does the real work now. + +Sept 29, 1999 + Just found out that cygnus is, on 64bit targets, generating + 32bit offsets (as elf32 has, for example) with 64 bit + pointers (in references to text and data). + Whereas sgi has always generated 64bit dwarf with + 64 bit offsets (as in elf64) and 64bit pointers for + 64bit pointer objects. + I'll call the sgi approach 64-bit and the cygnus approach + 32bit-offsets. + + Cygnus is following the DWARF2 spec as written, so they are + right in doing only 32bit-offsets. + + Folks at sgi (including me) think that, as for elf64, + the offsets in dwarf for 64bit pointer-apps should be + 64 bits. We think it is only a matter of time + before we really *need* 64bit offsets and when that happens + it will be on an important app. Disk space is cheap, + so lets just go 64 bit on 64bit apps (such as ia64 apps) + to avoid a future problem. + I(davea@sgi.com) think the 'pointer-size' references in the dwarf + spec were really written for 64-bit pointer apps. + I don't recall serious consideration of 64bit pointer + apps in the committee deliberations (I did miss + a couple of meetings) and think 64bit offsets + are consistent with dwarf2, even though the speci + was not written for such. We think true full 64 bit + dwarf2 is the right way to go (the spec changes + are obvious: file and section offsets become 64bit + with 64bit pointer objects. + + MIPS/SGI is definitely 64-bit offsets for 64 bit objects, + cygnus is definitely 32bit-offsets for earlier 64bit pointer + environments. + + At any rate, now the dwarf reader allows and accomodates + both and the dwarf producer also accomodates both. + Some tweaking of the pro_init.c or dwarf_init_finish.c + files may be necessary in future: no other changes should + be needed to accomodate the two 64bit approaches, as + the library (and dwarfdump) now deal with both forms. + + +August 20, 1999 + Added some #ifndef/#define to pro_util.h to let libdwarf build + on more hosts. (since those hosts don't need the producer + code, AFAIK, zero values suffice for missing #defines.) + +July 21, 1999 + Now reader transparently reads either-endianness data + from an either-endianness object. + Updated dwarf.h and libdwarf.h to recognize + GNU egcs dwarf extensions and to print the egcs eh_frame + section. + +June 10, 1999 + gnu configure version of libdwarf made available for the + first time. + Still allows only same-endian-as-host in objects. + +August, 1994 + libdwarf source made available for ftp on sgigate.sgi.com + /ftp/pub + +June, 1994 + Consumer interface changed completely, following + "Candy Machine Interfaces" chapter from + "Writing Solid Code" by Steve Maguire (Microsoft Press). + +April, 1993 + Initial version of libdwarf for dwarf version 2 + written at sgi. diff --git a/libdwarf/README b/libdwarf/README new file mode 100644 index 0000000..bf96a58 --- /dev/null +++ b/libdwarf/README @@ -0,0 +1,199 @@ +To build libdwarf.a, type + ./configure + make +To build libdwarf.so, type + ./configure --enable-shared --disable-nonshared + make +To build both, type + ./configure --enable-shared + make + +No real install target is provided here, so 'make install' does +not do much. One can copy either or both of libdwarf.a libdwarf.so +to somewhere fairly standard (but intended for software you build) +like '/usr/local/lib'. Or anywhere else you want to copy it. + +To use dwarf or libdwarf, you may want to copy dwarf.h and +libdwarf.h somewhere convenient (possibly /usr/local/include), +and you may need to copy the libdwarf to a convenient spot +(/usr/local/lib is a traditional place for libraries one builds +oneself on Unix and Linux). +This copying is not needed to build dwarfdump. + + +Multi Threading, or using threads with libdwarf (Thread Safety): + Nothing in libdwarf does any locking. Every Dwarf_Debug + (such as returned by dwarf_init()) is fully independent + of all other Dwarf_Debug-s. However, calls to libdwarf can + change a Dwarf_Debug. So it is unsafe to have two different + threads accessing a single Dwarf_Debug simultaneously. + It is therefore sufficient to ensure than any one Dwarf_Debug + is only accessed from a single thread. + +Warnings like + "warning: cast from pointer to integer of different size" +at compile time are to be expected in dwarf_frame.c and +dwarf_frame2.c. Do not be alarmed. + +If your headers are not in the expected places, +use the make command line to add flags and include directories. +For example + ./configure + PREINCS="-I /usr/local/share/include" POSTINCS="-I /home/x/include" make +PREINCS content is inserted before CFLAGS as make(1) is running. +POSTINCS content is added after the CFLAGS value. + +To set LDFLAGS (which is used when building a .so and +in building gennames to create some source here), +do so at configure time, for example: + ./configure LDFLAGS="-L /var/tmp" +Or use PRELIBS and/or POSTLIBS at 'make' time similar to the use +of PREINCS and POSTINCS. + +If you are using the old frame interfaces and depend on +the use of DW_FRAME_CFA_COL you must add --enable-oldframecol +to the ./configure options to configure libdwarf. +See NEWS and libdwarf2.1.mm/pdf . + +To generate SGI IRIX 64 bit offsets (in the producer code) +configure with --enable-dwarf-format-sgi-irix. +To configure with only 32bit offsets (aka DWARF2) configure +with --enable-dwarf-format-strict-32bit. +By default the producer now generates 32bit offsets by default +but one can turn on DWARF3 64bit offset generation at runtime by ORing +DW_DLC_OFFSET_SIZE_64 onto the flags in the call to +dwarf_producer_init() (or dwarf_producer_init_b) [when the +address size is specified as 64 bit]. + +Mac OSX (June 2010): Since MacOSX does not use elf, there is no elf.h +header in the headers provided on MacOSX. +Use a search engine (like google) to find an elf.h you can use. +http://www.rockbox.org/tracker/9006?getfile=16683 +might be useful. +In addition, the archive (ar) program on MacOSX does not +automatically generate some data so modify the generated +Makefile to add -s to the options to ar. + +To enable dection of Windows pathnames as full paths +add --enable-windowspath. Doing this does mean things like +A:foo and \anything are treated as full paths (these are +unlikely path names on a POSIX system but are legal +POSIX partial paths). + +It is possible to request a shared library (libdwarf.so) build with + --enable-shared +To turn off the build of the archive library (libdwarf.a) specify + --disable-nonshared +but in this case you must specify --enable-shared or nothing will +build! + +TARGET DEPENDENCIES of .debug_frame: +dwarf.h + These should be revised if you have more than the defined + 63 'normal' registers. It's not harmful to have these too large! + Too small will lead to errors reading .debug_frame and .eh_frame. + DW_FRAME_HIGHEST_NORMAL_REGISTER + DW_FRAME_LAST_REG_NUM + + These you might revise, but can safely ignore if simply + using dwarfdump. If using the producer code you will want + to get these exactly right for your architecture. + DW_FRAME_RA_COL + DW_FRAME_STATIC_LINK + DW_FRAME_CFA_COL + +libdwarf.h + The DW_FRAME_REG_INITIAL_VALUE #define should be set to + the value appropriate to your architecture. See libdwarf.h + for details. + + If DW_REG_TABLE_SIZE is not set large enough attempts to + fill in the .debug_frame tables will get an error. + Should be at least as large as DW_FRAME_LAST_REG_NUM. + If it's too large nothing is harmed (but some extra space taken + at run time). + +If your printf does not support C standard %llx etc, +(such as MSWindows with long long), configure +option --enable-nonstandardprintf +and defines like DW_PR_DUx etc in libdwarf.h +provide a way to configure for that relatively easily. + + +The .debug_frame is so very architecture dependent +and because the host (where libdwarf/dwarfdump are executed) +and target (the objects read) could be different. +It's currently not supported to have dwarfdump/libdwarf determine +the architecture on-the-fly and do-the-right-thing. +Just setting DW_FRAME_LAST_REG_NUM and DW_FRAME_HIGHEST_NORMAL_REGISTER +and DW_REG_TABLE_SIZE high enough will likely suffice for most +purposes and most compilers/architectures.. +See comments in dwarf.h/libdwarf.h. + +It's perfectly safe to ignore the above suggestions as long +as libdwarf does not get a DW_DLE_DF_REG_NUM_TOO_HIGH error. +(which would only happen on reading .debug_frame or .eh_frame data). + +If you intend to use the libdwarf dwarf-producer code +for .debug_frame information +you must do a thorough analysys and revise dwarf.h +substantially to match the output target architecture. + +In general, in the producer code, numbers are copied from and +to integers with memcpy(). In case of endianness problems, +constants set in dwarf_producer_init() can fix the problems. +If one wants to produce a *different-endian* output the best +solution is to change the integer memcpy calls to call thru a +new dbg-based function pointer and have it 'do the right thing' +to adjust endianness. Set the function pointer correctly in +dwarf_producer_init() and the rest of the code will just call +thru the function pointer. Tedious work to find and change the +memcpy calls to be dbg->de_memcpy(), but once done the code is +no longer endian dependent (right now there is no way to ask +for cross-endian: a new flag needed or ?). + +leb128 numbers are endian-independent, so nothing need be +done with those for cross-endian support (the storage +of leb128 on disk is always little-endian). + +The .ps files are postscript. So those who cannot deal with mm +format files but do have a postscript printer (or have +ghostscript) can print the documents. +This form was chosen before pdf format existed... + +libdwarf2.1.pdf documents a way for a debugger to read dwarf information. +libdwarf2p.1.pdf documents a way for a compiler to generate dwarf information. +dwarf.v2.pdf documents Dwarf Version 2. +index.v2.pdf is an index to dwarf.v2.ps. +indexDW.v2 is a plain text index of dwarf #defines to dwarf.v2.ps +mips_extensions.ps documents the mips/sgi extensions to dwarf. + +See the Makefile for the commands used to build pdf files +libdwarf.2.1.pdf and libdwarf1p.1.pdf. + +pic is a picture processing tool (ATT command). +tbl is a table-processing tool. +(part of Documentor's Work Bench on ATT-like systems). +tbl and pic are available on linux. + +psroff is a name for a troff-like processor, part of +Documentor's Work Bench on IRIX. Substitute a +troff-like or nroff-like processor (GNU groff works fine). + +The index.v2.mm was generated by the dwarf-document writer +using some local ATT/USL tools (which neither SGI +nor the open-source community generally has, so +there is no way I know of to regenerate this). + +To use dwarf or libdwarf, you may want to install dwarf.h and +libdwarf.h somewhere convenient. + +You will also need libelf (libelf.a and/or libelf.so) and +libelf.h installed. These are available from GNU repositories +and from the normal Linux repositories for Linux releases. +On Ubuntu 20/04 for example: + sudo apt-get install libelf-dev libelf1 + +$Source: /home/davea/dwarf/dwarf-working/trunk/libdwarf/README,v $ +$Revision: 1.1 $ +$Date: 2009/11/23 17:15:37 $ diff --git a/libdwarf/bldDWindex.sh b/libdwarf/bldDWindex.sh new file mode 100644 index 0000000..537d44d --- /dev/null +++ b/libdwarf/bldDWindex.sh @@ -0,0 +1,24 @@ +sed -n -e '/^%%Page.*/p' -e '/.*DW_.*/p' <dwarf.v2.ps | +sed -n -e '/^%%Page.*/p' -e 's/.*\(DW_[a-z_A-Z]*\).*/\1/p' | +nawk ' /^%%Page/{ p = $2 } \ + /DW_/ { printf "%-30s %04d \n",$1,p \ + }' | sort -u | +nawk ' BEGIN {h = "xx"} \ + { \ + done = 0 ; \ + if ( $1 != h ) { \ + if(h != "xx") { \ + printf "%-30s %s\n",h, pgs ; \ + h = $1 ; \ + tv = $2 + 0 ; \ + done = 1 ; \ + pgs = "" tv \ + } \ + } \ + h = $1 ; \ + if(done == 0 ) { \ + tv = $2 + 0 ; \ + pgs = pgs ", " tv \ + } \ + } \ + END { printf "%-30s %s\n",h,pgs } ' diff --git a/libdwarf/cmplrs/dwarf_addr_finder.h b/libdwarf/cmplrs/dwarf_addr_finder.h new file mode 100644 index 0000000..0eda6d1 --- /dev/null +++ b/libdwarf/cmplrs/dwarf_addr_finder.h @@ -0,0 +1,55 @@ +/* + dwarf_addr_finder.h + $Source: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/include/cmplrs/RCS/dwarf_addr_finder.h,v $ + $Date: 2002/06/11 17:49:06 $ + + Defines user interface. + +*/ + +/* return codes for functions +*/ +#define DW_DLV_NO_ENTRY -1 +#define DW_DLV_OK 0 +#define DW_DLV_ERROR 1 + + +/* the following are the 'section' number passed to the called-back + function. + The called-back application must translate this to the + appropriate elf section number/pointer. + + Putting this burden on the application avoids having to store + the numbers in the Dwarf_Debug structure (thereby saving space + for most consumers). +*/ +#define DW_SECTION_INFO 0 +#define DW_SECTION_FRAME 1 +#define DW_SECTION_ARANGES 2 +#define DW_SECTION_LINE 3 +#define DW_SECTION_LOC 4 /* .debug_loc */ + +/* section is one of the above codes: it specifies a section. + secoff is the offset in the dwarf section. + existingAddr is the value at the specified offset (so the + called back routine can sanity check the proceedings). + It's up to the caller to know the size of an address (4 or 8) + and update the right number of bytes. +*/ +typedef int (*Dwarf_addr_callback_func) (int /*section*/, + Dwarf_Off /*secoff*/, Dwarf_Addr /*existingAddr*/); + +/* call this to do the work: it calls back thru cb_func + once per each address to be modified. + Once this returns you are done. + Returns DW_DLV_OK if finished ok. + Returns DW_DLV_ERROR if there was some kind of error, in which + the dwarf error number was passed back thu the dwerr ptr. + Returns DW_DLV_NO_ENTRY if there are no relevant dwarf sections, + so there were no addresses to be modified (and none + called back). +*/ +int _dwarf_addr_finder(dwarf_elf_handle elf_file_ptr, + Dwarf_addr_callback_func cb_func, + int *dwerr); + diff --git a/libdwarf/common.c b/libdwarf/common.c new file mode 100644 index 0000000..8e93197 --- /dev/null +++ b/libdwarf/common.c @@ -0,0 +1,71 @@ +/* + Copyright (C) 2008-2010 SN Systems. All Rights Reserved. + Portions Copyright (C) 2008-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +#include "common.h" + +void +print_version(const char * name) +{ +#ifdef _DEBUG + char *acType = "Debug"; +#else + char *acType = "Release"; +#endif /* _DEBUG */ + + char acVersion[60]; + snprintf(acVersion,sizeof(acVersion),"[%s %s %s]", + __DATE__,__TIME__,acType); + printf("%s %s\n",name,acVersion); +} + +void +print_args(int argc, char *argv[]) +{ + int index; + printf("Arguments: "); + for (index = 1; index < argc; ++index) { + printf("%s ",argv[index]); + } + printf("\n"); +} + +void +print_usage_message(const char *options[]) +{ + int index; + for (index = 0; *options[index]; ++index) { + printf("%s\n",options[index]); + } +} diff --git a/libdwarf/common.h b/libdwarf/common.h new file mode 100644 index 0000000..ab26b20 --- /dev/null +++ b/libdwarf/common.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2009-2010 SN Systems. All Rights Reserved. + Portions Copyright (C) 2009-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +#ifndef common_INCLUDED +#define common_INCLUDED + +#include <stdio.h> + + +void print_args(int argc, char *argv[]); +void print_usage_message(const char *options[]); +void print_version(const char * name); + +#endif /* common_INCLUDED */ diff --git a/libdwarf/config.h.in b/libdwarf/config.h.in new file mode 100644 index 0000000..895c15e --- /dev/null +++ b/libdwarf/config.h.in @@ -0,0 +1,143 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if you have the <alloca.h> header file. */ +#undef HAVE_ALLOCA_H + +/* Define 1 if want to allow producer to build with 32/64bit section offsets + per dwarf3 */ +#undef HAVE_DWARF2_99_EXTENSION + +/* Define to 1 if the elf64_getehdr function is in libelf.a. */ +#undef HAVE_ELF64_GETEHDR + +/* Define to 1 if the elf64_getshdr function is in libelf.a. */ +#undef HAVE_ELF64_GETSHDR + +/* Define 1 if Elf64_Rela defined. */ +#undef HAVE_ELF64_RELA + +/* Define 1 if Elf64_Sym defined. */ +#undef HAVE_ELF64_SYM + +/* Define to 1 if you have the <elfaccess.h> header file. */ +#undef HAVE_ELFACCESS_H + +/* Define to 1 if you have the <elf.h> header file. */ +#undef HAVE_ELF_H + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <libelf.h> header file. */ +#undef HAVE_LIBELF_H + +/* Define to 1 if you have the <libelf/libelf.h> header file. */ +#undef HAVE_LIBELF_LIBELF_H + +/* Define 1 if off64 is defined via libelf with GNU_SOURCE. */ +#undef HAVE_LIBELF_OFF64_OK + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define 1 if need nonstandard printf format for 64bit */ +#undef HAVE_NONSTANDARD_PRINTF_64_FORMAT + +/* Define 1 to default to old DW_FRAME_CFA_COL */ +#undef HAVE_OLD_FRAME_CFA_COL + +/* Define 1 if plain libelf builds. */ +#undef HAVE_RAW_LIBELF_OK + +/* Define 1 if R_IA_64_DIR32LSB is defined (might be enum value). */ +#undef HAVE_R_IA_64_DIR32LSB + +/* Define 1 if want producer to build with IRIX offset sizes */ +#undef HAVE_SGI_IRIX_OFFSETS + +/* Define 1 if we have the Windows specific header stdafx.h */ +#undef HAVE_STDAFX_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define 1 if want producer to build with only 32bit section offsets */ +#undef HAVE_STRICT_DWARF2_32BIT_OFFSET + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/ia64/elf.h> header file. */ +#undef HAVE_SYS_IA64_ELF_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define 1 if want to allow Windows full path detection */ +#undef HAVE_WINDOWS_PATH + +/* See if __uint32_t is predefined in the compiler. */ +#undef HAVE___UINT32_T + +/* Define 1 if __uint32_t is in sgidefs.h. */ +#undef HAVE___UINT32_T_IN_SGIDEFS_H + +/* Define 1 if sys/types.h defines __uint32_t. */ +#undef HAVE___UINT32_T_IN_SYS_TYPES_H + +/* See if __uint64_t is predefined in the compiler. */ +#undef HAVE___UINT64_T + +/* Define 1 if is in sgidefs.h. */ +#undef HAVE___UINT64_T_IN_SGIDEFS_H + +/* Define 1 if sys/types.h defines __uint64_t. */ +#undef HAVE___UINT64_T_IN_SYS_TYPES_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif diff --git a/libdwarf/configure b/libdwarf/configure new file mode 100755 index 0000000..900b80a --- /dev/null +++ b/libdwarf/configure @@ -0,0 +1,5480 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.67. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="libdwarf.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +dwarf_namestable +build_nonshared +dwfpic +build_shared +AR +RANLIB +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_shared +enable_nonshared +enable_namestable +enable_nonstandardprintf +enable_windowspath +enable_oldframecol +enable_dwarf_format_sgi_irix +enable_dwarf_format_strict_32bit +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-shared build shared library libdwarf.so + --disable-nonshared do not build archive library libdwarf.a + --enable-namestable Name string functions implemented as binary search + (default is with C switch) + --enable-nonstandardprintf + Use a special printf format for 64bit (default is + NO) + --enable-windowspath Detect certain Windows paths as full paths (default + is NO) + --enable-oldframecol Use HAVE_OLD_FRAME_CFA_COL (default is to use new + DW_FRAME_CFA_COL3) + --enable-dwarf-format-sgi-irix + Force producer to SGI IRIX offset dwarf. + --enable-dwarf-format-strict-32bit + Force producer to generate only DWARF format 32bit. + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.67 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval "test \"\${$3+set}\"" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.67. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5 ; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5 ; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5 ; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5 ; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if test "${ac_cv_prog_gcc_traditional+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgtty.h> +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <termio.h> +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + + +for ac_header in alloca.h elf.h elfaccess.h libelf.h libelf/libelf.h sys/types.h sys/ia64/elf.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for elf64_getehdr in -lelf" >&5 +$as_echo_n "checking for elf64_getehdr in -lelf... " >&6; } +if test "${ac_cv_lib_elf_elf64_getehdr+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lelf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char elf64_getehdr (); +int +main () +{ +return elf64_getehdr (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_elf_elf64_getehdr=yes +else + ac_cv_lib_elf_elf64_getehdr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_elf_elf64_getehdr" >&5 +$as_echo "$ac_cv_lib_elf_elf64_getehdr" >&6; } +if test "x$ac_cv_lib_elf_elf64_getehdr" = x""yes; then : + +$as_echo "#define HAVE_ELF64_GETEHDR 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for elf64_getshdr in -lelf" >&5 +$as_echo_n "checking for elf64_getshdr in -lelf... " >&6; } +if test "${ac_cv_lib_elf_elf64_getshdr+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lelf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char elf64_getshdr (); +int +main () +{ +return elf64_getshdr (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_elf_elf64_getshdr=yes +else + ac_cv_lib_elf_elf64_getshdr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_elf_elf64_getshdr" >&5 +$as_echo "$ac_cv_lib_elf_elf64_getshdr" >&6; } +if test "x$ac_cv_lib_elf_elf64_getshdr" = x""yes; then : + +$as_echo "#define HAVE_ELF64_GETSHDR 1" >>confdefs.h + +fi + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__uint32_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +__uint64_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> +int +main () +{ + __uint32_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T_IN_SYS_TYPES_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> +int +main () +{ + __uint64_t p; p = 3; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T_IN_SYS_TYPES_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <elf.h> +int +main () +{ + int p; p = R_IA_64_DIR32LSB; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_R_IA_64_DIR32LSB 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include <libelf.h> + +int +main () +{ + int p; p = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_RAW_LIBELF_OK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define _GNU_SOURCE +#include <libelf.h> + +int +main () +{ + off64_t p; p = 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_LIBELF_OFF64_OK 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint32_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT32_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint64_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sgidefs.h> +int +main () +{ + __uint64_t p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE___UINT64_T_IN_SGIDEFS_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <elf.h> +int +main () +{ + Elf64_Rela p; p.r_offset = 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_ELF64_RELA 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <elf.h> +int +main () +{ + Elf64_Sym p; p.st_info = 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_ELF64_SYM 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + +build_shared=none + + +# Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; +fi + +if test "x$enable_shared" = "xyes"; then : + + build_shared=libdwarf.so + + dwfpic=-fPIC + + +fi + +build_nonshared=libdwarf.a + +# Check whether --enable-nonshared was given. +if test "${enable_nonshared+set}" = set; then : + enableval=$enable_nonshared; +fi + +if test "x$enable_nonshared" = "xno"; then : + + build_nonshared=none + + +fi + + +dwarf_namestable=-s + +# Check whether --enable-namestable was given. +if test "${enable_namestable+set}" = set; then : + enableval=$enable_namestable; dwarf_namestable=-s + + dwarf_namestable=-t + +fi + + +# Check whether --enable-nonstandardprintf was given. +if test "${enable_nonstandardprintf+set}" = set; then : + enableval=$enable_nonstandardprintf; +$as_echo "#define HAVE_NONSTANDARD_PRINTF_64_FORMAT 1" >>confdefs.h + +fi + + +# Check whether --enable-windowspath was given. +if test "${enable_windowspath+set}" = set; then : + enableval=$enable_windowspath; +$as_echo "#define HAVE_WINDOWS_PATH 1" >>confdefs.h + +fi + + +# Check whether --enable-oldframecol was given. +if test "${enable_oldframecol+set}" = set; then : + enableval=$enable_oldframecol; +$as_echo "#define HAVE_OLD_FRAME_CFA_COL 1" >>confdefs.h + +fi + + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include "stdafx.h" +int +main () +{ + int p; p = 27; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_STDAFX_H 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +# Check whether --enable-dwarf_format_sgi_irix was given. +if test "${enable_dwarf_format_sgi_irix+set}" = set; then : + enableval=$enable_dwarf_format_sgi_irix; +$as_echo "#define HAVE_SGI_IRIX_OFFSETS 1" >>confdefs.h + +else + # Check whether --enable-dwarf_format_strict_32bit was given. +if test "${enable_dwarf_format_strict_32bit+set}" = set; then : + enableval=$enable_dwarf_format_strict_32bit; +$as_echo "#define HAVE_STRICT_DWARF2_32BIT_OFFSET 1" >>confdefs.h + +else + +$as_echo "#define HAVE_DWARF2_99_EXTENSION 1" >>confdefs.h + +fi + +fi + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.67. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.67, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/libdwarf/configure.in b/libdwarf/configure.in new file mode 100644 index 0000000..c8770f3 --- /dev/null +++ b/libdwarf/configure.in @@ -0,0 +1,134 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(libdwarf.h) +AC_CONFIG_HEADER(config.h) + +AC_PROG_CC +AC_C_BIGENDIAN +AC_GCC_TRADITIONAL +AC_PROG_INSTALL +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(AR, ar) + +dnl AC_ARFLAGS + +AC_CHECK_HEADERS(alloca.h elf.h elfaccess.h libelf.h libelf/libelf.h sys/types.h sys/ia64/elf.h) + +AC_CHECK_LIB(elf,elf64_getehdr, + AC_DEFINE(HAVE_ELF64_GETEHDR,1, + [Define to 1 if the elf64_getehdr function is in libelf.a.])) +AC_CHECK_LIB(elf,elf64_getshdr, + AC_DEFINE(HAVE_ELF64_GETSHDR,1, + [Define to 1 if the elf64_getshdr function is in libelf.a.])) +AC_TRY_COMPILE( , __uint32_t p; p = 3; ,AC_DEFINE(HAVE___UINT32_T,1, + [See if __uint32_t is predefined in the compiler.])) +AC_TRY_COMPILE( , __uint64_t p; p = 3; ,AC_DEFINE(HAVE___UINT64_T,1, + [See if __uint64_t is predefined in the compiler.])) +AC_TRY_COMPILE([#include <sys/types.h>],[ __uint32_t p; p = 3;] , + AC_DEFINE(HAVE___UINT32_T_IN_SYS_TYPES_H,1, + [Define 1 if sys/types.h defines __uint32_t.])) +AC_TRY_COMPILE([#include <sys/types.h>],[ __uint64_t p; p = 3;] , + AC_DEFINE(HAVE___UINT64_T_IN_SYS_TYPES_H,1, + [Define 1 if sys/types.h defines __uint64_t.])) +dnl checking for ia 64 types, which might be enums, using HAVE_R_IA_64_DIR32LSB +dnl to stand in for a small set. +AC_TRY_COMPILE([#include <elf.h>],[ int p; p = R_IA_64_DIR32LSB;] , + AC_DEFINE(HAVE_R_IA_64_DIR32LSB,1, + [Define 1 if R_IA_64_DIR32LSB is defined (might be enum value).])) + +AC_TRY_COMPILE([ +#include <libelf.h> +],[ int p; p = 0; ] , + AC_DEFINE(HAVE_RAW_LIBELF_OK,1, + [Define 1 if plain libelf builds.])) +AC_TRY_COMPILE([ +#define _GNU_SOURCE +#include <libelf.h> +],[ off64_t p; p = 0;] , + AC_DEFINE(HAVE_LIBELF_OFF64_OK,1, + [Define 1 if off64 is defined via libelf with GNU_SOURCE.])) + +dnl the existence of sgidefs.h does not prove it's truly SGI, nor +dnl prove that __uint32_t or __uint64_t is defined therein. +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint32_t p; p = 27;] , + AC_DEFINE(HAVE___UINT32_T_IN_SGIDEFS_H,1, + [Define 1 if __uint32_t is in sgidefs.h.])) +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint64_t p; p = 27;] , + AC_DEFINE(HAVE___UINT64_T_IN_SGIDEFS_H,1, + [Define 1 if __uint64_t is in sgidefs.h.])) +AC_TRY_COMPILE([#include <sgidefs.h>],[ __uint64_t p; p = 27;] , + AC_DEFINE(HAVE___UINT64_T_IN_SGIDEFS_H,1, + [Define 1 if is in sgidefs.h.])) +AC_TRY_COMPILE([#include <elf.h>],[ Elf64_Rela p; p.r_offset = 1; ], + AC_DEFINE(HAVE_ELF64_RELA,1, + [Define 1 if Elf64_Rela defined.])) +AC_TRY_COMPILE([#include <elf.h>],[ Elf64_Sym p; p.st_info = 1; ], + AC_DEFINE(HAVE_ELF64_SYM,1, + [Define 1 if Elf64_Sym defined.])) + + + +dnl default-disabled shared +AC_SUBST(build_shared,[none]) +AC_SUBST(dwfpic,[]) +AC_ARG_ENABLE(shared,AC_HELP_STRING([--enable-shared], + [build shared library libdwarf.so])) +AS_IF([ test "x$enable_shared" = "xyes"], [ + AC_SUBST(build_shared,[libdwarf.so]) + AC_SUBST(dwfpic,[-fPIC]) +]) + +dnl default-enabled nonshared +AC_SUBST(build_nonshared,[libdwarf.a]) +AC_ARG_ENABLE(nonshared,AC_HELP_STRING([--disable-nonshared], + [do not build archive library libdwarf.a])) +AS_IF([ test "x$enable_nonshared" = "xno"], [ + dnl We could turn on shared here if not already on. + AC_SUBST(build_nonshared,[none]) +]) + + +dnl This changes the gennames option from -s to -t +AC_SUBST(dwarf_namestable,[-s]) +AC_ARG_ENABLE(namestable,AC_HELP_STRING([--enable-namestable], + [Name string functions implemented as binary search (default is with C switch)]), + [ AC_SUBST(dwarf_namestable,[-s]) ] + [ AC_SUBST(dwarf_namestable,[-t]) ]) + +AC_ARG_ENABLE(nonstandardprintf,AS_HELP_STRING([--enable-nonstandardprintf], + [Use a special printf format for 64bit (default is NO)]), + [ AC_DEFINE([HAVE_NONSTANDARD_PRINTF_64_FORMAT],[1], + [Define 1 if need nonstandard printf format for 64bit] )], + []) + +AC_ARG_ENABLE(windowspath,AC_HELP_STRING([--enable-windowspath], + [Detect certain Windows paths as full paths (default is NO)]), + [ AC_DEFINE([HAVE_WINDOWS_PATH],[1], + [Define 1 if want to allow Windows full path detection] )], + []) + +AC_ARG_ENABLE(oldframecol,AC_HELP_STRING([--enable-oldframecol], + [Use HAVE_OLD_FRAME_CFA_COL (default is to use new DW_FRAME_CFA_COL3)]), + [ AC_DEFINE([HAVE_OLD_FRAME_CFA_COL],[1], + [Define 1 to default to old DW_FRAME_CFA_COL] )], + []) + +AC_TRY_COMPILE([#include "stdafx.h"],[ int p; p = 27;] , + AC_DEFINE(HAVE_STDAFX_H,1, + [Define 1 if we have the Windows specific header stdafx.h])) + +dnl See pro_init(), HAVE_DWARF2_99_EXTENSION also generates +dnl 32bit offset dwarf unless DW_DLC_OFFSET_SIZE_64 flag passed to +dnl pro_init. +AC_ARG_ENABLE(dwarf_format_sgi_irix, AC_HELP_STRING([--enable-dwarf-format-sgi-irix], + [Force producer to SGI IRIX offset dwarf.]), + [AC_DEFINE(HAVE_SGI_IRIX_OFFSETS,1, + [Define 1 if want producer to build with IRIX offset sizes] )], + + [AC_ARG_ENABLE(dwarf_format_strict_32bit, AC_HELP_STRING([--enable-dwarf-format-strict-32bit], + [Force producer to generate only DWARF format 32bit.]), + [AC_DEFINE(HAVE_STRICT_DWARF2_32BIT_OFFSET,1, + [Define 1 if want producer to build with only 32bit section offsets] )], + [AC_DEFINE(HAVE_DWARF2_99_EXTENSION,1, + [Define 1 if want to allow producer to build with 32/64bit section offsets per dwarf3] )])]) + +AC_OUTPUT(Makefile) diff --git a/libdwarf/dwarf.h b/libdwarf/dwarf.h new file mode 100644 index 0000000..92c36e9 --- /dev/null +++ b/libdwarf/dwarf.h @@ -0,0 +1,1182 @@ +/* + Copyright (C) 2000,2001,2003,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2007-2011 David Anderson. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +#ifndef __DWARF_H +#define __DWARF_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + dwarf.h DWARF debugging information values + $Revision: 1.41 $ $Date: 2006/04/17 00:09:56 $ + + The comment "DWARF3" appears where there are + new entries from DWARF3 as of 2004, "DWARF3f" + where there are new entries as of the November 2005 + public review document and other comments apply + where extension entries appear. + + Extensions part of DWARF4 are marked DWARF4. + + A few extension names have omitted the 'vendor id' + (See chapter 7, "Vendor Extensibility"). Please + always use a 'vendor id' string in extension names. + + Vendors should use a vendor string in names and + whereever possible avoid duplicating values used by + other vendor extensions +*/ + + +#define DW_TAG_array_type 0x01 +#define DW_TAG_class_type 0x02 +#define DW_TAG_entry_point 0x03 +#define DW_TAG_enumeration_type 0x04 +#define DW_TAG_formal_parameter 0x05 +#define DW_TAG_imported_declaration 0x08 +#define DW_TAG_label 0x0a +#define DW_TAG_lexical_block 0x0b +#define DW_TAG_member 0x0d +#define DW_TAG_pointer_type 0x0f +#define DW_TAG_reference_type 0x10 +#define DW_TAG_compile_unit 0x11 +#define DW_TAG_string_type 0x12 +#define DW_TAG_structure_type 0x13 +#define DW_TAG_subroutine_type 0x15 +#define DW_TAG_typedef 0x16 +#define DW_TAG_union_type 0x17 +#define DW_TAG_unspecified_parameters 0x18 +#define DW_TAG_variant 0x19 +#define DW_TAG_common_block 0x1a +#define DW_TAG_common_inclusion 0x1b +#define DW_TAG_inheritance 0x1c +#define DW_TAG_inlined_subroutine 0x1d +#define DW_TAG_module 0x1e +#define DW_TAG_ptr_to_member_type 0x1f +#define DW_TAG_set_type 0x20 +#define DW_TAG_subrange_type 0x21 +#define DW_TAG_with_stmt 0x22 +#define DW_TAG_access_declaration 0x23 +#define DW_TAG_base_type 0x24 +#define DW_TAG_catch_block 0x25 +#define DW_TAG_const_type 0x26 +#define DW_TAG_constant 0x27 +#define DW_TAG_enumerator 0x28 +#define DW_TAG_file_type 0x29 +#define DW_TAG_friend 0x2a +#define DW_TAG_namelist 0x2b + /* Early releases of this header had the following + misspelled with a trailing 's' */ +#define DW_TAG_namelist_item 0x2c /* DWARF3/2 spelling */ +#define DW_TAG_namelist_items 0x2c /* SGI misspelling/typo */ +#define DW_TAG_packed_type 0x2d +#define DW_TAG_subprogram 0x2e + /* The DWARF2 document had two spellings of the following + two TAGs, DWARF3 specifies the longer spelling. */ +#define DW_TAG_template_type_parameter 0x2f /* DWARF3/2 spelling*/ +#define DW_TAG_template_type_param 0x2f /* DWARF2 spelling*/ +#define DW_TAG_template_value_parameter 0x30 /* DWARF3/2 spelling*/ +#define DW_TAG_template_value_param 0x30 /* DWARF2 spelling*/ +#define DW_TAG_thrown_type 0x31 +#define DW_TAG_try_block 0x32 +#define DW_TAG_variant_part 0x33 +#define DW_TAG_variable 0x34 +#define DW_TAG_volatile_type 0x35 +#define DW_TAG_dwarf_procedure 0x36 /* DWARF3 */ +#define DW_TAG_restrict_type 0x37 /* DWARF3 */ +#define DW_TAG_interface_type 0x38 /* DWARF3 */ +#define DW_TAG_namespace 0x39 /* DWARF3 */ +#define DW_TAG_imported_module 0x3a /* DWARF3 */ +#define DW_TAG_unspecified_type 0x3b /* DWARF3 */ +#define DW_TAG_partial_unit 0x3c /* DWARF3 */ +#define DW_TAG_imported_unit 0x3d /* DWARF3 */ + /* Do not use DW_TAG_mutable_type */ +#define DW_TAG_mutable_type 0x3e /* Withdrawn from DWARF3 by DWARF3f. */ +#define DW_TAG_condition 0x3f /* DWARF3f */ +#define DW_TAG_shared_type 0x40 /* DWARF3f */ +#define DW_TAG_type_unit 0x41 /* DWARF4 */ +#define DW_TAG_rvalue_reference_type 0x42 /* DWARF4 */ +#define DW_TAG_template_alias 0x43 /* DWARF4 */ +#define DW_TAG_lo_user 0x4080 + +#define DW_TAG_MIPS_loop 0x4081 + +/* HP extensions: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz */ +#define DW_TAG_HP_array_descriptor 0x4090 /* HP */ + +/* GNU extensions. The first 3 missing the GNU_. */ +#define DW_TAG_format_label 0x4101 /* GNU. Fortran. */ +#define DW_TAG_function_template 0x4102 /* GNU. For C++ */ +#define DW_TAG_class_template 0x4103 /* GNU. For C++ */ +#define DW_TAG_GNU_BINCL 0x4104 /* GNU */ +#define DW_TAG_GNU_EINCL 0x4105 /* GNU */ + +/* GNU extension. http://gcc.gnu.org/wiki/TemplateParmsDwarf */ +#define DW_TAG_GNU_template_template_parameter 0x4106 /* GNU */ +#define DW_TAG_GNU_template_template_param 0x4106 /* GNU */ +#define DW_TAG_GNU_template_parameter_pack 0x4107 /* GNU */ +#define DW_TAG_GNU_formal_parameter_pack 0x4108 /* GNU */ + +#define DW_TAG_GNU_call_site 0x4109 /* GNU */ +#define DW_TAG_GNU_call_site_parameter 0x410a /* GNU */ + +/* ALTIUM extensions */ + /* DSP-C/Starcore __circ qualifier */ +#define DW_TAG_ALTIUM_circ_type 0x5101 /* ALTIUM */ + /* Starcore __mwa_circ qualifier */ +#define DW_TAG_ALTIUM_mwa_circ_type 0x5102 /* ALTIUM */ + /* Starcore __rev_carry qualifier */ +#define DW_TAG_ALTIUM_rev_carry_type 0x5103 /* ALTIUM */ + /* M16 __rom qualifier */ +#define DW_TAG_ALTIUM_rom 0x5111 /* ALTIUM */ + +/* The following 3 are extensions to support UPC */ +#define DW_TAG_upc_shared_type 0x8765 /* UPC */ +#define DW_TAG_upc_strict_type 0x8766 /* UPC */ +#define DW_TAG_upc_relaxed_type 0x8767 /* UPC */ + +/* PGI (STMicroelectronics) extensions. */ +#define DW_TAG_PGI_kanji_type 0xa000 /* PGI */ +#define DW_TAG_PGI_interface_block 0xa020 /* PGI */ +/* The following are SUN extensions */ +#define DW_TAG_SUN_function_template 0x4201 /* SUN */ +#define DW_TAG_SUN_class_template 0x4202 /* SUN */ +#define DW_TAG_SUN_struct_template 0x4203 /* SUN */ +#define DW_TAG_SUN_union_template 0x4204 /* SUN */ +#define DW_TAG_SUN_indirect_inheritance 0x4205 /* SUN */ +#define DW_TAG_SUN_codeflags 0x4206 /* SUN */ +#define DW_TAG_SUN_memop_info 0x4207 /* SUN */ +#define DW_TAG_SUN_omp_child_func 0x4208 /* SUN */ +#define DW_TAG_SUN_rtti_descriptor 0x4209 /* SUN */ +#define DW_TAG_SUN_dtor_info 0x420a /* SUN */ +#define DW_TAG_SUN_dtor 0x420b /* SUN */ +#define DW_TAG_SUN_f90_interface 0x420c /* SUN */ +#define DW_TAG_SUN_fortran_vax_structure 0x420d /* SUN */ +#define DW_TAG_SUN_hi 0x42ff /* SUN */ + + +#define DW_TAG_hi_user 0xffff + +#define DW_children_no 0 +#define DW_children_yes 1 + + + +#define DW_FORM_addr 0x01 +#define DW_FORM_block2 0x03 +#define DW_FORM_block4 0x04 +#define DW_FORM_data2 0x05 +#define DW_FORM_data4 0x06 +#define DW_FORM_data8 0x07 +#define DW_FORM_string 0x08 +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_data1 0x0b +#define DW_FORM_flag 0x0c +#define DW_FORM_sdata 0x0d +#define DW_FORM_strp 0x0e +#define DW_FORM_udata 0x0f +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref1 0x11 +#define DW_FORM_ref2 0x12 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref8 0x14 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_indirect 0x16 +#define DW_FORM_sec_offset 0x17 /* DWARF4 */ +#define DW_FORM_exprloc 0x18 /* DWARF4 */ +#define DW_FORM_flag_present 0x19 /* DWARF4 */ +/* 0x1a thru 0x1f were left unused accidentally. Reserved for future use. */ +#define DW_FORM_ref_sig8 0x20 /* DWARF4 */ + +#define DW_AT_sibling 0x01 +#define DW_AT_location 0x02 +#define DW_AT_name 0x03 +#define DW_AT_ordering 0x09 +#define DW_AT_subscr_data 0x0a +#define DW_AT_byte_size 0x0b +#define DW_AT_bit_offset 0x0c +#define DW_AT_bit_size 0x0d +#define DW_AT_element_list 0x0f +#define DW_AT_stmt_list 0x10 +#define DW_AT_low_pc 0x11 +#define DW_AT_high_pc 0x12 +#define DW_AT_language 0x13 +#define DW_AT_member 0x14 +#define DW_AT_discr 0x15 +#define DW_AT_discr_value 0x16 +#define DW_AT_visibility 0x17 +#define DW_AT_import 0x18 +#define DW_AT_string_length 0x19 +#define DW_AT_common_reference 0x1a +#define DW_AT_comp_dir 0x1b +#define DW_AT_const_value 0x1c +#define DW_AT_containing_type 0x1d +#define DW_AT_default_value 0x1e +#define DW_AT_inline 0x20 +#define DW_AT_is_optional 0x21 +#define DW_AT_lower_bound 0x22 +#define DW_AT_producer 0x25 +#define DW_AT_prototyped 0x27 +#define DW_AT_return_addr 0x2a +#define DW_AT_start_scope 0x2c +#define DW_AT_bit_stride 0x2e /* DWARF3 name */ +#define DW_AT_stride_size 0x2e /* DWARF2 name */ +#define DW_AT_upper_bound 0x2f +#define DW_AT_abstract_origin 0x31 +#define DW_AT_accessibility 0x32 +#define DW_AT_address_class 0x33 +#define DW_AT_artificial 0x34 +#define DW_AT_base_types 0x35 +#define DW_AT_calling_convention 0x36 +#define DW_AT_count 0x37 +#define DW_AT_data_member_location 0x38 +#define DW_AT_decl_column 0x39 +#define DW_AT_decl_file 0x3a +#define DW_AT_decl_line 0x3b +#define DW_AT_declaration 0x3c +#define DW_AT_discr_list 0x3d +#define DW_AT_encoding 0x3e +#define DW_AT_external 0x3f +#define DW_AT_frame_base 0x40 +#define DW_AT_friend 0x41 +#define DW_AT_identifier_case 0x42 +#define DW_AT_macro_info 0x43 +#define DW_AT_namelist_item 0x44 +#define DW_AT_priority 0x45 +#define DW_AT_segment 0x46 +#define DW_AT_specification 0x47 +#define DW_AT_static_link 0x48 +#define DW_AT_type 0x49 +#define DW_AT_use_location 0x4a +#define DW_AT_variable_parameter 0x4b +#define DW_AT_virtuality 0x4c +#define DW_AT_vtable_elem_location 0x4d +#define DW_AT_allocated 0x4e /* DWARF3 */ +#define DW_AT_associated 0x4f /* DWARF3 */ +#define DW_AT_data_location 0x50 /* DWARF3 */ +#define DW_AT_byte_stride 0x51 /* DWARF3f */ +#define DW_AT_stride 0x51 /* DWARF3 (do not use) */ +#define DW_AT_entry_pc 0x52 /* DWARF3 */ +#define DW_AT_use_UTF8 0x53 /* DWARF3 */ +#define DW_AT_extension 0x54 /* DWARF3 */ +#define DW_AT_ranges 0x55 /* DWARF3 */ +#define DW_AT_trampoline 0x56 /* DWARF3 */ +#define DW_AT_call_column 0x57 /* DWARF3 */ +#define DW_AT_call_file 0x58 /* DWARF3 */ +#define DW_AT_call_line 0x59 /* DWARF3 */ +#define DW_AT_description 0x5a /* DWARF3 */ +#define DW_AT_binary_scale 0x5b /* DWARF3f */ +#define DW_AT_decimal_scale 0x5c /* DWARF3f */ +#define DW_AT_small 0x5d /* DWARF3f */ +#define DW_AT_decimal_sign 0x5e /* DWARF3f */ +#define DW_AT_digit_count 0x5f /* DWARF3f */ +#define DW_AT_picture_string 0x60 /* DWARF3f */ +#define DW_AT_mutable 0x61 /* DWARF3f */ +#define DW_AT_threads_scaled 0x62 /* DWARF3f */ +#define DW_AT_explicit 0x63 /* DWARF3f */ +#define DW_AT_object_pointer 0x64 /* DWARF3f */ +#define DW_AT_endianity 0x65 /* DWARF3f */ +#define DW_AT_elemental 0x66 /* DWARF3f */ +#define DW_AT_pure 0x67 /* DWARF3f */ +#define DW_AT_recursive 0x68 /* DWARF3f */ +#define DW_AT_signature 0x69 /* DWARF4 */ +#define DW_AT_main_subprogram 0x6a /* DWARF4 */ +#define DW_AT_data_bit_offset 0x6b /* DWARF4 */ +#define DW_AT_const_expr 0x6c /* DWARF4 */ +#define DW_AT_enum_class 0x6d /* DWARF4 */ +#define DW_AT_linkage_name 0x6e /* DWARF4 */ + +/* In extensions, we attempt to include the vendor extension + in the name even when the vendor leaves it out. */ + +/* HP extensions. */ +#define DW_AT_HP_block_index 0x2000 /* HP */ + +/* Follows extension so dwarfdump prints the most-likely-useful name. */ +#define DW_AT_lo_user 0x2000 + +#define DW_AT_MIPS_fde 0x2001 /* MIPS/SGI */ +#define DW_AT_MIPS_loop_begin 0x2002 /* MIPS/SGI */ +#define DW_AT_MIPS_tail_loop_begin 0x2003 /* MIPS/SGI */ +#define DW_AT_MIPS_epilog_begin 0x2004 /* MIPS/SGI */ +#define DW_AT_MIPS_loop_unroll_factor 0x2005 /* MIPS/SGI */ +#define DW_AT_MIPS_software_pipeline_depth 0x2006 /* MIPS/SGI */ +#define DW_AT_MIPS_linkage_name 0x2007 /* MIPS/SGI, GNU, and others.*/ +#define DW_AT_MIPS_stride 0x2008 /* MIPS/SGI */ +#define DW_AT_MIPS_abstract_name 0x2009 /* MIPS/SGI */ +#define DW_AT_MIPS_clone_origin 0x200a /* MIPS/SGI */ +#define DW_AT_MIPS_has_inlines 0x200b /* MIPS/SGI */ +#define DW_AT_MIPS_stride_byte 0x200c /* MIPS/SGI */ +#define DW_AT_MIPS_stride_elem 0x200d /* MIPS/SGI */ +#define DW_AT_MIPS_ptr_dopetype 0x200e /* MIPS/SGI */ +#define DW_AT_MIPS_allocatable_dopetype 0x200f /* MIPS/SGI */ +#define DW_AT_MIPS_assumed_shape_dopetype 0x2010 /* MIPS/SGI */ +#define DW_AT_MIPS_assumed_size 0x2011 /* MIPS/SGI */ + +/* HP extensions. */ +#define DW_AT_HP_unmodifiable 0x2001 /* conflict: MIPS */ +#define DW_AT_HP_actuals_stmt_list 0x2010 /* conflict: MIPS */ +#define DW_AT_HP_proc_per_section 0x2011 /* conflict: MIPS */ +#define DW_AT_HP_raw_data_ptr 0x2012 /* HP */ +#define DW_AT_HP_pass_by_reference 0x2013 /* HP */ +#define DW_AT_HP_opt_level 0x2014 /* HP */ +#define DW_AT_HP_prof_version_id 0x2015 /* HP */ +#define DW_AT_HP_opt_flags 0x2016 /* HP */ +#define DW_AT_HP_cold_region_low_pc 0x2017 /* HP */ +#define DW_AT_HP_cold_region_high_pc 0x2018 /* HP */ +#define DW_AT_HP_all_variables_modifiable 0x2019 /* HP */ +#define DW_AT_HP_linkage_name 0x201a /* HP */ +#define DW_AT_HP_prof_flags 0x201b /* HP */ + +#define DW_AT_CPQ_discontig_ranges 0x2001 /* COMPAQ/HP */ +#define DW_AT_CPQ_semantic_events 0x2002 /* COMPAQ/HP */ +#define DW_AT_CPQ_split_lifetimes_var 0x2003 /* COMPAQ/HP */ +#define DW_AT_CPQ_split_lifetimes_rtn 0x2004 /* COMPAQ/HP */ +#define DW_AT_CPQ_prologue_length 0x2005 /* COMPAQ/HP */ + +#define DW_AT_INTEL_other_endian 0x2026 /* Intel, 1 if byte swapped. */ + +/* GNU extensions. */ +#define DW_AT_sf_names 0x2101 /* GNU */ +#define DW_AT_src_info 0x2102 /* GNU */ +#define DW_AT_mac_info 0x2103 /* GNU */ +#define DW_AT_src_coords 0x2104 /* GNU */ +#define DW_AT_body_begin 0x2105 /* GNU */ +#define DW_AT_body_end 0x2106 /* GNU */ +#define DW_AT_GNU_vector 0x2107 /* GNU */ + +/* Thread safety, see http://gcc.gnu.org/wiki/ThreadSafetyAnnotation . */ +/* The values here are from gcc-4.6.2 include/dwarf2.h. The + values are not given on the web page at all, nor on web pages + it refers to. */ +#define DW_AT_GNU_guarded_by 0x2108 /* GNU */ +#define DW_AT_GNU_pt_guarded_by 0x2109 /* GNU */ +#define DW_AT_GNU_guarded 0x210a /* GNU */ +#define DW_AT_GNU_pt_guarded 0x210b /* GNU */ +#define DW_AT_GNU_locks_excluded 0x210c /* GNU */ +#define DW_AT_GNU_exclusive_locks_required 0x210d /* GNU */ +#define DW_AT_GNU_shared_locks_required 0x210e /* GNU */ + +/* See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo */ +#define DW_AT_GNU_odr_signature 0x210f /* GNU */ + +/* See See http://gcc.gnu.org/wiki/TemplateParmsDwarf */ +/* The value here is from gcc-4.6.2 include/dwarf2.h. The value is + not consistent with the web page as of December 2011. */ +#define DW_AT_GNU_template_name 0x2110 /* GNU */ +/* The GNU call site extension. + See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open . */ +#define DW_AT_GNU_call_site_value 0x2111 /* GNU */ +#define DW_AT_GNU_call_site_data_value 0x2112 /* GNU */ +#define DW_AT_GNU_call_site_target 0x2113 /* GNU */ +#define DW_AT_GNU_call_site_target_clobbered 0x2114 /* GNU */ +#define DW_AT_GNU_tail_call 0x2115 /* GNU */ +#define DW_AT_GNU_all_tail_call_sites 0x2116 /* GNU */ +#define DW_AT_GNU_all_call_sites 0x2117 /* GNU */ +#define DW_AT_GNU_all_source_call_sites 0x2118 /* GNU */ + + + +/* ALTIUM extension: ALTIUM Compliant location lists (flag) */ +#define DW_AT_ALTIUM_loclist 0x2300 /* ALTIUM */ + +/* Sun extensions */ +#define DW_AT_SUN_template 0x2201 /* SUN */ +#define DW_AT_VMS_rtnbeg_pd_address 0x2201 /* VMS */ +#define DW_AT_SUN_alignment 0x2202 /* SUN */ +#define DW_AT_SUN_vtable 0x2203 /* SUN */ +#define DW_AT_SUN_count_guarantee 0x2204 /* SUN */ +#define DW_AT_SUN_command_line 0x2205 /* SUN */ +#define DW_AT_SUN_vbase 0x2206 /* SUN */ +#define DW_AT_SUN_compile_options 0x2207 /* SUN */ +#define DW_AT_SUN_language 0x2208 /* SUN */ +#define DW_AT_SUN_browser_file 0x2209 /* SUN */ +#define DW_AT_SUN_vtable_abi 0x2210 /* SUN */ +#define DW_AT_SUN_func_offsets 0x2211 /* SUN */ +#define DW_AT_SUN_cf_kind 0x2212 /* SUN */ +#define DW_AT_SUN_vtable_index 0x2213 /* SUN */ +#define DW_AT_SUN_omp_tpriv_addr 0x2214 /* SUN */ +#define DW_AT_SUN_omp_child_func 0x2215 /* SUN */ +#define DW_AT_SUN_func_offset 0x2216 /* SUN */ +#define DW_AT_SUN_memop_type_ref 0x2217 /* SUN */ +#define DW_AT_SUN_profile_id 0x2218 /* SUN */ +#define DW_AT_SUN_memop_signature 0x2219 /* SUN */ +#define DW_AT_SUN_obj_dir 0x2220 /* SUN */ +#define DW_AT_SUN_obj_file 0x2221 /* SUN */ +#define DW_AT_SUN_original_name 0x2222 /* SUN */ +#define DW_AT_SUN_hwcprof_signature 0x2223 /* SUN */ +#define DW_AT_SUN_amd64_parmdump 0x2224 /* SUN */ +#define DW_AT_SUN_part_link_name 0x2225 /* SUN */ +#define DW_AT_SUN_link_name 0x2226 /* SUN */ +#define DW_AT_SUN_pass_with_const 0x2227 /* SUN */ +#define DW_AT_SUN_return_with_const 0x2228 /* SUN */ +#define DW_AT_SUN_import_by_name 0x2229 /* SUN */ +#define DW_AT_SUN_f90_pointer 0x222a /* SUN */ +#define DW_AT_SUN_pass_by_ref 0x222b /* SUN */ +#define DW_AT_SUN_f90_allocatable 0x222c /* SUN */ +#define DW_AT_SUN_f90_assumed_shape_array 0x222d /* SUN */ +#define DW_AT_SUN_c_vla 0x222e /* SUN */ +#define DW_AT_SUN_return_value_ptr 0x2230 /* SUN */ +#define DW_AT_SUN_dtor_start 0x2231 /* SUN */ +#define DW_AT_SUN_dtor_length 0x2232 /* SUN */ +#define DW_AT_SUN_dtor_state_initial 0x2233 /* SUN */ +#define DW_AT_SUN_dtor_state_final 0x2234 /* SUN */ +#define DW_AT_SUN_dtor_state_deltas 0x2235 /* SUN */ +#define DW_AT_SUN_import_by_lname 0x2236 /* SUN */ +#define DW_AT_SUN_f90_use_only 0x2237 /* SUN */ +#define DW_AT_SUN_namelist_spec 0x2238 /* SUN */ +#define DW_AT_SUN_is_omp_child_func 0x2239 /* SUN */ +#define DW_AT_SUN_fortran_main_alias 0x223a /* SUN */ +#define DW_AT_SUN_fortran_based 0x223b /* SUN */ + +/* See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type . */ +#define DW_AT_use_GNAT_descriptive_type 0x2301 /* GNAT */ +#define DW_AT_GNAT_descriptive_type 0x2302 /* GNAT */ + +/* UPC extension */ +#define DW_AT_upc_threads_scaled 0x3210 /* UPC */ + +/* PGI (STMicroelectronics) extensions. */ +#define DW_AT_PGI_lbase 0x3a00 /* PGI. Block, constant, reference. This attribute is an ASTPLAB extension used to describe the array local base. */ +#define DW_AT_PGI_soffset 0x3a01 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the section offset, or the offset to the first element in the dimension. */ +#define DW_AT_PGI_lstride 0x3a02 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the linear stride or the distance between elements in the dimension. */ + +/* There are two groups of Apple extensions here, it is + unclear what exactly is correct. */ +#define DW_AT_APPLE_optimized 0x3fe1 /* Apple */ +#define DW_AT_APPLE_flags 0x3fe2 /* Apple */ +#define DW_AT_APPLE_isa 0x3fe3 /* Apple */ +#define DW_AT_APPLE_block 0x3fe4 /* Apple */ +#define DW_AT_APPLE_major_runtime_vers 0x3fe5 /* Apple */ +#define DW_AT_APPLE_runtime_class 0x3fe6 /* Apple */ +#define DW_AT_APPLE_omit_frame_ptr 0x3fe7 /* Apple */ + +/* Apple Extensions for closures */ +#define DW_AT_APPLE_closure 0x3fe4 /* Apple */ +/* Apple Extensions for Objective-C runtime info */ +#define DW_AT_APPLE_major_runtime_vers 0x3fe5 /* Apple */ +#define DW_AT_APPLE_runtime_class 0x3fe6 /* Apple */ + + +#define DW_AT_hi_user 0x3fff + +#define DW_OP_addr 0x03 +#define DW_OP_deref 0x06 +#define DW_OP_const1u 0x08 +#define DW_OP_const1s 0x09 +#define DW_OP_const2u 0x0a +#define DW_OP_const2s 0x0b +#define DW_OP_const4u 0x0c +#define DW_OP_const4s 0x0d +#define DW_OP_const8u 0x0e +#define DW_OP_const8s 0x0f +#define DW_OP_constu 0x10 +#define DW_OP_consts 0x11 +#define DW_OP_dup 0x12 +#define DW_OP_drop 0x13 +#define DW_OP_over 0x14 +#define DW_OP_pick 0x15 +#define DW_OP_swap 0x16 +#define DW_OP_rot 0x17 +#define DW_OP_xderef 0x18 +#define DW_OP_abs 0x19 +#define DW_OP_and 0x1a +#define DW_OP_div 0x1b +#define DW_OP_minus 0x1c +#define DW_OP_mod 0x1d +#define DW_OP_mul 0x1e +#define DW_OP_neg 0x1f +#define DW_OP_not 0x20 +#define DW_OP_or 0x21 +#define DW_OP_plus 0x22 +#define DW_OP_plus_uconst 0x23 +#define DW_OP_shl 0x24 +#define DW_OP_shr 0x25 +#define DW_OP_shra 0x26 +#define DW_OP_xor 0x27 +#define DW_OP_bra 0x28 +#define DW_OP_eq 0x29 +#define DW_OP_ge 0x2a +#define DW_OP_gt 0x2b +#define DW_OP_le 0x2c +#define DW_OP_lt 0x2d +#define DW_OP_ne 0x2e +#define DW_OP_skip 0x2f +#define DW_OP_lit0 0x30 +#define DW_OP_lit1 0x31 +#define DW_OP_lit2 0x32 +#define DW_OP_lit3 0x33 +#define DW_OP_lit4 0x34 +#define DW_OP_lit5 0x35 +#define DW_OP_lit6 0x36 +#define DW_OP_lit7 0x37 +#define DW_OP_lit8 0x38 +#define DW_OP_lit9 0x39 +#define DW_OP_lit10 0x3a +#define DW_OP_lit11 0x3b +#define DW_OP_lit12 0x3c +#define DW_OP_lit13 0x3d +#define DW_OP_lit14 0x3e +#define DW_OP_lit15 0x3f +#define DW_OP_lit16 0x40 +#define DW_OP_lit17 0x41 +#define DW_OP_lit18 0x42 +#define DW_OP_lit19 0x43 +#define DW_OP_lit20 0x44 +#define DW_OP_lit21 0x45 +#define DW_OP_lit22 0x46 +#define DW_OP_lit23 0x47 +#define DW_OP_lit24 0x48 +#define DW_OP_lit25 0x49 +#define DW_OP_lit26 0x4a +#define DW_OP_lit27 0x4b +#define DW_OP_lit28 0x4c +#define DW_OP_lit29 0x4d +#define DW_OP_lit30 0x4e +#define DW_OP_lit31 0x4f +#define DW_OP_reg0 0x50 +#define DW_OP_reg1 0x51 +#define DW_OP_reg2 0x52 +#define DW_OP_reg3 0x53 +#define DW_OP_reg4 0x54 +#define DW_OP_reg5 0x55 +#define DW_OP_reg6 0x56 +#define DW_OP_reg7 0x57 +#define DW_OP_reg8 0x58 +#define DW_OP_reg9 0x59 +#define DW_OP_reg10 0x5a +#define DW_OP_reg11 0x5b +#define DW_OP_reg12 0x5c +#define DW_OP_reg13 0x5d +#define DW_OP_reg14 0x5e +#define DW_OP_reg15 0x5f +#define DW_OP_reg16 0x60 +#define DW_OP_reg17 0x61 +#define DW_OP_reg18 0x62 +#define DW_OP_reg19 0x63 +#define DW_OP_reg20 0x64 +#define DW_OP_reg21 0x65 +#define DW_OP_reg22 0x66 +#define DW_OP_reg23 0x67 +#define DW_OP_reg24 0x68 +#define DW_OP_reg25 0x69 +#define DW_OP_reg26 0x6a +#define DW_OP_reg27 0x6b +#define DW_OP_reg28 0x6c +#define DW_OP_reg29 0x6d +#define DW_OP_reg30 0x6e +#define DW_OP_reg31 0x6f +#define DW_OP_breg0 0x70 +#define DW_OP_breg1 0x71 +#define DW_OP_breg2 0x72 +#define DW_OP_breg3 0x73 +#define DW_OP_breg4 0x74 +#define DW_OP_breg5 0x75 +#define DW_OP_breg6 0x76 +#define DW_OP_breg7 0x77 +#define DW_OP_breg8 0x78 +#define DW_OP_breg9 0x79 +#define DW_OP_breg10 0x7a +#define DW_OP_breg11 0x7b +#define DW_OP_breg12 0x7c +#define DW_OP_breg13 0x7d +#define DW_OP_breg14 0x7e +#define DW_OP_breg15 0x7f +#define DW_OP_breg16 0x80 +#define DW_OP_breg17 0x81 +#define DW_OP_breg18 0x82 +#define DW_OP_breg19 0x83 +#define DW_OP_breg20 0x84 +#define DW_OP_breg21 0x85 +#define DW_OP_breg22 0x86 +#define DW_OP_breg23 0x87 +#define DW_OP_breg24 0x88 +#define DW_OP_breg25 0x89 +#define DW_OP_breg26 0x8a +#define DW_OP_breg27 0x8b +#define DW_OP_breg28 0x8c +#define DW_OP_breg29 0x8d +#define DW_OP_breg30 0x8e +#define DW_OP_breg31 0x8f +#define DW_OP_regx 0x90 +#define DW_OP_fbreg 0x91 +#define DW_OP_bregx 0x92 +#define DW_OP_piece 0x93 +#define DW_OP_deref_size 0x94 +#define DW_OP_xderef_size 0x95 +#define DW_OP_nop 0x96 +#define DW_OP_push_object_address 0x97 /* DWARF3 */ +#define DW_OP_call2 0x98 /* DWARF3 */ +#define DW_OP_call4 0x99 /* DWARF3 */ +#define DW_OP_call_ref 0x9a /* DWARF3 */ +#define DW_OP_form_tls_address 0x9b /* DWARF3f */ +#define DW_OP_call_frame_cfa 0x9c /* DWARF3f */ +#define DW_OP_bit_piece 0x9d /* DWARF3f */ +#define DW_OP_implicit_value 0x9e /* DWARF4 */ +#define DW_OP_stack_value 0x9f /* DWARF4 */ + + + /* GNU extensions. */ +#define DW_OP_GNU_push_tls_address 0xe0 /* GNU */ + +/* Follows extension so dwarfdump prints the most-likely-useful name. */ +#define DW_OP_lo_user 0xe0 + + +#define DW_OP_GNU_uninit 0xf0 /* GNU */ +#define DW_OP_GNU_encoded_addr 0xf1 /* GNU */ +#define DW_OP_GNU_implicit_pointer 0xf2 /* GNU */ +#define DW_OP_GNU_entry_value 0xf3 /* GNU */ + + /* HP extensions. */ +#define DW_OP_HP_unknown 0xe0 /* HP conflict: GNU */ +#define DW_OP_HP_is_value 0xe1 /* HP */ +#define DW_OP_HP_fltconst4 0xe2 /* HP */ +#define DW_OP_HP_fltconst8 0xe3 /* HP */ +#define DW_OP_HP_mod_range 0xe4 /* HP */ +#define DW_OP_HP_unmod_range 0xe5 /* HP */ +#define DW_OP_HP_tls 0xe6 /* HP */ + +#define DW_OP_INTEL_bit_piece 0xe8 /* Intel: made obsolete by DW_OP_bit_piece above. */ + + /* Apple extension. */ +#define DW_OP_APPLE_uninit 0xf0 /* Apple */ +#define DW_OP_PGI_omp_thread_num 0xf8 /* PGI (STMicroelectronics) */ + +#define DW_OP_hi_user 0xff + +#define DW_ATE_address 0x1 +#define DW_ATE_boolean 0x2 +#define DW_ATE_complex_float 0x3 +#define DW_ATE_float 0x4 +#define DW_ATE_signed 0x5 +#define DW_ATE_signed_char 0x6 +#define DW_ATE_unsigned 0x7 +#define DW_ATE_unsigned_char 0x8 +#define DW_ATE_imaginary_float 0x9 /* DWARF3 */ +#define DW_ATE_packed_decimal 0xa /* DWARF3f */ +#define DW_ATE_numeric_string 0xb /* DWARF3f */ +#define DW_ATE_edited 0xc /* DWARF3f */ +#define DW_ATE_signed_fixed 0xd /* DWARF3f */ +#define DW_ATE_unsigned_fixed 0xe /* DWARF3f */ +#define DW_ATE_decimal_float 0xf /* DWARF3f */ + + +/* ALTIUM extensions. x80, x81 */ +#define DW_ATE_ALTIUM_fract 0x80 /* ALTIUM __fract type */ + +/* Follows extension so dwarfdump prints the most-likely-useful name. */ +#define DW_ATE_lo_user 0x80 + +/* Shown here to help dwarfdump build script. */ +#define DW_ATE_ALTIUM_accum 0x81 /* ALTIUM __accum type */ + +/* HP Floating point extensions. */ +#define DW_ATE_HP_float80 0x80 /* (80 bit). HP */ + + +#define DW_ATE_HP_complex_float80 0x81 /* Complex (80 bit). HP */ +#define DW_ATE_HP_float128 0x82 /* (128 bit). HP */ +#define DW_ATE_HP_complex_float128 0x83 /* Complex (128 bit). HP */ +#define DW_ATE_HP_floathpintel 0x84 /* (82 bit IA64). HP */ +#define DW_ATE_HP_imaginary_float80 0x85 /* HP */ +#define DW_ATE_HP_imaginary_float128 0x86 /* HP */ + +/* Sun extensions */ +#define DW_ATE_SUN_interval_float 0x91 +#define DW_ATE_SUN_imaginary_float 0x92 /* Obsolete: See DW_ATE_imaginary_float */ + +#define DW_ATE_hi_user 0xff + + +/* Decimal Sign codes. */ +#define DW_DS_unsigned 0x01 /* DWARF3f */ +#define DW_DS_leading_overpunch 0x02 /* DWARF3f */ +#define DW_DS_trailing_overpunch 0x03 /* DWARF3f */ +#define DW_DS_leading_separate 0x04 /* DWARF3f */ + +#define DW_DS_trailing_separate 0x05 /* DWARF3f */ + +/* Endian code name. */ +#define DW_END_default 0x00 /* DWARF3f */ +#define DW_END_big 0x01 /* DWARF3f */ +#define DW_END_little 0x02 /* DWARF3f */ + +#define DW_END_lo_user 0x40 /* DWARF3f */ +#define DW_END_hi_user 0xff /* DWARF3f */ + +/* For use with DW_TAG_SUN_codeflags + If DW_TAG_SUN_codeflags is accepted as a dwarf standard, then + standard dwarf ATCF entries start at 0x01 */ +#define DW_ATCF_lo_user 0x40 /* SUN */ +#define DW_ATCF_SUN_mop_bitfield 0x41 /* SUN */ +#define DW_ATCF_SUN_mop_spill 0x42 /* SUN */ +#define DW_ATCF_SUN_mop_scopy 0x43 /* SUN */ +#define DW_ATCF_SUN_func_start 0x44 /* SUN */ +#define DW_ATCF_SUN_end_ctors 0x45 /* SUN */ +#define DW_ATCF_SUN_branch_target 0x46 /* SUN */ +#define DW_ATCF_SUN_mop_stack_probe 0x47 /* SUN */ +#define DW_ATCF_SUN_func_epilog 0x48 /* SUN */ +#define DW_ATCF_hi_user 0xff /* SUN */ + +/* Accessibility code name. */ +#define DW_ACCESS_public 0x01 +#define DW_ACCESS_protected 0x02 +#define DW_ACCESS_private 0x03 + +/* Visibility code name. */ +#define DW_VIS_local 0x01 +#define DW_VIS_exported 0x02 +#define DW_VIS_qualified 0x03 + +/* Virtuality code name. */ +#define DW_VIRTUALITY_none 0x00 +#define DW_VIRTUALITY_virtual 0x01 +#define DW_VIRTUALITY_pure_virtual 0x02 + +#define DW_LANG_C89 0x0001 +#define DW_LANG_C 0x0002 +#define DW_LANG_Ada83 0x0003 +#define DW_LANG_C_plus_plus 0x0004 +#define DW_LANG_Cobol74 0x0005 +#define DW_LANG_Cobol85 0x0006 +#define DW_LANG_Fortran77 0x0007 +#define DW_LANG_Fortran90 0x0008 +#define DW_LANG_Pascal83 0x0009 +#define DW_LANG_Modula2 0x000a +#define DW_LANG_Java 0x000b /* DWARF3 */ +#define DW_LANG_C99 0x000c /* DWARF3 */ +#define DW_LANG_Ada95 0x000d /* DWARF3 */ +#define DW_LANG_Fortran95 0x000e /* DWARF3 */ +#define DW_LANG_PLI 0x000f /* DWARF3 */ +#define DW_LANG_ObjC 0x0010 /* DWARF3f */ +#define DW_LANG_ObjC_plus_plus 0x0011 /* DWARF3f */ +#define DW_LANG_UPC 0x0012 /* DWARF3f */ +#define DW_LANG_D 0x0013 /* DWARF3f */ +#define DW_LANG_Python 0x0014 /* DWARF4 */ +/* The following 2 are not yet formally approved October 2010, but + it seems extremely likely they will be approved as the committee + chair agrees these should be ok and no one on the committee + has objected. */ +#define DW_LANG_OpenCL 0x0015 /* Provisionally DWARF5 */ +#define DW_LANG_Go 0x0016 /* Provisionally DWARF5 */ +#define DW_LANG_lo_user 0x8000 +#define DW_LANG_Mips_Assembler 0x8001 /* MIPS */ +#define DW_LANG_Upc 0x8765 /* UPC, use + DW_LANG_UPC instead. */ +/* ALTIUM extension */ +#define DW_LANG_ALTIUM_Assembler 0x9101 /* ALTIUM */ + +/* Sun extensions */ +#define DW_LANG_SUN_Assembler 0x9001 /* SUN */ + +#define DW_LANG_hi_user 0xffff + +/* Identifier case name. */ +#define DW_ID_case_sensitive 0x00 +#define DW_ID_up_case 0x01 +#define DW_ID_down_case 0x02 +#define DW_ID_case_insensitive 0x03 + +/* Calling Convention Name. */ +#define DW_CC_normal 0x01 +#define DW_CC_program 0x02 +#define DW_CC_nocall 0x03 +#define DW_CC_lo_user 0x40 + +#define DW_CC_GNU_renesas_sh 0x40 /* GNU */ +#define DW_CC_GNU_borland_fastcall_i386 0x41 /* GNU */ + + + +/* ALTIUM extensions. */ +/* Function is an interrupt handler, return address on system stack. */ +#define DW_CC_ALTIUM_interrupt 0x65 /* ALTIUM*/ + +/* Near function model, return address on system stack. */ +#define DW_CC_ALTIUM_near_system_stack 0x66 /*ALTIUM */ + +/* Near function model, return address on user stack. */ +#define DW_CC_ALTIUM_near_user_stack 0x67 /* ALTIUM */ + +/* Huge function model, return address on user stack. */ +#define DW_CC_ALTIUM_huge_user_stack 0x68 /* ALTIUM */ + + +#define DW_CC_hi_user 0xff + +/* Inline Code Name. */ +#define DW_INL_not_inlined 0x00 +#define DW_INL_inlined 0x01 +#define DW_INL_declared_not_inlined 0x02 +#define DW_INL_declared_inlined 0x03 + +/* Ordering Name. */ +#define DW_ORD_row_major 0x00 +#define DW_ORD_col_major 0x01 + +/* Discriminant Descriptor Name. */ +#define DW_DSC_label 0x00 +#define DW_DSC_range 0x01 + +/* Line number standard opcode name. */ +#define DW_LNS_copy 0x01 +#define DW_LNS_advance_pc 0x02 +#define DW_LNS_advance_line 0x03 +#define DW_LNS_set_file 0x04 +#define DW_LNS_set_column 0x05 +#define DW_LNS_negate_stmt 0x06 +#define DW_LNS_set_basic_block 0x07 +#define DW_LNS_const_add_pc 0x08 +#define DW_LNS_fixed_advance_pc 0x09 +#define DW_LNS_set_prologue_end 0x0a /* DWARF3 */ +#define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */ +#define DW_LNS_set_isa 0x0c /* DWARF3 */ + +/* Line number extended opcode name. */ +#define DW_LNE_end_sequence 0x01 +#define DW_LNE_set_address 0x02 +#define DW_LNE_define_file 0x03 +#define DW_LNE_set_discriminator 0x04 /* DWARF4 */ + +/* HP extensions. */ +#define DW_LNE_HP_negate_is_UV_update 0x11 /* 17 HP */ +#define DW_LNE_HP_push_context 0x12 /* 18 HP */ +#define DW_LNE_HP_pop_context 0x13 /* 19 HP */ +#define DW_LNE_HP_set_file_line_column 0x14 /* 20 HP */ +#define DW_LNE_HP_set_routine_name 0x15 /* 21 HP */ +#define DW_LNE_HP_set_sequence 0x16 /* 22 HP */ +#define DW_LNE_HP_negate_post_semantics 0x17 /* 23 HP */ +#define DW_LNE_HP_negate_function_exit 0x18 /* 24 HP */ +#define DW_LNE_HP_negate_front_end_logical 0x19 /* 25 HP */ +#define DW_LNE_HP_define_proc 0x20 /* 32 HP */ + +#define DW_LNE_HP_source_file_correlation 0x80 /* HP */ +#define DW_LNE_lo_user 0x80 /* DWARF3 */ +#define DW_LNE_hi_user 0xff /* DWARF3 */ + +/* These are known values for DW_LNS_set_isa. */ +#define DW_ISA_UNKNOWN 0 +/* The following two are ARM specific. */ +#define DW_ISA_ARM_thumb 1 /* ARM ISA */ +#define DW_ISA_ARM_arm 2 /* ARM ISA */ + +/* Macro information. */ +#define DW_MACINFO_define 0x01 +#define DW_MACINFO_undef 0x02 +#define DW_MACINFO_start_file 0x03 +#define DW_MACINFO_end_file 0x04 +#define DW_MACINFO_vendor_ext 0xff + +/* CFA operator compaction (a space saving measure, see + the DWARF standard) means DW_CFA_extended and DW_CFA_nop + have the same value here. */ +#define DW_CFA_advance_loc 0x40 +#define DW_CFA_offset 0x80 +#define DW_CFA_restore 0xc0 +#define DW_CFA_extended 0 + +#define DW_CFA_nop 0x00 +#define DW_CFA_set_loc 0x01 +#define DW_CFA_advance_loc1 0x02 +#define DW_CFA_advance_loc2 0x03 +#define DW_CFA_advance_loc4 0x04 +#define DW_CFA_offset_extended 0x05 +#define DW_CFA_restore_extended 0x06 +#define DW_CFA_undefined 0x07 +#define DW_CFA_same_value 0x08 +#define DW_CFA_register 0x09 +#define DW_CFA_remember_state 0x0a +#define DW_CFA_restore_state 0x0b +#define DW_CFA_def_cfa 0x0c +#define DW_CFA_def_cfa_register 0x0d +#define DW_CFA_def_cfa_offset 0x0e +#define DW_CFA_def_cfa_expression 0x0f /* DWARF3 */ +#define DW_CFA_expression 0x10 /* DWARF3 */ +#define DW_CFA_offset_extended_sf 0x11 /* DWARF3 */ +#define DW_CFA_def_cfa_sf 0x12 /* DWARF3 */ +#define DW_CFA_def_cfa_offset_sf 0x13 /* DWARF3 */ +#define DW_CFA_val_offset 0x14 /* DWARF3f */ +#define DW_CFA_val_offset_sf 0x15 /* DWARF3f */ +#define DW_CFA_val_expression 0x16 /* DWARF3f */ + +#define DW_CFA_lo_user 0x1c +#define DW_CFA_low_user 0x1c /* Incorrect spelling, do not use. */ + +/* SGI/MIPS extension. */ +#define DW_CFA_MIPS_advance_loc8 0x1d /* MIPS */ + +/* GNU extensions. */ +#define DW_CFA_GNU_window_save 0x2d /* GNU */ +#define DW_CFA_GNU_args_size 0x2e /* GNU */ +#define DW_CFA_GNU_negative_offset_extended 0x2f /* GNU */ + +#define DW_CFA_high_user 0x3f + +/* GNU exception header encoding. See the Generic + Elf Specification of the Linux Standard Base (LSB). + http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html + The upper 4 bits indicate how the value is to be applied. + The lower 4 bits indicate the format of the data. +*/ +#define DW_EH_PE_absptr 0x00 /* GNU */ +#define DW_EH_PE_uleb128 0x01 /* GNU */ +#define DW_EH_PE_udata2 0x02 /* GNU */ +#define DW_EH_PE_udata4 0x03 /* GNU */ +#define DW_EH_PE_udata8 0x04 /* GNU */ +#define DW_EH_PE_sleb128 0x09 /* GNU */ +#define DW_EH_PE_sdata2 0x0A /* GNU */ +#define DW_EH_PE_sdata4 0x0B /* GNU */ +#define DW_EH_PE_sdata8 0x0C /* GNU */ + +#define DW_EH_PE_pcrel 0x10 /* GNU */ +#define DW_EH_PE_textrel 0x20 /* GNU */ +#define DW_EH_PE_datarel 0x30 /* GNU */ +#define DW_EH_PE_funcrel 0x40 /* GNU */ +#define DW_EH_PE_aligned 0x50 /* GNU */ + +#define DW_EH_PE_omit 0xff /* GNU. Means no value present. */ + + +/* Mapping from machine registers and pseudo-regs into the + .debug_frame table. DW_FRAME entries are machine specific. + These describe MIPS/SGI R3000, R4K, R4400 and all later + MIPS/SGI IRIX machines. They describe a mapping from + hardware register number to the number used in the table + to identify that register. + + The CFA (Canonical Frame Address) described in DWARF is + called the Virtual Frame Pointer on MIPS/SGI machines. + + The DW_FRAME* names here are MIPS/SGI specific. + Libdwarf interfaces defined in 2008 make the + frame definitions here (and the fixed table sizes + they imply) obsolete. They are left here for compatibility. +*/ +/* Default column used for CFA in the libdwarf reader client. + Assumes reg 0 never appears as + a register in DWARF information. Usable for MIPS, + but never a good idea, really. */ +#define DW_FRAME_CFA_COL 0 + +#define DW_FRAME_REG1 1 /* integer reg 1 */ +#define DW_FRAME_REG2 2 /* integer reg 2 */ +#define DW_FRAME_REG3 3 /* integer reg 3 */ +#define DW_FRAME_REG4 4 /* integer reg 4 */ +#define DW_FRAME_REG5 5 /* integer reg 5 */ +#define DW_FRAME_REG6 6 /* integer reg 6 */ +#define DW_FRAME_REG7 7 /* integer reg 7 */ +#define DW_FRAME_REG8 8 /* integer reg 8 */ +#define DW_FRAME_REG9 9 /* integer reg 9 */ +#define DW_FRAME_REG10 10 /* integer reg 10 */ +#define DW_FRAME_REG11 11 /* integer reg 11 */ +#define DW_FRAME_REG12 12 /* integer reg 12 */ +#define DW_FRAME_REG13 13 /* integer reg 13 */ +#define DW_FRAME_REG14 14 /* integer reg 14 */ +#define DW_FRAME_REG15 15 /* integer reg 15 */ +#define DW_FRAME_REG16 16 /* integer reg 16 */ +#define DW_FRAME_REG17 17 /* integer reg 17 */ +#define DW_FRAME_REG18 18 /* integer reg 18 */ +#define DW_FRAME_REG19 19 /* integer reg 19 */ +#define DW_FRAME_REG20 20 /* integer reg 20 */ +#define DW_FRAME_REG21 21 /* integer reg 21 */ +#define DW_FRAME_REG22 22 /* integer reg 22 */ +#define DW_FRAME_REG23 23 /* integer reg 23 */ +#define DW_FRAME_REG24 24 /* integer reg 24 */ +#define DW_FRAME_REG25 25 /* integer reg 25 */ +#define DW_FRAME_REG26 26 /* integer reg 26 */ +#define DW_FRAME_REG27 27 /* integer reg 27 */ +#define DW_FRAME_REG28 28 /* integer reg 28 */ +#define DW_FRAME_REG29 29 /* integer reg 29 */ +#define DW_FRAME_REG30 30 /* integer reg 30 */ +#define DW_FRAME_REG31 31 /* integer reg 31, aka ra */ + + /* MIPS1, 2 have only some of these 64-bit registers. + ** MIPS1 save/restore takes 2 instructions per 64-bit reg, and + ** in that case, the register is considered stored after the second + ** swc1. + */ +#define DW_FRAME_FREG0 32 /* 64-bit floating point reg 0 */ +#define DW_FRAME_FREG1 33 /* 64-bit floating point reg 1 */ +#define DW_FRAME_FREG2 34 /* 64-bit floating point reg 2 */ +#define DW_FRAME_FREG3 35 /* 64-bit floating point reg 3 */ +#define DW_FRAME_FREG4 36 /* 64-bit floating point reg 4 */ +#define DW_FRAME_FREG5 37 /* 64-bit floating point reg 5 */ +#define DW_FRAME_FREG6 38 /* 64-bit floating point reg 6 */ +#define DW_FRAME_FREG7 39 /* 64-bit floating point reg 7 */ +#define DW_FRAME_FREG8 40 /* 64-bit floating point reg 8 */ +#define DW_FRAME_FREG9 41 /* 64-bit floating point reg 9 */ +#define DW_FRAME_FREG10 42 /* 64-bit floating point reg 10 */ +#define DW_FRAME_FREG11 43 /* 64-bit floating point reg 11 */ +#define DW_FRAME_FREG12 44 /* 64-bit floating point reg 12 */ +#define DW_FRAME_FREG13 45 /* 64-bit floating point reg 13 */ +#define DW_FRAME_FREG14 46 /* 64-bit floating point reg 14 */ +#define DW_FRAME_FREG15 47 /* 64-bit floating point reg 15 */ +#define DW_FRAME_FREG16 48 /* 64-bit floating point reg 16 */ +#define DW_FRAME_FREG17 49 /* 64-bit floating point reg 17 */ +#define DW_FRAME_FREG18 50 /* 64-bit floating point reg 18 */ +#define DW_FRAME_FREG19 51 /* 64-bit floating point reg 19 */ +#define DW_FRAME_FREG20 52 /* 64-bit floating point reg 20 */ +#define DW_FRAME_FREG21 53 /* 64-bit floating point reg 21 */ +#define DW_FRAME_FREG22 54 /* 64-bit floating point reg 22 */ +#define DW_FRAME_FREG23 55 /* 64-bit floating point reg 23 */ +#define DW_FRAME_FREG24 56 /* 64-bit floating point reg 24 */ +#define DW_FRAME_FREG25 57 /* 64-bit floating point reg 25 */ +#define DW_FRAME_FREG26 58 /* 64-bit floating point reg 26 */ +#define DW_FRAME_FREG27 59 /* 64-bit floating point reg 27 */ +#define DW_FRAME_FREG28 60 /* 64-bit floating point reg 28 */ +#define DW_FRAME_FREG29 61 /* 64-bit floating point reg 29 */ +#define DW_FRAME_FREG30 62 /* 64-bit floating point reg 30 */ +#define DW_FRAME_FREG31 63 /* 64-bit floating point reg 31 */ + +#define DW_FRAME_FREG32 64 /* 64-bit floating point reg 18 */ +#define DW_FRAME_FREG33 65 /* 64-bit floating point reg 19 */ +#define DW_FRAME_FREG34 66 /* 64-bit floating point reg 20 */ +#define DW_FRAME_FREG35 67 /* 64-bit floating point reg 21 */ +#define DW_FRAME_FREG36 68 /* 64-bit floating point reg 22 */ +#define DW_FRAME_FREG37 69 /* 64-bit floating point reg 23 */ +#define DW_FRAME_FREG38 70 /* 64-bit floating point reg 24 */ +#define DW_FRAME_FREG39 71 /* 64-bit floating point reg 25 */ +#define DW_FRAME_FREG40 72 /* 64-bit floating point reg 26 */ +#define DW_FRAME_FREG41 73 /* 64-bit floating point reg 27 */ +#define DW_FRAME_FREG42 74 /* 64-bit floating point reg 28 */ +#define DW_FRAME_FREG43 75 /* 64-bit floating point reg 29 */ +#define DW_FRAME_FREG44 76 /* 64-bit floating point reg 30 */ +#define DW_FRAME_FREG45 77 /* 64-bit floating point reg 31 */ +#define DW_FRAME_FREG46 78 /* 64-bit floating point reg 18 */ +#define DW_FRAME_FREG47 79 /* 64-bit floating point reg 19 */ +#define DW_FRAME_FREG48 80 /* 64-bit floating point reg 20 */ +#define DW_FRAME_FREG49 81 /* 64-bit floating point reg 21 */ +#define DW_FRAME_FREG50 82 /* 64-bit floating point reg 22 */ +#define DW_FRAME_FREG51 83 /* 64-bit floating point reg 23 */ +#define DW_FRAME_FREG52 84 /* 64-bit floating point reg 24 */ +#define DW_FRAME_FREG53 85 /* 64-bit floating point reg 25 */ +#define DW_FRAME_FREG54 86 /* 64-bit floating point reg 26 */ +#define DW_FRAME_FREG55 87 /* 64-bit floating point reg 27 */ +#define DW_FRAME_FREG56 88 /* 64-bit floating point reg 28 */ +#define DW_FRAME_FREG57 89 /* 64-bit floating point reg 29 */ +#define DW_FRAME_FREG58 90 /* 64-bit floating point reg 30 */ +#define DW_FRAME_FREG59 91 /* 64-bit floating point reg 31 */ +#define DW_FRAME_FREG60 92 /* 64-bit floating point reg 22 */ +#define DW_FRAME_FREG61 93 /* 64-bit floating point reg 23 */ +#define DW_FRAME_FREG62 94 /* 64-bit floating point reg 24 */ +#define DW_FRAME_FREG63 95 /* 64-bit floating point reg 25 */ +#define DW_FRAME_FREG64 96 /* 64-bit floating point reg 26 */ +#define DW_FRAME_FREG65 97 /* 64-bit floating point reg 27 */ +#define DW_FRAME_FREG66 98 /* 64-bit floating point reg 28 */ +#define DW_FRAME_FREG67 99 /* 64-bit floating point reg 29 */ +#define DW_FRAME_FREG68 100 /* 64-bit floating point reg 30 */ +#define DW_FRAME_FREG69 101 /* 64-bit floating point reg 31 */ +#define DW_FRAME_FREG70 102 /* 64-bit floating point reg 22 */ +#define DW_FRAME_FREG71 103 /* 64-bit floating point reg 23 */ +#define DW_FRAME_FREG72 104 /* 64-bit floating point reg 24 */ +#define DW_FRAME_FREG73 105 /* 64-bit floating point reg 25 */ +#define DW_FRAME_FREG74 106 /* 64-bit floating point reg 26 */ +#define DW_FRAME_FREG75 107 /* 64-bit floating point reg 27 */ +#define DW_FRAME_FREG76 108 /* 64-bit floating point reg 28 */ + + +/* ***IMPORTANT NOTE, TARGET DEPENDENCY **** + The following 4 #defines are dependent on + the target cpu(s) that you apply libdwarf to. + Ensure that DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL + do not conflict with the range [0-DW_FRAME_STATIC_LINK]. + The value 63 works for MIPS cpus at least up to the R16000. + + For a cpu with more than 63 real registers + DW_FRAME_HIGHEST_NORMAL_REGISTER + must be increased for things to work properly! + Also ensure that DW_FRAME_UNDEFINED_VAL DW_FRAME_SAME_VAL + are not in the range [0-DW_FRAME_STATIC_LINK] + + Having DW_FRAME_HIGHEST_NORMAL_REGISTER be higher than + is strictly needed is safe. + +*/ + +#ifndef DW_FRAME_HIGHEST_NORMAL_REGISTER +#define DW_FRAME_HIGHEST_NORMAL_REGISTER 188 +#endif +/* This is the number of columns in the Frame Table. + This constant should + be kept in sync with DW_REG_TABLE_SIZE defined in libdwarf.h + It must also be large enough to be beyond the highest + compiler-defined-register (meaning DW_FRAME_RA_COL DW_FRAME_STATIC_LINK + in the MIPS/IRIX case */ +#ifndef DW_FRAME_LAST_REG_NUM +#define DW_FRAME_LAST_REG_NUM (DW_FRAME_HIGHEST_NORMAL_REGISTER + 3) +#endif + + +/* Column recording ra (return address from a function call). + This is common to many architectures, but as a 'simple register' + is not necessarily adequate for all architectures. + For MIPS/IRIX this register number is actually recorded on disk + in the .debug_frame section. + */ +#define DW_FRAME_RA_COL (DW_FRAME_HIGHEST_NORMAL_REGISTER + 1) + +/* Column recording static link applicable to up-level + addressing, as in IRIX mp code, pascal, etc. + This is common to many architectures but + is not necessarily adequate for all architectures. + For MIPS/IRIX this register number is actually recorded on disk + in the .debug_frame section. +*/ +#define DW_FRAME_STATIC_LINK (DW_FRAME_HIGHEST_NORMAL_REGISTER + 2) + + + +/* + DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL are + never on disk, just generated by libdwarf. See libdwarf.h + for their values. +*/ + + + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +#ifdef __cplusplus +} +#endif +#endif /* __DWARF_H */ diff --git a/libdwarf/dwarf.v2.mm b/libdwarf/dwarf.v2.mm new file mode 100644 index 0000000..5b12dac --- /dev/null +++ b/libdwarf/dwarf.v2.mm @@ -0,0 +1,7699 @@ +'\"#ident "%W%" +'\" $Source: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/libdwarf/RCS/dwarf.v2.mm,v $ +'\" +'\" $Revision: 1.2 $ +'\" +'\" DESCRIPTION +'\" +'\" Requirements for +'\" +'\" COMPILATION +'\" +'\" pic file.mm | tbl | troff -mm +'\" +'\" local mileage may vary +'\" +'\" AUTHOR +'\" +'\" UNIX International Programming Languages SIG +'\" +'\" COPYRIGHT +'\" +'\" Copyright (c) 1992,1993, UNIX International +'\" +'\" Permission to use, copy, modify, and distribute this documentation for +'\" any purpose and without fee is hereby granted, provided that the above +'\" copyright notice appears in all copies and that both that copyright +'\" notice and this permission notice appear in supporting documentation, +'\" and that the name UNIX International not be used in advertising or +'\" publicity pertaining to distribution of the software without specific, +'\" written prior permission. UNIX International makes no representations +'\" about the suitability of this documentation for any purpose. It is +'\" provided "as is" without express or implied warranty. +'\" +'\" UNIX INTERNATIONAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +'\" DOCUMENTATION, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +'\" FITNESS. IN NO EVENT SHALL UNIX INTERNATIONAL BE LIABLE FOR ANY +'\" SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +'\" RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +'\" CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +'\" CONNECTION WITH THE USE OR PERFORMANCE OF THIS DOCUMENTATION. +'\" +'\" NOTICE: +'\" +'\" UNIX International is making this documentation available as a +'\" reference point for the industry. While UNIX International believes +'\" that this specification is well defined in this first release of the +'\" document, minor changes may be made prior to products meeting this +'\" specification being made available from UNIX System Laboratories or +'\" UNIX International members. +'\" +'\" $Log$ +'\" Revision 1.1 1994/05/18 18:50:42 davea +'\" Initial revision +'\" +'\" +'\" Abbrevs for funny typeset words +.pl-0.25i +.ds aX U\s-2NIX\s+2 +.ds iX \*(aX International +.ds uL \s-2AT&T\ USL\s+2 +'\" +'\" uI should be set to 1 if the publication and copyright page is needed. +.nr uI 1 +'\" +'\" Make the appropriate replacements in this section! +'\" +'\" Set the ND date to the current date. +'\" tT is the formal document title +'\" tP is the name of the Project (if appropriate) +'\" tD is the short document title +'\" tE is the work group name (may be the same as the project name) +.ds tT DWARF Debugging Information Format +.ds tP +'\" Document name (i.e., without project name) +.ds tD DWARF Debugging Information Format +.ds tE Programming Languages SIG +'\" +'\" Define headers and footers macro +'\" +.ds fA Revision: 2.0.0 +'\" +'\" fB null to remove page numbers on cover page +.ds fB +.ds fC July 27, 1993 +.ds fE Industry Review Draft +.ds fF \*(tD +.PH "''''" +.PF "''\*(fE''" +.tr ~ +.SA 1 +.S 10 +.nr Ej 1 +.nr Hs 5 +.nr Hu 1 +.nr Hb 5 +.ds HP +2 +2 +1 +0 +0 +0 +0 +.ds HF 3 3 3 3 3 1 1 +.if n .ds HF 1 1 1 1 1 1 1 1 +'\" +'\" First page, print title and authors +'\" +.S +4 +.DS C + + + + + + +\fB\*(tT + +\s-2\*(tP\s+2\fP + +.DE +.S +.sp 3i +\*(iX +.br +\*(tE +.br +\*(fA (\*(fC) +.SK +.if \n(uI\{ +.DS C +.in -.25i +.B "Published by:" +.R + +\*(iX +Waterview Corporate Center +20 Waterview Boulevard +Parsippany, NJ 07054 + +for further information, contact: +Vice President of Marketing + +Phone: +1 201-263-8400 +Fax: +1 201-263-8401 +.DE +.P +Copyright \(co 1992, 1993 \*(iX, Inc. +.P +Permission to use, copy, modify, and distribute this +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appears in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the name \*(iX not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. \*(iX makes +no representations about the suitability of this documentation for any +purpose. It is provided "as is" without express or implied warranty. +.P +UNIX INTERNATIONAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS DOCUMENTATION, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO +EVENT SHALL UNIX INTERNATIONAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS DOCUMENTATION. +.sp 2l +.if \n(uI\{ +NOTICE: +.P +\*(iX is making this documentation available as a +reference point for the industry. +While \*(iX believes that this specification is well +defined in this first release of the document, +minor changes may be made prior to products meeting this specification +being made available from \*(aX System Laboratories or \*(iX members. +.sp 1l \} +Trademarks: +.P +Intel386 is a trademark of Intel Corporation. +.br +\*(aX\(rg is a registered trademark of \*(aX System Laboratories +in the United States and other countries. +.br +.OH "'''\s10\\\\*(tE\s0'" +.EH "'\s10\\\\*(tD\s0'''" +.SK +'\".VM 0 2 +.PF "''\s10\\\\*(fE\s0''" +.OF "'\s10\\\\*(fA'\\\\*(fB'\\\\*(fC\s0'" +.EF "'\s10\\\\*(fA'\\\\*(fB'\\\\*(fC\s0'" +'\" ----------------------------------------------------------------------- +'\". +'\" Reset page numbers +'\" +.nr P 1 +.nr % 1 +'\" +'\" Define headers and footers +'\" +.FH +'\" Turn on the page numbering in the footers +.ds fB Page % +'\" +'\" MACROEND +'\" +.if n .fp 2 R +.if n .fp 3 R +.tr ~ +\fR +.S 11 +.SA 1 +.tr ~ +.OP +.ds | | +.ds ~ ~ +.ds ' ' +.if t .ds Cw \&\f(CW +.if n .ds Cw \fB +.de Cf \" Place every other arg in Cw font, beginning with first +.if \\n(.$=1 \&\*(Cw\\$1\fP +.if \\n(.$=2 \&\*(Cw\\$1\fP\\$2 +.if \\n(.$=3 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP +.if \\n(.$=4 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4 +.if \\n(.$=5 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP +.if \\n(.$=6 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6 +.if \\n(.$=7 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP +.if \\n(.$=8 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8 +.if \\n(.$=9 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8\*(Cw +.. +'\" macros used by index generating tool +.deIX +.ie '\\n(.z'' .tm .Index: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 \\n% +.el \\!.ix \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 +.. +.deix +.ie '\\n(.z'' .tm .Index: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 \\n% +.el \\!.ix \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 +.. +.ta .5i +.5i +.5i +.5i +.5i +.5i +.5i +.5i +.HU "FOREWORD" +This document specifies the second generation of symbolic debugging +information based on the DWARF format that +has been developed by the \*(iX +Programming Languages Special Interest Group (SIG). +It is being circulated for industry review. +The first version of the DWARF specification was published +by \*(iX in January, 1992. The current version adds significant +new functionality, but its main thrust is to achieve a much +denser encoding of the DWARF information. Because of the new +encoding, DWARF Version 2 is not binary compatible with +DWARF Version 1. +.P +At this point, the SIG believes that this document sufficiently +supports the debugging needs of C, C++, FORTRAN 77, +Fortran90, Modula2 and Pascal, and we have +released it for public comment. We will accept comments on this +document until September 30, 1994. Comments may be directed via email +to the SIG mailing list (plsig@ui.org). If you are unable +to send email, paper mail, FAX, or machine readable copy +on \*(aX, MS-DOS, or Macintosh compatible media can be +sent to \*(iX at the address listed below, +and will be forwarded to the SIG. +.SP +.SP +.SP +.in +20 +UNIX International +.br +Waterview Corporate Center +.br +20 Waterview Boulevard +.br +Parsippany, NJ 07054 +.br +Phone: +1 201-263-8400 +.br +Fax: +1 201-263-8401 +.br +.in -20 +.nr H1 0 +.OP +.H 1 "INTRODUCTION" +\fR +This document defines the format for the information generated by +compilers, assemblers and linkage editors that is necessary for symbolic, +source-level debugging. The debugging information format does not favor the +design of any compiler or debugger. Instead, the goal is to create a method of +communicating an accurate picture of the source program to any debugger in a +form that is economically extensible to different languages while retaining +backward compatibility. +.P +The design of the debugging information format is open-ended, allowing for the +addition of new debugging information to accommodate new languages or +debugger capabilities while remaining compatible with other languages or +different debuggers. +.H 2 "Purpose and Scope" +The debugging information format described in this document is designed to +meet the symbolic, source-level debugging needs of +different languages in a unified fashion by +requiring language independent debugging information whenever possible. +.IX C++ %caa +.IX virtual functions +.IX Fortran +Individual needs, such as C++ virtual functions or Fortran common blocks are +accommodated by creating attributes that are used only for those +languages. The \*(iX \*(tE believes +that this document sufficiently covers the +.IX languages +debugging information needs of C, C++, FORTRAN77, Fortran90, +Modula2 and Pascal. +.IX C %c +.IX Modula2 +.IX Pascal +.IX FORTRAN77 +.IX Fortran90 +.P +This document describes DWARF Version 2, the second generation of debugging +.IX Version 2 +information based on the DWARF format. While DWARF Version 2 provides +new debugging information not available in Version 1, the primary focus +of the changes for Version 2 is the representation of the information, +rather than the information content itself. The basic structure of +the Version 2 format remains as in Version 1: the debugging information +is represented as a series of debugging information entries, each containing +one or more attributes (name/value pairs). +.IX debugging information entries +.IX attributes +The Version 2 representation, however, +is much more compact than the Version 1 representation. +.IX Version 1 +In some cases, this greater density has been achieved at the expense +of additional complexity or greater difficulty in producing and processing +the DWARF information. We believe that the reduction in I/O and in +memory paging should more than make up for any increase in processing time. +.P +Because the representation of information has changed from Version 1 to +Version 2, Version 2 DWARF information is not binary compatible +.IX compatibility +with Version 1 information. To make it easier for consumers to +support both Version 1 and Version 2 DWARF information, the Version +2 information has been moved to a different object file section, +.Cf .debug_info . +.IX \f(CW.debug_info\fP %debugai +.P +The intended audience for this document are the developers of +both producers and consumers of debugging information, typically +language compilers, debuggers and other tools that need to interpret +a binary program in terms of its original source. +.H 2 "Overview" +There are two major pieces to the description of the DWARF format in +this document. The first piece is the informational content +of the debugging entries. The second piece +is the way the debugging information is encoded and +represented in an object file. +.P +The informational content is described in sections two +through six. +Section two describes the overall structure of +the information and attributes that are common to many or all of +the different debugging information entries. +Sections three, four and five describe the specific debugging +information entries and how they communicate the +necessary information about the source program to a debugger. +Section six describes debugging information contained +outside of the debugging information entries, themselves. +The encoding of the DWARF information is +presented in section seven. +.P +Section eight describes some future directions for the DWARF +specification. +.P +In the following sections, text in normal font describes required aspects +of the DWARF format. Text in \fIitalics\fP is explanatory or supplementary +material, and not part of the format definition itself. +.H 2 "Vendor Extensibility" +.IX vendor extensions +This document does not attempt to cover all interesting languages or even +to cover all of the interesting debugging information needs for its primary +target languages (C, C++, FORTRAN77, Fortran90, Modula2, Pascal). +Therefore the document provides +vendors a way to define their own debugging information tags, attributes, +base type encodings, location operations, language names, +calling conventions and call frame instructions +by reserving a portion of the name space and valid values +for these constructs for vendor specific additions. Future versions +of this document will not use names or values reserved for vendor specific +additions. All names and values not reserved for vendor additions, however, +are reserved for future versions of this document. See section 7 for +details. +.H 2 "Changes from Version 1" +The following is a list of the major changes made to the DWARF Debugging +Information Format since Version 1 of the format was published (January +.IX Version 1 +20, 1992). The list is not meant to be exhaustive. +.BL +.LI +Debugging information entries have been moved from the +.Cf .debug +.IX \f(CW.debug\fP %debugaaa +to the +.Cf .debug_info +.IX \f(CW.debug_info\fP %debugai +section of an object file. +.LI +.IX tags +.IX attributes, names +.IX attributes, forms +The tag, attribute names and attribute forms encodings have been moved +out of the debugging information itself to a separate abbreviations table. +.IX abbreviations table +.LI +Explicit sibling pointers have been made optional. Each +.IX debugging information entries, siblings +entry now specifies (through the abbreviations table) whether +or not it has children. +.IX debugging information entries, child entries +.LI +New more compact attribute forms have been added, including a variable +length constant data form. Attribute values may now have any +.IX variable length data +.IX attributes, forms +.IX attributes, values +form within a given class of forms. +.LI +Location descriptions have been replaced by a new, more compact +and more expressive format. +.IX locations, descriptions +There is now a way of expressing multiple locations for an object +whose location changes during its lifetime. +.IX locations, lists +.LI +There is a new format for line number information +that provides information +for code contributed to a compilation unit from an included file. +Line number information is now in the +.IX line number information +.Cf .debug_line +.IX \f(CW.debug_line\fP %debugali +section of an object file. +.LI +The representation of the type of a declaration has been +reworked. +.IX declarations, types of +.LI +A new section provides an encoding for pre-processor macro information. +.IX macro information +.IX pre-processor +.LI +Debugging information entries now provide for the representation +of non-defining declarations of objects, functions or types. +.IX declarations, non-defining +.LI +More complete support for Modula2 and Pascal has been added. +.LI +There is now a way of describing locations for segmented address spaces. +.IX segmented address space +.IX address space, segmented +.LI +A new section provides an encoding for information about call +frame activations. +.IX call frame information +.IX activations +.LI +The representation of enumeration and array types has been +.IX enumerations +.IX arrays +reworked so that DWARF presents only a single way of +representing lists of items. +.LI +Support has been added for C++ templates and exceptions. +.IX C++ %caa +.IX templates +.IX exceptions +.LE +.OP +.H 1 "GENERAL DESCRIPTION" +.H 2 "The Debugging Information Entry" +DWARF uses a series of debugging information entries to define a +.IX debugging information entries +low-level representation of a source program. Each debugging +information entry is described by an identifying tag and +contains a series of attributes. +The tag specifies the class to which an entry +belongs, and the attributes define the specific characteristics +of the entry. +.P +.nr aX \n(Fg+1 +The set of required tag names is listed in Figure \n(aX. +.IX tags +The debugging information entries they identify are described in sections three, four and five. +.P +The debugging information entries in DWARF Version 2 are intended +to exist in the +.Cf .debug_info +section of an object file. +.IX \f(CW.debug_info\fP %debugai +.DF +.TS +center box; +lf(CW) lf(CW) +. +DW_TAG_access_declaration DW_TAG_array_type +DW_TAG_base_type DW_TAG_catch_block +DW_TAG_class_type DW_TAG_common_block +DW_TAG_common_inclusion DW_TAG_compile_unit +DW_TAG_const_type DW_TAG_constant +DW_TAG_entry_point DW_TAG_enumeration_type +DW_TAG_enumerator DW_TAG_file_type +DW_TAG_formal_parameter DW_TAG_friend +DW_TAG_imported_declaration DW_TAG_inheritance +DW_TAG_inlined_subroutine DW_TAG_label +DW_TAG_lexical_block DW_TAG_member +DW_TAG_module DW_TAG_namelist +DW_TAG_namelist_item DW_TAG_packed_type +DW_TAG_pointer_type DW_TAG_ptr_to_member_type +DW_TAG_reference_type DW_TAG_set_type +DW_TAG_string_type DW_TAG_structure_type +DW_TAG_subprogram DW_TAG_subrange_type +DW_TAG_subroutine_type DW_TAG_template_type_param +DW_TAG_template_value_param DW_TAG_thrown_type +DW_TAG_try_block DW_TAG_typedef +DW_TAG_union_type DW_TAG_unspecified_parameters +DW_TAG_variable DW_TAG_variant +DW_TAG_variant_part DW_TAG_volatile_type +DW_TAG_with_stmt +.TE +.FG "Tag names" +.DE +.H 2 "Attribute Types" +Each attribute value is characterized by an attribute name. +.IX attributes +.IX attributes, names +The set of attribute names is +.nr aX \n(Fg+1 +listed in Figure \n(aX. +.DF +.TS +center box; +lf(CW) lf(CW) +. +DW_AT_abstract_origin DW_AT_accessibility +DW_AT_address_class DW_AT_artificial +DW_AT_base_types DW_AT_bit_offset +DW_AT_bit_size DW_AT_byte_size +DW_AT_calling_convention DW_AT_common_reference +DW_AT_comp_dir DW_AT_const_value +DW_AT_containing_type DW_AT_count +DW_AT_data_member_location DW_AT_decl_column +DW_AT_decl_file DW_AT_decl_line +DW_AT_declaration DW_AT_default_value +DW_AT_discr DW_AT_discr_list +DW_AT_discr_value DW_AT_encoding +DW_AT_external DW_AT_frame_base +DW_AT_friend DW_AT_high_pc +DW_AT_identifier_case DW_AT_import +DW_AT_inline DW_AT_is_optional +DW_AT_language DW_AT_location +DW_AT_low_pc DW_AT_lower_bound +DW_AT_macro_info DW_AT_name +DW_AT_namelist_item DW_AT_ordering +DW_AT_priority DW_AT_producer +DW_AT_prototyped DW_AT_return_addr +DW_AT_segment DW_AT_sibling +DW_AT_specification DW_AT_start_scope +DW_AT_static_link DW_AT_stmt_list +DW_AT_stride_size DW_AT_string_length +DW_AT_type DW_AT_upper_bound +DW_AT_use_location DW_AT_variable_parameter +DW_AT_virtuality DW_AT_visibility +DW_AT_vtable_elem_location +.TE +.FG "Attribute names" +.DE +.P +The permissible values for an attribute belong to one or more classes +.IX attributes, values +.IX attributes, forms +of attribute value forms. Each form class may be represented in one or more +ways. For instance, some attribute values consist of a single piece +of constant data. ``Constant data'' is the class of attribute value +that those attributes may have. There are several representations +of constant data, however (one, two, four, eight bytes and variable +length data). The particular representation for any given instance +of an attribute is encoded along with the attribute name as part +of the information that guides the interpretation of a debugging +information entry. Attribute value forms may belong +to one of the following classes. +.VL 18 +.LI address +.IX attributes, addresses +Refers to some location in the address space of the described program. +.LI block +.IX attributes, blocks +An arbitrary number of uninterpreted bytes of data. +.LI constant +.IX attributes, constants +One, two, four or eight bytes of uninterpreted data, or data encoded +in the variable length format known as LEB128 (see section 7.6). +.IX variable length data +.IX LEB128 +.LI flag +.IX attributes, flags +A small constant that indicates the presence or absence of an attribute. +.LI reference +.IX attributes, references +Refers to some member of the set of debugging information entries that describe +the program. There are two types of reference. The first is an +offset relative to the beginning of the compilation unit in +which the reference occurs and must refer to an entry within +that same compilation unit. The second type of reference +is the address of any debugging information entry within +the same executable or shared object; it may refer to an entry +in a different compilation unit from the unit containing the +reference. +.LI string +.IX attributes, strings +A null-terminated sequence of zero or more (non-null) bytes. +Data in this form are generally printable strings. Strings +may be represented directly in the debugging information entry +or as an offset in a separate string table. +.LE +.P +There are no limitations on the ordering of attributes within a debugging +.IX attributes, ordering +information entry, but to prevent ambiguity, +no more than one attribute with a given name may appear in any debugging +information entry. +.H 2 "Relationship of Debugging Information Entries" +.I +A variety of needs can be met by permitting a single debugging +information entry to ``own'' an arbitrary number of other debugging +entries and by permitting the same debugging information entry to be +one of many owned by another debugging information entry. +This makes it possible to describe, for example, +the static block structure within +a source file, show the members of a structure, union, or class, and associate +declarations with source files or source files with shared objects. +.P +.R +The ownership relation +of debugging information entries is achieved naturally +.IX debugging information entries +because the debugging information is represented as a tree. +The nodes of the tree are the debugging information entries +themselves. The child entries of any node are exactly those +.IX debugging information entries, child entries +debugging information entries owned by that node.\*F +.FS +While the ownership relation of the debugging information +entries is represented as a tree, other relations among +the entries exist, for example, a pointer from an entry +representing a variable to another entry representing +the type of that variable. If all such relations are +taken into account, the debugging entries form a graph, +not a tree. +.FE +.P +The tree itself is represented by flattening it in prefix +order. Each debugging information entry +is defined either to have child entries or not to have child entries +(see section 7.5.3). +If an entry is defined not to have children, the next physically +succeeding entry is the sibling of the prior entry. If an entry +.IX debugging information entries, siblings +is defined to have children, the next physically succeeding entry +is the first child of the prior entry. Additional children of the parent +entry are represented as siblings of the first child. A chain +of sibling entries is terminated by a null entry. +.IX debugging information entries, null entries +.P +In cases where a producer of debugging information +feels that it will be important for consumers of that information +to quickly scan chains of sibling entries, ignoring the children +of individual siblings, that producer may attach an +.Cf AT_sibling +attribute to any debugging information entry. The value of +this attribute is a reference to the sibling entry of the +entry to which the attribute is attached. +.H 2 "Location Descriptions" +.I +The debugging information must provide consumers a way to find the location +of program variables, determine the bounds of dynamic arrays and strings +and possibly to find the base address of a subroutine's stack frame or +the return address of a subroutine. Furthermore, to meet the needs +of recent computer architectures and optimization techniques, the debugging +information must be able to describe the location of an object +whose location changes over the object's lifetime. +.P +.R +Information about the location of program objects is provided by +location descriptions. Location +.IX locations, descriptions +descriptions can be either of two forms: +.AL +.LI +\fILocation expressions\fP which are a language independent representation of +addressing rules +.IX locations, expressions +of arbitrary complexity built from a few basic +building blocks, or \fIoperations\fP. They are sufficient for describing +the location of any object as long as its lifetime is either static +or the same as the lexical block that owns it, and it does not move throughout +its lifetime. +.LI +\fILocation lists\fP which are used to describe objects that +.IX locations, lists +have a limited lifetime or change their location throughout their +lifetime. Location lists are more completely described below. +.LE +.P +The two forms are distinguished in a context sensitive manner. As the value +of an attribute, a location expression is +encoded as a block and a location list is encoded as a constant offset into +a location list table. +.P +.I +Note: The Version 1 concept of "location descriptions" was replaced in Version 2 +with this new abstraction because it is denser and more descriptive. +.IX Version 1 +.IX Version 2 +.R +.H 3 "Location Expressions" +A location expression consists of zero or more location operations. +.IX locations, expressions +An expression with zero operations +is used to denote an object that is +present in the source code but not present in the object code +(perhaps because of optimization). +.IX optimized code +The location operations fall into two categories, register names and +addressing operations. Register names always appear alone and indicate +that the referred object is contained inside a particular +register. Addressing operations are memory address computation +rules. All location operations are encoded as a stream of opcodes that +are each followed by zero or more literal operands. The number of operands +is determined by the opcode. +.H 3 "Register Name Operators" +.IX locations, register name operators +The following operations can be used to name a register. +.P +.I +Note that the +register number represents a DWARF specific mapping of numbers onto +the actual registers of a given architecture. +The mapping should be chosen to gain optimal density and +should be shared by all users of a given architecture. +The \*(tE recommends +that this mapping be defined by the ABI\*F +.IX ABI +.FS +\fISystem V Application Binary Interface\fP, consisting of the generic +interface and processor supplements for each target architecture. +.FE +authoring committee for each +architecture. +.R +.AL +.LI +.Cf DW_OP_reg0 , " DW_OP_reg1" ", ..., " DW_OP_reg31 +.br +The +\f(CWDW_OP_reg\fP\fIn\fP +operations encode the names of up to 32 registers, numbered from +0 through 31, inclusive. The object addressed is in register \fIn\fP. +.LI +.Cf DW_OP_regx +.br +The +.Cf DW_OP_regx +operation has a single unsigned LEB128 literal operand that encodes the +name of a register. +.LE +.H 3 "Addressing Operations" +.IX locations, stack +Each addressing operation represents a postfix operation on a simple stack +machine. Each element of the stack is the size of an +address on the target machine. +The value on the top of the stack after +``executing'' the location expression is taken to be the result (the address +of the object, or the value of the array bound, or the length of a +dynamic string). In the case of locations used for structure members, +.IX members, locations +the computation assumes that the base address of the containing structure +has been pushed on the stack before evaluation of the addressing operation. +.R +.H 4 "Literal Encodings" +.IX locations, literal encodings +The following operations all push a value onto the addressing stack. +.AL +.LI +.Cf DW_OP_lit0 , " DW_OP_lit1" ", ..., " DW_OP_lit31 +.br +The +\f(CWDW_OP_lit\fP\fIn\fP operations encode the unsigned +literal values from 0 through 31, inclusive. +.LI +.Cf DW_OP_addr +.br +The +.Cf DW_OP_addr +operation has a single operand that encodes a +machine address and whose size is the size of an address on the +target machine. +.LI +.Cf DW_OP_const1u +.br +The single operand of the +.Cf DW_OP_const1u +operation provides a 1-byte unsigned integer constant. +.LI +.Cf DW_OP_const1s +.br +The single operand of the +.Cf DW_OP_const1s +operation provides a +1-byte signed integer constant. +.LI +.Cf DW_OP_const2u +.br +The single operand of the +.Cf DW_OP_const2u +operation provides a +2-byte unsigned integer constant. +.LI +.Cf DW_OP_const2s +.br +The single operand of the +.Cf DW_OP_const2s +operation provides a +2-byte signed integer constant. +.LI +.Cf DW_OP_const4u +.br +The single operand of the +.Cf DW_OP_const4u +operation provides a +4-byte unsigned integer constant. +.LI +.Cf DW_OP_const4s +.br +The single operand of the +.Cf DW_OP_const4s +operation provides a +4-byte signed integer constant. +.LI +.Cf DW_OP_const8u +.br +The single operand of the +.Cf DW_OP_const8u +operation provides an +8-byte unsigned integer constant. +.LI +.Cf DW_OP_const8s +.br +The single operand of the +.Cf DW_OP_const8s +operation provides an +8-byte signed integer constant. +.LI +.Cf DW_OP_constu +.br +The single operand of the +.Cf DW_OP_constu +operation provides an +unsigned LEB128 integer constant. +.LI +.Cf DW_OP_consts +.br +The single operand of the +.Cf DW_OP_consts +operation provides a +signed LEB128 integer constant. +.LE +.H 4 "Register Based Addressing" +.IX locations, register based addressing +The following operations push a value onto the stack that +is the result of adding the contents of a register with +a given signed offset. +.AL +.LI +.Cf DW_OP_fbreg +.br +The +\f(CWDW_OP_fbreg\fP +operation provides a signed LEB128 offset from the address specified +by the location descriptor in the +.Cf DW_AT_frame_base +attribute of the current +.IX subroutines, frame base +function. \fI(This is typically a "stack pointer" register +plus or minus some +offset. On more sophisticated systems it might be a location list that +adjusts the offset according to changes in the stack pointer as +the PC changes.)\fP +.LI +.Cf DW_OP_breg0 , " DW_OP_breg1" ", ..., " DW_OP_breg31 +.br +The single operand of the +\f(CWDW_OP_breg\fP\fIn\fP +operations provides a signed LEB128 offset from the specified register. +.LI +.Cf DW_OP_bregx +.br +The +.Cf DW_OP_bregx +operation has two operands: a signed LEB128 offset from the specified register +which is defined with an unsigned LEB128 number. +.LE +.H 4 "Stack Operations" +.IX locations, stack +The following operations +manipulate the ``location stack.'' +Location operations that index the location stack assume that +the top of the stack (most recently added entry) has index 0. +.AL +.LI +.Cf DW_OP_dup +.br +The +.Cf DW_OP_dup +operation duplicates the value at the top of the location stack. +.LI +.Cf DW_OP_drop +.br +The +.Cf DW_OP_drop +operation pops the value at the top of the stack. +.LI +.Cf DW_OP_pick +.br +The single operand of the +.Cf DW_OP_pick +operation provides a 1-byte index. The stack entry with the specified index +(0 through 255, inclusive) is pushed on the stack. +.LI +.Cf DW_OP_over +.br +The +.Cf DW_OP_over +operation duplicates the entry currently second in the stack +at the top of the stack. This is equivalent to an +.Cf DW_OP_pick +operation, with index 1. +.LI +.Cf DW_OP_swap +.br +The +.Cf DW_OP_swap +operation swaps the top two stack entries. The entry at +the top of the stack becomes the second stack entry, and +the second entry becomes the top of the stack. +.LI +.Cf DW_OP_rot +.br +The +.Cf DW_OP_rot +operation rotates the first three stack entries. The entry at +the top of the stack becomes the third stack entry, the second entry +becomes the top of the stack, and the third entry becomes the second +entry. +.LI +.Cf DW_OP_deref +.br +The +.Cf DW_OP_deref +operation pops the top stack entry and treats it as an address. +The value retrieved from that address is pushed. The size of the +data retrieved from the dereferenced address is the size of an address +on the target machine. +.LI +.Cf DW_OP_deref_size +.br +The +.Cf DW_OP_deref_size +operation behaves like the +.Cf DW_OP_deref +operation: it +pops the top stack entry and treats it as an address. +The value retrieved from that address is pushed. +In the +.Cf DW_OP_deref_size +operation, however, +the size in bytes of the +data retrieved from the dereferenced address is specified by the +single operand. This operand is a 1-byte unsigned integral constant +whose value may not be larger than the size of an address on +the target machine. The data retrieved is zero extended to the size +of an address on the target machine before being pushed on +the expression stack. +.LI +.Cf DW_OP_xderef +.br +The +.Cf DW_OP_xderef +.IX address space, multiple +operation provides an extended dereference mechanism. The entry at the +top of the stack is treated as an address. The second stack entry +is treated as an ``address space identifier'' for those architectures +that support multiple address spaces. The top two stack elements +are popped, a data item is retrieved through an implementation-defined +address calculation and pushed as the new stack top. The size of the +data retrieved from the dereferenced address is the size of an address +on the target machine. +.LI +.Cf DW_OP_xderef_size +.br +The +.Cf DW_OP_xderef_size +operation behaves like the +.Cf DW_OP_xderef +operation: the entry at the +top of the stack is treated as an address. The second stack entry +is treated as an ``address space identifier'' for those architectures +that support multiple address spaces. The top two stack elements +are popped, a data item is retrieved through an implementation-defined +address calculation and pushed as the new stack top. +In the +.Cf DW_OP_xderef_size +operation, however, +the size in bytes of the +data retrieved from the dereferenced address is specified by the +single operand. This operand is a 1-byte unsigned integral constant +whose value may not be larger than the size of an address on +the target machine. The data retrieved is zero extended to the size +of an address on the target machine before being pushed on +the expression stack. +.LE +.H 4 "Arithmetic and Logical Operations" +.IX locations, arithmetic operations +.IX locations, logical operations +The following provide arithmetic and logical operations. +The arithmetic operations perform ``addressing arithmetic,'' +that is, unsigned arithmetic that wraps on an address-sized +boundary. The operations do not cause an exception on overflow. +.AL +.LI +.Cf DW_OP_abs +.br +The +.Cf DW_OP_abs +operation pops the top stack entry and pushes its absolute value. +.LI +.Cf DW_OP_and +.br +The +.Cf DW_OP_and +operation pops the top two stack values, performs a bitwise \fIand\fP +operation on the two, and pushes the result. +.LI +.Cf DW_OP_div +.br +The +.Cf DW_OP_div +operation pops the top two stack values, divides the former second entry +by the former top of the stack +using signed division, +and pushes the result. +.LI +.Cf DW_OP_minus +.br +The +.Cf DW_OP_minus +operation pops the top two stack values, subtracts the former top of the stack +from the former second entry, and pushes the result. +.LI +.Cf DW_OP_mod +.br +The +.Cf DW_OP_mod +operation pops the top two stack values and pushes the result of the +calculation: former second stack entry modulo the former top of the +stack. +.LI +.Cf DW_OP_mul +.br +The +.Cf DW_OP_mul +operation pops the top two stack entries, multiplies them together, +and pushes the result. +.LI +.Cf DW_OP_neg +.br +The +.Cf DW_OP_neg +operation pops the top stack entry, and pushes its negation. +.LI +.Cf DW_OP_not +.br +The +.Cf DW_OP_not +operation pops the top stack entry, and pushes its bitwise complement. +.LI +.Cf DW_OP_or +.br +The +.Cf DW_OP_or +operation pops the top two stack entries, performs a bitwise \fIor\fP +operation on the two, and pushes the result. +.LI +.Cf DW_OP_plus +.br +The +.Cf DW_OP_plus +operation pops the top two stack entries, adds them together, +and pushes the result. +.LI +.Cf DW_OP_plus_uconst +.br +The +.Cf DW_OP_plus_uconst +operation pops the top stack entry, adds it to the unsigned LEB128 +constant operand and pushes the result. +.I +This operation is supplied specifically to be able to encode more field +offsets in two bytes than can be done with "\f(CWDW_OP_lit\fP\fIn\fP\f(CW DW_OP_add\fP". +.R +.LI +.Cf DW_OP_shl +.br +The +.Cf DW_OP_shl +operation pops the top two stack entries, shifts the former second +entry left by the number of bits specified by the former top of +the stack, and pushes the result. +.LI +.Cf DW_OP_shr +.br +The +.Cf DW_OP_shr +operation pops the top two stack entries, shifts the former second +entry right (logically) by the number of bits specified by the former top of +the stack, and pushes the result. +.LI +.Cf DW_OP_shra +.br +The +.Cf DW_OP_shra +operation pops the top two stack entries, shifts the former second +entry right (arithmetically) by the number of bits specified by the former top of +the stack, and pushes the result. +.LI +.Cf DW_OP_xor +.br +The +.Cf DW_OP_xor +operation pops the top two stack entries, performs the logical +\fIexclusive-or\fP operation on the two, and pushes the result. +.LE +.H 4 "Control Flow Operations" +.IX locations, control flow operations +The following operations provide simple control of the flow of a location +expression. +.AL +.LI +Relational operators +.br +The six relational operators each pops the top two stack values, +compares the former top of the stack with the former second entry, +and pushes the constant value 1 onto the stack if the result of the +operation is true or the constant value 0 if the result of the operation +is false. The comparisons are done as signed operations. The six +operators are +.Cf DW_OP_le +(less than or equal to), +.Cf DW_OP_ge +(greater than or equal to), +.Cf DW_OP_eq +(equal to), +.Cf DW_OP_lt +(less than), +.Cf DW_OP_gt +(greater than) and +.Cf DW_OP_ne +(not equal to). +.LI +.Cf DW_OP_skip +.br +.Cf DW_OP_skip +is an unconditional branch. Its +single operand is a 2-byte signed integer constant. +The 2-byte constant is the number of bytes of the location +expression to skip from the current operation, beginning after the +2-byte constant. +.LI +.Cf DW_OP_bra +.br +.Cf DW_OP_bra +is a conditional branch. Its +single operand is a 2-byte signed integer constant. +This operation pops the top of stack. If the value +popped is not the constant 0, the 2-byte constant operand is the number +of bytes of the location +expression to skip from the current operation, beginning after the +2-byte constant. +.LE +.H 4 "Special Operations" +.IX locations, special operations +There are two special operations currently defined: +.AL +.LI +.Cf DW_OP_piece +.br +.I +Many compilers store a single variable in sets of registers, or store +a variable partially in memory and partially in registers. +.Cf DW_OP_piece +provides a way of describing how large a part of a variable +a particular addressing expression refers to. +.R +.P +.Cf DW_OP_piece +takes a single argument which is an unsigned LEB128 number. The number +describes the size in bytes of the piece of the object referenced +by the addressing expression whose result is at the top of +the stack. +.LI +.Cf DW_OP_nop +.br +The +.Cf DW_OP_nop +operation is a place holder. It has no effect on the location stack or +any of its values. +.LE +.H 3 "Sample Stack Operations" +.IX locations, examples +.I +The stack operations defined in section 2.4.3.3 are fairly +.IX locations, stack +conventional, but the following examples illustrate their behavior +graphically. +.R +.DS +.TS +box expand center tab(;); +l s l l s +lf(CW) lf(CW) lf(CW) lf(CW) lf(CW) +. +Before;Operation;After; +_ +0;17;DW_OP_dup;0;17 +1;29;;1;17 +2;1000;;2;29 +;;;3;1000 +_ +0;17;DW_OP_drop;0;29 +1;29;;1;1000 +2;1000;;;; +_ +0;17;DW_OP_pick 2;0;1000 +1;29;;1;17 +2;1000;;2;29 +;;;3;1000 +_ +0;17;DW_OP_over;0;29 +1;29;;1;17 +2;1000;;2;29 +;;;3;1000 +_ +0;17;DW_OP_swap;0;29 +1;29;;1;17 +2;1000;;2;1000 +_ +0;17;DW_OP_rot;0;29 +1;29;;1;1000 +2;1000;;2;17 +.TE +.DE +.H 3 "Example Location Expressions" +.I +.IX locations, examples +The addressing expression represented by a location expression, +if evaluated, generates the +runtime address of the value of a symbol except where the +.Cf DW_OP_reg n, +or +.Cf DW_OP_regx +operations are used. +.P +Here are some examples of how location operations are used to form location +expressions: +.R +.DS +\f(CWDW_OP_reg3\fI + The value is in register 3. + +\f(CWDW_OP_regx 54\fI + The value is in register 54. + +\f(CWDW_OP_addr 0x80d0045c\fI + The value of a static variable is + at machine address 0x80d0045c. + +\f(CWDW_OP_breg11 44\fI + Add 44 to the value in + register 11 to get the address of an + automatic variable instance. + +\f(CWDW_OP_fbreg -50\fI + Given an \f(CWDW_AT_frame_base\fI value of + "\f(CWOPBREG31 64\fI," this example + computes the address of a local variable + that is -50 bytes from a logical frame + pointer that is computed by adding + 64 to the current stack pointer (register 31). + +\f(CWDW_OP_bregx 54 32 DW_OP_deref\fI + A call-by-reference parameter + whose address is in the + word 32 bytes from where register + 54 points. + +\f(CWDW_OP_plus_uconst 4\fI + A structure member is four bytes + from the start of the structure + instance. The base address is + assumed to be already on the stack. + +\f(CWDW_OP_reg3 DW_OP_piece 4 DW_OP_reg10 DW_OP_piece 2\fI + A variable whose first four bytes reside + in register 3 and whose next two bytes + reside in register 10.\fR +.DE +.H 3 "Location Lists" +.IX locations, lists +Location lists are used in place of location expressions whenever +the object whose location is being described can change location +during its lifetime. Location lists are contained in a separate +object file section called +.Cf .debug_loc. +.IX \f(CW.debug_loc\fP %debugalo +A location list is indicated by a location +attribute whose value is represented as a +constant offset from the beginning of the +.Cf .debug_loc +section to the first byte of the list for the object in question. +.P +Each entry in a location list consists of: +.AL +.LI +A beginning address. This address is relative to the base address +of the compilation unit referencing this location list. It marks +the beginning of the address range over which the location is valid. +.LI +An ending address, again relative to the base address +of the compilation unit referencing this location list. It marks +the first address past the end of the address range over +which the location is valid. +.LI +A location expression describing the location of the object over the +range specified by the beginning and end addresses. +.LE +.P +Address ranges may overlap. When they do, they describe a situation +in which an object exists simultaneously in more than one place. +If all of the address ranges +in a given location list do not collectively cover the entire +range over which the object in question is defined, it is assumed +that the object is not available for the portion of the range that is not +covered. +.IX optimized code +.P +The end of any given location list is marked by a 0 for the beginning +address and a 0 for the end address; no location description is present. +A location list containing +only such a 0 entry describes an object that exists in the source +code but not in the executable program. +.H 2 "Types of Declarations" +.IX declarations, types of +Any debugging information entry describing a declaration that +has a type has a +.Cf DW_AT_type +attribute, whose value is a reference to another debugging +information entry. The entry referenced may describe +.IX base types +.IX types, base +a base type, that is, a type that is not defined in terms +.IX user-defined types +.IX types, user-defined +of other data types, or it may describe a user-defined type, +such as an array, structure or enumeration. Alternatively, +the entry referenced may describe a type modifier: constant, +packed, pointer, reference or volatile, which in turn will reference +another entry describing a type or type modifier (using a +.IX type modifiers +.IX types, modifiers +.IX types, packed +.IX types, constant +.IX types, pointer +.IX types, reference +.IX types, volatile +.Cf DW_AT_type +attribute of its own). See section 5 for descriptions of +the entries describing base types, user-defined types and +type modifiers. +.H 2 "Accessibility of Declarations" +.I +.IX accessibility +.IX declarations, accessibility +Some languages, notably C++ and Ada, have the concept of +.IX C++ %caa +the accessibility of an object or of some other program entity. +The accessibility specifies which classes of other program objects +are permitted access to the object in question. +.R +.P +The accessibility of a declaration is represented by a +.Cf DW_AT_accessibility +attribute, whose value is a constant drawn from the set of codes +.nr aX \n(Fg+1 +listed in Figure \n(aX. +.DF +.TS +box center; +lf(CW) +. +DW_ACCESS_public +DW_ACCESS_private +DW_ACCESS_protected +.TE +.FG "Accessibility codes" +.DE +.H 2 "Visibility of Declarations" +.I +.IX Modula2 +.IX visibility +.IX declarations, visibility +Modula2 has the concept of the visibility of a declaration. +The visibility specifies which declarations are to be visible outside +of the module in which they are declared. +.R +.P +The visibility of a declaration is represented by a +.Cf DW_AT_visibility +attribute, whose value is a constant drawn from the set of codes +.nr aX \n(Fg+1 +listed in Figure \n(aX. +.DF +.TS +box center; +lf(CW) +. +DW_VIS_local +DW_VIS_exported +DW_VIS_qualified +.TE +.FG "Visibility codes" +.DE +.H 2 "Virtuality of Declarations" +.I +.IX C++ %caa +.IX virtuality +.IX virtual functions +C++ provides for virtual and pure virtual structure or class +member functions and for virtual base classes. +.P +.R +The virtuality of a declaration is represented by a +.Cf DW_AT_virtuality +attribute, whose value is a constant drawn from the set of codes +.nr aX \n(Fg+1 +listed in Figure \n(aX. +.DF +.TS +box center; +lf(CW) +. +DW_VIRTUALITY_none +DW_VIRTUALITY_virtual +DW_VIRTUALITY_pure_virtual +.TE +.FG "Virtuality codes" +.DE +.H 2 "Artificial Entries" +.I +.IX artificial entries +A compiler may wish to generate debugging information entries +for objects or types that were not actually declared +in the source of the application. An example is a formal parameter +entry to represent the hidden +.Cf this +parameter that most C++ implementations pass as the first argument +to non-static member functions. +.R +.P +Any debugging information entry representing the declaration of an +object or type artificially generated by a compiler and +not explicitly declared by the source program may have a +.Cf DW_AT_artificial +attribute. The value of this attribute is a flag. +.H 2 "Target-Specific Addressing Information" +.I +.IX segmented address space +.IX address space, segmented +In some systems, addresses are specified as offsets within a given +segment rather than as locations within a single flat address space. +.R +.P +Any debugging information entry that contains a description of the +location of an object or subroutine may have a +.Cf DW_AT_segment +attribute, whose value is a location description. The description +evaluates to the segment value of the item being described. If +the entry containing the +.Cf DW_AT_segment +attribute has a +.Cf DW_AT_low_pc +or +.Cf DW_AT_high_pc +attribute, or a location description that evaluates to an address, +.IX locations, descriptions +.IX addresses, offset portion +then those values represent the offset portion of the address +within the segment specified by +.Cf DW_AT_segment . +.P +If an entry has no +.Cf DW_AT_segment +attribute, it inherits the segment value from its parent entry. +If none of the entries in the chain of parents for this entry +back to its containing compilation unit entry have +.Cf DW_AT_segment +attributes, then the entry is assumed to exist within a flat +address space. Similarly, if the entry has a +.IX flat address space +.IX address space, flat +.Cf DW_AT_segment +attribute containing an empty location description, that entry +is assumed to exist within a flat address space. +.P +.I +Some systems support different classes of addresses. The address +class may affect the way a pointer is dereferenced or the way +a subroutine is called. +.P +.R +Any debugging information entry representing a pointer or reference +type or a subroutine or subroutine type may have a +.IX types, pointer +.IX types, reference +.IX subroutines +.IX subroutines, types +.Cf DW_AT_address_class +.IX addresses, class +attribute, whose value is a constant. The set of permissible +values is specific to each target architecture. The value +.Cf DW_ADDR_none , +however, is common to all encodings, and means that no address class +has been specified. +.P +.I +For example, the Intel386\(tm processor might use the following +values: +.R +.DF +.TS +box center; +l l l +lf(CW) lf(CW) l +. +Name Value Meaning +_ +DW_ADDR_none 0 no class specified +DW_ADDR_near16 1 16-bit offset, no segment +DW_ADDR_far16 2 16-bit offset, 16-bit segment +DW_ADDR_huge16 3 16-bit offset, 16-bit segment +DW_ADDR_near32 4 32-bit offset, no segment +DW_ADDR_far32 5 32-bit offset, 16-bit segment +.TE +.FG "Example address class codes" +.DE +.H 2 "Non-Defining Declarations" +.IX declarations, non-defining +.IX declarations, defining +A debugging information entry representing a program object or type +typically represents the defining declaration of that object or type. In +certain contexts, however, a debugger might need information about a +declaration of a subroutine, object or type that is not also a +definition to evaluate an expression correctly. +.P +.I +As an example, consider the following fragment of C code: +.DS +\f(CWvoid myfunc() +{ + int x; + { + extern float x; + g(x); + } +}\fP +.DE +.P +ANSI-C scoping rules require that the value of the variable \f(CWx\fP +passed to the function \f(CWg\fP is the value of the global variable +\f(CWx\fP rather than of the local version. +.R +.P +Debugging information entries that represent non-defining declarations +of a program object or type have a +.Cf DW_AT_declaration +attribute, whose value is a flag. +.H 2 "Declaration Coordinates" +.I +It is sometimes useful in a debugger to be able to associate a declaration +with its occurrence in the program source. +.P +.R +.IX declarations, coordinates +Any debugging information entry representing the declaration of +an object, module, subprogram or type may have +.Cf DW_AT_decl_file , +.Cf DW_AT_decl_line +and +.Cf DW_AT_decl_column +attributes, each of whose value is a constant. +.P +The value of the +.Cf DW_AT_decl_file +attribute corresponds +to a file number from the statement information table for the compilation +.IX line number information +unit containing this debugging information entry and represents the +source file in which the declaration appeared (see section 6.2). +.IX source, files +The value 0 indicates that no source file has been specified. +.P +The value of the +.Cf DW_AT_decl_line +attribute represents the source line number at which the first +.IX source, lines +character of the identifier of the declared object appears. +The value 0 indicates that no source line has been specified. +.P +The value of the +.Cf DW_AT_decl_column +attribute represents the source column number at which the first +.IX source, columns +character of the identifier of the declared object appears. +The value 0 indicates that no column has been specified. +.H 2 "Identifier Names" +.IX identifiers, names +Any debugging information entry representing a program entity that +has been given a name may have a +.Cf DW_AT_name +attribute, whose value is a string representing the name as it appears +in the source program. A debugging information entry containing +no name attribute, or containing a name attribute whose value consists +of a name containing a single null byte, +represents a program entity for which no name was given in the source. +.I +.P +Note that since the names of program objects +described by DWARF are the names as they appear in the source program, +implementations of language translators that use some form of mangled +name (as do many implementations of C++) should use the unmangled +.IX C++ %caa +form of the name in the DWARF +.Cf DW_AT_name +attribute, including the keyword +.Cf operator , +if present. Sequences of multiple whitespace characters may be compressed. +.R +.OP +.H 1 "PROGRAM SCOPE ENTRIES" +This section describes debugging information entries that relate +to different levels of program scope: compilation unit, module, +subprogram, and so on. These entries may be thought of as +bounded by ranges of text addresses within the program. +.H 2 "Compilation Unit Entries" +An object file may be derived from one or more compilation units. Each +such compilation unit will be described by a debugging information +entry with the tag \f(CWDW_TAG_compile_unit\fP. +.I +.P +A compilation unit typically represents the text and data contributed +.IX compilation units +to an executable by a single relocatable object file. It may +be derived from several source files, including pre-processed ``include +files.'' +.R +.P +The compilation unit entry may have the following attributes: +.AL +.LI +A +.Cf DW_AT_low_pc +attribute whose value is the +relocated address of the first machine instruction generated for that +compilation unit. +.LI +A +.Cf DW_AT_high_pc +attribute whose value is the +relocated address of the first location +past the last machine instruction generated for that compilation unit. +.P +.I +The address may be beyond the last valid instruction in the executable, +of course, for this and other similar attributes. +.R +.P +The presence of low and high pc attributes in a compilation unit entry +imply that the code generated for that compilation unit is +contiguous and exists totally within the boundaries specified +by those two attributes. If that is not the case, no low +and high pc attributes should be produced. +.IX address space, contiguous +.LI +A +.Cf DW_AT_name +attribute whose value is a +null-terminated string containing the full or relative path name of +the primary source file from which the compilation unit was derived. +.IX source, files +.LI +A +.Cf DW_AT_language +attribute whose constant value is +.IX languages +a code indicating the source language of the compilation unit. +.nr aX \n(Fg+1 +The set of language names and their meanings are +given in Figure \n(aX. +.DF +.TS +box center; +lf(CW) lf(R) +. +DW_LANG_C Non-ANSI C, such as K&R +DW_LANG_C89 ISO/ANSI C +DW_LANG_C_plus_plus C++ +DW_LANG_Fortran77 FORTRAN77 +DW_LANG_Fortran90 Fortran90 +DW_LANG_Modula2 Modula2 +DW_LANG_Pascal83 ISO/ANSI Pascal +.TE +.FG "Language names" +.DE +.LI +A +.Cf DW_AT_stmt_list +attribute whose value is a reference to +line number information for this compilation unit. +.IX line number information +.P +This information is placed in a separate object file section from the debugging +information entries themselves. The value of the statement list attribute +is the offset in the \f(CW.debug_line\fP section of the first byte of the +line number information for this compilation unit. See section 6.2. +.LI +A +.Cf DW_AT_macro_info +attribute whose value is a reference to the macro information for this +compilation unit. +.IX macro information +.P +This information is placed in a separate object file section from the debugging +information entries themselves. The value of the macro information attribute +is the offset in the \f(CW.debug_macinfo\fP section of the first byte of the +macro information for this compilation unit. See section 6.3. +.LI +A +.Cf DW_AT_comp_dir +attribute whose value is a null-terminated string containing +the current working directory of the compilation command that +produced this compilation unit in whatever form makes sense +for the host system. +.P +.I +The suggested form for the value of the \f(CWDW_AT_comp_dir\fP +attribute on \*(aX systems is ``hostname\f(CW:\fPpathname''. If no +hostname is available, the suggested form is ``\f(CW:\fPpathname''. +.R +.LI +A +.Cf DW_AT_producer +attribute whose value is a null-terminated string containing information +about the compiler that produced the compilation unit. The +actual contents of the string will be specific to each producer, +but should begin with the name of the compiler vendor or some +other identifying character sequence that should avoid +confusion with other producer values. +.LI +A +.Cf DW_AT_identifier_case +.IX identifiers, case +attribute whose constant value is a code describing the treatment of +identifiers within this compilation unit. The set of identifier case +.nr aX \n(Fg+1 +codes is given in Figure \n(aX. +.DF +.TS +box center; +lf(CW) +. +DW_ID_case_sensitive +DW_ID_up_case +DW_ID_down_case +DW_ID_case_insensitive +.TE +.FG "Identifier case codes" +.DE +.P +.Cf DW_ID_case_sensitive +is the default for all compilation units that do not have this attribute. +It indicates that names given as the values of +.Cf DW_AT_name +attributes in debugging information entries for the compilation unit +reflect the names as they appear in the source program. +The debugger should be sensitive to the case of identifier names +when doing identifier lookups. +.P +.Cf DW_ID_up_case +means that the producer of the debugging information for this compilation +unit converted all source names to upper case. The values of the +name attributes may not reflect the names as they appear in the source +program. The debugger should convert all names to upper case +when doing lookups. +.P +.Cf DW_ID_down_case +means that the producer of the debugging information for this compilation +unit converted all source names to lower case. The values of the +name attributes may not reflect the names as they appear in the source +program. The debugger should convert all names to lower case when +doing lookups. +.P +.Cf DW_ID_case_insensitive +means that the values of the name attributes reflect the names +as they appear in the source program but that a case insensitive +lookup should be used to access those names. +.LI +A +.Cf DW_AT_base_types +.IX base types +.IX types, base +attribute whose value is a reference. This attribute points to +a debugging information entry representing another compilation +unit. It may be used to specify the compilation unit containing +the base type entries used by entries in the current compilation +unit (see section 5.1). +.P +.I +This attribute provides a consumer a way to find the definition +of base types for a compilation unit that does not itself +contain such definitions. This allows a consumer, for example, +to interpret a type conversion to a base type correctly. +.R +.LE +.R +.P +A compilation unit entry +owns debugging information entries that represent the declarations made in +the corresponding compilation unit. +.H 2 "Module Entries" +.I +Several languages have the concept of a ``module.'' +.IX modules +.P +.R +A module is +represented by a debugging information entry with the tag +.Cf DW_TAG_module . +Module entries may own other debugging information entries describing +program entities whose declaration scopes end at the end of the module +itself. +.P +If the module has a name, the module entry has a +.Cf DW_AT_name +attribute whose +value is a null-terminated string containing the module name as it appears +in the source program. +.P +If the module contains initialization code, the module entry +has a +.Cf DW_AT_low_pc +attribute whose value is the +relocated address of the first machine instruction generated for that +initialization code. It also has a +.Cf DW_AT_high_pc +attribute whose value is +the relocated address of the first location past the last machine +instruction generated for the initialization code. +.P +If the module has been assigned a priority, it may have a +.Cf DW_AT_priority +attribute. The value of this attribute is a reference to another +.IX modules, priority +debugging information entry describing a variable with a constant +value. The value of this variable is the actual constant +value of the module's priority, represented as it would be on the +target architecture. +.P +.I +.IX Modula2 +.IX modules, definition +A Modula2 definition module may be represented by a module entry +containing a +.Cf DW_AT_declaration +attribute. +.R +.H 2 "Subroutine and Entry Point Entries" +.IX subroutines +.IX entry points +The following tags exist to describe debugging information +entries for subroutines and entry points: +.VL 30 +.LI \f(CWDW_TAG_subprogram\fP +A global or file static subroutine or function. +.LI \f(CWDW_TAG_inlined_subroutine\fP +A particular inlined instance of a subroutine or function. +.LI \f(CWDW_TAG_entry_point\fP +A Fortran entry point. +.LE +.H 3 "General Subroutine and Entry Point Information" +The subroutine or entry point entry has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the subroutine or entry +point name as it appears in the source program. +.P +If the name of the subroutine described by an entry with the tag +.Cf DW_TAG_subprogram +is visible outside of its containing compilation unit, that +entry has a +.Cf DW_AT_external +attribute, whose value is a flag. +.IX declarations, external +.I +.P +.IX members, functions +.IX subroutines, members +Additional attributes for functions that are members of a class or +structure are described in section 5.5.5. +.P +A common debugger feature is to allow the debugger user to call a +subroutine within the subject program. In certain cases, however, +the generated code for a subroutine will not obey the standard calling +conventions for the target architecture and will therefore not +.IX calling conventions +be safe to call from within a debugger. +.R +.P +A subroutine entry may contain a +.Cf DW_AT_calling_convention +attribute, whose value is a constant. If this attribute is not +present, or its value is the constant +.Cf DW_CC_normal , +then the subroutine may be safely called by obeying the ``standard'' +calling conventions of the target architecture. If the value of +the calling convention attribute is the constant +.Cf DW_CC_nocall , +the subroutine does not obey standard calling conventions, and it +may not be safe for the debugger to call this subroutine. +.P +If the semantics of the language of the compilation unit +containing the subroutine entry distinguishes between ordinary subroutines +.IX main programs +and subroutines that can serve as the ``main program,'' that is, subroutines +that cannot be called directly following the ordinary calling conventions, +then the debugging information entry for such a subroutine may have a +calling convention attribute whose value is the constant +.Cf DW_CC_program . +.P +.I +The +.Cf DW_CC_program +value is intended to support Fortran main programs. +It is not intended as a way of finding the entry address for the program. +.R +.H 3 "Subroutine and Entry Point Return Types" +.IX subroutines, return types +.IX entry points, return types +If the subroutine or entry point is a function that returns a value, then +its debugging information entry has a +.Cf DW_AT_type +attribute to denote the type returned by that function. +.P +.I +Debugging information entries for C +.Cf void +.IX C %c +functions should not have an attribute for the return type. +.P +In ANSI-C there is a difference between the types of functions +declared using function prototype style declarations and those +declared using non-prototype declarations. +.IX subroutines, prototypes +.P +.R +A subroutine entry +declared with a function prototype style declaration may have a +.Cf DW_AT_prototyped +attribute, whose value is a flag. +.H 3 "Subroutine and Entry Point Locations" +.IX subroutines, locations +.IX entry points, locations +A subroutine entry has a +.Cf DW_AT_low_pc +attribute whose value is the relocated address of the first machine instruction +generated for the subroutine. +It also has a +.Cf DW_AT_high_pc +attribute whose value is the relocated address of the +first location past the last machine instruction generated +for the subroutine. +.P +.I +Note that for the low and high pc attributes to have meaning, DWARF +makes the assumption that the code for a single subroutine is allocated +in a single contiguous block of memory. +.IX address space, contiguous +.R +.P +An entry point has a +.Cf DW_AT_low_pc +attribute whose value is the relocated address of the first machine instruction +generated for the entry point. +.P +Subroutines and entry points may also have +.Cf DW_AT_segment +and +.Cf DW_AT_address_class +.IX segmented address space +.IX address space, segmented +.IX addresses, class +attributes, as appropriate, to specify which segments the code +for the subroutine resides in and the addressing mode to be used +in calling that subroutine. +.P +A subroutine entry representing a subroutine declaration +that is not also a definition does not have low and high pc attributes. +.IX declarations, non-defining +.H 3 "Declarations Owned by Subroutines and Entry Points" +.IX subroutines, declarations owned by +.IX entry points, declarations owned by +The declarations enclosed by a subroutine or entry point +are represented by debugging information entries that are +owned by the subroutine or entry point entry. +Entries representing the formal parameters of the subroutine or +entry point appear in +the same order as the corresponding declarations in the source program. +.IX attributes, ordering +.IX parameters, formal +.P +.I +There is no ordering requirement on entries for declarations that are +children of subroutine or entry point entries but that do not represent +formal parameters. The formal parameter entries may be interspersed +with other entries used by formal parameter entries, such as type entries. +.R +.P +The unspecified parameters of a variable parameter list +.IX parameters, unspecified +are represented by a debugging information entry with the tag +.Cf DW_TAG_unspecified_parameters . +.P +The entry for a subroutine or entry point that includes a Fortran +.IX Fortran +.IX common blocks +common block has a child entry with the tag +.Cf DW_TAG_common_inclusion . +The common inclusion entry has a +.Cf DW_AT_common_reference +attribute whose value is a reference to the debugging entry for +the common block being included (see section 4.2). +.H 3 "Low-Level Information" +A subroutine or entry point entry may have a +.Cf DW_AT_return_addr +.IX subroutines, return addresses +attribute, whose value is a location description. +The location calculated is the place where the return address for +the subroutine or entry point is stored. +.P +A subroutine or entry point entry may also have a +.Cf DW_AT_frame_base +.IX subroutines, frame base +attribute, whose value is a location description that +computes the ``frame base'' for the subroutine or entry point. +.P +.I +The frame base for a procedure is typically an address fixed +relative to the first unit of storage allocated for the procedure's +stack frame. The +.Cf DW_AT_frame_base +attribute can be used in several ways: +.AL +.LI +In procedures that need location lists to locate local variables, the +.Cf DW_AT_frame_base +can hold the needed location list, while all variables' +location descriptions can be simpler location expressions involving the frame +base. +.LI +It can be used as a key in resolving "up-level" addressing with nested +routines. (See +.Cf DW_AT_static_link , +below) +.LE +.P +Some languages support nested subroutines. In such languages, it is possible +.IX subroutines, nested +to reference the local variables of an outer subroutine from within +an inner subroutine. The +.Cf DW_AT_static_link +and +.Cf DW_AT_frame_base +attributes allow debuggers to support this same kind of referencing. +.R +.P +If a subroutine or entry point is nested, it may have a +.Cf DW_AT_static_link +attribute, whose value is a location description that +computes the frame base of the relevant instance of the subroutine +that immediately encloses the subroutine or entry point. +.P +In the context of supporting nested subroutines, the +.Cf DW_AT_frame_base +attribute value should obey the following constraints: +.AL +.LI +It should compute a value that does not change during the life of the procedure, +and +.LI +The computed value should be unique among instances of the same subroutine. +(For typical +.Cf DW_AT_frame_base +use, this means that a recursive +subroutine's stack frame must have non-zero size.) +.LE +.P +.I +If a debugger is attempting to resolve an up-level reference to a variable, it +uses the nesting structure of DWARF to determine which subroutine is the lexical +parent and the +.Cf DW_AT_static_link +value to identify the appropriate active frame +of the parent. It can then attempt to find the reference within the context +of the parent. +.R +.H 3 "Types Thrown by Exceptions" +.I +In C++ a subroutine may declare a set of types for which +.IX C++ %caa +.IX exceptions +that subroutine may generate or ``throw'' an exception. +.P +.R +If a subroutine explicitly declares that it may throw an +exception for one or more types, each such type is +represented by a debugging information entry with the tag +.Cf DW_TAG_thrown_type . +Each such entry is a child of the entry representing the +subroutine that may throw this type. All thrown type entries +should follow all entries representing the formal parameters +of the subroutine and precede all entries representing the +local variables or lexical blocks contained in the subroutine. +Each thrown type entry contains a +.Cf DW_AT_type +attribute, whose value is a reference to an entry describing +the type of the exception that may be thrown. +.H 3 "Function Template Instantiations" +.I +.IX C++ %caa +.IX templates +In C++ a function template is a generic +definition of a function that +is instantiated differently when called with values +of different types. DWARF does not represent the generic +template definition, but does represent each instantiation. +.R +.P +A template instantiation is represented by a debugging information +entry with the tag +.Cf DW_TAG_subprogram . +With three exceptions, +such an entry will contain the same attributes and have the same +types of child entries as would an entry for a subroutine +defined explicitly +using the instantiation types. The exceptions are: +.AL +.LI +Each formal parameterized type declaration appearing in the +template definition is represented by a debugging information entry +with the tag +.Cf DW_TAG_template_type_parameter . +Each such entry has a +.Cf DW_AT_name +attribute, whose value is a null-terminated +string containing the name of the formal type parameter as it +appears in the source program. The template type parameter +entry also has a +.Cf DW_AT_type +attribute describing the actual type by +which the formal is replaced for this instantiation. +All template type parameter entries should appear before +the entries describing the instantiated formal parameters +to the function. +.LI +.IX compilation units +If the compiler has generated a special compilation unit +to hold the template instantiation and that compilation unit +has a different name +from the compilation unit containing the template definition, +the name attribute for the debugging entry representing +that compilation unit should be empty or omitted. +.LI +.IX declarations, coordinates +If the subprogram entry representing the template instantiation +or any of its child entries +contain declaration coordinate attributes, those attributes +should refer to the source for the template definition, not +to any source generated artificially by the compiler for this +instantiation. +.LE +.H 3 "Inline Subroutines" +.IX subroutines, inline +A declaration or a definition of an inlinable subroutine +is represented by a debugging information entry with the tag +.Cf DW_TAG_subprogram . +The entry for a subroutine that is explicitly declared +to be available for inline expansion or that was expanded inline +implicitly by the compiler has a +.Cf DW_AT_inline +attribute whose value is a constant. The set of values +for the +.Cf DW_AT_inline +.nr aX \n(Fg+1 +attribute is given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) l +. +Name Meaning +_ +DW_INL_not_inlined Not declared inline nor inlined by the compiler +DW_INL_inlined Not declared inline but inlined by the compiler +DW_INL_declared_not_inlined Declared inline but not inlined by the compiler +DW_INL_declared_inlined Declared inline and inlined by the compiler +.TE +.FG "Inline codes" +.DE +.H 4 "Abstract Instances" +For the remainder of this discussion, +any debugging information entry that is owned (either directly or +indirectly) by a debugging information entry that contains the +.Cf DW_AT_inline +attribute will be referred to as an ``abstract instance entry.'' +Any subroutine entry that contains a +.Cf DW_AT_inline +attribute will be known as an ``abstract instance root.'' +Any set of abstract instance entries that are all children (either directly +or indirectly) of some abstract instance root, together with the root itself, +will be known as an ``abstract instance tree.'' +.P +A debugging information entry that is a member of an abstract instance +tree should not contain a +.Cf DW_AT_high_pc , +.Cf DW_AT_low_pc , +.Cf DW_AT_location , +.Cf DW_AT_return_addr , +.Cf DW_AT_start_scope , +or +.Cf DW_AT_segment +attribute. +.P +.I +It would not make sense to put these attributes +into abstract instance entries since +such entries do not represent actual (concrete) instances and thus +do not actually exist at run-time. +.P +.R +The rules for the relative location of entries belonging to abstract instance +trees are exactly +the same as for other similar types of entries that are not abstract. +Specifically, the rule that requires that an entry representing a +declaration be a direct child of the entry representing the scope of +the declaration applies equally to both abstract and +non-abstract entries. Also, the ordering rules for formal parameter entries, +member entries, and so on, all apply regardless of whether or not a given entry +is abstract. +.H 4 "Concrete Inlined Instances" +.IX subroutines, inlined +Each inline expansion of an inlinable subroutine is represented +by a debugging information entry with the tag +.Cf DW_TAG_inlined_subroutine . +Each such entry should be a direct child of the entry that represents the +scope within which the inlining occurs. +.P +Each inlined subroutine entry contains a +.Cf DW_AT_low_pc +attribute, representing the address of the first +instruction associated with the given inline +expansion. Each inlined subroutine entry also contains a +.Cf DW_AT_high_pc +attribute, representing the +address of the first location past the last instruction associated with +the inline expansion. +.P +For the remainder of this discussion, +any debugging information entry that is owned (either directly or indirectly) +by a debugging information entry with the tag +.Cf DW_TAG_inlined_subroutine +will be referred to as a ``concrete inlined instance entry.'' +Any entry that has the tag +.Cf DW_TAG_inlined_subroutine +will be known as +a ``concrete inlined instance root.'' +Any set of concrete inlined instance entries that are all children (either +directly or indirectly) of some concrete inlined instance root, together +with the root itself, will be known as a ``concrete inlined instance +tree.'' +.P +Each concrete inlined instance tree is uniquely associated with one (and +only one) abstract instance tree. +.P +.I +Note, however, that the reverse is not true. Any given abstract instance +tree may be associated with several different concrete inlined instance +trees, or may even be associated with zero concrete inlined instance +trees. +.P +.R +Also, each separate entry within a given concrete inlined instance tree is +uniquely associated with one particular entry in the associated abstract +instance tree. In other words, there is a one-to-one mapping from entries +in a given concrete inlined instance tree to the entries in the associated +abstract instance tree. +.P +.I +Note, however, that the reverse is not true. A given abstract instance +tree that is associated with a given concrete inlined instance tree +may (and quite probably will) contain more entries than the associated +concrete inlined instance tree (see below). +.R +.P +Concrete inlined instance entries do not have most of the attributes (except +for +.Cf DW_AT_low_pc , +.Cf DW_AT_high_pc , +.Cf DW_AT_location , +.Cf DW_AT_return_addr , +.Cf DW_AT_start_scope +and +.Cf DW_AT_segment ) +that such entries +would otherwise normally have. In place of these omitted attributes, +each concrete inlined instance entry has a +.Cf DW_AT_abstract_origin +attribute that +may be used to obtain the missing information (indirectly) from +the associated abstract instance entry. The value of the abstract +origin attribute is a reference to the associated abstract instance entry. +.P +For each pair of entries that are associated via a +.Cf DW_AT_abstract_origin +attribute, both members of the pair will have the same tag. So, for +example, an entry with the tag +.Cf DW_TAG_local_variable +can only be associated +with another entry that also has the tag +.Cf DW_TAG_local_variable. +The only exception to this rule is that the root of a concrete +instance tree (which must always have the tag +.Cf DW_TAG_inlined_subroutine ) +can only be associated with the root of its associated abstract +instance tree (which must have the tag +.Cf DW_TAG_subprogram ). +.P +In general, the structure and content of any given concrete +instance tree will be directly analogous to the structure and content +of its associated abstract instance tree. +There are two exceptions to this general rule however. +.AL +.LI +.IX anonymous types +No entries representing anonymous types are ever made a part +of any concrete instance inlined tree. +.LI +.IX members +No entries representing members of structure, union or class +types are ever made a part of any concrete inlined instance tree. +.LE +.P +.I +Entries that represent members and anonymous types are omitted from concrete +inlined instance trees because they would simply be redundant duplicates of +the corresponding entries in the associated abstract instance trees. If +any entry within a concrete inlined instance tree needs to refer to an +anonymous type that was declared within the scope of the +relevant inline function, the reference should simply refer to the abstract +instance entry for the given anonymous type. +.R +.P +.IX declarations, coordinates +If an entry within a concrete inlined instance tree contains +attributes describing the declaration coordinates of +that entry, +then those attributes should refer to the file, line and column +of the original declaration of the subroutine, not to the +point at which it was inlined. +.H 4 "Out-of-Line Instances of Inline Subroutines" +.IX subroutines, out-of-line +Under some conditions, compilers may need to generate concrete executable +instances of inline subroutines other than at points where those subroutines +are actually called. For the remainder of this discussion, +such concrete instances of inline subroutines will +be referred to as ``concrete out-of-line instances.'' +.P +.I +In C++, for example, taking the address of a function declared to be inline +can necessitate the generation of a concrete out-of-line +instance of the given function. +.P +.R +The DWARF representation of a concrete out-of-line instance of an inline +subroutine is essentially the same as for a concrete inlined instance of +that subroutine (as described in the preceding section). The representation +of such a concrete out-of-line instance makes use of +.Cf DW_AT_abstract_origin +attributes in exactly the same way as they are used for a concrete inlined +instance (that is, as references to corresponding entries +within the associated +abstract instance tree) and, as for concrete instance trees, the +entries for anonymous types and for all members are omitted. +.P +The differences between the DWARF representation of a concrete out-of-line +instance of a given subroutine and the representation of a concrete inlined +instance of that same subroutine are as follows: +.AL +.LI +The root entry for a concrete out-of-line instance of a given +inline subroutine has the same tag as does its associated +(abstract) inline subroutine entry (that is, it does not have the +tag +.Cf DW_TAG_inlined_subroutine ). +.LI +The root entry for a concrete out-of-line instance tree is +always directly owned by the same parent entry that +also owns the root entry of the associated abstract instance. +.LE +.H 2 "Lexical Block Entries" +.I +.IX lexical blocks +A lexical block is a bracketed sequence of source statements that may +contain any number of declarations. In some languages (C and C++) +blocks can be nested within other blocks to any depth. +.P +.R +A lexical block is represented by a debugging information entry +with the tag +.Cf DW_TAG_lexical_block . +.P +The lexical block entry has a +.Cf DW_AT_low_pc +attribute whose value is the +relocated address of the first machine instruction generated for the lexical +block. +The lexical block entry also has a +.Cf DW_AT_high_pc +attribute whose value is the +relocated address of the first location +past the last machine instruction generated for the lexical block. +.P +If a name has been given to the lexical block in the source program, +then the corresponding lexical block entry has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the name of the +lexical block as it appears in the source program. +.P +.I +This is not the +same as a C or C++ label (see below). +.R +.P +The lexical block entry owns debugging information entries that +describe the declarations within that lexical block. +There is one such debugging information entry for each local declaration +of an identifier or inner lexical block. +.H 2 "Label Entries" +.I +.IX labels +A label is a way of identifying a source statement. A labeled statement +is usually the target of one or more ``go to'' statements. +.P +.R +A label is represented by a debugging information entry +with the tag +.Cf DW_TAG_label . +The entry for a label should be owned by +the debugging information entry representing the scope within which the name +of the label could be legally referenced within the source program. +.P +The label entry has a +.Cf DW_AT_low_pc +attribute whose value is the +relocated address of the first machine instruction generated for the +statement identified by the label in the source program. +The label entry also has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the name of the +label as it appears in the source program. +.H 2 "With Statement Entries" +.I +.IX with statements +.IX Pascal +.IX Modula2 +Both Pascal and Modula support the concept of a ``with'' statement. +The with statement specifies a sequence of executable statements +within which the fields of a record variable may be referenced, unqualified +by the name of the record variable. +.P +.R +A with statement is represented by a debugging information entry with +the tag +.Cf DW_TAG_with_stmt . +A with statement entry has a +.Cf DW_AT_low_pc +attribute whose value is the relocated +address of the first machine instruction generated for the body of +the with statement. A with statement entry also has a +.Cf DW_AT_high_pc +attribute whose value is the relocated +address of the first location after the last machine instruction generated for the body of +the statement. +.P +The with statement entry has a +.Cf DW_AT_type +attribute, denoting +the type of record whose fields may be referenced without full qualification +within the body of the statement. It also has a +.Cf DW_AT_location +attribute, describing how to find the base address +of the record object referenced within the body of the with statement. +.H 2 "Try and Catch Block Entries" +.I +.IX C++ %caa +.IX exceptions +.IX try blocks +.IX catch blocks +In C++ a lexical block may be designated as a ``catch block.'' +A catch block is an exception handler that handles exceptions +thrown by an immediately preceding ``try block.'' A catch block +designates the type of the exception that it can handle. +.R +.P +A try block is represented by a debugging information entry +with the tag +.Cf DW_TAG_try_block . +A catch block is represented by a debugging information entry +with the tag +.Cf DW_TAG_catch_block . +Both try and catch block entries contain a +.Cf DW_AT_low_pc +attribute whose value is the +relocated address of the first machine instruction generated for that +block. These entries also contain a +.Cf DW_AT_high_pc +attribute whose value is the +relocated address of the first location +past the last machine instruction generated for that block. +.P +Catch block entries have at least one child entry, +an entry representing the type of exception accepted +by that catch block. This child entry will have one of the tags +.Cf DW_TAG_formal_parameter +or +.Cf DW_TAG_unspecified_parameters , +.IX parameters, formal +.IX parameters, unspecified +and will have the same form as other parameter entries. +.P +The first sibling of each try block entry will be a catch block +entry. +.OP +.H 1 "DATA OBJECT AND OBJECT LIST ENTRIES" +This section presents the debugging information entries that +describe individual data objects: variables, parameters and +constants, and lists of those objects that may be grouped +in a single declaration, such as a common block. +.H 2 "Data Object Entries" +.IX variables +.IX parameters, formal +.IX constants +Program variables, formal parameters and constants are represented +by debugging information entries with the tags +.Cf DW_TAG_variable , +.Cf DW_TAG_formal_parameter +and +.Cf DW_TAG_constant , +respectively. +.P +.I +The tag +.Cf DW_TAG_constant +is used for languages that distinguish between variables +that may have constant value and true named constants. +.R +.P +The debugging information entry for a program variable, formal +parameter or constant may have the following attributes: +.AL +.LI +A +.Cf DW_AT_name +attribute whose value is a null-terminated +string containing the data object name as it appears in the source program. +.P +.IX anonymous unions +.IX unions, anonymous +.IX C++ %caa +If a variable entry describes a C++ anonymous union, the name +attribute is omitted or consists of a single zero byte. +.LI +If the name of a variable is visible outside of its enclosing +compilation unit, the variable entry has a +.Cf DW_AT_external +.IX declarations, external +attribute, whose value is a flag. +.I +.P +.IX members, static data +The definitions of C++ static data members +of structures or classes are represented by variable entries flagged +as external. +.IX C %c +.IX C++ %caa +Both file static and local variables in C and C++ are represented +by non-external variable entries. +.R +.LI +A +.Cf DW_AT_location +attribute, whose value describes the location of a variable or parameter +at run-time. +.P +.IX declarations, non-defining +A data object entry representing a non-defining declaration of the object +will not have a location attribute, and will have the +.Cf DW_AT_declaration +attribute. +.P +In a variable entry representing the definition of the variable +(that is, with no +.Cf DW_AT_declaration +attribute) +if no location attribute is present, or if +the location attribute is present but describes +a null entry (as described in section 2.4), the variable +is assumed to exist in the source code but not in the executable +program (but see number 9, below). +.IX optimized code +.P +The location of a variable may be further specified with a +.Cf DW_AT_segment +attribute, if appropriate. +.IX segmented address space +.IX address space, segmented +.LI +A +.Cf DW_AT_type +attribute describing the type of the variable, constant or formal +parameter. +.LI +.IX members, static data +.IX declarations, defining +If the variable entry represents the defining declaration for a C++ static +data member of a structure, class or union, the entry has a +.Cf DW_AT_specification +attribute, whose value is a reference to the debugging information +entry representing the declaration of this data member. The +referenced entry will be a child of some class, structure or +union type entry. +.IX classes +.IX structures +.IX unions +.P +Variable entries containing the +.Cf DW_AT_specification +attribute do not need to duplicate information provided by the +declaration entry referenced by the specification attribute. +In particular, such variable entries do not need to contain +attributes for the name or type of the data member whose +definition they represent. +.LI +.I +Some languages distinguish between parameters whose value in the +calling function can be modified by the callee (variable parameters), +and parameters whose value in the calling function cannot be modified +by the callee (constant parameters). +.P +.R +If a formal parameter entry represents a parameter whose value +in the calling function may be modified by the callee, that entry +may have a +.Cf DW_AT_variable_parameter +attribute, whose value is a flag. The absence of this attribute +implies that the parameter's value in the calling function cannot +be modified by the callee. +.IX parameters, variable +.LI +.I +Fortran90 has the concept of an optional parameter. +.IX Fortran90 +.P +.R +.IX parameters, optional +If a parameter entry represents an optional parameter, it has a +.Cf DW_AT_is_optional +attribute, whose value is a flag. +.LI +.IX parameters, default value +A formal parameter entry describing a formal parameter that has a default +value may have a +.Cf DW_AT_default_value +attribute. The value of this attribute is a reference to the +debugging information entry for a variable or subroutine. The +default value of the parameter is the value of the variable (which +may be constant) or the value returned by the subroutine. If the +value of the +.Cf DW_AT_default_value +attribute is 0, it means that no default value has been specified. +.LI +.IX constants +An entry describing a variable whose value is constant +and not represented by an object in the address space of the program, +or an entry describing a named constant, +does not have a location attribute. Such entries have a +.Cf DW_AT_const_value +attribute, whose value may be a string or any of the constant +data or data block forms, as appropriate for the representation +of the variable's value. The value of this attribute is the actual +constant value of the variable, represented as it would be +on the target architecture. +.LI +.IX scope +.IX declarations, scope +If the scope of an object begins sometime after the low pc value +for the scope most closely enclosing the object, the +object entry may have a +.Cf DW_AT_start_scope +attribute. The value of this attribute is the offset in bytes of the beginning +of the scope for the object from the low pc value of the debugging +information entry that defines its scope. +.P +.I +The scope of a variable may begin somewhere in the middle of a lexical +block in a language that allows executable code in a +block before a variable declaration, or where one declaration +containing initialization code may change the scope of a subsequent +declaration. For example, in the following C code: +.DS +\f(CWfloat x = 99.99; + +int myfunc() +{ + float f = x; + float x = 88.99; + + return 0; +}\fP +.DE +.P +ANSI-C scoping rules require that the value of the variable \f(CWx\fP +assigned to the variable \f(CWf\fP in the initialization sequence +is the value of the global variable \f(CWx\fP, rather than the local \f(CWx\fP, +because the scope of the local variable \f(CWx\fP only starts after the full +declarator for the local \f(CWx\fP. +.R +.LE +.P +.H 2 "Common Block Entries" +.IX common blocks +.IX Fortran +A Fortran common block may be described by a debugging information +entry with the tag +.Cf DW_TAG_common_block . +The common block entry has a +.Cf DW_AT_name +attribute whose value is a null-terminated +string containing the common block name as it appears in the source program. +It also has a +.Cf DW_AT_location +attribute whose value describes the location of the beginning of the +common block. The common block entry owns debugging information +entries describing the variables contained within the common block. +.H 2 "Imported Declaration Entries" +.I +.IX declarations, imported +.IX imports +Some languages support the concept of importing into a given +module declarations made in a different module. +.R +.P +An imported declaration is represented by a debugging information +entry with the tag +.Cf DW_TAG_imported_declaration . +The entry for the imported declaration has a +.Cf DW_AT_name +attribute whose value +is a null-terminated string containing the name of the entity +whose declaration is being imported as it appears in the source +program. The imported declaration entry also has a +.Cf DW_AT_import +attribute, whose value is a reference to the debugging information +entry representing the declaration that is being imported. +.H 2 "Namelist Entries" +.I +.IX namelists +.IX Fortran90 +At least one language, Fortran90, has the concept of a namelist. +A namelist is an ordered list of the names of some set of declared objects. +The namelist object itself may be used as a replacement for the +list of names in various contexts. +.R +.P +A namelist is represented by a debugging information entry with +the tag +.Cf DW_TAG_namelist . +If the namelist itself has a name, the namelist entry has a +.Cf DW_AT_name +attribute, whose value is a null-terminated string containing the namelist's +name as it appears in the source program. +.P +Each name that is part of the namelist is represented by a debugging +information entry with the tag +.Cf DW_TAG_namelist_item . +Each such entry is a child of the namelist entry, and all of +the namelist item entries for a given namelist are ordered as were +the list of names they correspond to in the source program. +.P +Each namelist item entry contains a +.Cf DW_AT_namelist_item +attribute whose value is a reference to the debugging information +entry representing the declaration of the item whose name +appears in the namelist. +.OP +.H 1 "TYPE ENTRIES" +This section presents the debugging information entries +that describe program types: base types, modified types +and user-defined types. +.P +If the scope of the declaration of a named type begins sometime after +.IX scope +.IX declarations, scope +the low pc value +for the scope most closely enclosing the declaration, the +declaration may have a +.Cf DW_AT_start_scope +attribute. The value of this attribute is the offset in bytes of the beginning +of the scope for the declaration from the low pc value of the debugging +information entry that defines its scope. +.H 2 "Base Type Entries" +.I +.IX base types +.IX types, base +A base type is a data type that is not defined in terms of +other data types. Each programming language has a set of +base types that are considered to be built into that language. +.R +.P +A base type is represented by a debugging information entry +with the tag +.Cf DW_TAG_base_type . +A base type entry has a +.Cf DW_AT_name +attribute whose value is a null-terminated +string describing the name of the base type as recognized by +the programming language of the compilation unit containing +the base type entry. +.P +A base type entry also has a +.Cf DW_AT_encoding +attribute describing how the base type is encoded and is +to be interpreted. The value of this attribute is a constant. +The set of values and their meanings for the +.Cf DW_AT_encoding +.nr aX \n(Fg+1 +attribute is given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) l +. +Name Meaning +_ +DW_ATE_address linear machine address +DW_ATE_boolean true or false +DW_ATE_complex_float complex floating-point number +DW_ATE_float floating-point number +DW_ATE_signed signed binary integer +DW_ATE_signed_char signed character +DW_ATE_unsigned unsigned binary integer +DW_ATE_unsigned_char unsigned character +.TE +.FG "Encoding attribute values" +.DE +.P +All encodings assume the representation that is ``normal'' for +the target architecture. +.P +A base type entry has a +.Cf DW_AT_byte_size +attribute, whose value is a constant, +describing the size in bytes of the storage +unit used to represent an object of the given type. +.P +If the value of an object of the given type does not +fully occupy the storage unit described by the byte size attribute, +the base type entry may have a +.Cf DW_AT_bit_size +attribute and a +.Cf DW_AT_bit_offset +attribute, both of whose values are constants. +The bit size attribute describes the actual size in bits used +to represent a value of the given type. The bit offset +attribute describes the offset in bits of the high order +bit of a value of the given type from the high order bit +of the storage unit used to contain that value. +.I +.P +For example, the C type +.Cf int +on a machine that uses 32-bit integers would be +represented by a base type entry with a name +attribute whose value was ``\f(CWint\fP,'' an +encoding attribute whose value was +.Cf DW_ATE_signed +and a byte size attribute whose value was +.Cf 4 . +.R +.H 2 "Type Modifier Entries" +.IX type modifiers +.IX types, modifiers +A base or user-defined type may be modified in different +ways in different languages. A type modifier is represented +in DWARF by a debugging information entry with one of the +.nr aX \n(Fg+1 +tags given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) l +. +Tag Meaning +_ +DW_TAG_const_type C or C++ const qualified type +DW_TAG_packed_type Pascal packed type +DW_TAG_pointer_type The address of the object whose type is being modified +DW_TAG_reference_type A C++ reference to the object whose type is being modified +DW_TAG_volatile_type C or C++ volatile qualified type +.TE +.FG "Type modifier tags" +.DE +.P +.IX types, constant +.IX types, packed +.IX types, volatile +.IX types, pointer +.IX types, reference +Each of the type modifier entries has a +.Cf DW_AT_type +attribute, whose value is a reference to a debugging information +entry describing a base type, a user-defined type or another type +modifier. +.P +A modified type entry describing a pointer or reference type +may have a +.IX addresses, class +.Cf DW_AT_address_class +attribute +to describe how objects having the given pointer or reference type +ought to be dereferenced. +.P +When multiple type modifiers are chained together to modify +a base or user-defined type, they are ordered as if part of +a right-associative expression involving the base or user-defined +type. +.I +.P +As examples of how type modifiers are ordered, take the following +C declarations: +.R +.DS +.ta .5i +.5i +.5i +.5i +.5i +.5i +.5i +.5i +\f(CWconst char * volatile p;\fP + \fIwhich represents a volatile pointer to a constant character.\fP + \fIThis is encoded in DWARF as:\fP + \f(CWDW_TAG_volatile_type \(-> + DW_TAG_pointer_type \(-> + DW_TAG_const_type \(-> + DW_TAG_base_type\fP + +\f(CWvolatile char * const p;\fP + \fIon the other hand, represents a constant pointer + to a volatile character.\fP + \fIThis is encoded as:\fP + \f(CWDW_TAG_const_type \(-> + DW_TAG_pointer_type \(-> + DW_TAG_volatile_type \(-> + DW_TAG_base_type\fP + +.DE +.R +.H 2 "Typedef Entries" +.IX typedefs +Any arbitrary type named via a typedef is represented +by a debugging information entry with the tag +.Cf DW_TAG_typedef . +The typedef entry has a +.Cf DW_AT_name +attribute whose value is a null-terminated +string containing the name of the typedef as it appears in the +source program. +The typedef entry also contains a +.Cf DW_AT_type +attribute. +.P +If the debugging information entry for a typedef represents a +declaration of the type that is not also a definition, +it does not contain a type attribute. +.IX declarations, non-defining +.H 2 "Array Type Entries" +.I +.IX arrays +Many languages share the concept of an ``array,'' which is a +table of components of identical type. +.P +.R +An array type is represented by a debugging information entry with +the tag +.Cf DW_TAG_array_type . +.P +If a name has been given to the array type in the source program, then the +corresponding array type entry has a +.Cf DW_AT_name +attribute whose value is a +null-terminated string containing the array type name as it appears in the +source program. +.P +.IX arrays, ordering +The array type entry describing a multidimensional array may have a +.Cf DW_AT_ordering +attribute whose constant value is interpreted to mean either +row-major or column-major ordering of array elements. +The set of values and their meanings for the ordering attribute +.nr aX \n(Fg+1 +are listed in Figure \n(aX. +If no ordering attribute is present, the default ordering for +the source language (which is indicated by the +.Cf DW_AT_language +attribute of the enclosing compilation unit entry) +is assumed. +.DF +.TS +box center; +lf(CW) +. +DW_ORD_col_major +DW_ORD_row_major +.TE +.FG "Array ordering" +.DE +.P +The ordering attribute may optionally appear on one-dimensional arrays; it +will be ignored. +.P +An array type entry has a +.Cf DW_AT_type +attribute describing the type +of each element of the array. +.P +.IX arrays, stride +If the amount of storage allocated to hold each element of an object of +the given array type is different from the amount of storage that is normally +allocated to hold an individual object of the indicated element type, then +the array type entry has a +.Cf DW_AT_stride_size +attribute, whose constant value +represents the size in bits of each element of the array. +.P +If the size of the entire array can be determined statically at compile +time, the array type entry may have a +.Cf DW_AT_byte_size +attribute, whose constant value represents the total size in bytes of an +instance of the array type. +.P +.I +Note that if the size of the array can be determined statically at +compile time, this value can usually be computed by multiplying +the number of array elements by the size of each element. +.P +.R +Each array dimension is described by a debugging information +entry with either the tag +.IX subranges +.IX enumerations +.IX arrays, dimensions +.Cf DW_TAG_subrange_type +or the tag +.Cf DW_TAG_enumeration_type . +These entries are children of the array type entry and are +ordered to reflect the appearance of the dimensions in the source +program (i.e. leftmost dimension first, next to leftmost second, +and so on). +.P +.I +.IX C %c +In languages, such as ANSI-C, in which there is no concept of a +``multidimensional array,'' +an array of arrays may be represented by a debugging information entry +for a multidimensional array. +.R +.H 2 "Structure, Union, and Class Type Entries" +.I +The languages C, C++, and Pascal, among others, +allow the programmer to define types that +are collections of related components. In C and C++, these collections are +called ``structures.'' In Pascal, they are called ``records.'' The components +may be of different types. The components are called ``members'' in C and +C++, and ``fields'' in Pascal. +.P +.IX structures +.IX classes +.IX unions +.IX records +.IX C %c +.IX C++ %caa +.IX Pascal +The components of these collections each exist in their own space in +computer memory. The components of a C or C++ ``union'' all coexist in +the same memory. +.P +Pascal and other languages have a ``discriminated union,'' also called a +.IX variants +.IX discriminated unions +``variant record.'' Here, selection of a number of alternative substructures +(``variants'') is based on the value of a component that is not part of any of +those substructures (the ``discriminant''). +.P +Among the languages discussed in this document, +the ``class'' concept is unique to C++. A class is similar to a structure. +A C++ class or structure may have ``member functions'' which are subroutines +that are within the scope of a class or structure. +.R +.H 3 "General Structure Description" +Structure, union, and class types are represented by +debugging information entries with the tags +.Cf DW_TAG_structure_type , +.Cf DW_TAG_union_type +and +.Cf DW_TAG_class_type , +respectively. +If a name has been given to the structure, union, or class in the source +program, then the corresponding structure type, union type, or class type +entry has a +.Cf DW_AT_name +attribute whose value is a null-terminated string +containing the type name as it appears in the source program. +.P +If the size of an instance of the +structure type, union type, or class type entry can be determined +statically at compile time, the entry has a +.Cf DW_AT_byte_size +attribute whose constant value is the number of bytes required to +hold an instance of the structure, union, or class, and any padding bytes. +.I +.P +.IX structures, incomplete +.IX classes, incomplete +.IX unions, incomplete +For C and C++, an incomplete structure, union or class type is represented +by a structure, union or class entry that does not have +a byte size attribute and that has a +.Cf DW_AT_declaration +attribute. +.R +.P +The members of a structure, union, or class are represented by +debugging information entries that are owned by the corresponding +structure type, union type, or class type entry and appear in the same +order as the corresponding declarations in the source program. +.P +.I +.IX declarations, defining +.IX members, static data +.IX members, data +.IX members, functions +Data member declarations occurring within the declaration of a structure, +union or class type are considered to be ``definitions'' of those members, +with the exception of C++ ``static'' data members, whose definitions +appear outside of the declaration of the enclosing structure, union +or class type. Function member declarations appearing within a structure, +union or class type declaration are definitions only if the body +of the function also appears within the type declaration. +.R +.P +.IX declarations, non-defining +If the definition for a given member of the structure, union or class +does not appear within the body of the declaration, that member +also has a debugging information entry describing its definition. +That entry will have a +.Cf DW_AT_specification +attribute referencing +the debugging entry owned by the +body of the structure, union or class debugging entry and representing +a non-defining declaration of the data or function member. The +referenced entry will +not have information about the location of that member (low and high +pc attributes for function members, location descriptions for data +members) and will have a +.Cf DW_AT_declaration +attribute. +.H 3 "Derived Classes and Structures" +.IX classes, derived +.IX structures, derived +.IX inheritance +The class type or structure type entry that describes a derived class +or structure owns debugging information entries describing each of +the classes or structures it is derived from, ordered as they were +in the source program. Each such entry has the tag +.Cf DW_TAG_inheritance . +.P +An inheritance entry has a +.Cf DW_AT_type +attribute whose +value is a reference to the debugging information entry describing +the structure or class from which the parent structure or class +of the inheritance entry is derived. It also has a +.Cf DW_AT_data_member_location +attribute, whose value is a location description describing +the location of the beginning of +the data members contributed to the entire class by this +subobject relative to the beginning address of the data members of the +entire class. +.P +.IX accessibility +.IX virtuality +.IX classes, virtual base +An inheritance entry may have a +.Cf DW_AT_accessibility +attribute. +If no accessibility attribute is present, +private access is assumed. +If the structure or class referenced by the inheritance entry serves +as a virtual base class, the inheritance entry has a +.Cf DW_AT_virtuality +attribute. +.P +.I +In C++, a derived class may contain access declarations that +change the accessibility of individual class members from +the overall accessibility specified by the inheritance declaration. +A single access declaration may refer to a set of overloaded +names. +.R +.P +If a derived class or structure contains access declarations, +.IX access declarations +.IX C++ %caa +each such declaration may be represented by a debugging information +entry with the tag +.Cf DW_TAG_access_declaration . +Each such entry is a child of the structure or class type entry. +.P +An access declaration entry has a +.Cf DW_AT_name +attribute, whose value +is a null-terminated string representing the name used in the +declaration in the source program, including any class or structure +qualifiers. +.P +An access declaration entry also has a +.Cf DW_AT_accessibility +attribute +describing the declared accessibility of the named entities. +.H 3 "Friends" +.IX friends +.IX classes, friends +Each ``friend'' declared by +a structure, union or class type may be represented by +a debugging information entry that is a child of the structure, +union or class type entry; the friend entry has the tag +.Cf DW_TAG_friend. +.P +A friend entry has a +.Cf DW_AT_friend +attribute, whose value is a reference to the debugging information +entry describing the declaration of the friend. +.H 3 "Structure Data Member Entries" +.IX members, data +A data member (as opposed to a member function) is represented by +a debugging information entry with the tag +.Cf DW_TAG_member . +The member entry for a named member has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the member name +as it appears in the source program. If the member entry describes +a C++ anonymous union, the name attribute is omitted or consists +of a single zero byte. +.IX unions, anonymous +.IX anonymous unions +.P +The structure data member entry has a +.Cf DW_AT_type +attribute +to denote the type of that member. +.P +If the member entry is defined in the structure or class body, it has a +.Cf DW_AT_data_member_location +attribute whose value is a location +description that describes the location of that +member relative to the base address of the structure, union, or class that +most closely encloses the corresponding member declaration. +.I +.P +.IX locations, expressions +.IX locations, descriptions +The addressing expression represented by the location +description for a structure data member expects the base address +of the structure data member to be on the expression stack +before being evaluated. +.P +.IX unions +The location description for a data member of a union may be omitted, +since all data members of a union begin at the same address. +.R +.P +.IX bit fields +.IX members, bit fields +If the member entry describes a bit field, then that entry has the following +attributes: +.AL +.LI +A +.Cf DW_AT_byte_size +attribute whose constant value is the number of bytes that +contain an instance of the bit field and any padding bits. +.P +.I +The byte size attribute may be omitted if the size of the object containing +the bit field can be inferred from the type attribute of the data +member containing the bit field. +.R +.LI +A +.Cf DW_AT_bit_offset +attribute whose constant value is the number of bits +to the left of the leftmost (most significant) bit of the bit field value. +.LI +A +.Cf DW_AT_bit_size +attribute whose constant value is the number of bits occupied +by the bit field value. +.LE +.P +The location description for a bit field calculates the address of +an anonymous object containing the bit field. The address is +relative to the structure, union, or class that +most closely encloses the bit field declaration. The number +of bytes in this anonymous object is the value of the byte +size attribute of the bit field. The offset (in bits) +from the most significant bit of the +anonymous object to the most significant bit of the bit field is the +value of the bit offset attribute. +.I +.P +For example, take one possible representation of the following +structure definition in both big and little endian byte orders: +.DS +\f(CW +struct S { + int j:5; + int k:6; + int m:5; + int n:8; +};\fP +.DE +.P +In both cases, the location descriptions for the debugging information +entries for \f(CWj\fP, \f(CWk\fP, \f(CWm\fP and \f(CWn\fP +describe the address of +the same 32-bit word that contains all three members. +(In the big-endian case, +the location description addresses the most significant byte, in +the little-endian case, the least significant). +The following diagram shows the structure layout and lists the bit +offsets for each case. The offsets +are from the most significant bit of the object addressed by the location +description. +.PS +bitht = .3 +boxht = bitht +bitwid = .11 +nibwid = .75 * bitwid +bytewid = 8 * bitwid +boxwid = bytewid +define nibble X # nibble(len, "label", hi-left, hi-right, lo-left, lo-right, any) +N: box width $1*nibwid $2 $7 + { if $3 >= 0 then % "\s-4\|$3\s0" at N.w + (0,bitht/3) ljust % + } # curly on separate line for pic bug + { if $4 >= 0 then % "\s-4\|$4\s0" at N.e + (0,bitht/3) rjust % + } + { if $5 >= 0 then % "\s-4\|$5\s0" at N.w - (0,bitht/3) ljust % + } + { if $6 >= 0 then % "\s-4$6\|\s0" at N.e - (0,bitht/3) rjust % + } +X +define tbox X # tbox(width,"label", any) +T: box width $1*nibwid ht 1/6 $3 invis + { $2 at T.w ljust + } +X +.PE +.DS +.PS + down +H: tbox(20,"Bit Offsets:") + tbox(20,"\f(CW j:0\fP") + tbox(20,"\f(CW k:5\fP") + tbox(20,"\f(CW m:11\fP") + tbox(20,"\f(CW n:16\fP") + right +H: tbox(32, "Big-Endian", with .w at H.e) +H: nibble(5,"\f(CWj\fP",0,-1,31,-1,with .nw at H.sw) +H: nibble(6,"\f(CWk\fP",-1,-1,26,-1) +H: nibble(5,"\f(CWm\fP",-1,-1,20,-1) +H: nibble(8,"\f(CWn\fP",-1,-1,15,-1) +H: nibble(8,"\fIpad\fP",-1,-1,7,0) +.PE +.DE +.DS +.PS + down +H: tbox(20,"Bit Offsets:") + tbox(20,"\f(CW j:27\fP") + tbox(20,"\f(CW k:21\fP") + tbox(20,"\f(CW m:16\fP") + tbox(20,"\f(CW n:8\fP") + right +H: tbox(32, "Little-Endian", with .w at H.e) +H: nibble(8,"\f2pad\fP",-1,-1,31,-1, with .nw at H.sw) +H: nibble(8,"\f(CWn\fP",-1,-1,23,-1) +H: nibble(5,"\f(CWm\fP",-1,-1,15,-1) +H: nibble(6,"\f(CWk\fP",-1,-1,10,-1) +H: nibble(5,"\f(CWj\fP",-1,0,4,0) +.PE +.DE +.R +.H 3 "Structure Member Function Entries" +.IX subroutines, members +.IX members, functions +.IX members, locations +A member function is represented in the debugging information by a +debugging information entry with the tag +.Cf DW_TAG_subprogram . +The member function entry may contain the same attributes and follows +the same rules as non-member global subroutine entries (see section 3.3). +.P +.IX virtuality +.IX virtual functions +If the member function entry describes a virtual function, then that entry +has a +.Cf DW_AT_virtuality +attribute. +.P +An entry for a virtual function also has a +.Cf DW_AT_vtable_elem_location +attribute whose value contains a location +description yielding the address of the slot for the function +within the virtual function table for the enclosing class or structure. +.P +.IX declarations, defining +If a subroutine entry represents the defining declaration +of a member function and that definition appears outside +of the body of the enclosing class or structure declaration, +the subroutine entry has a +.Cf DW_AT_specification +attribute, whose value is a reference to the debugging information +entry representing the declaration of this function member. The +referenced entry will be a child of some class or structure +type entry. +.P +Subroutine entries containing the +.Cf DW_AT_specification +attribute do not need to duplicate information provided by the +declaration entry referenced by the specification attribute. +In particular, such entries do not need to contain +attributes for the name or return type of the function member whose +definition they represent. +.H 3 "Class Template Instantiations" +.I +.IX C++ %caa +.IX templates +In C++ a class template is a generic +definition of a class type that +is instantiated differently when an instance of the class +is declared or defined. The generic description of the class +may include both parameterized types and parameterized constant +values. DWARF does not represent the generic +template definition, but does represent each instantiation. +.R +.P +A class template instantiation is represented by a debugging information +with the tag +.Cf DW_TAG_class_type . +With four exceptions, +such an entry will contain the same attributes and have the same +types of child entries as would an entry for a class type defined +explicitly using the instantiation types and values. +The exceptions are: +.AL +.LI +Each formal parameterized type declaration appearing in the +template definition is represented by a debugging information entry +with the tag +.Cf DW_TAG_template_type_parameter . +Each such entry has a +.Cf DW_AT_name +attribute, whose value is a null-terminated +string containing the name of the formal type parameter as it +appears in the source program. The template type parameter +entry also has a +.Cf DW_AT_type +attribute describing the actual type by +which the formal is replaced for this instantiation. +.LI +Each formal parameterized value declaration appearing +in the templated definition is represented by a debugging information +entry with the tag +.Cf DW_TAG_template_value_parameter . +Each such entry has a +.Cf DW_AT_name +attribute, whose value is a null-terminated +string containing the name of the formal value parameter as it +appears in the source program. The template value parameter +entry also has a +.Cf DW_AT_type +attribute describing the type of the parameterized +value. Finally, the template value parameter entry has a +.Cf DW_AT_const_value +attribute, whose value is the actual constant value of the value +parameter for this instantiation as represented on the target +architecture. +.LI +.IX compilation units +If the compiler has generated a special compilation unit +to hold the template instantiation and that compilation unit +has a different name +from the compilation unit containing the template definition, +the name attribute for the debugging entry representing +that compilation unit should be empty or omitted. +.LI +.IX declarations, coordinates +If the class type entry representing the template instantiation +or any of its child entries +contain declaration coordinate attributes, those attributes +should refer to the source for the template definition, not +to any source generated artificially by the compiler. +.LE +.H 3 "Variant Entries" +.IX variants +.IX discriminated unions +A variant part of a structure is represented by a debugging +information entry with the tag +.Cf DW_TAG_variant_part +and is owned by the corresponding structure type +entry. +.P +.IX discriminants +If the variant part has a discriminant, the discriminant is represented +by a separate debugging information entry which is a child of +the variant part entry. This entry has the form of a structure data member +entry. +The variant part entry will have a +.Cf DW_AT_discr +attribute whose value is a +reference to the member entry for the discriminant. +.P +If the variant part +does not have a discriminant (tag field), the variant part entry has a +.Cf DW_AT_type +attribute to represent the tag type. +.P +Each variant of a particular variant part is represented by a debugging +information entry with the tag +.Cf DW_TAG_variant +and is a child of the variant part entry. The value that selects a +given variant may be represented in one of three ways. The +variant entry may have a +.Cf DW_AT_discr_value +attribute whose value represents a single case label. +The value of this attribute +is encoded as an LEB128 number. The number is signed if the tag +type for the variant part containing this variant is +a signed type. The number is unsigned if the tag type is an unsigned type. +.P +Alternatively, the variant entry may contain a +.Cf DW_AT_discr_list +attribute, whose value represents a list of discriminant values. +This list is represented by any of the block forms and may contain +a mixture of case labels and label ranges. Each item on the list +is prefixed with a discriminant value descriptor that determines whether +the list item represents a single label or a label range. +A single case label is represented as an LEB128 +number as defined above +for the +.Cf DW_AT_discr_value +attribute. A label range is represented by two LEB128 numbers, +the low value of the range followed by the high value. Both values +follow the rules for signedness just described. +The discriminant value descriptor is a constant that may have +.nr aX \n(Fg+1 +one of the values given in Figure \n(aX. +.DF +.TS +center box; +lf(CW) +. +DW_DSC_label +DW_DSC_range +.TE +.FG "Discriminant descriptor values" +.DE +.P +If a variant entry has neither a +.Cf DW_AT_discr_value +attribute nor a +.Cf DW_AT_discr_list +attribute, or if it has a +.Cf DW_AT_discr_list +attribute with 0 size, the variant is a default variant. +.P +The components selected by a particular variant are represented +by debugging information entries owned by the corresponding variant +entry and appear in the same order as the corresponding declarations in +the source program. +.H 2 "Enumeration Type Entries" +.I +.IX enumerations +An ``enumeration type'' is a scalar that can assume one of a fixed number of +symbolic values. +.P +.R +An enumeration type is represented by a debugging information entry +with the tag +.Cf DW_TAG_enumeration_type . +.P +If a name has been given to the enumeration type in the source program, +then the corresponding enumeration type entry has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the enumeration type +name as it appears in the source program. +These entries also have a +.Cf DW_AT_byte_size +attribute whose +constant value is the number of bytes required to hold an +instance of the enumeration. +.P +Each enumeration literal is represented by a debugging information +entry with the tag +.Cf DW_TAG_enumerator . +Each such entry is a child of the enumeration type entry, and +the enumerator entries appear in the same order as the declarations of +the enumeration literals in the source program. +.P +Each enumerator entry has a +.Cf DW_AT_name +attribute, whose value is +a null-terminated string containing the name of the enumeration +literal as it appears in the source program. Each enumerator +entry also has a +.Cf DW_AT_const_value +attribute, whose value is the actual numeric value of the enumerator +as represented on the target system. +.H 2 "Subroutine Type Entries" +.I +.IX subroutines, types +It is possible in C to declare pointers to subroutines that return a value +of a specific type. In both ANSI C and C++, it is possible to declare +pointers to subroutines that not only return a value of a specific type, +but accept only arguments of specific types. The type of such pointers +would be described with a ``pointer to'' modifier applied to a user-defined +type. +.R +.P +A subroutine type is represented by a debugging information entry +with the tag +.Cf DW_TAG_subroutine_type . +If a name has been given to the subroutine type in the source program, +then the corresponding subroutine type entry has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the subroutine type +name as it appears in the source program. +.P +.IX subroutines, return types +If the subroutine type describes a function that returns a value, then +the subroutine type entry has a +.Cf DW_AT_type +attribute +to denote the type returned by the subroutine. +If the types of the arguments are necessary to describe the subroutine type, +then the corresponding subroutine type entry owns debugging +information entries that describe the arguments. +These debugging information entries appear in the order +that the corresponding argument types appear in the source program. +.P +.I +.IX C %c +.IX subroutines, prototypes +In ANSI-C there is a difference between the types of functions +declared using function prototype style declarations and those +declared using non-prototype declarations. +.P +.R +A subroutine entry +declared with a function prototype style declaration may have a +.Cf DW_AT_prototyped +attribute, whose value is a flag. +.P +Each debugging information entry +owned by a subroutine type entry has a tag whose value has one of +two possible interpretations. +.AL +.LI +.IX parameters, formal +Each debugging information entry that is owned by a subroutine type entry and +that defines a single argument of a specific type has the tag +.Cf DW_TAG_formal_parameter . +.P +The formal parameter entry has a type attribute +to denote the type of the corresponding formal parameter. +.LI +The unspecified parameters of a variable parameter list are represented by a +debugging information entry owned by the subroutine type entry with the tag +.Cf DW_TAG_unspecified_parameters . +.IX parameters, unspecified +.LE +.H 2 "String Type Entries" +.I +.IX string types +.IX Fortran +A ``string'' is a sequence of characters that have specific semantics and +operations that separate them from arrays of characters. +Fortran is one of +the languages that has a string type. +.R +.P +A string type is represented by a debugging information entry +with the tag +.Cf DW_TAG_string_type . +If a name has been given to the string type in the source program, +then the corresponding string type entry has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the string type +name as it appears in the source program. +.P +The string type entry may have a +.Cf DW_AT_string_length +attribute whose value is a location description +yielding the location where the length of the string +is stored in the program. The string type entry may also have a +.Cf DW_AT_byte_size +attribute, whose constant value is the size in bytes of the data +to be retrieved from the location referenced by the string length +attribute. If no byte size attribute is present, the size of the +data to be retrieved is the same as the size of an address on +the target machine. +.P +If no string length attribute is present, the string type entry may have +a +.Cf DW_AT_byte_size +attribute, whose constant value is the length in bytes of +the string. +.H 2 "Set Entries" +.I +Pascal provides the concept of a ``set,'' which represents a group of +values of ordinal type. +.P +.R +.IX Pascal +.IX set types +A set is represented by a debugging information entry +with the tag +.Cf DW_TAG_set_type . +If a name has been given to the set type, +then the set type entry has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the set type name +as it appears in the source program. +.P +The set type entry has a +.Cf DW_AT_type +attribute to denote the type +of an element of the set. +.P +If the amount of storage allocated to hold each element of an object of +the given set type is different from the amount of storage that is normally +allocated to hold an individual object of the indicated element type, then +the set type entry has a +.Cf DW_AT_byte_size +attribute, whose constant value +represents the size in bytes of an instance of the set type. +.H 2 "Subrange Type Entries" +.I +Several languages support the concept of a ``subrange'' type object. +These objects can represent a subset of the values that an +object of the basis type for the subrange can represent. +Subrange type entries may also be used to represent the bounds +of array dimensions. +.R +.P +.IX subranges +A subrange type is represented by a debugging information entry +with the tag +.Cf DW_TAG_subrange_type . +If a name has been given to the subrange type, +then the subrange type entry has a +.Cf DW_AT_name +attribute +whose value is a null-terminated string containing the subrange type name +as it appears in the source program. +.P +The subrange entry may have a +.Cf DW_AT_type +attribute to describe +the type of object of whose values this subrange is a subset. +.P +If the amount of storage allocated to hold each element of an object of +the given subrange type is different from the amount of storage that is normally +allocated to hold an individual object of the indicated element type, then +the subrange type entry has a +.Cf DW_AT_byte_size +attribute, whose constant value +represents the size in bytes of each element of the subrange type. +.P +The subrange entry may have the attributes +.Cf DW_AT_lower_bound +and +.Cf DW_AT_upper_bound +to describe, respectively, the lower and upper bound values +of the subrange. +The +.Cf DW_AT_upper_bound +attribute may be replaced by a +.Cf DW_AT_count +attribute, whose value describes the number of elements in +the subrange rather than the value of the last element. +If a bound or count value is described by a constant +not represented in the program's address space and can +be represented by one of the constant attribute forms, then the value +of the lower or upper bound or count attribute may be one of the constant +types. Otherwise, the value of the lower or upper bound or count +attribute is a reference to a debugging information entry describing +an object containing the bound value or itself describing a constant +value. +.P +If either the lower or upper bound or count values are missing, the +bound value is assumed to be a language-dependent default +constant. +.P +.I +.IX C %c +.IX C++ %caa +.IX Fortran +The default lower bound value for C or C++ is 0. For Fortran, +it is 1. No other default values are currently defined by DWARF. +.R +.P +If the subrange entry has no type attribute describing the basis +type, the basis type is assumed to be the same as the object +described by the lower bound attribute (if it references an object). +If there is no lower bound attribute, or it does not reference +an object, the basis type is the type of the upper bound or count +attribute +(if it references an object). If there is no upper bound or count attribute +or it does not reference an object, the type is assumed to be +the same type, in the source language +of the compilation unit containing the subrange entry, +as a signed integer with the same size +as an address on the target machine. +.H 2 "Pointer to Member Type Entries" +.I +In C++, a pointer to a data or function member of a class or +structure is a unique type. +.P +.R +.IX C++ %caa +.IX members, pointers to +.IX pointers to members +A debugging information entry +representing the type of an object that is a pointer to a structure +or class member has the tag +.Cf DW_TAG_ptr_to_member_type . +.P +If the pointer to member type has a name, the pointer to member entry +has a +.Cf DW_AT_name +attribute, whose value is a null-terminated string +containing the type name as it appears in the source program. +.P +The pointer to member entry has a +.Cf DW_AT_type +attribute to describe +the type of the class or structure member to which objects +of this type may point. +.P +The pointer to member entry also has a +.Cf DW_AT_containing_type +attribute, whose value is a reference to a debugging information +entry for the class or structure to whose members objects of +this type may point. +.P +Finally, the pointer to member entry has a +.Cf DW_AT_use_location +attribute whose value is a location description that computes +the address of the member of the class or structure to which the +pointer to member type entry can point. +.P +.I +The method used to find the address of a given member +of a class or structure is common to any instance of that +class or structure and to any instance of the pointer or +member type. The method is thus associated +with the type entry, rather than with each instance of the type. +.P +The +.Cf DW_AT_use_location +expression, however, cannot be used on its own, but must +be used in conjunction with the location expressions for +a particular object of the given pointer to member type +and for a particular structure or class instance. The +.Cf DW_AT_use_location +attribute expects two values to be pushed onto the location expression +stack before the +.Cf DW_AT_use_location +expression is evaluated. The first value pushed should be +the value of the pointer to member object itself. +The second value pushed should be the base address of the entire +structure or union instance containing the member whose +address is being calculated. +.P +So, for an expression like +.DS + \f(CWobject.*mbr_ptr\fP +.DE +where \f(CWmbr_ptr\fP has some pointer to member type, +a debugger should: +.AL +.LI +Push the value of +.Cf mbr_ptr +onto the location expression stack. +.LI +Push the base address of +.Cf object +onto the location expression stack. +.LI +Evaluate the +.Cf DW_AT_use_location +expression for the type of +.Cf mbr_ptr . +.LE +.R +.H 2 "File Type Entries" +.I +Some languages, such as Pascal, provide a first class data type +to represent files. +.R +.P +.IX Pascal +.IX file types +A file type is represented by a debugging information entry +with the tag +.Cf DW_TAG_file_type. +If the file type has a name, the file type entry +has a +.Cf DW_AT_name +attribute, whose value is a null-terminated string +containing the type name as it appears in the source program. +.P +The file type entry has a +.Cf DW_AT_type +attribute describing the type +of the objects contained in the file. +.P +The file type entry also has a +.Cf DW_AT_byte_size +attribute, whose value +is a constant representing the size in bytes of an instance +of this file type. +.OP +.H 1 "OTHER DEBUGGING INFORMATION" +This section describes debugging information that +is not represented in the form of debugging information +entries and is not contained within the +.Cf .debug_info +section. +.H 2 "Accelerated Access" +.I +.IX accelerated access +A debugger frequently needs to find the debugging information for +a program object defined outside of the compilation unit +where the debugged program is currently stopped. Sometimes +it will know only the name of the object; sometimes only the address. +To find the debugging information +associated with a global object by name, using the DWARF debugging information +entries alone, a debugger would need +to run through all entries at the highest scope within each +compilation unit. For lookup by address, for a subroutine, +a debugger can use the low and high pc attributes +of the compilation unit entries to quickly narrow down the search, +but these attributes only cover +the range of addresses for the text associated with a compilation +unit entry. To find the debugging information associated with a +data object, an exhaustive search would be needed. +Furthermore, any search through debugging information entries for +different compilation units within a large program +would potentially require the access of many memory pages, +probably hurting debugger performance. +.R +.P +To make lookups of program objects by name or by address faster, +a producer of DWARF information may provide two different types +of tables containing information about the debugging information +entries owned by a particular compilation unit entry in a more condensed +format. +.H 3 "Lookup by Name" +.IX lookup, by name +For lookup by name, a table is maintained in a separate +object file section called +.Cf .debug_pubnames . +.IX \f(CW.debug_pubnames\fP %debugap +The table consists of sets of variable length entries, each +set describing the names of global objects whose definitions +or declarations are represented by debugging information entries +owned by a single compilation unit. Each set begins +with a header containing four values: the total length of the entries +for that set, not including the length field itself, a version number, +the offset from the beginning of the +.Cf .debug_info +.IX \f(CW.debug_info\fP %debugai +section of the compilation unit entry referenced by the set and +the size in bytes of the contents of the +.Cf .debug_info +section generated to represent that compilation unit. This +header is followed by a variable number of offset/name pairs. +Each pair consists of the offset from the beginning of the compilation +unit entry corresponding to the current set to the +debugging information entry for +the given object, followed by a null-terminated character +string representing the name of the object as given by +the +.Cf DW_AT_name +attribute of the referenced debugging entry. +Each set of names is terminated by zero. +.P +.IX C++ %caa +.IX members, static data +In the case of the name of a static data member or function member +of a C++ structure, class or union, the name presented +in the +.Cf .debug_pubnames +section is not the simple name given by the +.Cf DW_AT_name +attribute of the referenced debugging entry, but rather +the fully class qualified name of the data or function member. +.IX identifiers, names +.H 3 "Lookup by Address" +.IX lookup, by address +For lookup by address, a table is maintained in a separate +object file section called +.Cf .debug_aranges . +.IX \f(CW.debug_aranges\fP %debugaar +The table consists of sets of variable length entries, each +set describing the portion of the program's address space that +is covered by a single compilation unit. Each set begins +with a header containing five values: +.AL +.LI +The total length of the entries +for that set, not including the length field itself. +.LI +A version number. +.LI +The offset from the beginning of the +.Cf .debug_info +.IX \f(CW.debug_info\fP %debugai +section of the compilation unit entry referenced by the set. +.LI +The size in bytes of an address on the target architecture. For +segmented addressing, this is the size of the offset portion of the +.IX addresses, offset portion +.IX addresses, size of +address. +.LI +.IX address space, segmented +.IX segmented address space +The size in bytes of a segment descriptor on the target architecture. +If the target system uses a flat address space, this value is 0. +.LE +.P +This +header is followed by a variable number of address +range descriptors. Each descriptor is a pair consisting of +the beginning address +of a range of text or data covered by some entry owned +by the corresponding compilation unit entry, followed by the length +of that range. A particular set is terminated by an entry consisting +of two zeroes. By scanning the table, a debugger can quickly +decide which compilation unit to look in to find the debugging information +for an object that has a given address. +.H 2 "Line Number Information" +.I +.IX line number information +A source-level debugger will need to know how to associate statements in +the source files with the corresponding machine instruction addresses in +the executable object or the shared objects used by that executable +object. Such an association would make it possible for the debugger user +to specify machine instruction addresses in terms of source statements. +This would be done by specifying the line number and the source file +containing the statement. The debugger can also use this information to +display locations in terms of the source files and to single step from +statement to statement. +.R +.P +As mentioned in section 3.1, above, +the line number information generated for a compilation unit +is represented in the \f(CW.debug_line\fP section of an object file and is +referenced by a corresponding compilation unit debugging information entry +in the \f(CW.debug_info\fP section. +.IX \f(CW.debug_info\fP %debugai +.IX \f(CW.debug_line\fP %debugali +.I +.P +If space were not a consideration, the information +provided in the +.Cf .debug_line +section could be represented as a large matrix, +with one row for each instruction in the emitted +object code. The matrix would have columns for: +.DL +.LI +the source file name +.LI +the source line number +.LI +the source column number +.LI +whether this instruction is the beginning of a source statement +.LI +whether this instruction is the beginning of a basic block. +.LE +.P +Such a matrix, however, would be impractically large. We shrink it with +two techniques. First, we delete from the matrix each row whose file, +line and source column information is identical with that of its predecessors. +Second, we design a byte-coded language for a state machine and store a stream +of bytes in the object file instead of the matrix. This language can be +much more compact than the matrix. When a consumer of the statement +information executes, it must ``run'' the state machine to generate +the matrix for each compilation unit it is interested in. The concept +of an encoded matrix also leaves room for expansion. In the future, +columns can be added to the matrix to encode other things that are +related to individual instruction addresses. +.R +.H 3 "Definitions" +.IX line number information, definitions +The following terms are used in the description of the line number information +format: +.VL 20 +.LI "state machine" +The hypothetical machine used by a consumer of the line number information +to expand the byte-coded instruction stream into a +matrix of line number information. +.LI "statement program" +A series of byte-coded line number information instructions representing one +compilation unit. +.LI "basic block" +A sequence of instructions that is entered only at the first instruction +and exited only at the last instruction. We define a procedure invocation +to be an exit from a basic block. +.LI "sequence" +A series of contiguous target machine instructions. One compilation +unit may emit multiple sequences (that is, not all instructions within +a compilation unit are assumed to be contiguous). +.LI "sbyte" +Small signed integer. +.LI "ubyte" +Small unsigned integer. +.LI "uhalf" +Medium unsigned integer. +.LI "sword" +Large signed integer. +.LI "uword" +Large unsigned integer. +.LI "LEB128" +.IX LEB128 +Variable length signed and unsigned data. See section 7.6. +.LE +.H 3 "State Machine Registers" +.IX line number information, state machine registers +The statement information state machine has the following registers: +.VL 20 +.LI "\f(CWaddress\fP" +The program-counter value corresponding to a machine instruction generated +by the compiler. +.LI "\f(CWfile\fP" +An unsigned integer indicating the identity of the source file corresponding +to a machine instruction. +.IX source, files +.LI "\f(CWline\fP" +.IX source, lines +An unsigned integer indicating a source line number. Lines are numbered +beginning at 1. The compiler may emit the value 0 in cases where an +instruction cannot be attributed to any source line. +.LI "\f(CWcolumn\fP" +.IX source, columns +An unsigned integer indicating a column number within a source line. +Columns are numbered beginning at 1. The value 0 is reserved to indicate +that a statement begins at the ``left edge'' of the line. +.LI "\f(CWis_stmt\fP" +A boolean indicating that the current instruction is the beginning of a +statement. +.LI "\f(CWbasic_block\fP" +A boolean indicating that the current instruction is the beginning of +a basic block. +.LI "\f(CWend_sequence\fP" +A boolean indicating that the current address is that of the first +byte after the end of a sequence of target machine instructions. +.LE +.P +At the beginning of each sequence within a statement program, the +state of the registers is: +.DS +.TS +; +lf(CW) l. +address 0 +file 1 +line 1 +column 0 +is_stmt determined by \f(CWdefault_is_stmt\fP in the statement program prologue +basic_block ``false'' +end_sequence ``false'' +.TE +.DE +.H 3 "Statement Program Instructions" +The state machine instructions in a statement program belong to one +of three categories: +.VL 20 +.LI "special opcodes" +.IX line number information, special opcodes +These have a ubyte opcode field and no arguments. +Most of the instructions in a statement program are special opcodes. +.LI "standard opcodes" +.IX line number information, standard opcodes +These have a ubyte opcode field which may be followed by zero or more +LEB128 arguments (except for +.Cf DW_LNS_fixed_advance_pc , +see below). +The opcode implies the number of arguments and their +meanings, but the statement program prologue also specifies the number +of arguments for each standard opcode. +.LI "extended opcodes" +.IX line number information, extended opcodes +These have a multiple byte format. The first byte is zero; +the next bytes are an unsigned LEB128 integer giving the number of bytes +in the instruction itself (does not include the first zero byte or the size). +The remaining bytes are the instruction itself. +.LE +.H 3 "The Statement Program Prologue" +.IX line number information, prologue +The optimal encoding of line number information depends to a certain +degree upon the architecture of the target machine. The statement program +prologue provides information used by consumers in decoding the statement +program instructions for a particular compilation unit and also provides +information used throughout the rest of the statement program. The statement +program for each compilation unit begins with a prologue containing the +following fields in order: +.AL +.LI +.Cf total_length +(uword) +.br +The size in bytes of the statement information for this compilation unit +(not including the +.Cf total_length +field itself). +.LI +.Cf version +(uhalf) +.br +Version identifier for the statement information format. +.LI +.Cf prologue_length +(uword) +.br +The number of bytes following the +.Cf prologue_length +field to the beginning of the first byte of the statement program itself. +.LI +.Cf minimum_instruction_length +(ubyte) +.br +The size in bytes of the smallest target machine instruction. Statement +program opcodes that alter the +.Cf address +register first multiply their operands by this value. +.LI +.Cf default_is_stmt +(ubyte) +.br +The initial value of the +.Cf is_stmt +register. +.P +.I +A simple code generator +that emits machine instructions in the order implied by the source program +would set this to ``true,'' and every entry in the matrix would represent +a statement boundary. A pipeline scheduling code generator would set +this to ``false'' and emit a specific statement program opcode for each +instruction that represented a statement boundary. +.R +.LI +.Cf line_base +(sbyte) +.br +This parameter affects the meaning of the special opcodes. See below. +.LI +.Cf line_range +(ubyte) +.br +This parameter affects the meaning of the special opcodes. See below. +.LI +.Cf opcode_base +(ubyte) +.br +The number assigned to the first special opcode. +.LI +.Cf standard_opcode_lengths +(array of ubyte) +.br +This array specifies the number of LEB128 operands for each of +the standard opcodes. The first element of the array corresponds +to the opcode whose value is 1, and the last element corresponds +to the opcode whose value is +.Cf "opcode_base - 1" . +By increasing +.Cf opcode_base , +and adding elements to this array, new standard opcodes +can be added, while allowing consumers who do not know about these +new opcodes to be able to skip them. +.LI +.Cf include_directories +(sequence of path names) +.br +The sequence contains an entry for each path that was searched +for included source files in this compilation. (The paths include +those directories specified explicitly by the user for the compiler +to search and those the compiler searches without explicit direction). +Each path entry is either a full +path name or is relative to the current directory of the compilation. +The current directory of the compilation is understood to be the first entry +and is not explicitly represented. +Each entry is a null-terminated +string containing a full path name. The last entry is followed by +a single null byte. +.LI +.Cf file_names +(sequence of file entries) +.br +.IX source, files +The sequence contains an entry for each source file that contributed +to the statement information for this compilation unit or is +used in other contexts, such as in a declaration coordinate +or a macro file inclusion. Each entry +has a null-terminated string containing the file name, +an unsigned LEB128 number representing the directory index of the +directory in which the file was found, +an unsigned LEB128 number representing the time of last modification for +the file and an unsigned LEB128 number representing the length in +bytes of the file. A compiler may choose to emit LEB128(0) for the +time and length fields to indicate that this information is not +available. The last entry is followed by a single null byte. +.P +The directory index represents an entry in the +.Cf include_directories +section. The index is LEB128(0) if the file was found in +the current directory of the compilation, LEB128(1) if it was +found in the first directory in the +.Cf include_directories +section, and so on. The directory index is ignored for file names +that represent full path names. +.P +The statement program assigns numbers to each of the file entries +in order, beginning with 1, and uses those numbers instead of file +names in the +.Cf file +register. +.P +A compiler may generate a single null byte for the file names field +and define file names using the extended opcode +.Cf DEFINE_FILE . +.LE +.H 3 "The Statement Program" +As stated before, the goal of a statement program is to build a +matrix representing +one compilation unit, which may have produced multiple sequences of +target-machine instructions. Within a sequence, addresses may only increase. +(Line numbers may decrease in cases of pipeline scheduling.) +.H 4 "Special Opcodes" +.IX line number information, special opcodes +Each 1-byte special opcode has the following effect on the state machine: +.AL +.LI +Add a signed integer to the +.Cf line +register. +.LI +Multiply an unsigned integer by the +.Cf minimum_instruction_length +field of the statement program prologue and +add the result to the +.Cf address +register. +.LI +Append a row to the matrix using the current values of the state machine +registers. +.LI +Set the +.Cf basic_block +register to ``false.'' +.LE +.P +All of the special opcodes do those same four things; +they differ from one another +only in what values they add to the +.Cf line +and +.Cf address +registers. +.P +.I +Instead of assigning a fixed meaning to each special opcode, the statement +program uses several +parameters in the prologue to configure the instruction set. There are two +reasons for this. +First, although the opcode space available for special opcodes now +ranges from 10 through 255, the lower bound may increase if one adds new +standard opcodes. Thus, the +.Cf opcode_base +field of the statement program +prologue gives the value of the first special opcode. +Second, the best choice of special-opcode meanings depends on the target +architecture. For example, for a RISC machine where the compiler-generated code +interleaves instructions from different lines to schedule the pipeline, +it is important to be able to add a negative value to the +.Cf line +register +to express the fact that a later instruction may have been emitted for an +earlier source line. For a machine where pipeline scheduling never occurs, +it is advantageous to trade away the ability to decrease the +.Cf line +register +(a standard opcode provides an alternate way to decrease the line number) in +return for the ability to add larger positive values to the +.Cf address +register. To permit this variety of strategies, the statement program prologue +defines a +.Cf line_base +field that specifies the minimum value which a special opcode can add +to the +.Cf line +register and a +.Cf line_range +field that defines the range of +values it can add to the +.Cf line +register. +.R +.P +A special opcode value is chosen based on the amount that needs to +be added to the +.Cf line +and +.Cf address +registers. The maximum line increment +for a special opcode is the value of the +.Cf line_base +field in the +prologue, plus the value of the +.Cf line_range +field, minus 1 +(\f(CWline base + line range - 1\fP). If the desired line increment +is greater than the maximum line increment, a standard opcode +must be used instead of a special opcode. +The ``address advance'' is calculated by dividing the desired address +increment by the +.Cf minimum_instruction_length +field from the +prologue. The special opcode is then calculated using the following +formula: +.br + \f(CWopcode = (desired line increment - line_base) + +.br + (line_range * address advance) + opcode_base\fP +.br +If the resulting opcode is greater than 255, a standard opcode +must be used instead. +.P +To decode a special opcode, subtract the +.Cf opcode_base +from +the opcode itself. The amount to increment the +.Cf address +register is +the adjusted opcode divided by the +.Cf line_range . +The amount to +increment the +.Cf line +register is the +.Cf line_base +plus the result +of the adjusted opcode modulo the +.Cf line_range . +That is, +.br + \f(CWline increment = line_base + (adjusted opcode % line_range)\fP +.br +.P +.I +As an example, suppose that the +.Cf opcode_base +is 16, +.Cf line_base +is -1 and +.Cf line_range +is 4. +This means that we can use a special opcode whenever two successive +rows in the matrix have source line numbers differing by any value within +the range [-1, 2] (and, because of the limited number of opcodes available, +when the difference between addresses is within the range [0, 59]). +.P +The opcode mapping would be: +.R +.DS +.TS +box center; +l l l +nf(CW) nf(CW) nf(CW) +. +Opcode Line advance Address advance +_ +16 -1 0 +17 0 0 +18 1 0 +19 2 0 +20 -1 1 +21 0 1 +22 1 1 +23 2 1 +... ... ... +253 0 59 +254 1 59 +255 2 59 +.TE +.DE +.P +There is no requirement that the expression \f(CW255 - line_base + 1\fP be an +integral multiple of +.Cf line_range . +.H 4 "Standard Opcodes" +.IX line number information, standard opcodes +There are currently 9 standard ubyte opcodes. In the future +additional ubyte opcodes may be defined by setting the +.Cf opcode_base +field in the statement program +prologue to a value greater than 10. +.AL +.LI +.Cf DW_LNS_copy +.br +Takes no arguments. Append a row to the matrix using the current values of +the state-machine registers. Then set the +.Cf basic_block +register to ``false.'' +.LI +.Cf DW_LNS_advance_pc +.br +Takes a single unsigned LEB128 operand, +multiplies it by the +.Cf minimum_instruction_length +field of the prologue, and adds the result to the +.Cf address +register of the state machine. +.LI +.Cf DW_LNS_advance_line +.br +Takes a single signed LEB128 operand and adds +that value to the +.Cf line +register of the state machine. +.LI +.Cf DW_LNS_set_file +.br +Takes a single unsigned LEB128 operand and stores +it in the +.Cf file +register of the state machine. +.LI +.Cf DW_LNS_set_column +.br +Takes a single unsigned LEB128 operand and stores +it in the +.Cf column +register of the state machine. +.LI +.Cf DW_LNS_negate_stmt +.br +Takes no arguments. +Set the +.Cf is_stmt +register of the state machine to the +logical negation of its current value. +.LI +.Cf DW_LNS_set_basic_block +.br +Takes no arguments. Set the +.Cf basic_block +register of the state machine to ``true.'' +.LI +.Cf DW_LNS_const_add_pc +.br +Takes no arguments. +Add to the +.Cf address +register of the state machine the +address increment value corresponding to special +opcode 255. +.P +.I +The motivation for +.Cf DW_LNS_const_add_pc +is this: when the statement program needs +to advance the address by a small amount, it can use a single special +opcode, which occupies a single byte. When it needs to advance the +address by up to twice the range of the last special opcode, it can use +.Cf DW_LNS_const_add_pc +followed by a special opcode, for a total of two bytes. +Only if it needs to advance the address by more than twice that range +will it need to use both +.Cf DW_LNS_advance_pc +and a special opcode, requiring three or more bytes. +.R +.LI +.Cf DW_LNS_fixed_advance_pc +.br +Takes a single uhalf operand. Add to the +.Cf address +register of the state machine the value of the (unencoded) operand. +This is the only extended opcode that takes an argument that is not +a variable length number. +.P +.I +The motivation for +.Cf DW_LNS_fixed_advance_pc +is this: existing assemblers cannot emit +.Cf DW_LNS_advance_pc +or special opcodes because they cannot encode LEB128 numbers +or judge when the computation of a special opcode overflows and requires +the use of +.Cf DW_LNS_advance_pc . +Such assemblers, however, can use +.Cf DW_LNS_fixed_advance_pc +instead, sacrificing compression. +.R +.LE +.H 4 "Extended Opcodes" +.IX line number information, extended opcodes +There are three extended opcodes currently defined. The first byte +following the length field of the encoding for each contains a sub-opcode. +.AL +.LI +\f(CWDW_LNE_end_sequence\fP +.br +Set the +.Cf end_sequence +register of the state machine +to ``true'' and append a row to the matrix using the +current values of the state-machine registers. Then +reset the registers to the initial values specified +above. +.P +Every statement program sequence must end with a +.Cf DW_LNE_end_sequence +instruction which creates a +row whose address is that of the byte after the last target machine instruction +of the sequence. +.LI +\f(CWDW_LNE_set_address\fP +.br +Takes a single relocatable address as an operand. The size of the +operand is the size appropriate to hold an address on the target machine. +Set the +.Cf address +register to the value given by the +relocatable address. +.P +.I +All of the other statement program opcodes that affect the +.Cf address +register add a delta to it. +This instruction stores a relocatable value into it instead. +.R +.LI +\f(CWDW_LNE_define_file\fP +.br +.IX source, files +Takes 4 arguments. The first is a null terminated string containing a +source file name. The second is an +unsigned LEB128 number representing the directory index of the +directory in which the file was found. +The third is an unsigned LEB128 number representing +the time of last modification of the file. The fourth is an unsigned +LEB128 number representing the length in bytes of the file. +The time and length fields may contain LEB128(0) if the information is +not available. +.P +The directory index represents an entry in the +.Cf include_directories +section of the statement program prologue. +The index is LEB128(0) if the file was found in +the current directory of the compilation, LEB128(1) if it was +found in the first directory in the +.Cf include_directories +section, and so on. The directory index is ignored for file names +that represent full path names. +.P +The files are numbered, starting at 1, +in the order in which they appear; the names in the prologue +come before names defined by the +.Cf DW_LNE_define_file +instruction. +These numbers are used in the the +.Cf file +register of the state machine. +.LE +.P +.I +Appendix 3 gives some sample statement programs. +.R +.H 2 "Macro Information" +.I +.IX macro information +.IX pre-processor +.IX C %c +.IX C++ %caa +Some languages, such as C and C++, provide a way to replace text +in the source program with macros defined either in the source +file itself, or in another file included by the source file. +Because these macros are not themselves defined in the target +language, it is difficult to represent their definitions +using the standard language constructs of DWARF. The debugging +information therefore reflects the state of the source after +the macro definition has been expanded, rather than as the +programmer wrote it. +The macro information table provides a way of preserving the original +source in the debugging information. +.R +.P +As described in section 3.1, the macro information for a given +compilation unit is represented in the +.Cf .debug_macinfo +.IX \f(CW.debug_macinfo\fP %debugam +section of an object file. The macro information for each compilation +unit is represented as a series of ``macinfo'' entries. Each +macinfo entry consists of a ``type code'' and up to two additional +operands. The series of entries for a given compilation unit +ends with an entry containing a type code of 0. +.H 3 "Macinfo Types" +The valid macinfo types are as follows: +.VL 30 +.LI \f(CWDW_MACINFO_define\fP +A macro definition. +.LI \f(CWDW_MACINFO_undef\fP +A macro un-definition. +.LI \f(CWDW_MACINFO_start_file\fP +The start of a new source file inclusion. +.LI \f(CWDW_MACINFO_end_file\fP +The end of the current source file inclusion. +.LI \f(CWDW_MACINFO_vendor_ext\fP +Vendor specific macro information directives that do not fit +into one of the standard categories. +.LE +.H 4 "Define and Undefine Entries" +.IX macro information, define and undefine entries +All +.Cf DW_MACINFO_define +and +.Cf DW_MACINFO_undef +entries have two operands. +The first operand encodes the line number of the source line +.IX source, lines +on which the relevant defining or undefining +pre-processor directives appeared. +.P +The second operand consists of a null-terminated character string. +In the case of a +.Cf DW_MACINFO_undef +entry, the value of this +string will be simply the name of the pre-processor +symbol which was undefined at the indicated source line. +.P +In the case of a +.Cf DW_MACINFO_define +entry, the value of this +string will be the name of the pre-processor symbol +that was defined at the indicated source line, +followed immediately by the macro formal parameter +list including the surrounding parentheses (in the +case of a function-like macro) followed by the +definition string for the macro. If there is no +formal parameter list, then the name of the defined +macro is followed directly by its definition string. +.P +In the case of a function-like macro definition, no +whitespace characters should appear between the +name of the defined macro and the following left +parenthesis. Also, no whitespace characters should +appear between successive formal parameters in the +formal parameter list. (Successive formal parameters +should, however, be separated by commas.) Also, exactly +one space character +should separate the right parenthesis which terminates +the formal parameter list and the following definition +string. +.P +In the case of a ``normal'' (i.e. non-function-like) +macro definition, exactly one space character +should separate the name of the defined macro from the following definition +text. +.H 4 "Start File Entries" +.IX macro information, start file entries +Each +.Cf DW_MACINFO_start_file +entry also has two operands. The first operand +encodes the line number of the +source line on which the inclusion pre-processor +directive occurred. +.P +.IX source, files +The second operand encodes a +source file name index. This index corresponds to a file +number in the statement information table for the relevant +compilation unit. This index +indicates (indirectly) the name of the file +which is being included by the inclusion directive on +the indicated source line. +.H 4 "End File Entries" +.IX macro information, end file entries +A +.Cf DW_MACINFO_end_file +entry has no operands. The presence of the entry marks the end of +the current source file inclusion. +.H 4 "Vendor Extension Entries" +.IX macro information, vendor extensions +.IX vendor extensions +A +.Cf DW_MACINFO_vendor_ext +entry has two operands. +The first is a constant. The second is a null-terminated +character string. +The meaning and/or significance of these operands is +intentionally left undefined by this specification. +.P +A consumer must be able to totally ignore all +.Cf DW_MACINFO_vendor_ext +entries that it does not understand. +.H 3 "Base Source Entries" +.IX macro information, base source entries +In addition to producing a matched pair of +.Cf DW_MACINFO_start_file +and +.Cf DW_MACINFO_end_file +entries for +each inclusion directive actually processed during +compilation, a producer should generate such a matched +pair also for the ``base'' source file submitted to the +compiler for compilation. If the base source file +.IX source, files +for a compilation is submitted to the compiler via +some means other than via a named disk file (e.g. via +the standard input \fIstream\fP on a UNIX system) then the +compiler should still produce this matched pair of +.Cf DW_MACINFO_start_file +and +.Cf DW_MACINFO_end_file +entries for +the base source file, however, the file name indicated +(indirectly) by the +.Cf DW_MACINFO_start_file +entry of the +pair should reference a statement information file name entry consisting +of a null string. +.H 3 "Macinfo Entries for Command Line Options" +.IX macro information, command line options +In addition to producing +.Cf DW_MACINFO_define +and +.Cf DW_MACINFO_undef +entries for each of the define and +undefine directives processed during compilation, the +DWARF producer should generate a +.Cf DW_MACINFO_define +or +.Cf DW_MACINFO_undef +entry for each pre-processor symbol +which is defined or undefined by some +means other than via a define or undefine directive +within the compiled source text. In particular, +pre-processor symbol definitions and un-definitions +which occur as a result of command line options +(when invoking the compiler) should be represented by +their own +.Cf DW_MACINFO_define +and +.Cf DW_MACINFO_undef +entries. +.P +All such +.Cf DW_MACINFO_define +and +.Cf DW_MACINFO_undef +entries representing compilation options should appear +before the first +.Cf DW_MACINFO_start_file +entry for that compilation unit and should encode the value +0 in their line number operands. +.H 3 " General Rules and Restrictions" +.IX line number information, general rules +All macinfo entries within a +.Cf .debug_macinfo +section for a given compilation unit should appear in the same order +in which the directives were processed by the compiler. +.P +All macinfo entries representing command line options +should appear in the same order as the relevant command +line options were given to the compiler. In the case +where the compiler itself implicitly supplies one or +more macro definitions or un-definitions in addition +to those which may be specified on the command line, +macinfo entries should also be produced for these +implicit definitions and un-definitions, and +these entries should also appear in the proper order +relative to each other and to any definitions or +undefinitions given explicitly by the user on the +command line. +.H 2 "Call Frame Information" +.IX call frame information +.IX activations +.I +Debuggers often need to be able to view and modify the state of any +subroutine activation that is on the call stack. An activation +consists of: +.BL +.LI +A code location that is within the subroutine. This location is +either the place where the program stopped when the debugger got +control (e.g. a breakpoint), or is a place where a subroutine +made a call or was interrupted by an asynchronous event (e.g. a +signal). +.LI +An area of memory that is allocated on a stack called a ``call +frame.'' The call frame is identified by an address on the +stack. We refer to this address as the Canonical Frame Address or CFA. +.LI +A set of registers that are in use by the subroutine at the code +location. +.LE +.P +Typically, a set of registers are designated to be preserved across a +call. If a callee wishes to use such a register, it saves the value +that the register had at entry time in its call frame and restores it +on exit. The code that allocates space on the call frame stack and +performs the save operation is called the subroutine's prologue, and the +code that performs the restore operation and deallocates the frame is +called its epilogue. Typically, the prologue code is physically at the +beginning of a subroutine and the epilogue code is at the end. +.P +To be able to view or modify an activation that is not on the top of +the call frame stack, the debugger must ``virtually unwind'' the stack of +activations until it finds the activation of interest. +A debugger unwinds a +stack in steps. Starting with the current activation it restores any +registers that were preserved by the current activation and computes the +predecessor's CFA and code location. This has the logical effect of +returning from the current subroutine to its predecessor. We say that +the debugger virtually unwinds the stack because it preserves enough +information to be able to ``rewind'' the stack back to the state it was +in before it attempted to unwind it. +.P +The unwinding operation needs to know where registers are saved and how +to compute the predecessor's CFA and code location. When considering +an architecture-independent way of encoding this information one has to +consider a number of special things. +.BL +.LI +Prologue and epilogue code is not always in distinct blocks at the +beginning and end of a subroutine. It is common to duplicate the +epilogue code at the site of each return from the code. Sometimes +a compiler breaks up the register save/unsave operations and moves +them into the body of the subroutine to just where they are needed. +.LI +Compilers use different ways to manage the call frame. Sometimes +they use a frame pointer register, sometimes not. +.LI +The algorithm to compute the CFA changes as you progress through +the prologue and epilogue code. (By definition, the CFA value +does not change.) +.LI +Some subroutines have no call frame. +.LI +Sometimes a register is saved in another register that by +convention does not need to be saved. +.LI +Some architectures have special instructions that +perform some or all of the register management in one instruction, +leaving special information on the stack that indicates how +registers are saved. +.LI +Some architectures treat return address values +specially. For example, in one architecture, +the call instruction guarantees that the low order two +bits will be zero and the return instruction ignores those bits. +This leaves two bits of storage that are available to other uses +that must be treated specially. +.LE +.R +.H 3 "Structure of Call Frame Information" +.IX call frame information, structure +DWARF supports virtual unwinding by defining an architecture independent +basis for recording how procedures save and restore registers throughout +their lifetimes. This basis must be augmented on some machines with +specific information that is defined by either an architecture specific +ABI authoring committee, a hardware vendor, or a compiler producer. +.IX ABI +.IX vendor extensions +The body defining a specific augmentation is referred to +below as the ``augmenter.'' +.P +Abstractly, this mechanism describes a very large table that has the +following structure: +.TS +center; +l l l l l l +l s s s s s. +LOC CFA R0 R1 ... RN +L0 +L1 +\... +LN +.TE +.P +The first column indicates an address for every location that contains +code in a program. (In shared objects, this is an object-relative +offset.) The remaining columns contain virtual unwinding rules that are +associated with the indicated location. The first column of the rules +defines the CFA rule which is a register and a signed offset that are +added together to compute the CFA value. +.P +The remaining columns are labeled by register number. This includes +some registers that have special designation on some architectures such +as the PC and the stack pointer register. (The actual mapping of +registers for a particular architecture is performed by the augmenter.) +The register columns contain rules that describe +whether a given register has been saved and the rule to find +the value for the register in the previous frame. +.P +The register rules are: +.IX call frame information, register rules +.VL 20 +.LI "undefined" +A register that has this rule has no value in the +previous frame. (By convention, it is not preserved by a callee.) +.LI "same value" +This register has not been modified from the +previous frame. (By convention, it is preserved by the callee, +but the callee has not modified it.) +.LI "offset(N)" +The previous value of this register is saved at the address CFA+N where +CFA is the current CFA value and N is a signed offset. +.LI "register(R)" +The previous value of this register is stored in +another register numbered R. +.LI "architectural" +The rule is defined externally to this specification by the augmenter. +.LE +.P +.I +This table would be extremely large if actually constructed as +described. Most of the entries at any point in the table are identical +to the ones above them. The whole table can be represented quite +compactly by recording just the differences starting at the beginning +address of each subroutine in the program. +.R +.P +The virtual unwind information is encoded in a self-contained section +called +.Cf .debug_frame . +.IX \f(CW.debug_frame\fP %debugaf +Entries in a +.Cf .debug_frame +section are aligned on +.IX call frame information, Common Information Entry +an addressing unit boundary and come in two forms: A Common Information +Entry (CIE) and a Frame Description Entry (FDE). +Sizes of data objects used in the encoding of the +.Cf .debug_frame +section are described in terms of the same data definitions +used for the line number information (see section 6.2.1). +.P +A Common Information Entry holds information that is shared among many +Frame Descriptors. There is at least one CIE in every non-empty +.Cf .debug_frame +section. A CIE contains the following fields, in order: +.AL +.LI +\f(CWlength\fP +.br +A uword constant that gives the number of bytes of the CIE +structure, not including the length field, itself +(length mod <addressing unit size> == 0). +.LI +\f(CWCIE_id\fP +.br +A uword constant that is used to distinguish CIEs +from FDEs. +.LI +\f(CWversion\fP +.br +A ubyte version number. This number is specific to the call frame +information and is independent of the DWARF version number. +.LI +\f(CWaugmentation\fP +.br +A null terminated string that identifies the +augmentation to this CIE or to the FDEs that use +it. If a reader encounters an augmentation string that is +unexpected, then only the following fields can be read: +CIE: +.Cf length , +.Cf CIE_id , +.Cf version , +.Cf augmentation ; +FDE: +.Cf length , +.Cf CIE_pointer , +.Cf initial_location , +.Cf address_range . +If there is no augmentation, this value is a zero byte. +.LI +\f(CWcode_alignment_factor\fP +.br +An unsigned LEB128 constant that is factored out +of all advance location instructions (see below). +.LI +\f(CWdata_alignment_factor\fP +.br +A signed LEB128 constant that is factored out +of all offset instructions (see below.) +.LI +\f(CWreturn_address_register\fP +.br +A ubyte constant that indicates +which column in the rule table represents the return address +of the function. Note that this column might not correspond +to an actual machine register. +.LI +\f(CWinitial_instructions\fP +.br +A sequence of rules that are interpreted to +create the initial setting of each column in the table. +.LI +\f(CWpadding\fP +.br +Enough +.Cf DW_CFA_nop +instructions to make the size of this entry +match the +.Cf length +value above. +.LE +.P +An FDE contains the following fields, in order: +.IX call frame information, Frame Description Entry +.AL +.LI +\f(CWlength\fP +.br +A uword constant that gives the number of bytes of the header +and instruction stream for this function (not including the length +field itself) (length mod <addressing unit size> == 0). +.LI +\f(CWCIE_pointer\fP +.br +A uword constant offset into the +.Cf .debug_frame +section that denotes the CIE that is associated with this FDE. +.LI +\f(CWinitial_location\fP +An addressing-unit sized constant indicating +the address of the first location associated with this table entry. +.LI +\f(CWaddress_range\fP +.br +An addressing unit sized constant indicating the +number of bytes of program instructions described by this entry. +.LI +\f(CWinstructions\fP +.br +A sequence of table defining instructions that are +described below. +.LE +.H 3 "Call Frame Instructions" +.IX call frame information, instructions +Each call frame instruction is defined to +take 0 or more operands. Some of the operands may be +encoded as part of the opcode (see section 7.23). +The instructions are as follows: +.AL +.LI +.Cf DW_CFA_advance_loc +takes a single argument that represents a constant delta. +The required action is to +create a new table row with a location value that +is computed by taking the current entry's location value and +adding (delta * \f(CWcode_alignment_factor\fP). All other values in the +new row are initially identical to the current row. +.LI +.Cf DW_CFA_offset +takes two arguments: +an unsigned LEB128 constant representing a factored offset +and a register number. The required action is +to change the rule for the register indicated by the register +number to be an offset(N) rule with a value of +(N = factored offset * \f(CWdata_alignment_factor\fP). +.LI +.Cf DW_CFA_restore +takes a single argument that represents a register number. +The required action is +to change the rule for the indicated register +to the rule assigned it by the \f(CWinitial_instructions\fP in the CIE. +.LI +.Cf DW_CFA_set_loc +takes a single argument that represents an address. +The required action is to create a new table row +using the specified address as the location. +All other values in the +new row are initially identical to the current row. +The new location value should always be greater than the current +one. +.LI +.Cf DW_CFA_advance_loc1 +takes a single ubyte argument that represents a constant delta. +This instruction is identical to +.Cf DW_CFA_advance_loc +except for the encoding and size of the delta argument. +.LI +.Cf DW_CFA_advance_loc2 +takes a single uhalf argument that represents a constant delta. +This instruction is identical to +.Cf DW_CFA_advance_loc +except for the encoding and size of the delta argument. +.LI +.Cf DW_CFA_advance_loc4 +takes a single uword argument that represents a constant delta. +This instruction is identical to +.Cf DW_CFA_advance_loc +except for the encoding and size of the delta argument. +.LI +.Cf DW_CFA_offset_extended +takes two unsigned LEB128 arguments representing a register number +and a factored offset. +This instruction is identical to +.Cf DW_CFA_offset +except for the encoding and size of the register argument. +.LI +.Cf DW_CFA_restore_extended +takes a single unsigned LEB128 argument that represents a register number. +This instruction is identical to +.Cf DW_CFA_restore +except for the encoding and size of the register argument. +.LI +.Cf DW_CFA_undefined +takes a single unsigned LEB128 argument that represents a register number. +The required action is to set the rule for the specified register +to ``undefined.'' +.LI +.Cf DW_CFA_same_value +takes a single unsigned LEB128 argument that represents a register number. +The required action is to set the rule for the specified register +to ``same value.'' +.LI +.Cf DW_CFA_register +takes two unsigned LEB128 arguments representing register numbers. +The required action is to set the rule for the first register +to be the second register. +.LI +\f(CWDW_CFA_remember_state\fP +.LI +\f(CWDW_CFA_restore_state\fP +.br +These instructions define a stack of information. Encountering the +.Cf DW_CFA_remember_state +instruction means to save the rules for every register +on the current row on the stack. Encountering the +.Cf DW_CFA_restore_state +instruction means to pop the set of rules +off the stack and place them in the current row. +.I +(This +operation is useful for compilers that move epilogue +code into the body of a function.) +.R +.LI +.Cf DW_CFA_def_cfa +takes two unsigned LEB128 arguments representing a +register number and an offset. +The required action is to define the current CFA rule +to use the provided register and offset. +.LI +.Cf DW_CFA_def_cfa_register +takes a single unsigned LEB128 argument representing a register +number. The required action is to define the current CFA +rule to use the provided register (but to keep the old offset). +.LI +.Cf DW_CFA_def_cfa_offset +takes a single unsigned LEB128 argument representing an offset. +The required action is to define the current CFA +rule to use the provided offset (but to keep the old register). +.LI +.Cf DW_CFA_nop +has no arguments and no required actions. It is used as padding +to make the FDE an appropriate size. +.LE +.H 3 "Call Frame Instruction Usage" +.IX call frame information, usage +.I +To determine the virtual unwind rule set for a given location (L1), one +searches through the FDE headers looking at the +.Cf initial_location +and +.Cf address_range +values to see if L1 is contained in the FDE. If so, then: +.AL +.LI +Initialize a register set by reading the +.Cf initial_instructions +field of the associated CIE. +.LI +Read and process the FDE's instruction sequence until a +.Cf DW_CFA_advance_loc , +.Cf DW_CFA_set_loc , +or the end of the instruction stream is +encountered. +.LI +If a +.Cf DW_CFA_advance_loc +or +.Cf DW_CFA_set_loc +instruction was encountered, then +compute a new location value (L2). If L1 >= L2 then process the +instruction and go back to step 2. +.LI +The end of the instruction stream can be thought of as a +.br +\f(CWDW_CFA_set_loc( initial_location + address_range )\fP +.br +instruction. +Unless the FDE is ill-formed, L1 should be less than L2 at this point. +.LE +.P +The rules in the register set now apply to location L1. +.P +For an example, see Appendix 5. +.R +.OP +.H 1 "DATA REPRESENTATION" +This section describes the binary representation of the debugging +information entry itself, of the +attribute types and of other fundamental elements described above. +.H 2 "Vendor Extensibility" +.IX vendor extensions +To reserve a portion of the DWARF name space and ranges of +enumeration values for use for vendor specific extensions, +.IX tags +.IX types, base +.IX base types +.IX locations, expressions +.IX calling conventions +.IX call frame information +special labels are reserved for tag names, attribute names, +base type encodings, location operations, language names, +calling conventions and call frame instructions. +The labels denoting the beginning and end of the reserved value +range for vendor specific extensions consist of the appropriate prefix ( +.Cf DW_TAG , +.Cf DW_AT , +.Cf DW_ATE , +.Cf DW_OP , +.Cf DW_LANG , +.CF DW_CC +or +.Cf DW_CFA +respectively) followed by +.Cf _lo_user +or +.Cf _hi_user . +For example, for entry tags, the special labels are +.Cf DW_TAG_lo_user +and +.Cf DW_TAG_hi_user . +Values in the range between \fIprefix\fP\f(CW_lo_user\fP and +\fIprefix\fP\f(CW_hi_user\fP +inclusive, are reserved for vendor specific extensions. +Vendors may use values in this range without +conflicting with current or future system-defined values. +All other values are reserved for use by the system. +.P +Vendor defined tags, attributes, base type encodings, location atoms, +language names, calling conventions and call frame instructions, +conventionally use the form +\fIprefix\f(CW_\fIvendor_id\f(CW_\fIname\fR, where \fIvendor_id\fP is some +identifying character sequence chosen so as to avoid conflicts with other +vendors. +.P +.IX compatibility +To ensure that extensions added by one vendor may be safely ignored +by consumers that do not understand those extensions, +the following rules should be followed: +.AL +.LI +New attributes should be added in such a way that a debugger may recognize +the format of a new attribute value without knowing the content of that +attribute value. +.LI +The semantics of any new attributes should not alter the semantics of +previously existing attributes. +.LI +The semantics of any new tags +should not conflict with the semantics of previously existing tags. +.LE +.H 2 "Reserved Error Values" +.IX error values +As a convenience for consumers of DWARF information, +the value 0 is reserved in the encodings for attribute names, attribute +forms, base type encodings, location operations, languages, +statement program opcodes, macro information entries and tag names +to represent an error condition or unknown value. DWARF does +not specify names for these reserved values, since they do not +represent valid encodings for the given type and should not appear +in DWARF debugging information. +.H 2 "Executable Objects and Shared Objects" +The relocated addresses in the debugging information for an executable +object are virtual addresses and the relocated addresses in the +debugging information for a shared object are offsets relative to +the start of the lowest segment used by that shared object. +.P +.I +This requirement makes the debugging information for shared objects +position independent. +Virtual addresses in a shared object may be calculated by adding the +offset to the base address at which the object was attached. +This offset is available in the run-time linker's data structures. +.H 2 "File Constraints" +All debugging information entries in a relocatable object file, +executable object or shared +object are required to be physically contiguous. +.H 2 "Format of Debugging Information" +.IX Version 2 +For each compilation unit compiled with a DWARF Version 2 producer, +.IX compilation units +.IX compilation units, header +a contribution is made to the +.Cf .debug_info +.IX \f(CW.debug_info\fP %debugai +section of the object file. Each such contribution consists of +a compilation unit header followed by a series of debugging information +entries. Unlike the information encoding for DWARF Version 1, Version 2 +.IX Version 1 +debugging information entries do not themselves contain the debugging +information entry tag or the attribute name and form encodings for +each attribute. Instead, each debugging information entry begins with +a code that represents an entry in a separate abbreviations table. +This code is followed directly by a series of attribute values. +The appropriate entry in the abbreviations table guides the interpretation +of the information contained directly in the +.Cf .debug_info +section. Each compilation unit is associated with a particular +abbreviation table, but multiple compilation units may share +the same table. +.IX abbreviations table +.I +.P +This encoding was based on the observation that typical DWARF producers +produce a very limited number of different types of debugging information +entries. By extracting the common information from those entries +into a separate table, we are able to compress the generated information. +.R +.H 3 "Compilation Unit Header" +.IX compilation units, header +The header for the series of debugging information entries contributed +by a single compilation unit consists of the following information: +.AL +.LI +A 4-byte unsigned integer representing the length of the +.Cf .debug_info +contribution for that compilation unit, not including the length field itself. +.LI +A 2-byte unsigned integer representing the version of the DWARF information +for that compilation unit. For DWARF Version 2, the value in this field is 2. +.IX Version 2 +.LI +A 4-byte unsigned offset into the +.Cf .debug_abbrev +.IX \f(CW.debug_abbrev\fP %debugaab +section. This offset associates the compilation unit with a particular +set of debugging information entry abbreviations. +.LI +.IX segmented address space +.IX address space, segmented +.IX addresses, size of +A 1-byte unsigned integer representing the size in bytes of an address +on the target architecture. If the system uses segmented addressing, +this value represents the size of the offset portion of an address. +.IX addresses, offset portion +.LE +.P +.I +The compilation unit header does not replace the +.Cf DW_TAG_compile_unit +debugging information entry. It is additional information that +is represented outside the standard DWARF tag/attributes format. +.R +.H 3 "Debugging Information Entry" +Each debugging information entry begins with an unsigned LEB128 +.IX debugging information entries +number containing the abbreviation code for the entry. +This code represents an entry within the abbreviation table associated +with the compilation unit containing this entry. The abbreviation +.IX abbreviations table +code is followed by a series of attribute values. +.IX attributes, values +.P +On some architectures, there are alignment constraints on section boundaries. +To make it easier to pad debugging information sections to satisfy +such constraints, the abbreviation code 0 is reserved. Debugging +information entries consisting of only the 0 abbreviation code are considered +null entries. +.IX debugging information entries, null entries +.H 3 "Abbreviation Tables" +.IX abbreviations table +The abbreviation tables for all compilation units are contained in +a separate object file section called +.Cf .debug_abbrev . +.IX \f(CW.debug_abbrev\fP %debugaab +As mentioned before, multiple compilation units may share the same +abbreviation table. +.P +The abbreviation table for a single compilation +unit consists of a series of abbreviation declarations. +Each declaration specifies the tag and attributes for a particular +.IX tags +.IX attributes +form of debugging information entry. Each declaration begins with +an unsigned LEB128 number representing the abbreviation code itself. +It is this code that appears at the beginning of a debugging information +entry in the +.Cf .debug_info +section. As described above, the abbreviation code 0 is reserved for null +debugging information entries. +The abbreviation code is followed by another unsigned LEB128 +number that encodes the entry's tag. +.IX tags +.nr aX \n(Fg+1 +.nr bX \n(Fg+2 +The encodings for the tag names are given in Figures \n(aX +and \n(bX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Tag name Value +_ +DW_TAG_array_type 0x01 +DW_TAG_class_type 0x02 +DW_TAG_entry_point 0x03 +DW_TAG_enumeration_type 0x04 +DW_TAG_formal_parameter 0x05 +DW_TAG_imported_declaration 0x08 +DW_TAG_label 0x0a +DW_TAG_lexical_block 0x0b +DW_TAG_member 0x0d +DW_TAG_pointer_type 0x0f +DW_TAG_reference_type 0x10 +DW_TAG_compile_unit 0x11 +DW_TAG_string_type 0x12 +DW_TAG_structure_type 0x13 +DW_TAG_subroutine_type 0x15 +DW_TAG_typedef 0x16 +DW_TAG_union_type 0x17 +DW_TAG_unspecified_parameters 0x18 +DW_TAG_variant 0x19 +DW_TAG_common_block 0x1a +DW_TAG_common_inclusion 0x1b +DW_TAG_inheritance 0x1c +DW_TAG_inlined_subroutine 0x1d +DW_TAG_module 0x1e +DW_TAG_ptr_to_member_type 0x1f +DW_TAG_set_type 0x20 +DW_TAG_subrange_type 0x21 +DW_TAG_with_stmt 0x22 +DW_TAG_access_declaration 0x23 +DW_TAG_base_type 0x24 +DW_TAG_catch_block 0x25 +DW_TAG_const_type 0x26 +DW_TAG_constant 0x27 +DW_TAG_enumerator 0x28 +DW_TAG_file_type 0x29 +.TE +.FG "Tag encodings (part 1)" +.DE +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Tag name Value +_ +DW_TAG_friend 0x2a +DW_TAG_namelist 0x2b +DW_TAG_namelist_item 0x2c +DW_TAG_packed_type 0x2d +DW_TAG_subprogram 0x2e +DW_TAG_template_type_param 0x2f +DW_TAG_template_value_param 0x30 +DW_TAG_thrown_type 0x31 +DW_TAG_try_block 0x32 +DW_TAG_variant_part 0x33 +DW_TAG_variable 0x34 +DW_TAG_volatile_type 0x35 +DW_TAG_lo_user 0x4080 +DW_TAG_hi_user 0xffff +.TE +.FG "Tag encodings (part 2)" +.DE +.P +Following the tag encoding is a 1-byte value that determines +whether a debugging information entry using this abbreviation +has child entries or not. If the value is +.Cf DW_CHILDREN_yes , +the next physically succeeding entry of any debugging information +entry using this abbreviation is the first child of the prior entry. +If the 1-byte value following the abbreviation's tag encoding +is +.Cf DW_CHILDREN_no , +the next physically succeeding entry of any debugging information entry +using this abbreviation is a sibling of the prior entry. (Either +the first child or sibling entries may be null entries). +.IX debugging information entries, siblings +.IX debugging information entries, child entries +.IX debugging information entries, null entries +.nr aX \n(Fg+1 +The encodings for the child determination byte are given in Figure \n(aX. +(As mentioned in section 2.3, each chain of sibling entries is +terminated by a null entry). +.IX debugging information entries, null entries +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Child determination name Value +_ +DW_CHILDREN_no 0 +DW_CHILDREN_yes 1 +.TE +.FG "Child determination encodings" +.DE +.P +Finally, the child encoding is followed by a series of attribute specifications. +.IX attributes +Each attribute specification consists of two parts. The first part +is an unsigned LEB128 number representing the attribute's name. +.IX attributes, names +The second part is an unsigned LEB128 number representing the +attribute's form. The series of attribute specifications ends +.IX attributes, forms +with an entry containing 0 for the name and 0 for the form. +.P +The attribute form +.Cf DW_FORM_indirect +is a special case. For attributes with this form, the attribute value +itself in the +.Cf .debug_info +section begins with an unsigned LEB128 number that represents its form. +This allows producers to choose forms for particular attributes dynamically, +without having to add a new entry to the abbreviation table. +.P +The abbreviations for a given compilation unit end with an entry +consisting of a 0 byte for the abbreviation code. +.I +.P +See Appendix 2 for a depiction of the organization +of the debugging information. +.R +.H 3 "Attribute Encodings" +.nr aX \n(Fg+1 +.nr bX \n(Fg+2 +The encodings for the attribute names are given in Figures \n(aX +and \n(bX. +.DF +.TS +box center; +l l l +lf(CW) lf(CW) l +. +Attribute name Value Classes +_ +DW_AT_sibling 0x01 reference +DW_AT_location 0x02 block, constant +DW_AT_name 0x03 string +DW_AT_ordering 0x09 constant +DW_AT_byte_size 0x0b constant +DW_AT_bit_offset 0x0c constant +DW_AT_bit_size 0x0d constant +DW_AT_stmt_list 0x10 constant +DW_AT_low_pc 0x11 address +DW_AT_high_pc 0x12 address +DW_AT_language 0x13 constant +DW_AT_discr 0x15 reference +DW_AT_discr_value 0x16 constant +DW_AT_visibility 0x17 constant +DW_AT_import 0x18 reference +DW_AT_string_length 0x19 block, constant +DW_AT_common_reference 0x1a reference +DW_AT_comp_dir 0x1b string +DW_AT_const_value 0x1c string, constant, block +DW_AT_containing_type 0x1d reference +DW_AT_default_value 0x1e reference +DW_AT_inline 0x20 constant +DW_AT_is_optional 0x21 flag +DW_AT_lower_bound 0x22 constant, reference +DW_AT_producer 0x25 string +DW_AT_prototyped 0x27 flag +DW_AT_return_addr 0x2a block, constant +DW_AT_start_scope 0x2c constant +DW_AT_stride_size 0x2e constant +DW_AT_upper_bound 0x2f constant, reference +.TE +.FG "Attribute encodings, part 1" +.DE +.DF +.TS +box center; +l l l +lf(CW) lf(CW) l +. +Attribute name Value Classes +_ +DW_AT_abstract_origin 0x31 reference +DW_AT_accessibility 0x32 constant +DW_AT_address_class 0x33 constant +DW_AT_artificial 0x34 flag +DW_AT_base_types 0x35 reference +DW_AT_calling_convention 0x36 constant +DW_AT_count 0x37 constant, reference +DW_AT_data_member_location 0x38 block, reference +DW_AT_decl_column 0x39 constant +DW_AT_decl_file 0x3a constant +DW_AT_decl_line 0x3b constant +DW_AT_declaration 0x3c flag +DW_AT_discr_list 0x3d block +DW_AT_encoding 0x3e constant +DW_AT_external 0x3f flag +DW_AT_frame_base 0x40 block, constant +DW_AT_friend 0x41 reference +DW_AT_identifier_case 0x42 constant +DW_AT_macro_info 0x43 constant +DW_AT_namelist_item 0x44 block +DW_AT_priority 0x45 reference +DW_AT_segment 0x46 block, constant +DW_AT_specification 0x47 reference +DW_AT_static_link 0x48 block, constant +DW_AT_type 0x49 reference +DW_AT_use_location 0x4a block, constant +DW_AT_variable_parameter 0x4b flag +DW_AT_virtuality 0x4c constant +DW_AT_vtable_elem_location 0x4d block, reference +DW_AT_lo_user 0x2000 \(em +DW_AT_hi_user 0x3fff \(em +.TE +.FG "Attribute encodings, part 2" +.DE +.P +.IX attributes, forms +The attribute form governs how the value of the attribute is encoded. +The possible forms may belong to one of the following +form classes: +.VL 18 +.LI address +.IX attributes, addresses +Represented as an object of appropriate size to hold an +address on the target machine (\f(CWDW_FORM_addr\fP). +This address is relocatable in +a relocatable object file and is relocated in an +executable file or shared object. +.LI "block" +.IX attributes, blocks +Blocks come in four forms. The first consists of a 1-byte length +followed by 0 to 255 contiguous information bytes (\f(CWDW_FORM_block1\fP). +The second consists of a 2-byte length +followed by 0 to 65,535 contiguous information bytes (\f(CWDW_FORM_block2\fP). +The third consists of a 4-byte length +followed by 0 to 4,294,967,295 contiguous information bytes (\f(CWDW_FORM_block4\fP). +The fourth consists of an unsigned LEB128 length followed by the number +of bytes specified by the length (\f(CWDW_FORM_block\fP). +In all forms, the length is the number of information bytes that follow. +The information bytes may contain any mixture of relocated (or +relocatable) addresses, references to other debugging information entries or +data bytes. +.LI "constant" +.IX attributes, constants +There are six forms of constants: +one, two, four and eight byte values (respectively, +.Cf DW_FORM_data1 , +.Cf DW_FORM_data2 , +.Cf DW_FORM_data4 , +and +.Cf DW_FORM_data8 ). +.IX variable length data +.IX LEB128 +There are also variable length constant data forms encoded +using LEB128 numbers (see below). Both signed (\f(CWDW_FORM_sdata\fP) +and unsigned (\f(CWDW_FORM_udata\fP) variable length constants are available. +.LI flag +.IX attributes, flags +A flag is represented as a single byte of data (\f(CWDW_FORM_flag\fP). +If the flag has value zero, it indicates the absence of the attribute. +If the flag has a non-zero value, it indicates the presence of +the attribute. +.LI reference +.IX attributes, references +There are two types of reference. The first is an +offset relative to the first byte of the compilation unit header +for the compilation unit containing the reference. +The offset must refer to an entry within +that same compilation unit. There are five forms for this +type of reference: +one, two, four and eight byte offsets (respectively, +.Cf DW_FORM_ref1 , +.Cf DW_FORM_ref2 , +.Cf DW_FORM_ref4 , +and +.Cf DW_FORM_ref8 ). +There are is also an unsigned variable length offset encoded +using LEB128 numbers (\f(CWDW_FORM_ref_udata\fP). +.P +The second type of reference +is the address of any debugging information entry within +the same executable or shared object; it may refer to an entry +in a different compilation unit from the unit containing the +reference. This type of reference (\f(CWDW_FORM_ref_addr\fP) is the +size of an address on the target architecture; it is relocatable +in a relocatable object file and relocated in an executable file +or shared object. +.P +.I +The use of compilation unit relative references will reduce +the number of link-time relocations and so speed up linking. +.P +The use of address-type references allows for the commonization +of information, such as types, across compilation units. +.R +.LI string +.IX attributes, strings +A string is a sequence of contiguous non-null bytes followed by one null +byte. A string may be represented immediately in the debugging information +entry itself (\f(CWDW_FORM_string\fP), or may be represented as a 4-byte offset +into a string table contained in the +.Cf .debug_str +.IX \f(CW.debug_str\fP %debugas +.IX string table +section of the object file (\f(CWDW_FORM_strp\fP). +.LE +.P +.nr aX \n(Fg+1 +The form encodings are listed in Figure \n(aX. +.DF +.TS +box center; +l l l +lf(CW) lf(CW) l +. +Form name Value Class +_ +DW_FORM_addr 0x01 address +DW_FORM_block2 0x03 block +DW_FORM_block4 0x04 block +DW_FORM_data2 0x05 constant +DW_FORM_data4 0x06 constant +DW_FORM_data8 0x07 constant +DW_FORM_string 0x08 string +DW_FORM_block 0x09 block +DW_FORM_block1 0x0a block +DW_FORM_data1 0x0b constant +DW_FORM_flag 0x0c flag +DW_FORM_sdata 0x0d constant +DW_FORM_strp 0x0e string +DW_FORM_udata 0x0f constant +DW_FORM_ref_addr 0x10 reference +DW_FORM_ref1 0x11 reference +DW_FORM_ref2 0x12 reference +DW_FORM_ref4 0x13 reference +DW_FORM_ref8 0x14 reference +DW_FORM_ref_udata 0x15 reference +DW_FORM_indirect 0x16 (see section 7.5.3) +.TE +.FG "Attribute form encodings" +.DE +.H 2 "Variable Length Data" +.IX variable length data +.IX LEB128 +The special constant data forms +.Cf DW_FORM_sdata +and +.Cf DW_FORM_udata +are encoded using ``Little Endian Base 128'' (LEB128) +numbers. LEB128 is a scheme for encoding integers densely that +exploits the assumption that most integers are small in magnitude. +(This encoding is equally suitable whether the target machine +architecture represents data in big-endian or little-endian order. +It is ``little endian'' only in the sense that it avoids using space +to represent the ``big'' end of an unsigned integer, when the big +end is all zeroes or sign extension bits). +.P +.Cf DW_FORM_udata +(unsigned LEB128) numbers are encoded as follows: +start at the +low order end of an unsigned integer and chop it into 7-bit chunks. +Place each chunk into the low order 7 bits of a byte. Typically, +several of the high order bytes will be zero; discard them. Emit the +remaining bytes in a stream, starting with the low order byte; +set the high order bit on each byte except the last emitted byte. +The high bit of zero on the last byte indicates to the decoder +that it has encountered the last byte. +.P +The integer zero is a special case, consisting of a single zero byte. +.P +.I +.nr aX \n(Fg+1 +Figure \n(aX gives some examples of +.Cf DW_FORM_udata +numbers. The +.Cf 0x80 +in each case is the high order bit of the byte, indicating that +an additional byte follows: +.R +.DF +.TS +box center; +l l l +nf(CW) lf(CW) lf(CW) +. +Number First byte Second byte +_ +2 2 \(em +127 127 \(em +128 0+0x80 1 +129 1+0x80 1 +130 2+0x80 1 +12857 57+0x80 100 +.TE +.FG "Examples of unsigned LEB128 encodings" +.DE +.P +The encoding for +.Cf DW_FORM_sdata +(signed, 2s complement LEB128) numbers is similar, except that the +criterion for discarding high order bytes is not whether they are +zero, but whether they consist entirely of sign extension bits. +Consider the 32-bit integer +.Cf -2 . +The three high level bytes of the number are sign extension, thus LEB128 +would represent it as a single byte containing the low order 7 bits, +with the high order bit cleared to indicate the end of the byte +stream. Note that there is nothing within the LEB128 representation +that indicates whether an encoded number is signed or unsigned. +The decoder must know what type of number to expect. +.P +.I +.nr aX \n(Fg+1 +Figure \n(aX gives some examples of +.Cf DW_FORM_sdata +numbers. +.R +.P +.I +Appendix 4 gives algorithms for encoding and decoding these forms. +.R +.DF +.TS +box center; +l l l +nf(CW) lf(CW) lf(CW) +. +Number First byte Second byte +_ +2 2 \(em +-2 0x7e \(em +127 127+0x80 0 +-127 1+0x80 0x7f +128 0+0x80 1 +-128 0+0x80 0x7f +129 1+0x80 1 +-129 0x7f+0x80 0x7e +.TE +.FG "Examples of signed LEB128 encodings" +.DE +.H 2 "Location Descriptions" +.H 3 "Location Expressions" +.IX locations, descriptions +.IX locations, expressions +A location expression is stored in a block of contiguous bytes. +The bytes form a set of operations. +Each location operation has a 1-byte code +that identifies that operation. Operations can be followed +by one or more bytes of additional data. All operations in a +location expression are concatenated from left to right. +The encodings for the operations in a location expression +.IX locations, expressions +.nr aX \n(Fg+1 +.nr bX \n(Fg+2 +are described in Figures \n(aX and \n(bX. +.DS +.TS +center box; +l l l l +lf(CW) lf(CW) l l +. +Operation Code No. of Operands Notes +_ +DW_OP_addr 0x03 1 constant address (size target specific) +DW_OP_deref 0x06 0 +DW_OP_const1u 0x08 1 1-byte constant +DW_OP_const1s 0x09 1 1-byte constant +DW_OP_const2u 0x0a 1 2-byte constant +DW_OP_const2s 0x0b 1 2-byte constant +DW_OP_const4u 0x0c 1 4-byte constant +DW_OP_const4s 0x0d 1 4-byte constant +DW_OP_const8u 0x0e 1 8-byte constant +DW_OP_const8s 0x0f 1 8-byte constant +DW_OP_constu 0x10 1 ULEB128 constant +DW_OP_consts 0x11 1 SLEB128 constant +DW_OP_dup 0x12 0 +DW_OP_drop 0x13 0 +DW_OP_over 0x14 0 +DW_OP_pick 0x15 1 1-byte stack index +DW_OP_swap 0x16 0 +DW_OP_rot 0x17 0 +DW_OP_xderef 0x18 0 +DW_OP_abs 0x19 0 +DW_OP_and 0x1a 0 +DW_OP_div 0x1b 0 +DW_OP_minus 0x1c 0 +DW_OP_mod 0x1d 0 +DW_OP_mul 0x1e 0 +DW_OP_neg 0x1f 0 +DW_OP_not 0x20 0 +DW_OP_or 0x21 0 +DW_OP_plus 0x22 0 +DW_OP_plus_uconst 0x23 1 ULEB128 addend +DW_OP_shl 0x24 0 +DW_OP_shr 0x25 0 +DW_OP_shra 0x26 0 +.TE +.FG "Location operation encodings, part 1" +.DE +.DS +.TS +center box; +l l l l +lf(CW) lf(CW) l l +. +Operation Code No. of Operands Notes +_ +DW_OP_xor 0x27 0 +DW_OP_skip 0x2f 1 signed 2-byte constant +DW_OP_bra 0x28 1 signed 2-byte constant +DW_OP_eq 0x29 0 +DW_OP_ge 0x2a 0 +DW_OP_gt 0x2b 0 +DW_OP_le 0x2c 0 +DW_OP_lt 0x2d 0 +DW_OP_ne 0x2e 0 +DW_OP_lit0 0x30 0 literals 0..31 = (DW_OP_LIT0|literal) +DW_OP_lit1 0x31 0 +\.\.\. +DW_OP_lit31 0x4f 0 +DW_OP_reg0 0x50 0 reg 0..31 = (DW_OP_REG0|regnum) +DW_OP_reg1 0x51 0 +\.\.\. +DW_OP_reg31 0x6f 0 +DW_OP_breg0 0x70 1 SLEB128 offset +DW_OP_breg1 0x71 1 base reg 0..31 = (DW_OP_BREG0|regnum) +\.\.\. +DW_OP_breg31 0x8f 1 +DW_OP_regx 0x90 1 ULEB128 register +DW_OP_fbreg 0x91 1 SLEB128 offset +DW_OP_bregx 0x92 2 ULEB128 register followed by SLEB128 offset +DW_OP_piece 0x93 1 ULEB128 size of piece addressed +DW_OP_deref_size 0x94 1 1-byte size of data retrieved +DW_OP_xderef_size 0x95 1 1-byte size of data retrieved +DW_OP_nop 0x96 0 +DW_OP_lo_user 0xe0 +DW_OP_hi_user 0xff +.TE +.FG "Location operation encodings, part 2" +.DE +.H 3 "Location Lists" +.IX locations, lists +Each entry in a location list consists of two relative addresses +followed by a 2-byte length, followed by a block of contiguous +bytes. The length specifies the number of bytes in the block +that follows. The two addresses are the same size as used by +.Cf DW_FORM_addr +on the target machine. +.H 2 "Base Type Encodings" +.nr aX \n(Fg+1 +.IX base types +.IX types, base +The values of the constants used in the +.Cf DW_AT_encoding +attribute are given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Base type encoding name Value +_ +DW_ATE_address 0x1 +DW_ATE_boolean 0x2 +DW_ATE_complex_float 0x3 +DW_ATE_float 0x4 +DW_ATE_signed 0x5 +DW_ATE_signed_char 0x6 +DW_ATE_unsigned 0x7 +DW_ATE_unsigned_char 0x8 +DW_ATE_lo_user 0x80 +DW_ATE_hi_user 0xff +.TE +.FG "Base type encoding values" +.DE +.H 2 "Accessibility Codes" +.nr aX \n(Fg+1 +.IX accessibility +.IX declarations, accessibility +The encodings of the constants used in the +.Cf DW_AT_accessibility +attribute are given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Accessibility code name Value +_ +DW_ACCESS_public 1 +DW_ACCESS_protected 2 +DW_ACCESS_private 3 +.TE +.FG "Accessibility encodings" +.DE +.H 2 "Visibility Codes" +.nr aX \n(Fg+1 +The encodings of the constants used in the +.Cf DW_AT_visibility +.IX visibility +.IX declarations, visibility +attribute are given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Visibility code name Value +_ +DW_VIS_local 1 +DW_VIS_exported 2 +DW_VIS_qualified 3 +.TE +.FG "Visibility encodings" +.DE +.H 2 "Virtuality Codes" +.nr aX \n(Fg+1 +.IX virtuality +The encodings of the constants used in the +.Cf DW_AT_virtuality +attribute are given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Virtuality code name Value +_ +DW_VIRTUALITY_none 0 +DW_VIRTUALITY_virtual 1 +DW_VIRTUALITY_pure_virtual 2 +.TE +.FG "Virtuality encodings" +.DE +.H 2 "Source Languages" +.nr aX \n(Fg+1 +.IX languages +The encodings for source languages are given in Figure \n(aX. +Names marked with \(dg and their associated +values are reserved, but the languages +they represent are not supported in DWARF Version 2. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Language name Value +_ +DW_LANG_C89 0x0001 +DW_LANG_C 0x0002 +DW_LANG_Ada83\(dg 0x0003 +DW_LANG_C_plus_plus 0x0004 +DW_LANG_Cobol74\(dg 0x0005 +DW_LANG_Cobol85\(dg 0x0006 +DW_LANG_Fortran77 0x0007 +DW_LANG_Fortran90 0x0008 +DW_LANG_Pascal83 0x0009 +DW_LANG_Modula2 0x000a +DW_LANG_lo_user 0x8000 +DW_LANG_hi_user 0xffff +.TE +.FG "Language encodings" +.DE +.H 2 "Address Class Encodings" +.IX addresses, class +The value of the common address class encoding +.Cf DW_ADDR_none +is 0. +.H 2 "Identifier Case" +.IX identifiers, case +The encodings of the constants used in the +.Cf DW_AT_identifier_case +.nr aX \n(Fg+1 +attribute are given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Identifier Case Name Value +_ +DW_ID_case_sensitive 0 +DW_ID_up_case 1 +DW_ID_down_case 2 +DW_ID_case_insensitive 3 +.TE +.FG "Identifier case encodings" +.DE +.H 2 "Calling Convention Encodings" +.IX calling conventions +The encodings for the values of the +.Cf DW_AT_calling_convention +.nr aX \n(Fg+1 +attribute are given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Calling Convention Name Value +_ +DW_CC_normal 0x1 +DW_CC_program 0x2 +DW_CC_nocall 0x3 +DW_CC_lo_user 0x40 +DW_CC_hi_user 0xff +.TE +.FG "Calling convention encodings" +.DE +.H 2 "Inline Codes" +.IX subroutines, inline +The encodings of the constants used in the +.Cf DW_AT_inline +.nr aX \n(Fg+1 +attribute are given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Inline Code Name Value +_ +DW_INL_not_inlined 0 +DW_INL_inlined 1 +DW_INL_declared_not_inlined 2 +DW_INL_declared_inlined 3 +.TE +.FG "Inline encodings" +.DE +.H 2 "Array Ordering" +.IX arrays, ordering +The encodings for the values of the order attributes of arrays +.nr aX \n(Fg+1 +is given in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Ordering name Value +_ +DW_ORD_row_major 0 +DW_ORD_col_major 1 +.TE +.FG "Ordering encodings" +.DE +.H 2 "Discriminant Lists" +.IX variants +.IX discriminated unions +.IX discriminants +The descriptors used in the +.Cf DW_AT_dicsr_list +attribute are encoded as 1-byte constants. +.nr aX \n(Fg+1 +The defined values are presented in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Descriptor Name Value +_ +DW_DSC_label 0 +DW_DSC_range 1 +.TE +.FG "Discriminant descriptor encodings" +.DE +.H 2 "Name Lookup Table" +.IX lookup, by name +Each set of entries in the table of global names contained in the +.Cf .debug_pubnames +.IX \f(CW.debug_pubnames\fP %debugap +section begins with a header consisting of: a 4-byte length containing +the length of the set of entries for this compilation unit, not including +the length field itself; a 2-byte version identifier containing +the value 2 for DWARF Version 2; a 4-byte offset into the +.Cf .debug_info +section; and a 4-byte length containing the size in bytes +of the contents of the +.Cf .debug_info +section generated to represent this compilation unit. +This header is followed by a series of tuples. +Each tuple consists of a 4-byte offset +followed by a string of non-null bytes terminated by one null byte. +Each set is terminated by a 4-byte word containing the value 0. +.H 2 "Address Range Table" +.IX lookup, by address +Each set of entries in the table of address ranges contained in the +.Cf .debug_aranges +.IX \f(CW.debug_aranges\fP %debugaar +section begins with a header consisting of: a 4-byte length containing +the length of the set of entries for this compilation unit, not including +the length field itself; a 2-byte version identifier containing +the value 2 for DWARF Version 2; a 4-byte offset into the +.Cf .debug_info +section; a 1-byte unsigned integer containing the size in bytes of an +address (or the offset portion of an address for segmented addressing) +.IX addresses, offset portion +.IX addresses, size of +on the target system; and a 1-byte unsigned integer containing the +size in bytes of a segment descriptor on the target system. +This header is followed by a series of tuples. +Each tuple consists of an address and a length, each +in the size appropriate for an address on the target architecture. +The first tuple following the header in each set begins at +an offset that is a multiple of the size of a single tuple +(that is, twice the size of an address). The header is +padded, if necessary, to the appropriate boundary. +Each set of tuples is terminated by a 0 for the address and 0 for the length. +.H 2 "Line Number Information" +.IX line number information +.IX line number information, definitions +The sizes of the integers used in the line number and +call frame information sections are as follows: +.VL 15 +.LI "sbyte" +Signed 1-byte value. +.LI "ubyte" +Unsigned 1-byte value. +.LI "uhalf" +Unsigned 2-byte value. +.LI "sword" +Signed 4-byte value. +.LI "uword" +Unsigned 4-byte value. +.LI +.LE +.P +.IX Version 2 +The version number in the statement program prologue is 2 for +DWARF Version 2. +The boolean values ``true'' and ``false'' used by the statement +information program are encoded as a single byte containing the +value 0 for ``false,'' and a non-zero value for ``true.'' +The encodings for the pre-defined standard opcodes are given +.IX line number information, standard opcodes +.nr aX \n(Fg+1 +in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Opcode Name Value +_ +DW_LNS_copy 1 +DW_LNS_advance_pc 2 +DW_LNS_advance_line 3 +DW_LNS_set_file 4 +DW_LNS_set_column 5 +DW_LNS_negate_stmt 6 +DW_LNS_set_basic_block 7 +DW_LNS_const_add_pc 8 +DW_LNS_fixed_advance_pc 9 +.TE +.FG "Standard Opcode Encodings" +.DE +The encodings for the pre-defined extended opcodes are given +.IX line number information, extended opcodes +.nr aX \n(Fg+1 +in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Opcode Name Value +_ +DW_LNE_end_sequence 1 +DW_LNE_set_address 2 +DW_LNE_define_file 3 +.TE +.FG "Extended Opcode Encodings" +.DE +.H 2 "Macro Information" +.IX macro information +.IX source, files +The source line numbers and source file indices encoded in the +macro information section are represented as unsigned LEB128 numbers +as are the constants in an +.Cf DW_MACINFO_vendor_ext +entry. +The macinfo type is encoded as a single byte. The encodings are given +.nr aX \n(Fg+1 +in Figure \n(aX. +.DF +.TS +box center; +l l +lf(CW) lf(CW) +. +Macinfo Type Name Value +_ +DW_MACINFO_define 1 +DW_MACINFO_undef 2 +DW_MACINFO_start_file 3 +DW_MACINFO_end_file 4 +DW_MACINFO_vendor_ext 255 +.TE +.FG "Macinfo Type Encodings" +.DE +.H 2 "Call Frame Information" +.IX call frame information +The value of the CIE id in the CIE header is +.Cf 0xffffffff . +The initial value of the CIE version number is 1. +.P +Call frame instructions are encoded in one or more bytes. +.IX call frame information, instructions +The primary opcode is encoded in the high order two bits of +the first byte (that is, opcode = byte >> 6). +An operand or extended opcode may be encoded in the low order +6 bits. Additional operands are encoded in subsequent bytes. +The instructions and their encodings are presented +.nr aX \n(Fg+1 +in Figure \n(aX. +.DS +.TS +center box; +l l l l l +lf(CW) lf(CW) l l +lf(CW) lf(CW) l l +lf(CW) lf(CW) l l +lf(CW) lf(CW) lf(CW) l. +Instruction High 2 Bits Low 6 Bits Operand 1 Operand 2 +_ +DW_CFA_advance_loc 0x1 delta +DW_CFA_offset 0x2 register ULEB128 offset +DW_CFA_restore 0x3 register +DW_CFA_set_loc 0 0x01 address +DW_CFA_advance_loc1 0 0x02 1-byte delta +DW_CFA_advance_loc2 0 0x03 2-byte delta +DW_CFA_advance_loc4 0 0x04 4-byte delta +DW_CFA_offset_extended 0 0x05 ULEB128 register ULEB128 offset +DW_CFA_restore_extended 0 0x06 ULEB128 register +DW_CFA_undefined 0 0x07 ULEB128 register +DW_CFA_same_value 0 0x08 ULEB128 register +DW_CFA_register 0 0x09 ULEB128 register ULEB128 register +DW_CFA_remember_state 0 0x0a +DW_CFA_restore_state 0 0x0b +DW_CFA_def_cfa 0 0x0c ULEB128 register ULEB128 offset +DW_CFA_def_cfa_register 0 0x0d ULEB128 register +DW_CFA_def_cfa_offset 0 0x0e ULEB128 offset +DW_CFA_nop 0 0 +DW_CFA_lo_user 0 0x1c +DW_CFA_hi_user 0 0x3f +.TE +.FG "Call frame instruction encodings" +.DE +.H 2 "Dependencies" +The debugging information in this format is intended to exist in the +.Cf .debug_abbrev , +.Cf .debug_aranges , +.Cf .debug_frame , +.Cf .debug_info , +.Cf .debug_line , +.Cf .debug_loc , +.Cf .debug_macinfo , +.Cf .debug_pubnames +and +.Cf .debug_str +.IX \f(CW.debug_abbrev\fP %debugaab +.IX \f(CW.debug_aranges\fP %debugaar +.IX \f(CW.debug_frame\fP %debugaf +.IX \f(CW.debug_info\fP %debugai +.IX \f(CW.debug_line\fP %debugali +.IX \f(CW.debug_loc\fP %debugalo +.IX \f(CW.debug_macinfo\fP %debugam +.IX \f(CW.debug_pubnames\fP %debugap +.IX \f(CW.debug_str\fP %debugas +sections of an object file. +The information is not word-aligned, so the assembler must provide a +way for the compiler to produce 2-byte and 4-byte quantities without +alignment restrictions, and the linker must be able to +relocate a 4-byte reference at an arbitrary alignment. +In target architectures with 64-bit addresses, the assembler and linker +must similarly handle 8-byte references at arbitrary alignments. +.OP +.H 1 "FUTURE DIRECTIONS" +The \*(iX \*(tE is working on a specification for a set of interfaces +for reading DWARF information, that will hide changes in the +representation of that information from its consumers. It is +hoped that using these interfaces will make the transition from +DWARF Version 1 to Version 2 much simpler and will make it +easier for a single consumer to support objects using either +Version 1 or Version 2 DWARF. +.P +A draft of this specification is available for review from +\*(iX. The \*(tE wishes to stress, however, that the specification +is still in flux. +.OP +.HU "Appendix 1 -- Current Attributes by Tag Value" +.P +The list below enumerates the attributes that are most applicable to each type +of debugging information entry. +DWARF does not in general require that a given debugging information +entry contain a particular attribute or set of attributes. Instead, a +DWARF producer is free to generate any, all, or none of the attributes +described in the text as being applicable to a given entry. Other +attributes (both those defined within this document but not explicitly +associated with the entry in question, and new, vendor-defined ones) +may also appear in a given debugging entry. +Therefore, the list may be +taken as instructive, but cannot be considered definitive. +.sp +.sp +.DS +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_access_declaration:DECL\(dg +:DW_AT_accessibility +:DW_AT_name +:DW_AT_sibling +_ +DW_TAG_array_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_declaration +:DW_AT_name +:DW_AT_ordering +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_stride_size +:DW_AT_type +:DW_AT_visibility +_ +DW_TAG_base_type:DW_AT_bit_offset +:DW_AT_bit_size +:DW_AT_byte_size +:DW_AT_encoding +:DW_AT_name +:DW_AT_sibling +_ +DW_TAG_catch_block:DW_AT_abstract_origin +:DW_AT_high_pc +:DW_AT_low_pc +:DW_AT_segment +:DW_AT_sibling +.TE +.DE +.br +\(dg +.Cf DW_AT_decl_column , +.Cf DW_AT_decl_file , +.Cf DW_AT_decl_line . +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_class_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_declaration +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_visibility +_ +DW_TAG_common_block:DECL +:DW_AT_declaration +:DW_AT_location +:DW_AT_name +:DW_AT_sibling +:DW_AT_visibility +_ +DW_TAG_common_inclusion:DECL +:DW_AT_common_reference +:DW_AT_declaration +:DW_AT_sibling +:DW_AT_visibility +_ +DW_TAG_compile_unit:DW_AT_base_types +:DW_AT_comp_dir +:DW_AT_identifier_case +:DW_AT_high_pc +:DW_AT_language +:DW_AT_low_pc +:DW_AT_macro_info +:DW_AT_name +:DW_AT_producer +:DW_AT_sibling +:DW_AT_stmt_list +_ +DW_TAG_const_type:DW_AT_sibling +:DW_AT_type +.TE +.DE +.br +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_constant:DECL +:DW_AT_accessibility +:DW_AT_constant_value +:DW_AT_declaration +:DW_AT_external +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_type +:DW_AT_visibility +_ +DW_TAG_entry_point:DW_AT_address_class +:DW_AT_low_pc +:DW_AT_name +:DW_AT_return_addr +:DW_AT_segment +:DW_AT_sibling +:DW_AT_static_link +:DW_AT_type +_ +DW_TAG_enumeration_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_declaration +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_visibility +_ +DW_TAG_enumerator:DECL +:DW_AT_const_value +:DW_AT_name +:DW_AT_sibling +_ +DW_TAG_file_type:DECL +:DW_AT_abstract_origin +:DW_AT_byte_size +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_type +:DW_AT_visibility +.TE +.DE +.br +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_formal_parameter:DECL +:DW_AT_abstract_origin +:DW_AT_artificial +:DW_AT_default_value +:DW_AT_is_optional +:DW_AT_location +:DW_AT_name +:DW_AT_segment +:DW_AT_sibling +:DW_AT_type +:DW_AT_variable_parameter +_ +DW_TAG_friend:DECL +:DW_AT_abstract_origin +:DW_AT_friend +:DW_AT_sibling +_ +DW_TAG_imported_declaration:DECL +:DW_AT_accessibility +:DW_AT_import +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +_ +DW_TAG_inheritance:DECL +:DW_AT_accessibility +:DW_AT_data_member_location +:DW_AT_sibling +:DW_AT_type +:DW_AT_virtuality +_ +DW_TAG_inlined_subroutine:DECL +:DW_AT_abstract_origin +:DW_AT_high_pc +:DW_AT_low_pc +:DW_AT_segment +:DW_AT_sibling +:DW_AT_return_addr +:DW_AT_start_scope +_ +DW_TAG_label:DW_AT_abstract_origin +:DW_AT_low_pc +:DW_AT_name +:DW_AT_segment +:DW_AT_start_scope +:DW_AT_sibling +.TE +.DE +.br +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_lexical_block:DW_AT_abstract_origin +:DW_AT_high_pc +:DW_AT_low_pc +:DW_AT_name +:DW_AT_segment +:DW_AT_sibling +_ +DW_TAG_member:DECL +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_bit_offset +:DW_AT_bit_size +:DW_AT_data_member_location +:DW_AT_declaration +:DW_AT_name +:DW_AT_sibling +:DW_AT_type +:DW_AT_visibility +_ +DW_TAG_module:DECL +:DW_AT_accessibility +:DW_AT_declaration +:DW_AT_high_pc +:DW_AT_low_pc +:DW_AT_name +:DW_AT_priority +:DW_AT_segment +:DW_AT_sibling +:DW_AT_visibility +_ +DW_TAG_namelist:DECL +:DW_AT_accessibility +:DW_AT_abstract_origin +:DW_AT_declaration +:DW_AT_sibling +:DW_AT_visibility +_ +DW_TAG_namelist_item:DECL +:DW_AT_namelist_item +:DW_AT_sibling +_ +DW_TAG_packed_type:DW_AT_sibling +:DW_AT_type +.TE +.DE +.br +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_pointer_type:DW_AT_address_class +:DW_AT_sibling +:DW_AT_type +_ +DW_TAG_ptr_to_member_type:DECL +:DW_AT_abstract_origin +:DW_AT_address_class +:DW_AT_containing_type +:DW_AT_declaration +:DW_AT_name +:DW_AT_sibling +:DW_AT_type +:DW_AT_use_location +:DW_AT_visibility +_ +DW_TAG_reference_type:DW_AT_address_class +:DW_AT_sibling +:DW_AT_type +_ +DW_TAG_set_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_declaration +:DW_AT_name +:DW_AT_start_scope +:DW_AT_sibling +:DW_AT_type +:DW_AT_visibility +_ +DW_TAG_string_type:DECL +:DW_AT_accessibility +:DW_AT_abstract_origin +:DW_AT_byte_size +:DW_AT_declaration +:DW_AT_name +:DW_AT_segment +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_string_length +:DW_AT_visibility +.TE +.DE +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_structure_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_declaration +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_visibility +_ +DW_TAG_subprogram:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_address_class +:DW_AT_artificial +:DW_AT_calling_convention +:DW_AT_declaration +:DW_AT_external +:DW_AT_frame_base +:DW_AT_high_pc +:DW_AT_inline +:DW_AT_low_pc +:DW_AT_name +:DW_AT_prototyped +:DW_AT_return_addr +:DW_AT_segment +:DW_AT_sibling +:DW_AT_specification +:DW_AT_start_scope +:DW_AT_static_link +:DW_AT_type +:DW_AT_visibility +:DW_AT_virtuality +:DW_AT_vtable_elem_location +.TE +.DE +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_subrange_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_count +:DW_AT_declaration +:DW_AT_lower_bound +:DW_AT_name +:DW_AT_sibling +:DW_AT_type +:DW_AT_upper_bound +:DW_AT_visibility +_ +DW_TAG_subroutine_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_address_class +:DW_AT_declaration +:DW_AT_name +:DW_AT_prototyped +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_type +:DW_AT_visibility +_ +DW_TAG_template_type_param:DECL +:DW_AT_name +:DW_AT_sibling +:DW_AT_type +_ +DW_TAG_template_value_param:DECL +:DW_AT_name +:DW_AT_const_value +:DW_AT_sibling +:DW_AT_type +_ +DW_TAG_thrown_type:DECL +:DW_AT_sibling +:DW_AT_type +_ +DW_TAG_try_block:DW_AT_abstract_origin +:DW_AT_high_pc +:DW_AT_low_pc +:DW_AT_segment +:DW_AT_sibling +.TE +.DE +.br +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_typedef:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_declaration +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_type +:DW_AT_visibility +_ +DW_TAG_union_type:DECL +:DW_AT_abstract_origin +:DW_AT_accessibility +:DW_AT_byte_size +:DW_AT_declaration +:DW_AT_friends +:DW_AT_name +:DW_AT_sibling +:DW_AT_start_scope +:DW_AT_visibility +_ +DW_TAG_unspecified_parameters:DECL +:DW_AT_abstract_origin +:DW_AT_artificial +:DW_AT_sibling +_ +DW_TAG_variable:DECL +:DW_AT_accessibility +:DW_AT_constant_value +:DW_AT_declaration +:DW_AT_external +:DW_AT_location +:DW_AT_name +:DW_AT_segment +:DW_AT_sibling +:DW_AT_specification +:DW_AT_start_scope +:DW_AT_type +:DW_AT_visibility +.TE +.DE +.br +.SK +.DS +.B "Appendix 1 (cont'd) -- Current Attributes by Tag Value" + + + +.TS +box, tab(:) ; +lfB lfB +lf(CW) lf(CW) . +TAG NAME:APPLICABLE ATTRIBUTES +_ +DW_TAG_variant:DECL +:DW_AT_accessibility +:DW_AT_abstract_origin +:DW_AT_declaration +:DW_AT_discr_list +:DW_AT_discr_value +:DW_AT_sibling +_ +DW_TAG_variant_part:DECL +:DW_AT_accessibility +:DW_AT_abstract_origin +:DW_AT_declaration +:DW_AT_discr +:DW_AT_sibling +:DW_AT_type +_ +DW_TAG_volatile_type:DW_AT_sibling +:DW_AT_type +_ +DW_TAG_with_statement:DW_AT_accessibility +:DW_AT_address_class +:DW_AT_declaration +:DW_AT_high_pc +:DW_AT_location +:DW_AT_low_pc +:DW_AT_segment +:DW_AT_sibling +:DW_AT_type +:DW_AT_visibility +.TE +.DE +.SK +.OP +.HU "Appendix 2 -- Organization of Debugging Information" +The following diagram depicts the relationship of the abbreviation +tables contained in the +.Cf .debug_abbrev +section to the information contained in the +.Cf .debug_info +section. Values are given in symbolic form, where possible. +.DF +.nf +.PS +scale=100 +define t201 | +[ box invis ht 154 wid 295 with .sw at 0,0 +"\f(CW\s9\&1\f1\s0" at 0,147 ljust +"\f(CW\s9\&DW_TAG_compile_unit\f1\s0" at 0,133 ljust +"\f(CW\s9\&DW_CHILDREN_yes\f1\s0" at 0,119 ljust +"\f(CW\s9\&DW_AT_name DW_FORM_string\f1\s0" at 0,105 ljust +"\f(CW\s9\&DW_AT_producer DW_FORM_string\f1\s0" at 0,91 ljust +"\f(CW\s9\&DW_AT_compdir DW_FORM_string\f1\s0" at 0,77 ljust +"\f(CW\s9\&DW_AT_language DW_FORM_data1\f1\s0" at 0,63 ljust +"\f(CW\s9\&DW_AT_low_poc DW_FORM_addr\f1\s0" at 0,49 ljust +"\f(CW\s9\&DW_AT_high_pc DW_FORM_addr\f1\s0" at 0,35 ljust +"\f(CW\s9\&DW_AT_stmt_list DW_FORM_indirect\f1\s0" at 0,21 ljust +"\f(CW\s9\&0 0\f1\s0" at 0,7 ljust +] | + +define t103 | +[ box invis ht 42 wid 74 with .sw at 0,0 +"\f(CW\s9\&4\f1\s0" at 0,35 ljust +"\f(CW\s9\&\"POINTER\"\f1\s0" at 0,21 ljust +"\f(CW\s9\&\f1\s0" at 0,7 ljust +] | + +define t177 | +[ box invis ht 28 wid 13 with .sw at 0,0 +"\f(CW\s9\&3\f1\s0" at 0,21 ljust +"\f(CW\s9\&\f1\s0" at 0,7 ljust +] | + +define t224 | +[ box invis ht 84 wid 280 with .sw at 0,0 +"\f(CW\s9\&4\f1\s0" at 0,77 ljust +"\f(CW\s9\&DW_TAG_typedef\f1\s0" at 0,63 ljust +"\f(CW\s9\&DW_CHILDREN_no\f1\s0" at 0,49 ljust +"\f(CW\s9\&DW_AT_name DW_FORM_string\f1\s0" at 0,35 ljust +"\f(CW\s9\&DW_AT_type DW_FORM_ref4 \f1\s0" at 0,21 ljust +"\f(CW\s9\&0 0 \f1\s0" at 0,7 ljust +] | + +define t149 | +[ box invis ht 28 wid 51 with .sw at 0,0 +"\f(CW\s9\&4\f1\s0" at 0,21 ljust +"\f(CW\s9\&\"strp\"\f1\s0" at 0,7 ljust +] | + +define t205 | +[ box invis ht 98 wid 280 with .sw at 0,0 +"\f(CW\s9\&2\f1\s0" at 0,91 ljust +"\f(CW\s9\&DW_TAG_base_type\f1\s0" at 0,77 ljust +"\f(CW\s9\&DW_CHILDREN_no\f1\s0" at 0,63 ljust +"\f(CW\s9\&DW_AT_name DW_FORM_string\f1\s0" at 0,49 ljust +"\f(CW\s9\&DW_AT_encoding DW_FORM_data1\f1\s0" at 0,35 ljust +"\f(CW\s9\&DW_AT_byte_size DW_FORM_data1\f1\s0" at 0,21 ljust +"\f(CW\s9\&0 0\f1\s0" at 0,7 ljust +] | + +define t126 | +[ box invis ht 126 wid 257 with .sw at 0,0 +"\f(CW\s9\&\"myfile.c\"\f1\s0" at 0,119 ljust +"\f(CW\s9\&\"Best Compiler Corp: Version 1.3\"\f1\s0" at 0,105 ljust +"\f(CW\s9\&\"mymachine:/home/mydir/src:\"\f1\s0" at 0,91 ljust +"\f(CW\s9\&DW_LANG_C89\f1\s0" at 0,77 ljust +"\f(CW\s9\&0x0\f1\s0" at 0,63 ljust +"\f(CW\s9\&0x55\f1\s0" at 0,49 ljust +"\f(CW\s9\&DW_FORM_data4\f1\s0" at 0,35 ljust +"\f(CW\s9\&0x0\f1\s0" at 0,21 ljust +"\f(CW\s9\&\f1\s0" at 0,7 ljust +] | + +define t219 | +[ box invis ht 70 wid 260 with .sw at 0,0 +"\f(CW\s9\&3\f1\s0" at 0,63 ljust +"\f(CW\s9\&DW_TAG_pointer_type\f1\s0" at 0,49 ljust +"\f(CW\s9\&DW_CHILDREN_no\f1\s0" at 0,35 ljust +"\f(CW\s9\&DW_AT_type DW_FORM_ref4\f1\s0" at 0,21 ljust +"\f(CW\s9\&0 0\f1\s0" at 0,7 ljust +] | + +define t109 | +[ box invis ht 42 wid 165 with .sw at 0,0 +"\f(CW\s9\&\"char\"\f1\s0" at 0,35 ljust +"\f(CW\s9\&DW_ATE_unsigned_char\f1\s0" at 0,21 ljust +"\f(CW\s9\&1\f1\s0" at 0,7 ljust +] | + +box invis ht 704 wid 680 with .sw at 0,0 +t201 with .nw at 376,657 +box ht 520 wid 320 with .nw at 360,672 +box ht 208 wid 280 with .nw at 24,208 +t103 with .nw at 40,353 +t177 with .nw at 40,398 +line from 360,176 to 680,176 +line from 360,280 to 680,280 +line from 360,368 to 680,368 +line from 360,488 to 680,488 +t224 with .nw at 376,270 +"\f(CW\s9\&0\f1\s0" at 376,164 ljust +"\f(CW\s9\&0\f1\s0" at 40,289 ljust +"\fI\s9\&e2\f1\s0" at 40,317 ljust +"\fI\s9\&e2:\f1\s0" at 0,389 ljust +"\f(CW\s9\&2\f1\s0" at 44,176 ljust +line from 24,128 to 304,128 +"\f(CW\s9\&...\f1\s0" at 44,113 ljust +t149 with .nw at 44,88 +"\fI\s9\&e2\f1\s0" at 44,49 ljust +"\f(CW\s9\&...\f1\s0" at 44,17 ljust +box ht 416 wid 280 with .nw at 24,688 +"\fI\s9\&length\f1\s0" at 44,192 ljust +"\f(CW\s9\&4\f1\s0" at 48,140 +"\fI\s9\&a1 (abbreviation table offset)\f1\s0" at 44,160 ljust +"\f(CW\s9\&4\f1\s0" at 44,624 +"\fI\s9\&a1 (abbreviation table offset)\f1\s0" at 40,640 ljust +t205 with .nw at 376,477 +"\fI\s9\&a1:\f1\s0" at 348,657 rjust +"\fI\s9\&length\f1\s0" at 40,672 ljust +"\fR\s10\&Abbreviation Table - .debug_abbrev\f1\s0" at 384,678 ljust +"\fR\s10\&Compilation Unit 1 - .debug_info\f1\s0" at 68,694 ljust +"\fR\s10\&Compilation Unit 2 - .debug_info\f1\s0" at 64,218 ljust +"\f(CW\s9\&2\f1\s0" at 44,656 +"\f(CW\s9\&1\f1\s0" at 44,605 +t126 with .nw at 36,599 +line from 24,616 to 304,616 +"\f(CW\s9\&2\f1\s0" at 40,461 ljust +t219 with .nw at 376,359 +line from 24,96 to 304,96 +line from 24,32 to 304,32 +t109 with .nw at 40,449 +"\fI\s9\&e1\f1\s0" at 40,373 ljust +"\fI\s9\&e1:\f1\s0" at 0,461 ljust +line from 24,480 to 304,480 +line from 24,400 to 304,400 +line from 24,360 to 304,360 +line from 24,304 to 304,304 +.PE +.fi +.DE +.SK +.OP +.HU "Appendix 3 -- Statement Program Examples" +.P +Consider this simple source file and the resulting machine code for +the Intel 8086 processor: +.DS +.S -2 +.TS +; +lf(CW) lf(CW) s +lf(CW) lf(CW) s +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) s +lf(CW) lf(CW) s +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) s +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) s +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) s +lf(CW) lf(CW) lf(CW). +1: int +2: main() + 0x239: push pb + 0x23a: mov bp,sp +3: { +4: printf("Omit needless words\en"); + 0x23c: mov ax,0xaa + 0x23f: push ax + 0x240: call _printf + 0x243: pop cx +5: exit(0); + 0x244: xor ax,ax + 0x246: push ax + 0x247: call _exit + 0x24a: pop cx +6: } + 0x24b: pop bp + 0x24c: ret +7: + 0x24d: +.TE +.S +2 +.DE +.P +If the statement program prologue specifies the following: +.DS +.S -2 +.TS +; +lf(CW) lf(CW). +minimum_instruction_length 1 +opcode_base 10 +line_base 1 +line_range 15 +.TE +.S +2 +.DE +.P +Then one encoding of the statement program would occupy 12 bytes +(the opcode \f(CWSPECIAL(\fIm\fP, \fIn\fP)\fR indicates the special +opcode generated for a line increment of \fIm\fP and an address increment +of \fIn\fP): +.DS +.S -2 +.TS +; +l l l +lf(CW) lf(CW) lf(CW). +Opcode Operand Byte Stream +_ +DW_LNS_advance_pc LEB128(0x239) 0x2, 0xb9, 0x04 +SPECIAL(2, 0) 0xb +SPECIAL(2, 3) 0x38 +SPECIAL(1, 8) 0x82 +SPECIAL(1, 7) 0x73 +DW_LNS_advance_pc LEB128(2) 0x2, 0x2 +DW_LNE_end_sequence 0x0, 0x1, 0x1 +.TE +.S +2 +.DE +.P +An alternate encoding of the same program using standard opcodes to +advance the program counter would occupy 22 bytes: +.DS +.S -2 +.TS +; +l l l +lf(CW) lf(CW) lf(CW). +Opcode Operand Byte Stream +_ +DW_LNS_fixed_advance_pc 0x239 0x9, 0x39, 0x2 +SPECIAL(2, 0) 0xb +DW_LNS_fixed_advance_pc 0x3 0x9, 0x3, 0x0 +SPECIAL(2, 0) 0xb +DW_LNS_fixed_advance_pc 0x8 0x9, 0x8, 0x0 +SPECIAL(1, 0) 0xa +DW_LNS_fixed_advance_pc 0x7 0x9, 0x7, 0x0 +SPECIAL(1, 0) 0xa +DW_LNS_fixed_advance_pc 0x2 0x9, 0x2, 0x0 +DW_LNE_end_sequence 0x0, 0x1, 0x1 +.TE +.S +2 +.DE +.SK +.OP +.HU "Appendix 4 -- Encoding and decoding variable length data" +.ta .5i +.5i +.5i +.5i +.5i +.5i +.5i +.5i +.P +Here are algorithms expressed in a C-like pseudo-code to encode and decode +signed and unsigned numbers in LEB128: +.P +\fBEncode an unsigned integer:\fP +.br +.DS +.S -2 +\f(CWdo +{ + byte = low order 7 bits of value; + value >>= 7; + if (value != 0) /* more bytes to come */ + set high order bit of byte; + emit byte; +} while (value != 0);\fP +.S +2 +.DE +.P +\fBEncode a signed integer:\fP +.br +.DS +.S -2 +\f(CWmore = 1; +negative = (value < 0); +size = no. of bits in signed integer; +while(more) +{ + byte = low order 7 bits of value; + value >>= 7; + /* the following is unnecessary if the implementation of >>= + * uses an arithmetic rather than logical shift for a signed + * left operand + */ + if (negative) + /* sign extend */ + value |= - (1 << (size - 7)); + /* sign bit of byte is 2nd high order bit (0x40) */ + if ((value == 0 && sign bit of byte is clear) || + (value == -1 && sign bit of byte is set)) + more = 0; + else + set high order bit of byte; + emit byte; +}\fP +.S +2 +.DE +.SK +.ta .5i +.5i +.5i +.5i +.5i +.5i +.5i +.5i +.P +\fBDecode unsigned LEB128 number:\fP +.br +.DS +.S -2 +\f(CWresult = 0; +shift = 0; +while(true) +{ + byte = next byte in input; + result |= (low order 7 bits of byte << shift); + if (high order bit of byte == 0) + break; + shift += 7; +}\fP +.S +2 +.DE +.P +\fBDecode signed LEB128 number:\fP +.br +.DS +.S -2 +\f(CWresult = 0; +shift = 0; +size = no. of bits in signed integer; +while(true) +{ + byte = next byte in input; + result |= (low order 7 bits of byte << shift); + shift += 7; + /* sign bit of byte is 2nd high order bit (0x40) */ + if (high order bit of byte == 0) + break; +} +if ((shift < size) && (sign bit of byte is set)) + /* sign extend */ + result |= - (1 << shift);\fP +.S +2 +.DE +.SK +.OP +.HU "Appendix 5 -- Call Frame Information Examples" +The following example uses a hypothetical RISC machine in the style of +the Motorola 88000. +.BL +.LI +Memory is byte addressed. +.LI +Instructions are all 4-bytes each and word aligned. +.LI +Instruction operands are typically of the form: +.br +.DS + <destination reg> <source reg> <constant> +.DE +.LI +The address for the load and store instructions is computed by +adding the contents of the source register with the constant. +.LI +There are 8 4-byte registers: +.br +.DS + R0 always 0 + R1 holds return address on call + R2-R3 temp registers (not preserved on call) + R4-R6 preserved on call + R7 stack pointer. +.DE +.LI +The stack grows in the negative direction. +.LE +.P +The following are two code fragments from a subroutine +called \f(CWfoo\fP that +uses a frame pointer (in addition to the stack pointer.) The first +column values are byte addresses. +.DS +.S -2 +.TS +; +lf(CW) lf(CW) s s +lf(CW) lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) lf(CW) lf(CW) +lf(CW) lf(CW) s s +lf(CW) lf(CW) s s +lf(CW) lf(CW) s s +lf(CW) lf(CW) lf(CW) lf(CW). + ;; start prologue +foo sub R7, R7, <fsize> ; Allocate frame +foo+4 store R1, R7, (<fsize>-4) ; Save the return address +foo+8 store R6, R7, (<fsize>-8) ; Save R6 +foo+12 add R6, R7, 0 ; R6 is now the Frame ptr +foo+16 store R4, R6, (<fsize>-12) ; Save a preserve reg. + ;; This subroutine does not change R5 + ... + ;; Start epilogue (R7 has been returned to entry value) +foo+64 load R4, R6, (<fsize>-12) ; Restore R4 +foo+68 load R6, R7, (<fsize>-8) ; Restore R6 +foo+72 load R1, R7, (<fsize>-4) ; Restore return address +foo+76 add R7, R7, <fsize> ; Deallocate frame +foo+80 jump R ; Return +foo+84 +.TE +.S +2 +.DE +.SK +The table for the \f(CWfoo\fP subroutine is as follows. +It is followed by the +corresponding fragments from the +.Cf .debug_frame +section. +.DS +.S -2 +.TS +tab(|); +lf(CW) lf(CW) lf(CW) lf(CW) lf(CW) lf(CW) lf(CW) lf(CW) lf(CW) lf(CW) lf(CW). +Loc|CFA|R0|R1|R2|R3|R4|R5|R6|R7|R8 +foo|[R7]+0|s|u|u|u|s|s|s|s|r1 +foo+4|[R7]+fsize|s|u|u|u|s|s|s|s|r1 +foo+8|[R7]+fsize|s|u|u|u|s|s|s|s|c4 +foo+12|[R7]+fsize|s|u|u|u|s|s|c8|s|c4 +foo+16|[R6]+fsize|s|u|u|u|s|s|c8|s|c4 +foo+20|[R6]+fsize|s|u|u|u|c12|s|c8|s|c4 +... +foo+64|[R6]+fsize|s|u|u|u|c12|s|c8|s|c4 +foo+68|[R6]+fsize|s|u|u|u|s|s|c8|s|c4 +foo+72|[R7]+fsize|s|u|u|u|s|s|s|s|c4 +foo+76|[R7]+fsize|s|u|u|u|s|s|s|s|r1 +foo+80|[R7]+0|s|u|u|u|s|s|s|s|r1 +.TE +.TS +; +l s +l l. +notes: +1. R8 is the return address +2. s = same_value rule +3. u = undefined rule +4. rN = register(N) rule +5. cN = offset(N) rule +.sp +.sp +.TE +.S +2 +.DE +.P +Common Information Entry (CIE): +.DS +.S -2 +.TS +; +lf(CW) lf(CW) lf(CW). +cie 32 ; length +cie+4 0xffffffff ; CIE_id +cie+8 1 ; version +cie+9 0 ; augmentation +cie+10 4 ; code_alignment_factor +cie+11 4 ; data_alignment_factor +cie+12 8 ; R8 is the return addr. +cie+13 DW_CFA_def_cfa (7, 0) ; CFA = [R7]+0 +cie+16 DW_CFA_same_value (0) ; R0 not modified (=0) +cie+18 DW_CFA_undefined (1) ; R1 scratch +cie+20 DW_CFA_undefined (2) ; R2 scratch +cie+22 DW_CFA_undefined (3) ; R3 scratch +cie+24 DW_CFA_same_value (4) ; R4 preserve +cie+26 DW_CFA_same_value (5) ; R5 preserve +cie+28 DW_CFA_same_value (6) ; R6 preserve +cie+30 DW_CFA_same_value (7) ; R7 preserve +cie+32 DW_CFA_register (8, 1) ; R8 is in R1 +cie+35 DW_CFA_nop ; padding +cie+36 +.TE +.S +2 +.DE +.SK +.P +Frame Description Entry (FDE): +.DS +.S -2 +.TS +; +lf(CW) lf(CW) lf(CW). +fde 40 ; length +fde+4 cie ; CIE_ptr +fde+8 foo ; initial_location +fde+12 84 ; address_range +fde+16 DW_CFA_advance_loc(1) ; instructions +fde+17 DW_CFA_def_cfa_offset(<fsize>/4) ; assuming <fsize> < 512 +fde+19 DW_CFA_advance_loc(1) +fde+20 DW_CFA_offset(8,1) +fde+22 DW_CFA_advance_loc(1) +fde+23 DW_CFA_offset(6,2) +fde+25 DW_CFA_advance_loc(1) +fde+26 DW_CFA_def_cfa_register(6) +fde+28 DW_CFA_advance_loc(1) +fde+29 DW_CFA_offset(4,3) +fde+31 DW_CFA_advance_loc(11) +fde+32 DW_CFA_restore(4) +fde+33 DW_CFA_advance_loc(1) +fde+34 DW_CFA_restore(6) +fde+35 DW_CFA_def_cfa_register(7) +fde+37 DW_CFA_advance_loc(1) +fde+38 DW_CFA_restore(8) +fde+39 DW_CFA_advance_loc(1) +fde+40 DW_CFA_def_cfa_offset(0) +fde+42 DW_CFA_nop ; padding +fde+43 DW_CFA_nop ; padding +fde+44 +.TE +.S +2 +.DE +.S +1 + +'\" +'\" Table of Contents stuff +'\" +.de TP +.sp 4 +.. +.VM +.de TY +.ce 1 +Table of Contents +.sp +.. +.nr Lf 1 +.ds Lf List of Figures +.SK +.TC 1 1 7 0 diff --git a/libdwarf/dwarf.v2.pdf b/libdwarf/dwarf.v2.pdf Binary files differnew file mode 100644 index 0000000..58358bc --- /dev/null +++ b/libdwarf/dwarf.v2.pdf diff --git a/libdwarf/dwarf_abbrev.c b/libdwarf/dwarf_abbrev.c new file mode 100644 index 0000000..a15bb80 --- /dev/null +++ b/libdwarf/dwarf_abbrev.c @@ -0,0 +1,289 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 above address. +*/ + + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_abbrev.h" + +int +dwarf_get_abbrev(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Abbrev * returned_abbrev, + Dwarf_Unsigned * length, + Dwarf_Unsigned * abbr_count, Dwarf_Error * error) +{ + Dwarf_Small *abbrev_ptr = 0; + Dwarf_Small *abbrev_section_end = 0; + Dwarf_Half attr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Abbrev ret_abbrev = 0; + Dwarf_Unsigned labbr_count = 0; + Dwarf_Unsigned utmp = 0; + + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + if (dbg->de_debug_abbrev.dss_data == 0) { + /* Loads abbrev section (and .debug_info as we do those + together). */ + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + } + + if (offset >= dbg->de_debug_abbrev.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + ret_abbrev = (Dwarf_Abbrev) _dwarf_get_alloc(dbg, DW_DLA_ABBREV, 1); + if (ret_abbrev == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + ret_abbrev->ab_dbg = dbg; + if (returned_abbrev == 0 || abbr_count == 0) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + _dwarf_error(dbg, error, DW_DLE_DWARF_ABBREV_NULL); + return (DW_DLV_ERROR); + } + + + *abbr_count = 0; + if (length != NULL) + *length = 1; + + abbrev_ptr = dbg->de_debug_abbrev.dss_data + offset; + abbrev_section_end = + dbg->de_debug_abbrev.dss_data + dbg->de_debug_abbrev.dss_size; + + DECODE_LEB128_UWORD(abbrev_ptr, utmp); + ret_abbrev->ab_code = (Dwarf_Word) utmp; + if (ret_abbrev->ab_code == 0) { + *returned_abbrev = ret_abbrev; + *abbr_count = 0; + if (length) { + *length = 1; + } + return (DW_DLV_OK); + } + + DECODE_LEB128_UWORD(abbrev_ptr, utmp); + ret_abbrev->ab_tag = utmp; + ret_abbrev->ab_has_child = *(abbrev_ptr++); + ret_abbrev->ab_abbrev_ptr = abbrev_ptr; + + do { + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(abbrev_ptr, utmp2); + attr = (Dwarf_Half) utmp2; + DECODE_LEB128_UWORD(abbrev_ptr, utmp2); + attr_form = (Dwarf_Half) utmp2; + + if (attr != 0) + (labbr_count)++; + + } while (abbrev_ptr < abbrev_section_end && + (attr != 0 || attr_form != 0)); + + if (abbrev_ptr > abbrev_section_end) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR); + return (DW_DLV_ERROR); + } + + if (length != NULL) + *length = abbrev_ptr - dbg->de_debug_abbrev.dss_data - offset; + + *returned_abbrev = ret_abbrev; + *abbr_count = labbr_count; + return (DW_DLV_OK); +} + +int +dwarf_get_abbrev_code(Dwarf_Abbrev abbrev, + Dwarf_Unsigned * returned_code, + Dwarf_Error * error) +{ + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return (DW_DLV_ERROR); + } + + *returned_code = abbrev->ab_code; + return (DW_DLV_OK); +} + +/* DWARF defines DW_TAG_hi_user as 0xffff so no tag should be + over 16 bits. */ +int +dwarf_get_abbrev_tag(Dwarf_Abbrev abbrev, + Dwarf_Half * returned_tag, Dwarf_Error * error) +{ + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return (DW_DLV_ERROR); + } + + *returned_tag = abbrev->ab_tag; + return (DW_DLV_OK); +} + + +int +dwarf_get_abbrev_children_flag(Dwarf_Abbrev abbrev, + Dwarf_Signed * returned_flag, + Dwarf_Error * error) +{ + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return (DW_DLV_ERROR); + } + + *returned_flag = abbrev->ab_has_child; + return (DW_DLV_OK); +} + + +int +dwarf_get_abbrev_entry(Dwarf_Abbrev abbrev, + Dwarf_Signed index, + Dwarf_Half * returned_attr_num, + Dwarf_Signed * form, + Dwarf_Off * offset, Dwarf_Error * error) +{ + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Byte_Ptr abbrev_end = 0; + Dwarf_Byte_Ptr mark_abbrev_ptr = 0; + Dwarf_Half attr = 0; + Dwarf_Half attr_form = 0; + + if (index < 0) + return (DW_DLV_NO_ENTRY); + + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return (DW_DLV_ERROR); + } + + if (abbrev->ab_code == 0) { + return (DW_DLV_NO_ENTRY); + } + + if (abbrev->ab_dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + + abbrev_ptr = abbrev->ab_abbrev_ptr; + abbrev_end = + abbrev->ab_dbg->de_debug_abbrev.dss_data + + abbrev->ab_dbg->de_debug_abbrev.dss_size; + + for (attr = 1, attr_form = 1; + index >= 0 && abbrev_ptr < abbrev_end && (attr != 0 || + attr_form != 0); + index--) { + Dwarf_Unsigned utmp4; + + mark_abbrev_ptr = abbrev_ptr; + DECODE_LEB128_UWORD(abbrev_ptr, utmp4); + attr = (Dwarf_Half) utmp4; + DECODE_LEB128_UWORD(abbrev_ptr, utmp4); + attr_form = (Dwarf_Half) utmp4; + } + + if (abbrev_ptr >= abbrev_end) { + _dwarf_error(abbrev->ab_dbg, error, DW_DLE_ABBREV_DECODE_ERROR); + return (DW_DLV_ERROR); + } + + if (index >= 0) { + return (DW_DLV_NO_ENTRY); + } + + if (form != NULL) + *form = attr_form; + if (offset != NULL) + *offset = mark_abbrev_ptr - abbrev->ab_dbg->de_debug_abbrev.dss_data; + + *returned_attr_num = (attr); + return DW_DLV_OK; +} + +/* This function is not entirely safe to call. + The problem is that the DWARF[234] specification does not insist + that bytes in .debug_abbrev that are not referenced by .debug_info + or .debug_types need to be initialized to anything specific. + Any garbage bytes may cause trouble. Not all compilers/linkers + leave unreferenced garbage bytes in .debug_abbrev, so this may + work for most objects. */ +int +dwarf_get_abbrev_count(Dwarf_Debug dbg) +{ + Dwarf_Abbrev ab; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned attr_count = 0; + Dwarf_Unsigned abbrev_count = 0; + int abres = DW_DLV_OK; + Dwarf_Error err; + + while ((abres = dwarf_get_abbrev(dbg, offset, &ab, + &length, &attr_count, + &err)) == DW_DLV_OK) { + + ++abbrev_count; + offset += length; + dwarf_dealloc(dbg, ab, DW_DLA_ABBREV); + } + return abbrev_count; +} + diff --git a/libdwarf/dwarf_abbrev.h b/libdwarf/dwarf_abbrev.h new file mode 100644 index 0000000..80adf1c --- /dev/null +++ b/libdwarf/dwarf_abbrev.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +/* In a given CU, one of these is (eventually) set up + for every abbreviation we need to find (and for all. + those ealier in the abbreviations for that CU). + So we don't want elements needlessly big. +*/ +struct Dwarf_Abbrev_s { + /* No TAG should exceed DW_TAG_hi_user, 0xffff, but + we do allow a larger value here. */ + Dwarf_Word ab_tag; + /* Abbreviations are numbered (normally sequentially from + 1 and so 16 bits is not enough! */ + Dwarf_Word ab_code; + Dwarf_Small ab_has_child; + Dwarf_Byte_Ptr ab_abbrev_ptr; + Dwarf_Debug ab_dbg; +}; diff --git a/libdwarf/dwarf_addr_finder.c b/libdwarf/dwarf_addr_finder.c new file mode 100644 index 0000000..303ca45 --- /dev/null +++ b/libdwarf/dwarf_addr_finder.c @@ -0,0 +1,680 @@ +/* + + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* This code used by SGI-IRIX rqs processing, not needed by + any other system or application. + The 'We need' and 'FIX' here are left in for historical + interest, the code is not really used in the public libdwarf + or applications. +*/ + +#include "config.h" +#include "libdwarfdefs.h" +#ifdef HAVE_ELF_H +#include <elf.h> +#endif +#include <dwarf.h> +#include <libdwarf.h> +#include "dwarf_base_types.h" +#include "dwarf_alloc.h" +#include "dwarf_opaque.h" +#include "dwarf_arange.h" +#include "dwarf_line.h" +#include "dwarf_frame.h" +#include <cmplrs/dwarf_addr_finder.h> +#include "dwarf_error.h" + +typedef unsigned long long ull; + +static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, + int *errval); +static int handle_debug_info(Dwarf_Debug dbg, int *errval); +static int handle_debug_frame(Dwarf_Debug dbg, + Dwarf_addr_callback_func cb_func, int *errval); +static int handle_debug_aranges(Dwarf_Debug dbg, + Dwarf_addr_callback_func cb_func, int *errval); +static int handle_debug_line(Dwarf_Debug dbg, + Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval); +static int handle_debug_loc(void); + + +/* A static variable is not thread-safe, but this is only + used by SGI-internal software which is single-threaded + so the static variable is safe. +*/ +static Dwarf_addr_callback_func send_addr_note; + +/* A function which should probably not be used outside + of SGI. Intended to be used by executable and + shared-library post-processor software. +*/ +int +_dwarf_addr_finder(dwarf_elf_handle elf_file_ptr, + Dwarf_addr_callback_func cb_func, int *dwerr) +{ + + Dwarf_Error err = 0; + Dwarf_Debug dbg = 0; + int res = 0; + int errval = 0; + int sections_found = 0; + + res = dwarf_elf_init(elf_file_ptr, DW_DLC_READ, /* errhand */ 0, + /* errarg */ 0, &dbg, &err); + if (res == DW_DLV_ERROR) { + int errv = (int) dwarf_errno(err); + return errv; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + send_addr_note = cb_func; + res = handle_debug_info(dbg, &errval); + switch (res) { + case DW_DLV_OK: + ++sections_found; + break; + case DW_DLV_NO_ENTRY: + + break; + default: + case DW_DLV_ERROR: + dwarf_finish(dbg, &err); + *dwerr = errval; + return res; + } + + res = handle_debug_aranges(dbg, cb_func, &errval); + switch (res) { + case DW_DLV_OK: + ++sections_found; + break; + case DW_DLV_NO_ENTRY: + break; + default: + case DW_DLV_ERROR: + dwarf_finish(dbg, &err); + *dwerr = errval; + return res; + } + res = handle_debug_frame(dbg, cb_func, &errval); + switch (res) { + case DW_DLV_OK: + ++sections_found; + break; + case DW_DLV_NO_ENTRY: + break; + default: + case DW_DLV_ERROR: + dwarf_finish(dbg, &err); + *dwerr = errval; + return res; + } + + res = handle_debug_loc(); /* does nothing */ + switch (res) { + case DW_DLV_OK: + ++sections_found; + break; + case DW_DLV_NO_ENTRY: + break; + default: + case DW_DLV_ERROR: + /* IMPOSSIBLE : handle_debug_loc cannot return this */ + dwarf_finish(dbg, &err); + *dwerr = errval; + return res; + } + + + + *dwerr = 0; + res = dwarf_finish(dbg, &err); + if (res == DW_DLV_ERROR) { + *dwerr = (int) dwarf_errno(err); + return DW_DLV_ERROR; + } + if (sections_found == 0) { + return DW_DLV_NO_ENTRY; + } + return DW_DLV_OK; + +} + +/* Return DW_DLV_OK, ERROR, or NO_ENTRY. */ +static int +handle_debug_info(Dwarf_Debug dbg, int *errval) +{ + Dwarf_Unsigned nxtoff = 1; + Dwarf_Unsigned hdr_length; + Dwarf_Half version_stamp; + Dwarf_Unsigned abbrev_offset; + Dwarf_Half addr_size; + Dwarf_Error err; + int terminate_now = 0; + int res = 0; + Dwarf_Die sibdie; + int sibres; + int nres = DW_DLV_OK; + + + for (nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp, + &abbrev_offset, + &addr_size, &nxtoff, &err); + terminate_now == 0 && nres == DW_DLV_OK; + nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp, + &abbrev_offset, + &addr_size, &nxtoff, &err)) { + + Dwarf_Die curdie = 0; + + /* Try to get the compilation unit die */ + sibres = dwarf_siblingof(dbg, curdie, &sibdie, &err); + if (sibres == DW_DLV_OK) { + res = do_this_die_and_dealloc(dbg, sibdie, errval); + switch (res) { + case DW_DLV_OK: + break; + case DW_DLV_NO_ENTRY: + break; + default: + case DW_DLV_ERROR: + return DW_DLV_ERROR; + } + } else if (sibres == DW_DLV_ERROR) { + *errval = (int) dwarf_errno(err); + return DW_DLV_ERROR; + } else { + /* NO ENTRY! */ + /* impossible? */ + } + + } + if (nres == DW_DLV_ERROR) { + int localerr = (int) dwarf_errno(err); + + *errval = localerr; + return DW_DLV_ERROR; + } + return DW_DLV_OK; +} + +static int + might_have_addr[] = { + DW_AT_high_pc, + DW_AT_low_pc, +}; +static int might_have_locdesc[] = { + DW_AT_segment, + DW_AT_return_addr, + DW_AT_frame_base, + DW_AT_static_link, + DW_AT_data_member_location, + DW_AT_string_length, + DW_AT_location, + DW_AT_use_location, + DW_AT_vtable_elem_location, +}; + +/* Return DW_DLV_OK if handling this went ok. */ +static int +handle_attr_addr(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum, + Dwarf_Error * perr) +{ + int res = DW_DLV_OK; + Dwarf_Off offset; + Dwarf_Addr addr; + Dwarf_Half form; + int ares; + + Dwarf_Attribute attr; + + ares = dwarf_attr(die, attrnum, &attr, perr); + if (ares == DW_DLV_OK) { + int formres = dwarf_whatform(attr, &form, perr); + + switch (formres) { + case DW_DLV_OK: + break; + case DW_DLV_ERROR: + case DW_DLV_NO_ENTRY: /* impossible. */ + return formres; + + } + + switch (form) { + case DW_FORM_ref_addr: + case DW_FORM_addr: + res = dwarf_attr_offset(die, attr, &offset, perr); + if (res == DW_DLV_OK) { + ares = dwarf_formaddr(attr, &addr, perr); + if (ares == DW_DLV_OK) { + send_addr_note(DW_SECTION_INFO, offset, addr); + } else if (ares == DW_DLV_ERROR) { + return ares; + } + /* no entry: ok. */ + } else { + /* NO_ENTRY is impossible. */ + res = DW_DLV_ERROR; + } + break; + + default: + /* surprising! An error? */ + /* do nothing */ + ; + } + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); + } else { + res = ares; + } + return res; +} + +/* Return DW_DLV_OK if handling this went ok. */ +static int +handle_attr_locdesc(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum, + Dwarf_Error * perr) +{ + int retval = DW_DLV_OK; + Dwarf_Attribute attr; + Dwarf_Locdesc *llbuf; + Dwarf_Signed i; + Dwarf_Off offset; + Dwarf_Loc *locp; + unsigned int entindx; + int res; + int ares; + + + ares = dwarf_attr(die, attrnum, &attr, perr); + if (ares == DW_DLV_OK) { + Dwarf_Half form; + int fres = dwarf_whatform(attr, &form, perr); + + if (fres == DW_DLV_OK) { + switch (form) { + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + /* must be location description */ + res = dwarf_attr_offset(die, attr, &offset, perr); + llbuf = 0; + if (res == DW_DLV_OK) { + Dwarf_Signed count; + int lres = dwarf_loclist(attr, &llbuf, &count, perr); + if (lres != DW_DLV_OK) { + return lres; + } + if (count != 1) { + /* this cannot happen! */ + /* perr? */ + _dwarf_error(dbg, perr, + DW_DLE_LOCDESC_COUNT_WRONG); + retval = DW_DLV_ERROR; + return retval; + } + for (i = 0; i < count; ++i) { + unsigned int ents = llbuf[i].ld_cents; + + locp = llbuf[i].ld_s; + for (entindx = 0; entindx < ents; entindx++) { + Dwarf_Loc *llocp; + + llocp = locp + entindx; + if (llocp->lr_atom == DW_OP_addr) { + send_addr_note(DW_SECTION_INFO, offset + + llocp->lr_offset + 1 + /* The offset is the + offset of the atom, + ** and we know the + addr is 1 past it. */ + , llocp->lr_number); + } + } + } + + + if (count > 0) { + for (i = 0; i < count; ++i) { + dwarf_dealloc(dbg, llbuf[i].ld_s, + DW_DLA_LOC_BLOCK); + } + dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC); + } + } else { + retval = res; + } + break; + + default: + /* must be a const offset in debug_loc */ + ; /* do nothing */ + } + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); + } /* else error or no entry */ + retval = fres; + } else { + retval = ares; + } + return retval; +} + +/* Return DW_DLV_OK, or DW_DLV_ERROR + + Handle the addrs in a single die. */ +static int +process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval) +{ + Dwarf_Error err; + Dwarf_Half i; + Dwarf_Half newattrnum; + int res; + int tres; + Dwarf_Half ltag; + + Dwarf_Off doff; + int doffres = dwarf_dieoffset(newdie, &doff, &err); + + if (doffres != DW_DLV_OK) { + if (doffres == DW_DLV_ERROR) { + *errval = (int) dwarf_errno(err); + } + return doffres; + } + tres = dwarf_tag(newdie, <ag, &err); + if (tres != DW_DLV_OK) { + return tres; + } + if (DW_TAG_compile_unit == ltag) { + /* Because of the way the dwarf_line code works, we do lines + only per compile unit. This may turn out to be wrong if + we have lines left unconnected to a CU. of course such + lines will not, at present, be used by gnome. This is + not ideal as coded due to the dwarf_line.c issue. */ + int lres = handle_debug_line(dbg, newdie, send_addr_note, errval); + if (lres == DW_DLV_ERROR) { + return lres; + } + } + + for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) { + int resattr; + Dwarf_Bool hasattr; + + newattrnum = might_have_addr[i]; + err = 0; + resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); + if (DW_DLV_OK == resattr) { + if (hasattr) { + res = handle_attr_addr(dbg, newdie, newattrnum, &err); + if (res != DW_DLV_OK) { + *errval = (int) dwarf_errno(err); + return DW_DLV_ERROR; + } + } + } else { + if (resattr == DW_DLV_ERROR) { + *errval = (int) dwarf_errno(err); + return resattr; + } + } + } + for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) { + int resattr; + Dwarf_Bool hasattr; + + newattrnum = might_have_locdesc[i]; + err = 0; + resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); + if (DW_DLV_OK == resattr) { + if (hasattr) { + res = + handle_attr_locdesc(dbg, newdie, newattrnum, &err); + if (res != DW_DLV_OK) { + *errval = (int) dwarf_errno(err); + return DW_DLV_ERROR; + } + } + } else { + if (resattr == DW_DLV_ERROR) { + *errval = (int) dwarf_errno(err); + return resattr; + } + } + } + + return DW_DLV_OK; +} + +/* Handle siblings as a list, + Do children by recursing. + Effectively this is walking the tree preorder. + + This dealloc's any die passed to it, so the + caller should not do that dealloc. + It seems more logical to have the one causing + the alloc to do the dealloc, but that way this + routine became a mess. +*/ +static int +do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval) +{ + + Dwarf_Die prevdie = 0; + Dwarf_Die newdie = die; + Dwarf_Error err = 0; + int res = 0; + int sibres = DW_DLV_OK; + int tres = DW_DLV_OK; + Dwarf_Die sibdie; + + while (sibres == DW_DLV_OK) { + Dwarf_Die ch_die; + + + res = process_this_die_attrs(dbg, newdie, errval); + switch (res) { + case DW_DLV_OK: + break; + case DW_DLV_NO_ENTRY: + break; + default: + case DW_DLV_ERROR: + if (prevdie) { + dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); + prevdie = 0; + } + return DW_DLV_ERROR; + } + + tres = dwarf_child(newdie, &ch_die, &err); + + if (tres == DW_DLV_OK) { + res = do_this_die_and_dealloc(dbg, ch_die, errval); + switch (res) { + case DW_DLV_OK: + break; + case DW_DLV_NO_ENTRY: + break; + default: + case DW_DLV_ERROR: + if (prevdie) { + dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); + prevdie = 0; + } + return DW_DLV_ERROR; + } + } else if (tres == DW_DLV_ERROR) { + /* An error! */ + *errval = (int) dwarf_errno(err); + if (prevdie) { + dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); + prevdie = 0; + } + dwarf_dealloc(dbg, err, DW_DLA_ERROR); + return DW_DLV_ERROR; + } /* else was NO ENTRY */ + prevdie = newdie; + sibdie = 0; + sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err); + if (prevdie) { + dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); + prevdie = 0; + } + newdie = sibdie; + + } + if (sibres == DW_DLV_NO_ENTRY) { + return DW_DLV_OK; + } + /* error. */ + *errval = (int) dwarf_errno(err); + if (prevdie) { + dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); + prevdie = 0; + } + dwarf_dealloc(dbg, err, DW_DLA_ERROR); + return DW_DLV_ERROR; + +} + + +static int +handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, + int *errval) +{ + int retval = DW_DLV_OK; + int res; + Dwarf_Error err; + Dwarf_Addr *addrlist; + Dwarf_Off *offsetlist; + Dwarf_Signed count; + int i; + + res = + _dwarf_frame_address_offsets(dbg, &addrlist, &offsetlist, + &count, &err); + if (res == DW_DLV_OK) { + for (i = 0; i < count; i++) { + cb_func(DW_SECTION_FRAME, offsetlist[i], addrlist[i]); + } + dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR); + dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR); + } else if (res == DW_DLV_NO_ENTRY) { + retval = res; + } else { + *errval = (int) dwarf_errno(err); + retval = DW_DLV_ERROR; + } + return retval; + +} +static int +handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, + int *errval) +{ + int retval = DW_DLV_OK; + Dwarf_Error err; + Dwarf_Addr *aranges; + Dwarf_Signed count; + int indx; + Dwarf_Off *offsets; + + retval = + _dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count, + &err); + if (retval == DW_DLV_OK) { + if (count == 0) { + retval = DW_DLV_NO_ENTRY; + } else { + for (indx = 0; indx < count; indx++) { + cb_func(DW_SECTION_ARANGES, offsets[indx], + aranges[indx]); + } + } + dwarf_dealloc(dbg, aranges, DW_DLA_ADDR); + dwarf_dealloc(dbg, offsets, DW_DLA_ADDR); + } else if (retval == DW_DLV_NO_ENTRY) { + ; /* do nothing */ + } else { + *errval = (int) dwarf_errno(err); + retval = DW_DLV_ERROR; + } + return retval; +} +static int +handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, + Dwarf_addr_callback_func cb_func, int *errval) +{ + int retval = DW_DLV_OK; + int res; + Dwarf_Error err; + Dwarf_Addr *addrlist; + Dwarf_Off *offsetlist; + Dwarf_Unsigned count; + Dwarf_Unsigned i; + + res = + _dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist, + &count, &err); + if (res == DW_DLV_OK) { + for (i = 0; i < count; i++) { + cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]); + + } + dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR); + dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR); + } else if (res == DW_DLV_NO_ENTRY) { + retval = res; + } else { + *errval = (int) dwarf_errno(err); + retval = DW_DLV_ERROR; + } + return retval; +} + +/* We need to add support for this. Currently we do not + generate this section. + FIX! +*/ +static int +handle_debug_loc(void) +{ + int retval = DW_DLV_NO_ENTRY; + + return retval; +} diff --git a/libdwarf/dwarf_alloc.c b/libdwarf/dwarf_alloc.c new file mode 100644 index 0000000..353fb6f --- /dev/null +++ b/libdwarf/dwarf_alloc.c @@ -0,0 +1,1270 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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. +*/ + + +#undef DEBUG + +#include "config.h" +#include "dwarf_incl.h" +#include <sys/types.h> + +#include <stdlib.h> +#include <stdio.h> +#include "malloc_check.h" + +/* These files are included to get the sizes + of structs to set the ah_bytes_one_struct field + of the Dwarf_Alloc_Hdr_s structs for each + allocation type. +*/ +#include "dwarf_line.h" +#include "dwarf_global.h" +#include "dwarf_arange.h" +#include "dwarf_abbrev.h" +#include "dwarf_die_deliv.h" +#include "dwarf_frame.h" +#include "dwarf_loc.h" +#include "dwarf_funcs.h" +#include "dwarf_types.h" +#include "dwarf_vars.h" +#include "dwarf_weaks.h" +#include "dwarf_harmless.h" + + +static void _dwarf_free_special_error(Dwarf_Ptr space); + +#ifdef DWARF_SIMPLE_MALLOC +static void _dwarf_simple_malloc_add_to_list(Dwarf_Debug dbg, + Dwarf_Ptr addr, + unsigned long size, + short alloc_type); +static void _dwarf_simple_malloc_delete_from_list(Dwarf_Debug dbg, + Dwarf_Ptr space, + short alloc_type); +void _dwarf_simple_malloc_botch(int err); + +#endif /* DWARF_SIMPLE_MALLOC */ + + + + +/* This macro adds the size of a pointer to the size of a + struct that is given to it. It rounds up the size to + be a multiple of the size of a pointer. This is done + so that every struct returned by _dwarf_get_alloc() + can be preceded by a pointer to the chunk it came from. + Before allocating, it checks if the size of struct is less than + the size of a pointer. If yes, it returns the size + of 2 pointers. The returned size should be at least + the size of 2 pointers, since the first points to the + chunk the struct was allocated from, and the second + is used to link the free list. + + We want DW_RESERVE to be at least the size of + a long long and at least the size of a pointer because + our struct has a long long and we want that aligned right. + Now Standard C defines long long as 8 bytes, so lets + make that standard. It will become unworkable when + long long or pointer grows beyound 8 bytes. + Unclear what to do with wierd requirements, like + 36 bit pointers. +*/ +#define DW_RESERVE 8 + +/* Round size up to the next multiple of DW_RESERVE bytes +*/ +#define ROUND_SIZE(inputsize) \ + (((inputsize) % (DW_RESERVE)) == 0 ? \ + (inputsize): \ + ((inputsize) + \ + (DW_RESERVE) - ((inputsize) % (DW_RESERVE)) )) + +#define ROUND_SIZE_WITH_POINTER(i_size) (ROUND_SIZE(i_size) + DW_RESERVE) + +/* SMALL_ALLOC is for trivia where allocation is a waste. + Things that should be removed, really. */ +#define SMALL_ALLOC 2 + +/* BASE_ALLOC is where a basic allocation makes sense, + but 'not too large'. + No thorough evaluation of this value has been done, though + it was found wasteful of memory to have BASE_ALLOC be as large as + BIG_ALLOC. */ +#define BASE_ALLOC 64 + +/* BIG_ALLOC is where a larger-than-BASE_ALLOC + allocation makes sense, but still 'not too large'. + No thorough evaluation of this value has been done. */ +#define BIG_ALLOC 128 + +/* This translates into de_alloc_hdr index + the 0,1,1 entries are special: they don't use the + table values at all. + Rearranging the DW_DLA values would break binary compatibility + so that is not an option. +*/ +struct ial_s { + int ia_al_num; /* Index into de_alloc_hdr table. */ + + /* In bytes, one struct instance. This does not account for extra + space needed per block, but that (DW_RESERVE) will be added in + later where it is needed + (DW_RESERVE space never added in here). */ + int ia_struct_size; + + + /* Number of instances per alloc block. MUST be > 0. */ + int ia_base_count; + + int (*specialconstructor) (Dwarf_Debug, void *); + void (*specialdestructor) (void *); +}; + +static const +struct ial_s index_into_allocated[ALLOC_AREA_INDEX_TABLE_MAX] = { + {0, 1, 1, 0, 0}, /* 0 none */ + {0, 1, 1, 0, 0}, /* 1 DW_DLA_STRING */ + {1, sizeof(Dwarf_Loc), BASE_ALLOC, 0, 0} ,/* 2 DW_DLA_LOC */ + {2, sizeof(Dwarf_Locdesc), BASE_ALLOC, 0, 0} , /* 3 DW_DLA_LOCDESC */ + {0, 1, 1, 0, 0} , /* not used *//* 4 DW_DLA_ELLIST */ + {0, 1, 1, 0, 0} , /* not used *//* 5 DW_DLA_BOUNDS */ + {3, sizeof(Dwarf_Block), BASE_ALLOC, 0, 0} , /* 6 DW_DLA_BLOCK */ + + /* the actual dwarf_debug structure */ /* 7 DW_DLA_DEBUG */ + {0, 1, 1, 0, 0} , + + {4, sizeof(struct Dwarf_Die_s), BIG_ALLOC, 0, 0},/* 8 DW_DLA_DIE */ + {5, sizeof(struct Dwarf_Line_s), BIG_ALLOC, 0, 0},/* 9 DW_DLA_LINE */ + + /* 10 DW_DLA_ATTR */ + {6, sizeof(struct Dwarf_Attribute_s), BIG_ALLOC * 2, 0, 0}, + + {0, 1, 1, 0, 0}, /* not used */ /* 11 DW_DLA_TYPE */ + {0, 1, 1, 0, 0}, /* not used */ /* 12 DW_DLA_SUBSCR */ + + /* 13 DW_DLA_GLOBAL */ + {7, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, + + /* 14 DW_DLA_ERROR */ + {8, sizeof(struct Dwarf_Error_s), BASE_ALLOC, 0, 0}, + + {0, 1, 1, 0, 0}, /* 15 DW_DLA_LIST */ + {0, 1, 1, 0, 0}, /* not used *//* 16 DW_DLA_LINEBUF */ + + /* 17 DW_DLA_ARANGE */ + {9, sizeof(struct Dwarf_Arange_s), BASE_ALLOC, 0, 0}, + + /* 18 DW_DLA_ABBREV */ + {10, sizeof(struct Dwarf_Abbrev_s), BIG_ALLOC, 0, 0}, + + /* 19 DW_DLA_FRAME_OP */ + {11, sizeof(Dwarf_Frame_Op), BIG_ALLOC, 0, 0} , + + /* 20 DW_DLA_CIE */ + {12, sizeof(struct Dwarf_Cie_s), BASE_ALLOC, 0, 0}, + + {13, sizeof(struct Dwarf_Fde_s), BASE_ALLOC, 0, 0},/* 21 DW_DLA_FDE */ + {0, 1, 1, 0, 0}, /* 22 DW_DLA_LOC_BLOCK */ + {0, 1, 1, 0, 0}, /* 23 DW_DLA_FRAME_BLOCK */ + + /* 24 DW_DLA_FUNC UNUSED */ + {14, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, + + /* 25 DW_DLA_TYPENAME UNUSED */ + {15, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, + + /* 26 DW_DLA_VAR UNUSED */ + {16, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, + + /* 27 DW_DLA_WEAK UNUSED */ + {17, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, + + {0, 1, 1, 0, 0}, /* 28 DW_DLA_ADDR */ + {0, 1,1,0,0 }, /* 29 DW_DLA_RANGES */ + + /* The following DW_DLA data types + are known only inside libdwarf. */ + + /* 30 DW_DLA_ABBREV_LIST */ + {18, sizeof(struct Dwarf_Abbrev_List_s), BIG_ALLOC, 0, 0}, + + /* 31 DW_DLA_CHAIN */ + {19, sizeof(struct Dwarf_Chain_s), BIG_ALLOC, 0, 0}, + + /* 32 DW_DLA_CU_CONTEXT */ + {20, sizeof(struct Dwarf_CU_Context_s), BASE_ALLOC, 0, 0}, + + {21, sizeof(struct Dwarf_Frame_s), BASE_ALLOC, + _dwarf_frame_constructor, + _dwarf_frame_destructor}, /* 33 DW_DLA_FRAME */ + + /* 34 DW_DLA_GLOBAL_CONTEXT */ + {22, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0}, + + /* 35 DW_DLA_FILE_ENTRY */ + {23, sizeof(struct Dwarf_File_Entry_s), BASE_ALLOC, 0, 0}, + + /* 36 DW_DLA_LINE_CONTEXT */ + {24, sizeof(struct Dwarf_Line_Context_s), BASE_ALLOC, 0, 0}, + + /* 37 DW_DLA_LOC_CHAIN */ + {25, sizeof(struct Dwarf_Loc_Chain_s), BASE_ALLOC, 0, 0}, + + /* 38 DW_DLA_HASH_TABLE */ + {26, sizeof(struct Dwarf_Hash_Table_s),BASE_ALLOC, 0, 0}, + + /* The following really use Global struct: used to be unique struct + per type, but now merged (11/99). The opaque types + are visible in the interface. The types for + DW_DLA_FUNC, DW_DLA_TYPENAME, DW_DLA_VAR, DW_DLA_WEAK also use + the global types. */ + + /* 39 DW_DLA_FUNC_CONTEXT */ + {27, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0}, + + /* 40 DW_DLA_TYPENAME_CONTEXT */ + {28, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0}, + + /* 41 DW_DLA_VAR_CONTEXT */ + {29, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0}, + + /* 42 DW_DLA_WEAK_CONTEXT */ + {30, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0}, + + /* 43 DW_DLA_PUBTYPES_CONTEXT DWARF3 */ + {31, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0}, + + {0,1,1,0,0 }, /* 44 DW_DLA_HASH_TABLE_ENTRY */ + + +}; + +#ifndef DWARF_SIMPLE_MALLOC + +/* This function is given a pointer to the header + structure that is used to allocate 1 struct of + the type given by alloc_type. It first checks + if a struct is available in its free list. If + not, it checks if 1 is available in its blob, + which is a chunk of memory that is reserved for + its use. If not, it malloc's a chunk. The + initial part of it is used to store the end + address of the chunk, and also to keep track + of the number of free structs in that chunk. + This information is used for freeing the chunk + when all the structs in it are free. + + Assume all input arguments have been validated. + + This function can be used only to allocate 1 + struct of the given type. + + It returns a pointer to the struct that the + user can use. It returns NULL only when it + is out of free structs, and cannot malloc + any more. The struct returned is zero-ed. + + A pointer to the chunk that the struct belongs + to is stored in the bytes preceding the + returned address. Since this pointer it + never overwritten, when a struct is allocated + from the free_list this pointer does not + have to be written. In the 2 other cases, + where the struct is allocated from a new + chunk, or the blob, a pointer to the chunk + is written. +*/ +static Dwarf_Ptr +_dwarf_find_memory(Dwarf_Alloc_Hdr alloc_hdr) +{ + /* Pointer to the struct allocated. */ + Dwarf_Small *ret_mem = 0; + + /* Pointer to info about chunks allocated. */ + Dwarf_Alloc_Area alloc_area; + + /* Size of chunk malloc'ed when no free structs left. */ + Dwarf_Signed mem_block_size; + + /* Pointer to block malloc'ed. */ + Dwarf_Small *mem_block; + + /* Check the alloc_area from which the last allocation was made + (most recent new block). If that is not successful, then search + the list of alloc_area's from alloc_header. */ + alloc_area = alloc_hdr->ah_last_alloc_area; + if (alloc_area == NULL || alloc_area->aa_free_structs_in_chunk == 0) + for (alloc_area = alloc_hdr->ah_alloc_area_head; + alloc_area != NULL; alloc_area = alloc_area->aa_next) { + + if (alloc_area->aa_free_structs_in_chunk > 0) { + break; /* found a free entry! */ + } + + } + + if (alloc_area != NULL) { + alloc_area->aa_free_structs_in_chunk--; + + if (alloc_area->aa_free_list != NULL) { + ret_mem = alloc_area->aa_free_list; + + /* Update the free list. The initial part of the struct is + used to hold a pointer to the next struct on the free + list. In this way, the free list chain is maintained at + 0 memory cost. */ + alloc_area->aa_free_list = + ((Dwarf_Free_List) ret_mem)->fl_next; + } else if (alloc_area->aa_blob_start < alloc_area->aa_blob_end) { + ret_mem = alloc_area->aa_blob_start; + + /* Store pointer to chunk this struct belongs to in the + first few bytes. Return pointer to bytes after this + pointer storage. */ + *(Dwarf_Alloc_Area *) ret_mem = alloc_area; + ret_mem += DW_RESERVE; + + alloc_area->aa_blob_start += alloc_hdr->ah_bytes_one_struct; + } else { + /* else fall thru , though it should be impossible to fall + thru. And represents a disastrous programming error if + we get here. */ +#ifdef DEBUG + fprintf(stderr, "libdwarf Internal error start %x end %x\n", + (int) alloc_area->aa_blob_start, + (int) alloc_area->aa_blob_end); +#endif + } + } + + /* New memory has to malloc'ed since there are no free structs. */ + if (ret_mem == 0) { + Dwarf_Word rounded_area_hdr_size; + + alloc_hdr->ah_chunks_allocated++; + + { /* this nonsense avoids a warning */ + /* CONSTCOND would be better */ + unsigned long v = sizeof(struct Dwarf_Alloc_Area_s); + + rounded_area_hdr_size = ROUND_SIZE(v); + } + + /* Allocate memory to contain the required number of structs + and the Dwarf_Alloc_Area_s to control it. */ + mem_block_size = alloc_hdr->ah_bytes_malloc_per_chunk + + rounded_area_hdr_size; + + mem_block = malloc(mem_block_size); + if (mem_block == NULL) { + return (NULL); + } + + + /* Attach the Dwarf_Alloc_Area_s struct to the list of chunks + malloc'ed for this struct type. Also initialize the fields + of the Dwarf_Alloc_Area_s. */ + alloc_area = (Dwarf_Alloc_Area) mem_block; + alloc_area->aa_prev = 0; + if (alloc_hdr->ah_alloc_area_head != NULL) { + alloc_hdr->ah_alloc_area_head->aa_prev = alloc_area; + } + alloc_area->aa_free_list = 0; + alloc_area->aa_next = alloc_hdr->ah_alloc_area_head; + alloc_hdr->ah_alloc_area_head = alloc_area; + + alloc_area->aa_alloc_hdr = alloc_hdr; + alloc_area->aa_free_structs_in_chunk = + (Dwarf_Sword) alloc_hdr->ah_structs_per_chunk - 1; + if (alloc_area->aa_free_structs_in_chunk < 1) { + /* If we get here, there is a disastrous programming error + somewhere. */ +#ifdef DEBUG + fprintf(stderr, + "libdwarf Internal error: free structs in chunk %d\n", + (int) alloc_area->aa_free_structs_in_chunk); +#endif + return NULL; + } + + /* The struct returned begins immediately after the + Dwarf_Alloc_Area_s struct. */ + ret_mem = mem_block + rounded_area_hdr_size; + alloc_area->aa_blob_start = + ret_mem + alloc_hdr->ah_bytes_one_struct; + alloc_area->aa_blob_end = mem_block + mem_block_size; + + /* Store pointer to chunk this struct belongs to in the first + few bytes. Return pointer to bytes after this pointer + storage. */ + *(Dwarf_Alloc_Area *) ret_mem = alloc_area; + ret_mem += DW_RESERVE; + } + + alloc_hdr->ah_last_alloc_area = alloc_area; + alloc_hdr->ah_struct_user_holds++; + memset(ret_mem, 0, alloc_hdr->ah_bytes_one_struct - DW_RESERVE); + return (ret_mem); +} + +#endif /* ndef DWARF_SIMPLE_MALLOC */ + +/* This function returns a pointer to a region + of memory. For alloc_types that are not + strings or lists of pointers, only 1 struct + can be requested at a time. This is indicated + by an input count of 1. For strings, count + equals the length of the string it will + contain, i.e it the length of the string + plus 1 for the terminating null. For lists + of pointers, count is equal to the number of + pointers. For DW_DLA_FRAME_BLOCK, DW_DLA_RANGES, and + DW_DLA_LOC_BLOCK allocation types also, count + is the count of the number of structs needed. + + This function cannot be used to allocate a + Dwarf_Debug_s struct. */ +Dwarf_Ptr +_dwarf_get_alloc(Dwarf_Debug dbg, + Dwarf_Small alloc_type, Dwarf_Unsigned count) +{ + Dwarf_Alloc_Hdr alloc_hdr; + + Dwarf_Ptr ret_mem; + + Dwarf_Signed size = 0; + unsigned int index; + unsigned int type = alloc_type; + + if (dbg == NULL) { + return (NULL); + } + + if (type >= ALLOC_AREA_INDEX_TABLE_MAX) { + /* internal error */ + return NULL; + } + index = index_into_allocated[type].ia_al_num; + /* Zero also illegal but not tested for */ + + /* If the Dwarf_Debug is not fully set up, we will get index 0 for + any type and must do something. 'Not fully set up' can only + happen for DW_DLA_ERROR, I (davea) believe, and for that we call + special code here.. */ + + if (index == 0) { + if (alloc_type == DW_DLA_STRING) { + size = count; + } else if (alloc_type == DW_DLA_LIST) { + size = count * sizeof(Dwarf_Ptr); + } else if (alloc_type == DW_DLA_FRAME_BLOCK) { + size = count * sizeof(Dwarf_Frame_Op); + } else if (alloc_type == DW_DLA_LOC_BLOCK) { + size = count * sizeof(Dwarf_Loc); + } else if (alloc_type == DW_DLA_HASH_TABLE_ENTRY) { + size = count * sizeof(struct Dwarf_Hash_Table_Entry_s); + } else if (alloc_type == DW_DLA_ADDR) { + size = count * + (sizeof(Dwarf_Addr) > sizeof(Dwarf_Off) ? + sizeof(Dwarf_Addr) : sizeof(Dwarf_Off)); + } else if (alloc_type == DW_DLA_RANGES) { + size = count * sizeof(Dwarf_Ranges); + } else if (alloc_type == DW_DLA_ERROR) { + void *m = _dwarf_special_no_dbg_error_malloc(); + + dwarf_malloc_check_alloc_data(m, DW_DLA_ERROR); + return m; + + } else { + /* If we get here, there is a disastrous programming error + somewhere. */ +#ifdef DEBUG + fprintf(stderr, + "libdwarf Internal error: type %d unexpected\n", + (int) type); +#endif + } + } else { + alloc_hdr = &dbg->de_alloc_hdr[index]; + if (alloc_hdr->ah_bytes_one_struct > 0) { +#ifdef DWARF_SIMPLE_MALLOC + size = alloc_hdr->ah_bytes_one_struct; +#else + { + void *m = _dwarf_find_memory(alloc_hdr); + + dwarf_malloc_check_alloc_data(m, type); + if (index_into_allocated[type].specialconstructor) { + int res = + index_into_allocated[type]. + specialconstructor(dbg, m); + if (res != DW_DLV_OK) { + /* We leak what we allocated in + _dwarf_find_memory when constructor fails. */ + return NULL; + } + } + return m; + } +#endif + + } else { + /* Special case: should not really happen at all. */ + if (type == DW_DLA_ERROR) { + /* dwarf_init failure. Because dbg is incomplete we + won't use it to record the malloc. */ + void *m = _dwarf_special_no_dbg_error_malloc(); + + dwarf_malloc_check_alloc_data(m, DW_DLA_ERROR); + return m; + } else { + /* If we get here, there is a disastrous programming + error somewhere. */ +#ifdef DWARF_SIMPLE_MALLOC + _dwarf_simple_malloc_botch(3); +#endif +#ifdef DEBUG + fprintf(stderr, + "libdwarf Internal error: Type %d unexpected\n", + (int) type); +#endif + } + } + } + + ret_mem = malloc(size); +#ifdef DWARF_SIMPLE_MALLOC + _dwarf_simple_malloc_add_to_list(dbg, ret_mem, + (unsigned long) size, type); +#endif + if (ret_mem != NULL) + memset(ret_mem, 0, size); + + dwarf_malloc_check_alloc_data(ret_mem, type); + if (index_into_allocated[type].specialconstructor) { + int res = + index_into_allocated[type].specialconstructor(dbg, ret_mem); + if (res != DW_DLV_OK) { + /* We leak what we allocated in _dwarf_find_memory when + constructor fails. */ + return NULL; + } + } + + return (ret_mem); +} + + + +/* + This function is used to deallocate a region of memory + that was obtained by a call to _dwarf_get_alloc. Note + that though dwarf_dealloc() is a public function, + _dwarf_get_alloc() isn't. + + For lists, typically arrays of pointers, it is assumed + that the space was allocated by a direct call to malloc, + and so a straight free() is done. This is also the case + for variable length blocks such as DW_DLA_FRAME_BLOCK + and DW_DLA_LOC_BLOCK and DW_DLA_RANGES. + + For strings, the pointer might point to a string in + .debug_info or .debug_string. After this is checked, + and if found not to be the case, a free() is done, + again on the assumption that a malloc was used to + obtain the space. + + For other types of structs, a pointer to the chunk that + the struct was allocated out of, is present in the bytes + preceding the pointer passed in. For this chunk it is + checked whether all the structs in that chunk are now free. + If so, the entire chunk is free_ed. Otherwise, the space + is added to the free list for that chunk, and the free count + incremented. + + This function does not return anything. +*/ +void +dwarf_dealloc(Dwarf_Debug dbg, + Dwarf_Ptr space, Dwarf_Unsigned alloc_type) +{ + Dwarf_Alloc_Hdr alloc_hdr; + Dwarf_Alloc_Area alloc_area; + unsigned int type = alloc_type; + unsigned int index; + + if (space == NULL) { + return; + } + if (type == DW_DLA_ERROR) { + /* Get pointer to Dwarf_Alloc_Area this struct came from. See + dwarf_alloc.h ROUND_SIZE_WITH_POINTER stuff */ +#ifdef DWARF_SIMPLE_MALLOC + _dwarf_simple_malloc_delete_from_list(dbg, space, type); + free(space); + return; +#endif + alloc_area = + *(Dwarf_Alloc_Area *) ((char *) space - DW_RESERVE); + if (alloc_area == 0) { + /* This is the special case of a failed dwarf_init(). Also + (and more signficantly) there are a variety of other + situations where libdwarf does not *know* what dbg is + involved (because of a libdwarf-caller-error) so + libdwarf uses NULL as the dbg. Those too wind up here. */ + _dwarf_free_special_error(space); + dwarf_malloc_check_dealloc_data(space, type); + return; + } + + } + if (dbg == NULL) { + /* App error, or an app that failed to succeed in a + dwarf_init() call. */ + return; + } + if (type >= ALLOC_AREA_INDEX_TABLE_MAX) { + /* internal or user app error */ + return; + } + + index = index_into_allocated[type].ia_al_num; + /* A string pointer may point into .debug_info or .debug_string. + Otherwise, they are directly malloc'ed. */ + dwarf_malloc_check_dealloc_data(space, type); + if (index == 0) { + if (type == DW_DLA_STRING) { + if ((Dwarf_Small *) space >= dbg->de_debug_info.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_info.dss_data + dbg->de_debug_info.dss_size) + return; + if ((Dwarf_Small *) space >= dbg->de_debug_types.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_types.dss_data + dbg->de_debug_types.dss_size) + return; + + if (dbg->de_debug_line.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_line.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_line.dss_data + dbg->de_debug_line.dss_size) + return; + + if (dbg->de_debug_pubnames.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_pubnames.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_pubnames.dss_data + + dbg->de_debug_pubnames.dss_size) + return; + + if (dbg->de_debug_frame.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_frame.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_frame.dss_data + dbg->de_debug_frame.dss_size) + return; + + if (dbg->de_debug_str.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_str.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_str.dss_data + dbg->de_debug_str.dss_size) + return; + + if (dbg->de_debug_funcnames.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_funcnames.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_funcnames.dss_data + + dbg->de_debug_funcnames.dss_size) + return; + + if (dbg->de_debug_typenames.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_typenames.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_typenames.dss_data + + dbg->de_debug_typenames.dss_size) + return; + if (dbg->de_debug_pubtypes.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_pubtypes.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_pubtypes.dss_data + + dbg->de_debug_pubtypes.dss_size) + return; + + if (dbg->de_debug_varnames.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_varnames.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_varnames.dss_data + + dbg->de_debug_varnames.dss_size) + return; + + if (dbg->de_debug_weaknames.dss_data != NULL && + (Dwarf_Small *) space >= dbg->de_debug_weaknames.dss_data && + (Dwarf_Small *) space < + dbg->de_debug_weaknames.dss_data + + dbg->de_debug_weaknames.dss_size) + return; + +#ifdef DWARF_SIMPLE_MALLOC + _dwarf_simple_malloc_delete_from_list(dbg, space, type); +#endif + free(space); + return; + } + + if (type == DW_DLA_LIST || + type == DW_DLA_FRAME_BLOCK || + type == DW_DLA_LOC_BLOCK || type == DW_DLA_ADDR || + type == DW_DLA_RANGES || + type == DW_DLA_HASH_TABLE_ENTRY) { + +#ifdef DWARF_SIMPLE_MALLOC + _dwarf_simple_malloc_delete_from_list(dbg, space, type); +#endif + free(space); + return; + } + /* else is an alloc type that is not used */ + /* app or internal error */ +#ifdef DWARF_SIMPLE_MALLOC + _dwarf_simple_malloc_botch(4); +#endif + return; + + } + if (index_into_allocated[type].specialdestructor) { + index_into_allocated[type].specialdestructor(space); + } +#ifdef DWARF_SIMPLE_MALLOC + _dwarf_simple_malloc_delete_from_list(dbg, space, type); + free(space); +#else /* !DWARF_SIMPLE_MALLOC */ + alloc_hdr = &dbg->de_alloc_hdr[index]; + + /* Get pointer to Dwarf_Alloc_Area this struct came from. See + dwarf_alloc.h ROUND_SIZE_WITH_POINTER stuff */ + alloc_area = *(Dwarf_Alloc_Area *) ((char *) space - DW_RESERVE); + + /* ASSERT: alloc_area != NULL If NULL we could abort, let it + coredump below, or return, pretending all is well. We go on, + letting program crash. Is caller error. */ + + /* Check that the alloc_hdr field of the alloc_area we have is + pointing to the right alloc_hdr. This is used to catch use of + incorrect deallocation code by the user. */ + if (alloc_area->aa_alloc_hdr != alloc_hdr) { + /* If we get here, the user has called dwarf_dealloc wrongly or + there is some other disastrous error. By leaking mem here we + try to be safe... */ +#ifdef DEBUG + fprintf(stderr, + "libdwarf Internal error: type %d hdr mismatch %lx %lx " + "area ptr %lx\n", + (int) type, + (long) alloc_area->aa_alloc_hdr, + (long) alloc_hdr, (long) alloc_area); +#endif + return; + } + + alloc_hdr->ah_struct_user_holds--; + alloc_area->aa_free_structs_in_chunk++; + + /* Give chunk back to malloc only when every struct is freed */ + if (alloc_area->aa_free_structs_in_chunk == + alloc_hdr->ah_structs_per_chunk) { + if (alloc_area->aa_prev != NULL) { + alloc_area->aa_prev->aa_next = alloc_area->aa_next; + } else { + alloc_hdr->ah_alloc_area_head = alloc_area->aa_next; + } + + if (alloc_area->aa_next != NULL) { + alloc_area->aa_next->aa_prev = alloc_area->aa_prev; + } + + alloc_hdr->ah_chunks_allocated--; + + if (alloc_area == alloc_hdr->ah_last_alloc_area) { + alloc_hdr->ah_last_alloc_area = NULL; + } + memset(alloc_area, 0, sizeof(*alloc_area)); + free(alloc_area); + } + + else { + ((Dwarf_Free_List) space)->fl_next = alloc_area->aa_free_list; + alloc_area->aa_free_list = space; + } +#endif /* !DWARF_SIMPLE_MALLOC */ +} + + +/* + Allocates space for a Dwarf_Debug_s struct, + since one does not exist. +*/ +Dwarf_Debug +_dwarf_get_debug(void + ) +{ + Dwarf_Debug dbg; + + dbg = (Dwarf_Debug) malloc(sizeof(struct Dwarf_Debug_s)); + if (dbg == NULL) { + return (NULL); + } else { + memset(dbg, 0, sizeof(struct Dwarf_Debug_s)); + } + return (dbg); +} + + +/* + Sets up the Dwarf_Debug_s struct for all the + allocation types currently defined. + Allocation types DW_DLA_STRING, DW_DLA_LIST, + DW_DLA_FRAME_BLOCK, DW_DLA_LOC_BLOCK, DW_DLA_RANGES are + malloc'ed directly. + + This routine should be called after _dwarf_setup(), + so that information about the sizes of the Dwarf + sections can be used to decide the number of + structs of each type malloc'ed. + + Also DW_DLA_ELLIST, DW_DLA_BOUNDS, DW_DLA_TYPE, + DW_DLA_SUBSCR, DW_DLA_LINEBUF allocation types + are currently not used. + The ah_bytes_one_struct and ah_structs_per_chunk fields for + these types have been set to 1 for efficiency + in dwarf_get_alloc(). + + Ah_alloc_num should be greater than 1 for all + types that are currently being used. + + Therefore, for these allocation types the + ah_bytes_one_struct, and ah_structs_per_chunk fields do not + need to be initialized. + + Being an internal routine, assume proper dbg. +*/ + +Dwarf_Debug +_dwarf_setup_debug(Dwarf_Debug dbg) +{ + int i; + + for (i = 1; i <= MAX_DW_DLA; i++) { + const struct ial_s *ialp = &index_into_allocated[i]; + unsigned int hdr_index = ialp->ia_al_num; + Dwarf_Word str_size = ialp->ia_struct_size; + Dwarf_Word str_count = ialp->ia_base_count; + Dwarf_Word rnded_size = ROUND_SIZE_WITH_POINTER(str_size); + + Dwarf_Alloc_Hdr alloc_hdr = &dbg->de_alloc_hdr[hdr_index]; + + alloc_hdr->ah_bytes_one_struct = (Dwarf_Half) rnded_size; + + /* ah_structs_per_chunk must be >0 else we are in trouble */ + alloc_hdr->ah_structs_per_chunk = str_count; + alloc_hdr->ah_bytes_malloc_per_chunk = rnded_size * str_count; + } + return (dbg); +} + +/* + This function prints out the statistics + collected on allocation of memory chunks. +*/ +void +dwarf_print_memory_stats(Dwarf_Debug dbg) +{ + Dwarf_Alloc_Hdr alloc_hdr; + Dwarf_Shalf i; + + /* Alloc types start at 1, not 0. Hence, the first NULL string, and + also a size of MAX_DW_DLA + 1. */ + char *alloc_type_name[MAX_DW_DLA + 1] = { + "", + "DW_DLA_STRING", + "DW_DLA_LOC", + "DW_DLA_LOCDESC", + "DW_DLA_ELLIST", + "DW_DLA_BOUNDS", + "DW_DLA_BLOCK", + "DW_DLA_DEBUG", + "DW_DLA_DIE", + "DW_DLA_LINE", + "DW_DLA_ATTR", + "DW_DLA_TYPE", + "DW_DLA_SUBSCR", + "DW_DLA_GLOBAL", + "DW_DLA_ERROR", + "DW_DLA_LIST", + "DW_DLA_LINEBUF", + "DW_DLA_ARANGE", + "DW_DLA_ABBREV", + "DW_DLA_FRAME_OP", + "DW_DLA_CIE", + "DW_DLA_FDE", + "DW_DLA_LOC_BLOCK", + "DW_DLA_FRAME_BLOCK", + "DW_DLA_FUNC", + "DW_DLA_TYPENAME", + "DW_DLA_VAR", + "DW_DLA_WEAK", + "DW_DLA_ADDR", + "DW_DLA_RANGES", + "DW_DLA_ABBREV_LIST", + "DW_DLA_CHAIN", + "DW_DLA_CU_CONTEXT", + "DW_DLA_FRAME", + "DW_DLA_GLOBAL_CONTEXT", + "DW_DLA_FILE_ENTRY", + "DW_DLA_LINE_CONTEXT", + "DW_DLA_LOC_CHAIN", + "DW_DLA_HASH_TABLE", + "DW_DLA_FUNC_CONTEXT", + "DW_DLA_TYPENAME_CONTEXT", + "DW_DLA_VAR_CONTEXT", + "DW_DLA_WEAK_CONTEXT", + "DW_DLA_PUBTYPES_CONTEXT", + "DW_DLA_HASH_TABLE_ENTRY", + }; + + if (dbg == NULL) + return; + + printf("Size of Dwarf_Debug %4ld bytes\n", + (long) sizeof(*dbg)); + printf("Size of Dwarf_Alloc_Hdr_s %4ld bytes\n", + (long) sizeof(struct Dwarf_Alloc_Hdr_s)); + printf("size of Dwarf_Alloc_Area_s %4ld bytes\n", + (long) sizeof(struct Dwarf_Alloc_Area_s)); + + printf(" Alloc Type Curr Structs byt str\n"); + printf(" ---------- ---- ------- per per\n"); + for (i = 1; i <= MAX_DW_DLA; i++) { + int indx = index_into_allocated[i].ia_al_num; + + alloc_hdr = &dbg->de_alloc_hdr[indx]; + if (alloc_hdr->ah_bytes_one_struct != 1) { + printf("%2d %-25s %6d %8d %6d %6d\n", + (int) i, + alloc_type_name[i], + (int) alloc_hdr->ah_chunks_allocated, + (int) alloc_hdr->ah_struct_user_holds, + (int) alloc_hdr->ah_bytes_malloc_per_chunk, + (int) alloc_hdr->ah_structs_per_chunk); + } + } +} + + +#ifndef DWARF_SIMPLE_MALLOC +/* + This recursively frees + the chunks still allocated, and + forward chained through the aa_next + pointer. +*/ +static void +_dwarf_recursive_free(Dwarf_Alloc_Area alloc_area) +{ + if (alloc_area->aa_next != NULL) { + _dwarf_recursive_free(alloc_area->aa_next); + } + + alloc_area->aa_next = 0; + alloc_area->aa_prev = 0; + free(alloc_area); +} +#endif + +/* In the 'rela' relocation case we might have malloc'd + space to ensure it is read-write. In that case, free the space. */ +static void +rela_free(struct Dwarf_Section_s * sec) +{ + if (sec->dss_data_was_malloc) { + free(sec->dss_data); + } + sec->dss_data = 0; + sec->dss_data_was_malloc = 0; +} + +static void +freecontextlist(Dwarf_Debug dbg, Dwarf_Debug_InfoTypes dis) +{ + Dwarf_CU_Context context = 0; + Dwarf_CU_Context nextcontext = 0; + for (context = dis->de_cu_context_list; + context; context = nextcontext) { + Dwarf_Hash_Table hash_table = context->cc_abbrev_hash_table; + _dwarf_free_abbrev_hash_table_contents(dbg,hash_table); + nextcontext = context->cc_next; + dwarf_dealloc(dbg, hash_table, DW_DLA_HASH_TABLE); + dwarf_dealloc(dbg, context, DW_DLA_CU_CONTEXT); + } +} + +/* + Used to free all space allocated for this Dwarf_Debug. + The caller should assume that the Dwarf_Debug pointer + itself is no longer valid upon return from this function. + + In case of difficulty, this function simply returns quietly. +*/ +int +_dwarf_free_all_of_one_debug(Dwarf_Debug dbg) +{ + Dwarf_Alloc_Hdr alloc_hdr = 0; + Dwarf_Shalf i = 0; + + if (dbg == NULL) { + return (DW_DLV_ERROR); + } + + /* To do complete validation that we have no surprising missing or + erroneous deallocs it is advisable to do the dwarf_deallocs here + that are not things the user can otherwise request. + Housecleaning. */ + freecontextlist(dbg,&dbg->de_info_reading); + freecontextlist(dbg,&dbg->de_types_reading); + + /* Housecleaning done. Now really free all the space. */ +#ifdef DWARF_SIMPLE_MALLOC + if (dbg->de_simple_malloc_base) { + struct simple_malloc_record_s *smp = dbg->de_simple_malloc_base; + + while (smp) { + int i; + struct simple_malloc_record_s *prev_smp = 0; + + for (i = 0; i < smp->sr_used; ++i) { + struct simple_malloc_entry_s *cur; + + cur = &smp->sr_entry[i]; + if (cur->se_addr != 0) { + free(cur->se_addr); + cur->se_addr = 0; + } + } + prev_smp = smp; + smp = smp->sr_next; + free(prev_smp); + } + dbg->de_simple_malloc_base = 0; + } +#else + for (i = 1; i < ALLOC_AREA_REAL_TABLE_MAX; i++) { + int indx = i; + + alloc_hdr = &dbg->de_alloc_hdr[indx]; + if (alloc_hdr->ah_alloc_area_head != NULL) { + _dwarf_recursive_free(alloc_hdr->ah_alloc_area_head); + } + } + +#endif + rela_free(&dbg->de_debug_info); + rela_free(&dbg->de_debug_types); + rela_free(&dbg->de_debug_abbrev); + rela_free(&dbg->de_debug_line); + rela_free(&dbg->de_debug_loc); + rela_free(&dbg->de_debug_aranges); + rela_free(&dbg->de_debug_macinfo); + rela_free(&dbg->de_debug_pubnames); + rela_free(&dbg->de_debug_str); + rela_free(&dbg->de_debug_frame); + rela_free(&dbg->de_debug_frame_eh_gnu); + rela_free(&dbg->de_debug_pubtypes); + rela_free(&dbg->de_debug_funcnames); + rela_free(&dbg->de_debug_typenames); + rela_free(&dbg->de_debug_varnames); + rela_free(&dbg->de_debug_weaknames); + rela_free(&dbg->de_debug_ranges); + dwarf_harmless_cleanout(&dbg->de_harmless_errors); + + memset(dbg, 0, sizeof(*dbg)); /* Prevent accidental use later. */ + free(dbg); + return (DW_DLV_OK); +} + +/* A special case: we have no dbg, no alloc header etc. + So create something out of thin air that we can recognize + in dwarf_dealloc. + Something with the prefix (prefix space hidden from caller). + + Only applies to DW_DLA_ERROR, making up an error record. */ +struct Dwarf_Error_s * +_dwarf_special_no_dbg_error_malloc(void) +{ + /* The union unused things are to guarantee proper alignment */ + union u { + Dwarf_Alloc_Area ptr_not_used; + struct Dwarf_Error_s base_not_used; + char data_space[sizeof(struct Dwarf_Error_s) + + (DW_RESERVE * 2)]; + }; + char *mem; + + mem = malloc(sizeof(union u)); + + if (mem == 0) { + return 0; + + } + memset(mem, 0, sizeof(union u)); + mem += DW_RESERVE; + return (struct Dwarf_Error_s *) mem; +} + +/* The free side of _dwarf_special_no_dbg_error_malloc() +*/ +static void +_dwarf_free_special_error(Dwarf_Ptr space) +{ + char *mem = (char *) space; + + mem -= DW_RESERVE; + free(mem); +} + + +#ifdef DWARF_SIMPLE_MALLOC +/* here solely for planting a breakpoint. */ +/* ARGSUSED */ +void +_dwarf_simple_malloc_botch(int err) +{ + fprintf(stderr,"simple malloc botch %d\n",err); +} +static void +_dwarf_simple_malloc_add_to_list(Dwarf_Debug dbg, + Dwarf_Ptr addr, + unsigned long size, short alloc_type) +{ + struct simple_malloc_record_s *cur; + struct simple_malloc_entry_s *newentry; + + if (!dbg->de_simple_malloc_base) { + /* First entry to this routine. */ + dbg->de_simple_malloc_base = + malloc(sizeof(struct simple_malloc_record_s)); + if (!dbg->de_simple_malloc_base) { + _dwarf_simple_malloc_botch(7); + return; /* no memory, give up */ + } + memset(dbg->de_simple_malloc_base, + 0, sizeof(struct simple_malloc_record_s)); + } + cur = dbg->de_simple_malloc_base; + + if (cur->sr_used >= DSM_BLOCK_COUNT) { + /* Better not be > than as that means chaos */ + + /* Create a new block to link at the head. */ + + struct simple_malloc_record_s *newblock = + malloc(sizeof(struct simple_malloc_record_s)); + if (!newblock) { + _dwarf_simple_malloc_botch(8); + return; /* Can do nothing, out of memory */ + } + memset(newblock, 0, sizeof(struct simple_malloc_record_s)); + /* Link the new block at the head of the chain, and make it + 'current' */ + dbg->de_simple_malloc_base = newblock; + newblock->sr_next = cur; + cur = newblock; + } + newentry = &cur->sr_entry[cur->sr_used]; + newentry->se_addr = addr; + newentry->se_size = size; + newentry->se_type = alloc_type; + ++cur->sr_used; +} + +/* + DWARF_SIMPLE_MALLOC: testing the hypothesis that the existing + malloc scheme here (see _dwarf_get_alloc()) is pointless complexity. + + DWARF_SIMPLE_MALLOC also makes it easy for a malloc-tracing + tool to verify libdwarf malloc has no botches (though of course + such does not test the complicated standard-libdwarf-alloc code). + + To properly answer the question, the simple-malloc allocate + and delete should be something other than a simple list. + Perhaps a heap, or perhaps a red-black tree. + +*/ +static void +_dwarf_simple_malloc_delete_from_list(Dwarf_Debug dbg, + Dwarf_Ptr space, short alloc_type) +{ + if (space == 0) { + _dwarf_simple_malloc_botch(6); + } + if (dbg->de_simple_malloc_base) { + struct simple_malloc_record_s *smp = dbg->de_simple_malloc_base; + + while (smp) { + int i; + + for (i = 0; i < smp->sr_used; ++i) { + struct simple_malloc_entry_s *cur; + + cur = &smp->sr_entry[i]; + if (cur->se_addr == space) { + if (cur->se_type != alloc_type) { + _dwarf_simple_malloc_botch(0); + } + cur->se_addr = 0; + return; + } + } + smp = smp->sr_next; + } + } + /* Never found the space. */ + _dwarf_simple_malloc_botch(1); + return; + +} +#endif diff --git a/libdwarf/dwarf_alloc.h b/libdwarf/dwarf_alloc.h new file mode 100644 index 0000000..c0eb2a7 --- /dev/null +++ b/libdwarf/dwarf_alloc.h @@ -0,0 +1,168 @@ +/* + Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +/* #define DWARF_SIMPLE_MALLOC 1 */ + +Dwarf_Ptr _dwarf_get_alloc(Dwarf_Debug, Dwarf_Small, Dwarf_Unsigned); +Dwarf_Debug _dwarf_get_debug(void); +Dwarf_Debug _dwarf_setup_debug(Dwarf_Debug); +int _dwarf_free_all_of_one_debug(Dwarf_Debug); + +typedef struct Dwarf_Alloc_Area_s *Dwarf_Alloc_Area; +typedef struct Dwarf_Free_List_s *Dwarf_Free_List; + +/* ALLOC_AREA_INDEX_TABLE_MAX is the size of the + struct ial_s index_into_allocated array in dwarf_alloc.c +*/ +#define ALLOC_AREA_INDEX_TABLE_MAX 45 +/* ALLOC_AREA_REAL_TABLE_MAX is the size of the array needed + to hold pointers to dwarf alloc chunk areas. + It's smaller as some of the index_into_allocated + entries (they look like {0,1,1,0,0} ) + are treated specially and don't use 'chunks'. +*/ +#define ALLOC_AREA_REAL_TABLE_MAX 32 + +/* + This struct is used to chain all the deallocated + structs on the free list of each chain. The structs + are chained internally, by using the memory they + contain. +*/ +struct Dwarf_Free_List_s { + Dwarf_Free_List fl_next; +}; + + +/* + This struct is used to manage all the chunks malloc'ed + for a particular alloc_type. Many of the fields are + initialized by dwarf_init(). +*/ +struct Dwarf_Alloc_Hdr_s { + + /* Count of actual number of structs user app holds pointers to + currently. */ + Dwarf_Sword ah_struct_user_holds; + + /* Size of each struct that will be allocated for this alloc_type. + Initialized by dwarf_init(). */ + Dwarf_Half ah_bytes_one_struct; + + /* Number of structs of this alloc_type that will be contained in + each chunk that is malloc'ed. Initialized by dwarf_init(). */ + Dwarf_Word ah_structs_per_chunk; + + /* Number of bytes malloc'ed per chunk which is basically + (ah_bytes_one_struct+_DWARF_RESERVE) * ah_alloc_num. */ + Dwarf_Word ah_bytes_malloc_per_chunk; + + /* Count of chunks currently allocated for type. */ + Dwarf_Sword ah_chunks_allocated; + + /* Points to a chain of Dwarf_Alloc_Area_s structs that represent + all the chunks currently allocated for the alloc_type. */ + Dwarf_Alloc_Area ah_alloc_area_head; + + /* Last Alloc Area that was allocated by malloc. The + free-space-search area looks here first and only if it is full + goes thru the list pointed to by ah_alloc_area_head. */ + Dwarf_Alloc_Area ah_last_alloc_area; +}; + + +/* + This struct is used to manage each chunk that is + malloc'ed for a particular alloc_type. For each + allocation type, the allocation header points to + a list of all the chunks malloc'ed for that type. +*/ +struct Dwarf_Alloc_Area_s { + + /* Points to the free list of structs in the chunk. */ + Dwarf_Ptr aa_free_list; + + /* Count of the number of free structs in the chunk. This includes + both those on the free list, and in the blob. */ + Dwarf_Sword aa_free_structs_in_chunk; + + /* Points to the first byte of the blob from which struct will be + allocated. A struct is put on the free_list only when it + dwarf_deallocated. Initial allocations are from the blob. */ + Dwarf_Small *aa_blob_start; + + /* Points just past the last byte of the blob. */ + Dwarf_Small *aa_blob_end; + + /* Points to alloc_hdr this alloc_area is linked to: The owner, in + other words. */ + Dwarf_Alloc_Hdr aa_alloc_hdr; + + /* Used for chaining Dwarf_Alloc_Area_s atructs. Alloc areas are + doubly linked to enable deletion from the list in constant time. */ + Dwarf_Alloc_Area aa_next; + Dwarf_Alloc_Area aa_prev; +}; + +struct Dwarf_Error_s *_dwarf_special_no_dbg_error_malloc(void); + +#ifdef DWARF_SIMPLE_MALLOC +/* + DWARF_SIMPLE_MALLOC is for testing the hypothesis that the existing + complex malloc scheme in libdwarf is pointless complexity. + + DWARF_SIMPLE_MALLOC also makes it easy for a malloc-tracing + tool to verify libdwarf malloc has no botches (though of course + such does not test the complicated standard-libdwarf-alloc code). +*/ + +struct simple_malloc_entry_s { + Dwarf_Small *se_addr; + unsigned long se_size; + short se_type; +}; +#define DSM_BLOCK_COUNT (1000) +#define DSM_BLOCK_SIZE (sizeof(struct simple_malloc_entry_s)*DSM_BLOCK_COUNT) + +/* We do this so dwarf_dealloc can really free everything */ +struct simple_malloc_record_s { + struct simple_malloc_record_s *sr_next; + int sr_used; + struct simple_malloc_entry_s sr_entry[DSM_BLOCK_COUNT]; +}; + + + +#endif /* DWARF_SIMPLE_MALLOC */ diff --git a/libdwarf/dwarf_arange.c b/libdwarf/dwarf_arange.c new file mode 100644 index 0000000..fe74385 --- /dev/null +++ b/libdwarf/dwarf_arange.c @@ -0,0 +1,616 @@ +/* + + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_arange.h" +#include "dwarf_global.h" /* for _dwarf_fixup_* */ + + +/* Common code for two user-visible routines to share. + Errors here result in memory leaks, but errors here + are serious (making aranges unusable) so we assume + callers will not repeat the error often or mind the leaks. +*/ +static int +dwarf_get_aranges_list(Dwarf_Debug dbg, + Dwarf_Chain * chain_out, + Dwarf_Signed * chain_count_out, + Dwarf_Error * error) +{ + /* Sweeps through the arange. */ + Dwarf_Small *arange_ptr = 0; + Dwarf_Small *arange_ptr_start = 0; + + /* Start of arange header. Used for rounding offset of arange_ptr + to twice the tuple size. Libdwarf requirement. */ + Dwarf_Small *header_ptr = 0; + + /* Version of .debug_aranges header. */ + Dwarf_Half version = 0; + + /* Offset of current set of aranges into .debug_info. */ + Dwarf_Off info_offset = 0; + + /* Size in bytes of addresses in target. */ + Dwarf_Small address_size = 0; + + /* Size in bytes of segment offsets in target. */ + Dwarf_Small segment_size = 0; + + /* Count of total number of aranges. */ + Dwarf_Unsigned arange_count = 0; + + Dwarf_Arange arange = 0; + + /* Used to chain Dwarf_Aranges structs. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain prev_chain = NULL; + Dwarf_Chain head_chain = NULL; + if (!dbg->de_debug_aranges.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + arange_ptr = dbg->de_debug_aranges.dss_data; + arange_ptr_start = arange_ptr; + do { + /* Length of current set of aranges. */ + Dwarf_Unsigned length = 0; + Dwarf_Small remainder = 0; + Dwarf_Small *arange_ptr_past_end = 0; + Dwarf_Unsigned range_entry_size = 0; + + int local_length_size; + + /*REFERENCED*/ /* Not used in this instance of the macro */ + int local_extension_size = 0; + + header_ptr = arange_ptr; + + /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */ + READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, + arange_ptr, local_length_size, + local_extension_size); + arange_ptr_past_end = arange_ptr + length; + + + READ_UNALIGNED(dbg, version, Dwarf_Half, + arange_ptr, sizeof(Dwarf_Half)); + arange_ptr += sizeof(Dwarf_Half); + length = length - sizeof(Dwarf_Half); + if (version != CURRENT_VERSION_STAMP) { + _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); + return (DW_DLV_ERROR); + } + + READ_UNALIGNED(dbg, info_offset, Dwarf_Off, + arange_ptr, local_length_size); + arange_ptr += local_length_size; + length = length - local_length_size; + /* This applies to debug_info only, not to debug_types. */ + if (info_offset >= dbg->de_debug_info.dss_size) { + FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset, + "arange info offset.a"); + if (info_offset >= dbg->de_debug_info.dss_size) { + _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + } + + address_size = *(Dwarf_Small *) arange_ptr; + if(address_size > sizeof(Dwarf_Addr)) { + _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR); + return DW_DLV_ERROR; + } + if(address_size == 0) { + _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR); + return DW_DLV_ERROR; + } + /* It is not an error if the sizes differ. + Unusual, but not an error. */ + arange_ptr = arange_ptr + sizeof(Dwarf_Small); + length = length - sizeof(Dwarf_Small); + + /* Even DWARF2 had a segment_size field here, meaning + size in bytes of a segment descriptor on the target + system. */ + segment_size = *(Dwarf_Small *) arange_ptr; + if(segment_size > sizeof(Dwarf_Addr)) { + _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD); + return (DW_DLV_ERROR); + } + arange_ptr = arange_ptr + sizeof(Dwarf_Small); + length = length - sizeof(Dwarf_Small); + + range_entry_size = 2*address_size + segment_size; + /* Round arange_ptr offset to next multiple of address_size. */ + remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) % + (range_entry_size); + if (remainder != 0) { + arange_ptr = arange_ptr + (2 * address_size) - remainder; + length = length - ((2 * address_size) - remainder); + } + do { + Dwarf_Addr range_address = 0; + Dwarf_Unsigned segment_selector = 0; + Dwarf_Unsigned range_length = 0; + /* For segmented address spaces, the first field to + read is a segment selector (new in DWARF4). + Surprising since the segment_size was always there + in the table header! */ + if(version == 4 && segment_size != 0) { + READ_UNALIGNED(dbg, segment_selector, Dwarf_Unsigned, + arange_ptr, segment_size); + arange_ptr += address_size; + length = length - address_size; + } + + READ_UNALIGNED(dbg, range_address, Dwarf_Addr, + arange_ptr, address_size); + arange_ptr += address_size; + length = length - address_size; + + READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned, + arange_ptr, address_size); + arange_ptr += address_size; + length = length - address_size; + + { + /* We used to suppress all-zero entries, but + now we return all aranges entries so we show + the entire content. March 31, 2010. */ + + arange = (Dwarf_Arange) + _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); + if (arange == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + arange->ar_segment_selector = segment_selector; + arange->ar_segment_selector_size = segment_size; + arange->ar_address = range_address; + arange->ar_length = range_length; + arange->ar_info_offset = info_offset; + arange->ar_dbg = dbg; + arange_count++; + + curr_chain = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + curr_chain->ch_item = arange; + if (head_chain == NULL) + head_chain = prev_chain = curr_chain; + else { + prev_chain->ch_next = curr_chain; + prev_chain = curr_chain; + } + } + /* The current set of ranges is terminated by + range_address 0 and range_length 0, but that + does not necessarily terminate the ranges for this CU! + There can be multiple sets in that DWARF + does not explicitly forbid multiple sets. + DWARF2,3,4 section 7.20 + We stop short to avoid overrun of the end of the CU. */ + + } while (arange_ptr_past_end >= (arange_ptr + range_entry_size)); + + /* A compiler could emit some padding bytes here. dwarf2/3 + (dwarf4 sec 7.20) does not clearly make extra padding + bytes illegal. */ + if (arange_ptr_past_end < arange_ptr) { + char buf[200]; + Dwarf_Unsigned pad_count = arange_ptr - arange_ptr_past_end; + Dwarf_Unsigned offset = arange_ptr - arange_ptr_start; + snprintf(buf,sizeof(buf),"DW_DLE_ARANGE_LENGTH_BAD." + " 0x%" DW_PR_XZEROS DW_PR_DUx + " pad bytes at offset 0x%" DW_PR_XZEROS DW_PR_DUx + " in .debug_aranges", + pad_count, offset); + dwarf_insert_harmless_error(dbg,buf); + } + /* For most compilers, arange_ptr == arange_ptr_past_end at + this point. But not if there were padding bytes */ + arange_ptr = arange_ptr_past_end; + } while (arange_ptr < + dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size); + + if (arange_ptr != + dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) { + _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR); + return (DW_DLV_ERROR); + } + *chain_out = head_chain; + *chain_count_out = arange_count; + return DW_DLV_OK; +} + +/* + This function returns the count of the number of + aranges in the .debug_aranges section. It sets + aranges to point to a block of Dwarf_Arange's + describing the arange's. It returns DW_DLV_ERROR + on error. + + Must be identical in most aspects to + dwarf_get_aranges_addr_offsets! + +*/ +int +dwarf_get_aranges(Dwarf_Debug dbg, + Dwarf_Arange ** aranges, + Dwarf_Signed * returned_count, Dwarf_Error * error) +{ + /* Count of total number of aranges. */ + Dwarf_Signed arange_count = 0; + + Dwarf_Arange *arange_block = 0; + + /* Used to chain Dwarf_Aranges structs. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain prev_chain = NULL; + Dwarf_Chain head_chain = NULL; + Dwarf_Unsigned i = 0; + int res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error); + if (res != DW_DLV_OK) { + return res; + } + + res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error); + if(res != DW_DLV_OK) { + return res; + } + + arange_block = (Dwarf_Arange *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count); + if (arange_block == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + curr_chain = head_chain; + for (i = 0; i < arange_count; i++) { + *(arange_block + i) = curr_chain->ch_item; + prev_chain = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); + } + + *aranges = arange_block; + *returned_count = (arange_count); + return DW_DLV_OK; +} + +/* + This function returns DW_DLV_OK if it succeeds + and DW_DLV_ERR or DW_DLV_OK otherwise. + count is set to the number of addresses in the + .debug_aranges section. + For each address, the corresponding element in + an array is set to the address itself(aranges) and + the section offset (offsets). + Must be identical in most aspects to + dwarf_get_aranges! +*/ +int +_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg, + Dwarf_Addr ** addrs, + Dwarf_Off ** offsets, + Dwarf_Signed * count, + Dwarf_Error * error) +{ + Dwarf_Unsigned i = 0; + + /* Used to chain Dwarf_Aranges structs. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain prev_chain = NULL; + Dwarf_Chain head_chain = NULL; + + Dwarf_Signed arange_count = 0; + Dwarf_Addr *arange_addrs = 0; + Dwarf_Off *arange_offsets = 0; + + int res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + + if (error != NULL) + *error = NULL; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error); + if (res != DW_DLV_OK) { + return res; + } + + res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error); + if(res != DW_DLV_OK) { + return res; + } + + arange_addrs = (Dwarf_Addr *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); + if (arange_addrs == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + arange_offsets = (Dwarf_Off *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); + if (arange_offsets == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + curr_chain = head_chain; + for (i = 0; i < arange_count; i++) { + Dwarf_Arange ar = curr_chain->ch_item; + + arange_addrs[i] = ar->ar_address; + arange_offsets[i] = ar->ar_info_offset; + prev_chain = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, ar, DW_DLA_ARANGE); + dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); + } + *count = arange_count; + *offsets = arange_offsets; + *addrs = arange_addrs; + return (DW_DLV_OK); +} + + +/* + This function takes a pointer to a block + of Dwarf_Arange's, and a count of the + length of the block. It checks if the + given address is within the range of an + address range in the block. If yes, it + returns the appropriate Dwarf_Arange. + Otherwise, it returns DW_DLV_ERROR. +*/ +int +dwarf_get_arange(Dwarf_Arange * aranges, + Dwarf_Unsigned arange_count, + Dwarf_Addr address, + Dwarf_Arange * returned_arange, Dwarf_Error * error) +{ + Dwarf_Arange curr_arange = 0; + Dwarf_Unsigned i = 0; + + if (aranges == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGES_NULL); + return (DW_DLV_ERROR); + } + for (i = 0; i < arange_count; i++) { + curr_arange = *(aranges + i); + if (address >= curr_arange->ar_address && + address < + curr_arange->ar_address + curr_arange->ar_length) { + *returned_arange = curr_arange; + return (DW_DLV_OK); + } + } + + return (DW_DLV_NO_ENTRY); +} + + +/* + This function takes an Dwarf_Arange, + and returns the offset of the first + die in the compilation-unit that the + arange belongs to. Returns DW_DLV_ERROR + on error. + + For an arange, the cu_die can only be from debug_info, + not debug_types, it seems. +*/ +int +dwarf_get_cu_die_offset(Dwarf_Arange arange, + Dwarf_Off * returned_offset, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Off offset = 0; + + if (arange == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); + return (DW_DLV_ERROR); + } + dbg = arange->ar_dbg; + offset = arange->ar_info_offset; + /* This applies to debug_info only, not to debug_types. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + } + *returned_offset = offset + _dwarf_length_of_cu_header(dbg, offset, true); + return DW_DLV_OK; +} + +/* This function takes an Dwarf_Arange, + and returns the offset of the CU header + in the compilation-unit that the + arange belongs to. Returns DW_DLV_ERROR + on error. + Ensures .debug_info loaded so + the cu_offset is meaningful. */ +int +dwarf_get_arange_cu_header_offset(Dwarf_Arange arange, + Dwarf_Off * cu_header_offset_returned, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + if (arange == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); + return (DW_DLV_ERROR); + } + dbg = arange->ar_dbg; + /* This applies to debug_info only, not to debug_types. */ + /* Like dwarf_get_arange_info this ensures debug_info loaded: + the cu_header is in debug_info and will be used else + we would not call dwarf_get_arange_cu_header_offset. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + } + *cu_header_offset_returned = arange->ar_info_offset; + return DW_DLV_OK; +} + + + + +/* + This function takes a Dwarf_Arange, and returns + true if it is not NULL. It also stores the start + address of the range in *start, the length of the + range in *length, and the offset of the first die + in the compilation-unit in *cu_die_offset. It + returns false on error. + If cu_die_offset returned ensures .debug_info loaded so + the cu_die_offset is meaningful. +*/ +int +dwarf_get_arange_info(Dwarf_Arange arange, + Dwarf_Addr * start, + Dwarf_Unsigned * length, + Dwarf_Off * cu_die_offset, Dwarf_Error * error) +{ + if (arange == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); + return (DW_DLV_ERROR); + } + + if (start != NULL) + *start = arange->ar_address; + if (length != NULL) + *length = arange->ar_length; + if (cu_die_offset != NULL) { + Dwarf_Debug dbg = arange->ar_dbg; + Dwarf_Off offset = arange->ar_info_offset; + + /* This applies to debug_info only, not to debug_types. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + } + *cu_die_offset = + offset + _dwarf_length_of_cu_header(dbg, offset,true); + } + return (DW_DLV_OK); +} + + +/* New for DWARF4, entries may have segment information. + *segment is only meaningful if *segment_entry_size is non-zero. */ +int +dwarf_get_arange_info_b(Dwarf_Arange arange, + Dwarf_Unsigned* segment, + Dwarf_Unsigned* segment_entry_size, + Dwarf_Addr * start, + Dwarf_Unsigned* length, + Dwarf_Off * cu_die_offset, + Dwarf_Error * error) +{ + if (arange == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); + return (DW_DLV_ERROR); + } + + if(segment != NULL) { + *segment = arange->ar_segment_selector; + } + if(segment_entry_size != NULL) { + *segment_entry_size = arange->ar_segment_selector_size; + } + if (start != NULL) + *start = arange->ar_address; + if (length != NULL) + *length = arange->ar_length; + if (cu_die_offset != NULL) { + Dwarf_Debug dbg = arange->ar_dbg; + Dwarf_Off offset = arange->ar_info_offset; + + /* This applies to debug_info only, not to debug_types. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + } + *cu_die_offset = + offset + _dwarf_length_of_cu_header(dbg, offset,true); + } + return (DW_DLV_OK); +} diff --git a/libdwarf/dwarf_arange.h b/libdwarf/dwarf_arange.h new file mode 100644 index 0000000..e5833b9 --- /dev/null +++ b/libdwarf/dwarf_arange.h @@ -0,0 +1,71 @@ +/* + + Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +/* This structure is used to read an arange into. */ +struct Dwarf_Arange_s { + + /* The segment selector. Only non-zero if Dwarf4, only + meaningful if ar_segment_selector_size non-zero */ + Dwarf_Unsigned ar_segment_selector; + + /* Starting address of the arange, ie low-pc. */ + Dwarf_Addr ar_address; + + /* Length of the arange. */ + Dwarf_Unsigned ar_length; + + + /* Offset into .debug_info of the start of the compilation-unit + containing this set of aranges. + Applies only to .debug_info, not .debug_types. */ + Dwarf_Off ar_info_offset; + + /* Corresponding Dwarf_Debug. */ + Dwarf_Debug ar_dbg; + + Dwarf_Half ar_segment_selector_size; +}; + + + +int +_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg, + Dwarf_Addr ** addrs, + Dwarf_Off ** offsets, + Dwarf_Signed * count, + Dwarf_Error * error); diff --git a/libdwarf/dwarf_base_types.h b/libdwarf/dwarf_base_types.h new file mode 100644 index 0000000..0258c76 --- /dev/null +++ b/libdwarf/dwarf_base_types.h @@ -0,0 +1,118 @@ +/* + + Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "libdwarfdefs.h" + +#define true 1 +#define false 0 + +/* To identify a cie */ +#define DW_CIE_ID ~(0x0) +#define DW_CIE_VERSION 1 /* DWARF2 */ +#define DW_CIE_VERSION3 3 /* DWARF3 */ +#define DW_CIE_VERSION4 4 /* DWARF4 */ + +#define DW_CU_VERSION2 2 +#define DW_CU_VERSION3 3 +#define DW_CU_VERSION4 4 + +/* DWARF2,3 and 4 */ +#define DW_ARANGES_VERSION2 2 + +#define DW_LINE_VERSION2 2 +#define DW_LINE_VERSION3 3 +#define DW_LINE_VERSION4 4 + + +/* These are allocation type codes for structs that + are internal to the Libdwarf Consumer library. */ +#define DW_DLA_ABBREV_LIST DW_DLA_RANGES + 1 +#define DW_DLA_CHAIN DW_DLA_RANGES + 2 +#define DW_DLA_CU_CONTEXT DW_DLA_RANGES + 3 +#define DW_DLA_FRAME DW_DLA_RANGES + 4 +#define DW_DLA_GLOBAL_CONTEXT DW_DLA_RANGES + 5 +#define DW_DLA_FILE_ENTRY DW_DLA_RANGES + 6 +#define DW_DLA_LINE_CONTEXT DW_DLA_RANGES + 7 +#define DW_DLA_LOC_CHAIN DW_DLA_RANGES + 8 +#define DW_DLA_HASH_TABLE DW_DLA_RANGES + 9 +#define DW_DLA_FUNC_CONTEXT DW_DLA_RANGES + 10 +#define DW_DLA_TYPENAME_CONTEXT DW_DLA_RANGES + 11 +#define DW_DLA_VAR_CONTEXT DW_DLA_RANGES + 12 +#define DW_DLA_WEAK_CONTEXT DW_DLA_RANGES + 13 +#define DW_DLA_PUBTYPES_CONTEXT DW_DLA_RANGES + 14 /* DWARF3 */ +#define DW_DLA_HASH_TABLE_ENTRY DW_DLA_RANGES + 15 + +/* Maximum number of allocation types for allocation routines. */ +#define MAX_DW_DLA DW_DLA_HASH_TABLE_ENTRY + +/*Dwarf_Word is unsigned word usable for index, count in memory */ +/*Dwarf_Sword is signed word usable for index, count in memory */ +/* The are 32 or 64 bits depending if 64 bit longs or not, which + fits the ILP32 and LP64 models + These work equally well with ILP64. */ + +typedef unsigned long Dwarf_Word; +typedef signed long Dwarf_Sword; + +typedef signed char Dwarf_Sbyte; +typedef unsigned char Dwarf_Ubyte; +typedef signed short Dwarf_Shalf; +typedef Dwarf_Small *Dwarf_Byte_Ptr; + +/* These 2 are fixed sizes which must not vary with the + ILP32/LP64 model. Between these two, stay at 32 bit. */ +typedef __uint32_t Dwarf_ufixed; +typedef __int32_t Dwarf_sfixed; + +/* In various places the code mistakenly associates + forms 8 bytes long with Dwarf_Signed or Dwarf_Unsigned + This is not a very portable assumption. + The following should be used instead for 64 bit integers. +*/ +typedef __uint64_t Dwarf_ufixed64; +typedef __int64_t Dwarf_sfixed64; + + +typedef struct Dwarf_Abbrev_List_s *Dwarf_Abbrev_List; +typedef struct Dwarf_File_Entry_s *Dwarf_File_Entry; +typedef struct Dwarf_CU_Context_s *Dwarf_CU_Context; +typedef struct Dwarf_Hash_Table_s *Dwarf_Hash_Table; +typedef struct Dwarf_Hash_Table_Entry_s *Dwarf_Hash_Table_Entry; + + +typedef struct Dwarf_Alloc_Hdr_s *Dwarf_Alloc_Hdr; diff --git a/libdwarf/dwarf_die_deliv.c b/libdwarf/dwarf_die_deliv.c new file mode 100644 index 0000000..9ef5c45 --- /dev/null +++ b/libdwarf/dwarf_die_deliv.c @@ -0,0 +1,1214 @@ +/* + + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#ifdef HAVE_ELF_H +#include <elf.h> +#endif +#include <stdio.h> +#include "dwarf_die_deliv.h" + + +static int +dwarf_next_cu_header_internal(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Half * offset_size, + Dwarf_Half * extension_size, + Dwarf_Sig8 * signature, + Dwarf_Unsigned *typeoffset, + Dwarf_Unsigned * next_cu_offset, + Dwarf_Error * error); + +/* New October 2011. Enables client code to know if + it is a debug_info or debug_types context. */ +Dwarf_Bool +dwarf_get_die_infotypes_flag(Dwarf_Die die) +{ + return die->di_is_info; +} + +/* + For a given Dwarf_Debug dbg, this function checks + if a CU that includes the given offset has been read + or not. If yes, it returns the Dwarf_CU_Context + for the CU. Otherwise it returns NULL. Being an + internal routine, it is assumed that a valid dbg + is passed. + + **This is a sequential search. May be too slow. + + If debug_info and debug_abbrev not loaded, this will + wind up returning NULL. So no need to load before calling + this. +*/ +static Dwarf_CU_Context +_dwarf_find_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset,Dwarf_Bool is_info) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + + if (offset >= dis->de_last_offset) + return (NULL); + + if (dis->de_cu_context != NULL && + dis->de_cu_context->cc_next != NULL && + dis->de_cu_context->cc_next->cc_debug_offset == offset) { + + return (dis->de_cu_context->cc_next); + } + + if (dis->de_cu_context != NULL && + dis->de_cu_context->cc_debug_offset <= offset) { + + for (cu_context = dis->de_cu_context; + cu_context != NULL; cu_context = cu_context->cc_next) { + + if (offset >= cu_context->cc_debug_offset && + offset < cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size) { + + return (cu_context); + } + } + } + + for (cu_context = dis->de_cu_context_list; + cu_context != NULL; cu_context = cu_context->cc_next) { + + if (offset >= cu_context->cc_debug_offset && + offset < cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size) { + + return (cu_context); + } + } + + return (NULL); +} + + +/* This routine checks the dwarf_offdie() list of + CU contexts for the right CU context. */ +static Dwarf_CU_Context +_dwarf_find_offdie_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset, + Dwarf_Bool is_info) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + + for (cu_context = dis->de_offdie_cu_context; + cu_context != NULL; cu_context = cu_context->cc_next) + + if (offset >= cu_context->cc_debug_offset && + offset < cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size) + + return (cu_context); + + return (NULL); +} + + +/* This function is used to create a CU Context for + a compilation-unit that begins at offset in + .debug_info. The CU Context is attached to the + list of CU Contexts for this dbg. It is assumed + that the CU at offset has not been read before, + and so do not call this routine before making + sure of this with _dwarf_find_CU_Context(). + Returns NULL on error. As always, being an + internal routine, assumes a good dbg. + + This function must always set a dwarf error code + before returning NULL. Always. */ +static Dwarf_CU_Context +_dwarf_make_CU_Context(Dwarf_Debug dbg, + Dwarf_Off offset,Dwarf_Bool is_info,Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Unsigned length = 0; + Dwarf_Signed abbrev_offset = 0; + Dwarf_Unsigned typeoffset = 0; + Dwarf_Sig8 signaturedata; + Dwarf_Unsigned types_extra_len = 0; + Dwarf_Byte_Ptr cu_ptr = 0; + int local_extension_size = 0; + int local_length_size = 0; + Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + Dwarf_Unsigned section_size = is_info? dbg->de_debug_info.dss_size: + dbg->de_debug_types.dss_size; + + cu_context = + (Dwarf_CU_Context) _dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1); + if (cu_context == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (NULL); + } + cu_context->cc_dbg = dbg; + cu_context->cc_is_info = is_info; + + { + Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + cu_ptr = (Dwarf_Byte_Ptr) (dataptr+offset); + } + + /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */ + READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, + cu_ptr, local_length_size, local_extension_size); + cu_context->cc_length_size = local_length_size; + cu_context->cc_extension_size = local_extension_size; + + + cu_context->cc_length = (Dwarf_Word) length; + + READ_UNALIGNED(dbg, cu_context->cc_version_stamp, Dwarf_Half, + cu_ptr, sizeof(Dwarf_Half)); + cu_ptr += sizeof(Dwarf_Half); + + READ_UNALIGNED(dbg, abbrev_offset, Dwarf_Signed, + cu_ptr, local_length_size); + cu_ptr += local_length_size; + cu_context->cc_abbrev_offset = (Dwarf_Sword) abbrev_offset; + + cu_context->cc_address_size = *(Dwarf_Small *) cu_ptr; + ++cu_ptr; + + + + if(cu_context->cc_address_size > sizeof(Dwarf_Addr)) { + _dwarf_error(dbg, error, DW_DLE_CU_ADDRESS_SIZE_BAD); + return (NULL); + } + if(!is_info) { + /* debug_types CU headers have extra header bytes. */ + types_extra_len = sizeof(signaturedata) + local_length_size; + } + if ((length < (CU_VERSION_STAMP_SIZE + local_length_size + + CU_ADDRESS_SIZE_SIZE + types_extra_len)) || + ((offset + length + local_length_size + local_extension_size) > + section_size)) { + + dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); + _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR); + return (NULL); + } + + if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP + && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP3 + && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) { + dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); + _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); + return (NULL); + } + if (!is_info) { + if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) { + dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); + _dwarf_error(dbg, error, DW_DLE_DEBUG_TYPES_ONLY_DWARF4); + return (NULL); + } + /* Now read the debug_types extra header fields of + the signature (8 bytes) and the typeoffset. */ + memcpy(&signaturedata,cu_ptr,sizeof(signaturedata)); + cu_ptr += sizeof(signaturedata); + READ_UNALIGNED(dbg, typeoffset, Dwarf_Unsigned, + cu_ptr, local_length_size); + cu_context->cc_typeoffset = typeoffset; + cu_context->cc_signature = signaturedata; + { + Dwarf_Unsigned cu_len = length - (local_length_size + + local_extension_size); + if(typeoffset >= cu_len) { + dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); + _dwarf_error(dbg, error, DW_DLE_DEBUG_TYPEOFFSET_BAD); + return (NULL); + } + } + } + + if (abbrev_offset >= dbg->de_debug_abbrev.dss_size) { + dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); + _dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR); + return (NULL); + } + + cu_context->cc_abbrev_hash_table = + (Dwarf_Hash_Table) _dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE, 1); + if (cu_context->cc_abbrev_hash_table == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (NULL); + } + + cu_context->cc_debug_offset = (Dwarf_Word) offset; + + dis->de_last_offset = (Dwarf_Word) (offset + length + + local_extension_size + local_length_size); + + if (dis->de_cu_context_list == NULL) { + dis->de_cu_context_list = cu_context; + dis->de_cu_context_list_end = cu_context; + } else { + dis->de_cu_context_list_end->cc_next = cu_context; + dis->de_cu_context_list_end = cu_context; + } + + return (cu_context); +} + +static int +reloc_incomplete(Dwarf_Error err) +{ + int e = dwarf_errno(err); + if( e == DW_DLE_RELOC_MISMATCH_INDEX || + e == DW_DLE_RELOC_MISMATCH_RELOC_INDEX || + e == DW_DLE_RELOC_MISMATCH_STRTAB_INDEX || + e == DW_DLE_RELOC_SECTION_MISMATCH || + e == DW_DLE_RELOC_SECTION_MISSING_INDEX || + e == DW_DLE_RELOC_SECTION_LENGTH_ODD || + e == DW_DLE_RELOC_SECTION_PTR_NULL || + e == DW_DLE_RELOC_SECTION_MALLOC_FAIL || + e == DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD ) { + return 1; + } + return 0; +} + + + +/* Returns offset of next compilation-unit thru next_cu_offset + pointer. + It sequentially moves from one + cu to the next. The current cu is recorded + internally by libdwarf. + + The _b form is new for DWARF4 adding new returned fields. */ +int +dwarf_next_cu_header(Dwarf_Debug dbg, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Unsigned * next_cu_offset, + Dwarf_Error * error) +{ + Dwarf_Bool is_info = true; + return dwarf_next_cu_header_internal(dbg, + is_info, + cu_header_length, + version_stamp, + abbrev_offset, + address_size, + 0,0,0,0, + next_cu_offset, + error); +} +int +dwarf_next_cu_header_b(Dwarf_Debug dbg, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Half * offset_size, + Dwarf_Half * extension_size, + Dwarf_Unsigned * next_cu_offset, + Dwarf_Error * error) +{ + Dwarf_Bool is_info = true; + return dwarf_next_cu_header_internal(dbg, + is_info, + cu_header_length, + version_stamp, + abbrev_offset, + address_size, + offset_size,extension_size, + 0,0, + next_cu_offset, + error); +} + +int +dwarf_next_cu_header_c(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Half * offset_size, + Dwarf_Half * extension_size, + Dwarf_Sig8 * signature, + Dwarf_Unsigned * typeoffset, + Dwarf_Unsigned * next_cu_offset, + Dwarf_Error * error) +{ + return dwarf_next_cu_header_internal(dbg, + is_info, + cu_header_length, + version_stamp, + abbrev_offset, + address_size, + offset_size, + extension_size, + signature, + typeoffset, + next_cu_offset, + error); +} +static int +dwarf_next_cu_header_internal(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Half * offset_size, + Dwarf_Half * extension_size, + Dwarf_Sig8 * signature, + Dwarf_Unsigned *typeoffset, + Dwarf_Unsigned * next_cu_offset, + Dwarf_Error * error) +{ + /* Offset for current and new CU. */ + Dwarf_Unsigned new_offset = 0; + + /* CU Context for current CU. */ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug_InfoTypes dis = 0; + Dwarf_Unsigned section_size = 0; + + + + /* ***** BEGIN CODE ***** */ + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + dis = is_info? &dbg->de_info_reading: &dbg->de_types_reading; + /* Get offset into .debug_info of next CU. If dbg has no context, + this has to be the first one. */ + if (dis->de_cu_context == NULL) { + Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + new_offset = 0; + if (!dataptr) { + Dwarf_Error err2= 0; + int res = is_info?_dwarf_load_debug_info(dbg, &err2): + _dwarf_load_debug_types(dbg,&err2); + + if (res != DW_DLV_OK) { + if(reloc_incomplete(err2)) { + /* We will assume all is ok, though it is not. + Relocation errors need not be fatal. */ + char msg_buf[200]; + snprintf(msg_buf,sizeof(msg_buf), + "Relocations did not complete successfully, but we are " + " ignoring error: %s",dwarf_errmsg(err2)); + dwarf_insert_harmless_error(dbg,msg_buf); + res = DW_DLV_OK; + } else { + if( error) { + *error = err2; + } + return res; + } + + } + } + + } else { + new_offset = dis->de_cu_context->cc_debug_offset + + dis->de_cu_context->cc_length + + dis->de_cu_context->cc_length_size + + dis->de_cu_context->cc_extension_size; + } + + /* Check that there is room in .debug_info beyond the new offset + for at least a new cu header. If not, return 0 to indicate end + of debug_info section, and reset de_cu_debug_info_offset to + enable looping back through the cu's. */ + section_size = is_info? dbg->de_debug_info.dss_size: + dbg->de_debug_types.dss_size; + if ((new_offset + _dwarf_length_of_cu_header_simple(dbg,is_info)) >= + section_size) { + dis->de_cu_context = NULL; + return (DW_DLV_NO_ENTRY); + } + + /* Check if this CU has been read before. */ + cu_context = _dwarf_find_CU_Context(dbg, new_offset,is_info); + + /* If not, make CU Context for it. */ + if (cu_context == NULL) { + cu_context = _dwarf_make_CU_Context(dbg, new_offset,is_info, error); + if (cu_context == NULL) { + /* Error if CU Context could not be made. Since + _dwarf_make_CU_Context has already registered an error + we do not do that here: we let the lower error pass + thru. */ + return (DW_DLV_ERROR); + } + } + + dis->de_cu_context = cu_context; + + if (cu_header_length != NULL) { + *cu_header_length = cu_context->cc_length; + } + + if (version_stamp != NULL) { + *version_stamp = cu_context->cc_version_stamp; + } + if (abbrev_offset != NULL) { + *abbrev_offset = cu_context->cc_abbrev_offset; + } + + if (address_size != NULL) { + *address_size = cu_context->cc_address_size; + } + if (offset_size != NULL) { + *offset_size = cu_context->cc_length_size; + } + if (extension_size != NULL) { + *extension_size = cu_context->cc_extension_size; + } + if(!is_info) { + if(signature) { + *signature = cu_context->cc_signature; + } + if(typeoffset) { + *typeoffset = cu_context->cc_typeoffset; + } + } + + new_offset = new_offset + cu_context->cc_length + + cu_context->cc_length_size + cu_context->cc_extension_size; + *next_cu_offset = new_offset; + return (DW_DLV_OK); +} + +static int +dwarf_ptr_CU_offset(Dwarf_CU_Context cu_context, + Dwarf_Byte_Ptr di_ptr, + Dwarf_Bool is_info, + Dwarf_Off * cu_off) +{ + Dwarf_Debug dbg = cu_context->cc_dbg; + Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + *cu_off = (di_ptr - dataptr); + return DW_DLV_OK; +} +#if 0 +/* Just for debug purposes */ +void print_sib_offset(Dwarf_Die sibling) +{ + Dwarf_Off sib_off; + Dwarf_Error error; + dwarf_dieoffset(sibling,&sib_off,&error); + fprintf(stderr," SIB OFF = 0x%" DW_PR_XZEROS DW_PR_DUx,sib_off); +} +void print_ptr_offset(Dwarf_CU_Context cu_context,Dwarf_Byte_Ptr di_ptr) +{ + Dwarf_Off ptr_off; + dwarf_ptr_CU_offset(cu_context,di_ptr,&ptr_off); + fprintf(stderr," PTR OFF = 0x%" DW_PR_XZEROS DW_PR_DUx,ptr_off); +} +#endif + + +/* Validate the sibling DIE. This only makes sense to call + if the sibling's DIEs have been travsersed and + dwarf_child() called on each, + so that the last DIE dwarf_child saw was the last. + Essentially ensuring that (after such traversal) that we + are in the same place a sibling attribute would identify. + In case we return DW_DLV_ERROR, the global offset of the last + DIE traversed by dwarf_child is returned through *offset + + It is essentially guaranteed that dbg->de_last_die + is a stale DIE pointer of a deallocated DIE when we get here. + It must not be used as a DIE pointer here, + just as a sort of anonymous pointer that we just check against + NULL. + + There is a (subtle?) dependence on the fact that when we call this + the last dwarf_child() call would have been for this sibling. + Meaning that this works in a depth-first traversal even though there + is no stack of 'de_last_die' values. + + The check for dbg->de_last_die just ensures sanity. + + If one is switching between normal debug_frame and eh_frame + (traversing them in tandem, let us say) in a single + Dwarf_Debug this validator makes no sense. + It works if one processes a .debug_frame (entirely) and + then an eh_frame (or vice versa) though. + Use caution. +*/ +int +dwarf_validate_die_sibling(Dwarf_Die sibling,Dwarf_Off *offset) +{ + Dwarf_Debug dbg = 0; + Dwarf_Error *error = 0; + Dwarf_Debug_InfoTypes dis = 0; + CHECK_DIE(sibling, DW_DLV_ERROR); + dbg = sibling->di_cu_context->cc_dbg; + + dis = sibling->di_is_info? &dbg->de_info_reading: &dbg->de_types_reading; + + *offset = 0; + if (dis->de_last_die && dis->de_last_di_ptr) { + if (sibling->di_debug_ptr == dis->de_last_di_ptr) { + return (DW_DLV_OK); + } + } + /* Calculate global offset used for error reporting */ + dwarf_ptr_CU_offset(sibling->di_cu_context, + dis->de_last_di_ptr,sibling->di_is_info,offset); + return (DW_DLV_ERROR); +} + +/* This function does two slightly different things + depending on the input flag want_AT_sibling. If + this flag is true, it checks if the input die has + a DW_AT_sibling attribute. If it does it returns + a pointer to the start of the sibling die in the + .debug_info section. Otherwise it behaves the + same as the want_AT_sibling false case. + + If the want_AT_sibling flag is false, it returns + a pointer to the immediately adjacent die in the + .debug_info section. + + Die_info_end points to the end of the .debug_info + portion for the cu the die belongs to. It is used + to check that the search for the next die does not + cross the end of the current cu. Cu_info_start points + to the start of the .debug_info portion for the + current cu, and is used to add to the offset for + DW_AT_sibling attributes. Finally, has_die_child + is a pointer to a Dwarf_Bool that is set true if + the present die has children, false otherwise. + However, in case want_AT_child is true and the die + has a DW_AT_sibling attribute *has_die_child is set + false to indicate that the children are being skipped. + + die_info_end points to the last byte+1 of the cu. */ +static Dwarf_Byte_Ptr +_dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr, + Dwarf_CU_Context cu_context, + Dwarf_Byte_Ptr die_info_end, + Dwarf_Byte_Ptr cu_info_start, + Dwarf_Bool want_AT_sibling, + Dwarf_Bool * has_die_child) +{ + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Word abbrev_code = 0; + Dwarf_Abbrev_List abbrev_list; + Dwarf_Half attr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Word leb128_length = 0; + Dwarf_Unsigned utmp = 0; + Dwarf_Debug dbg = 0; + + info_ptr = die_info_ptr; + DECODE_LEB128_UWORD(info_ptr, utmp); + abbrev_code = (Dwarf_Word) utmp; + if (abbrev_code == 0) { + return NULL; + } + + + abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code); + if (abbrev_list == NULL) { + return (NULL); + } + dbg = cu_context->cc_dbg; + + *has_die_child = abbrev_list->ab_has_child; + + abbrev_ptr = abbrev_list->ab_abbrev_ptr; + do { + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(abbrev_ptr, utmp2); + attr = (Dwarf_Half) utmp2; + DECODE_LEB128_UWORD(abbrev_ptr, utmp2); + attr_form = (Dwarf_Half) utmp2; + if (attr_form == DW_FORM_indirect) { + Dwarf_Unsigned utmp6; + + /* DECODE_LEB128_UWORD updates info_ptr */ + DECODE_LEB128_UWORD(info_ptr, utmp6); + attr_form = (Dwarf_Half) utmp6; + + } + + if (want_AT_sibling && attr == DW_AT_sibling) { + switch (attr_form) { + case DW_FORM_ref1: + offset = *(Dwarf_Small *) info_ptr; + break; + case DW_FORM_ref2: + /* READ_UNALIGNED does not update info_ptr */ + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_Half)); + break; + case DW_FORM_ref4: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_ufixed)); + break; + case DW_FORM_ref8: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_Unsigned)); + break; + case DW_FORM_ref_udata: + offset = + _dwarf_decode_u_leb128(info_ptr, &leb128_length); + break; + case DW_FORM_ref_addr: + /* Very unusual. The FORM is intended to refer to + a different CU, but a different CU cannot + be a sibling, can it? + We could ignore this and treat as if no DW_AT_sibling + present. Or derive the offset from it and if + it is in the same CU use it directly. + The offset here is *supposed* to be a global offset, + so adding cu_info_start is wrong to any offset + we find here unless cu_info_start + is zero! Lets pretend there is no DW_AT_sibling + attribute. */ + goto no_sibling_attr; + default: + return (NULL); + } + + /* Reset *has_die_child to indicate children skipped. */ + *has_die_child = false; + + /* A value beyond die_info_end indicates an error. Exactly + at die_info_end means 1-past-cu-end and simply means we + are at the end, do not return NULL. Higher level code + will detect that we are at the end. */ + if (cu_info_start + offset > die_info_end) { + /* Error case, bad DWARF. */ + return (NULL); + } + /* At or before end-of-cu */ + return (cu_info_start + offset); + } + + no_sibling_attr: + if (attr_form != 0) { + info_ptr += _dwarf_get_size_of_val(cu_context->cc_dbg, + attr_form, + cu_context->cc_address_size, + info_ptr, + cu_context->cc_length_size); + /* It is ok for info_ptr == die_info_end, as we will test + later before using a too-large info_ptr */ + if (info_ptr > die_info_end) { + /* More than one-past-end indicates a bug somewhere, + likely bad dwarf generation. */ + return (NULL); + } + } + } while (attr != 0 || attr_form != 0); + return (info_ptr); +} + +/* Multiple TAGs are in fact compile units. + Allow them all. + Return non-zero if a CU tag. + Else return 0. +*/ +static int +is_cu_tag(int t) +{ + if(t == DW_TAG_compile_unit || + t == DW_TAG_partial_unit || + t == DW_TAG_imported_unit || + t == DW_TAG_type_unit) { + return 1; + } + return 0; +} + +/* Given a Dwarf_Debug dbg, and a Dwarf_Die die, it returns + a Dwarf_Die for the sibling of die. In case die is NULL, + it returns (thru ptr) a Dwarf_Die for the first die in the current + cu in dbg. Returns DW_DLV_ERROR on error. + + It is assumed that every sibling chain including those with + only one element is terminated with a NULL die, except a + chain with only a NULL die. + + The algorithm moves from one die to the adjacent one. It + returns when the depth of children it sees equals the number + of sibling chain terminations. A single count, child_depth + is used to track the depth of children and sibling terminations + encountered. Child_depth is incremented when a die has the + Has-Child flag set unless the child happens to be a NULL die. + Child_depth is decremented when a die has Has-Child false, + and the adjacent die is NULL. Algorithm returns when + child_depth is 0. + + **NOTE: Do not modify input die, since it is used at the end. */ +int +dwarf_siblingof(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Die * caller_ret_die, Dwarf_Error * error) +{ + Dwarf_Bool is_info = true; + return dwarf_siblingof_b(dbg,die,is_info,caller_ret_die,error); +} +/* This is the new form, October 2011. On calling with 'die' NULL, + we cannot tell if this is debug_info or debug_types, so + we must be informed!. */ +int +dwarf_siblingof_b(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Bool is_info, + Dwarf_Die * caller_ret_die, Dwarf_Error * error) +{ + Dwarf_Die ret_die = 0; + Dwarf_Byte_Ptr die_info_ptr = 0; + Dwarf_Byte_Ptr cu_info_start = 0; + + /* die_info_end points 1-past end of die (once set) */ + Dwarf_Byte_Ptr die_info_end = 0; + Dwarf_Word abbrev_code = 0; + Dwarf_Unsigned utmp = 0; + /* Since die may be NULL, we rely on the input argument. */ + Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + + if (die == NULL) { + /* Find root die of cu */ + /* die_info_end is untouched here, need not be set in this + branch. */ + Dwarf_Off off2; + Dwarf_CU_Context context=0; + + /* If we've not loaded debug_info, de_cu_context will be NULL, + so no need to laod */ + + context = dis->de_cu_context; + if (context == NULL) { + _dwarf_error(dbg, error, DW_DLE_DBG_NO_CU_CONTEXT); + return (DW_DLV_ERROR); + } + + off2 = context->cc_debug_offset; + cu_info_start = dataptr + off2; + die_info_ptr = cu_info_start + + _dwarf_length_of_cu_header(dbg, off2,is_info); + die_info_end = cu_info_start + context->cc_length + + context->cc_length_size + + context->cc_extension_size; + } else { + /* Find sibling die. */ + Dwarf_Bool has_child = false; + Dwarf_Sword child_depth = 0; + Dwarf_CU_Context context=0; + + /* We cannot have a legal die unless debug_info was loaded, so + no need to load debug_info here. */ + CHECK_DIE(die, DW_DLV_ERROR); + + die_info_ptr = die->di_debug_ptr; + if (*die_info_ptr == 0) { + return (DW_DLV_NO_ENTRY); + } + context = die->di_cu_context; + cu_info_start = dataptr+ context->cc_debug_offset; + die_info_end = cu_info_start + context->cc_length + + context->cc_length_size + + context->cc_extension_size; + + if ((*die_info_ptr) == 0) { + return (DW_DLV_NO_ENTRY); + } + child_depth = 0; + do { + die_info_ptr = _dwarf_next_die_info_ptr(die_info_ptr, + die->di_cu_context, die_info_end, + cu_info_start, true, &has_child); + if (die_info_ptr == NULL) { + _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL); + return (DW_DLV_ERROR); + } + + /* die_info_end is one past end. Do not read it! + A test for ``!= die_info_end'' would work as well, + but perhaps < reads more like the meaning. */ + if(die_info_ptr < die_info_end) { + if ((*die_info_ptr) == 0 && has_child) { + die_info_ptr++; + has_child = false; + } + } + + /* die_info_ptr can be one-past-end. */ + if ((die_info_ptr == die_info_end) || + ((*die_info_ptr) == 0)) { + for (; child_depth > 0 && *die_info_ptr == 0; + child_depth--, die_info_ptr++); + } else { + child_depth = has_child ? child_depth + 1 : child_depth; + } + + } while (child_depth != 0); + } + + /* die_info_ptr > die_info_end is really a bug (possibly in dwarf + generation)(but we are past end, no more DIEs here), whereas + die_info_ptr == die_info_end means 'one past end, no more DIEs + here'. */ + if (die_info_ptr >= die_info_end) { + return (DW_DLV_NO_ENTRY); + } + + if ((*die_info_ptr) == 0) { + return (DW_DLV_NO_ENTRY); + } + + ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); + if (ret_die == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + ret_die->di_is_info = is_info; + ret_die->di_debug_ptr = die_info_ptr; + ret_die->di_cu_context = + die == NULL ? dis->de_cu_context : die->di_cu_context; + + DECODE_LEB128_UWORD(die_info_ptr, utmp); + if (die_info_ptr > die_info_end) { + /* We managed to go past the end of the CU!. + Something is badly wrong. */ + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR); + return (DW_DLV_ERROR); + } + abbrev_code = (Dwarf_Word) utmp; + if (abbrev_code == 0) { + /* Zero means a null DIE */ + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + return (DW_DLV_NO_ENTRY); + } + ret_die->di_abbrev_code = abbrev_code; + ret_die->di_abbrev_list = + _dwarf_get_abbrev_for_code(ret_die->di_cu_context, abbrev_code); + if (ret_die->di_abbrev_list == NULL ) { + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_LIST_NULL); + return (DW_DLV_ERROR); + } + if (die == NULL && !is_cu_tag(ret_die->di_abbrev_list->ab_tag)) { + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + _dwarf_error(dbg, error, DW_DLE_FIRST_DIE_NOT_CU); + return (DW_DLV_ERROR); + } + + *caller_ret_die = ret_die; + return (DW_DLV_OK); +} + + +int +dwarf_child(Dwarf_Die die, + Dwarf_Die * caller_ret_die, Dwarf_Error * error) +{ + Dwarf_Byte_Ptr die_info_ptr = 0; + + /* die_info_end points one-past-end of die area. */ + Dwarf_Byte_Ptr die_info_end = 0; + Dwarf_Die ret_die = 0; + Dwarf_Bool has_die_child = 0; + Dwarf_Debug dbg; + Dwarf_Word abbrev_code = 0; + Dwarf_Unsigned utmp = 0; + Dwarf_Small *dataptr = 0; + Dwarf_Debug_InfoTypes dis = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + dis = die->di_is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + die_info_ptr = die->di_debug_ptr; + + dataptr = die->di_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + + /* We are saving a DIE pointer here, but the pointer + will not be presumed live later, when it is tested. */ + dis->de_last_die = die; + dis->de_last_di_ptr = die_info_ptr; + + /* NULL die has no child. */ + if ((*die_info_ptr) == 0) + return (DW_DLV_NO_ENTRY); + + die_info_end = dataptr + + die->di_cu_context->cc_debug_offset + + die->di_cu_context->cc_length + + die->di_cu_context->cc_length_size + + die->di_cu_context->cc_extension_size; + + die_info_ptr = + _dwarf_next_die_info_ptr(die_info_ptr, die->di_cu_context, + die_info_end, NULL, false, + &has_die_child); + if (die_info_ptr == NULL) { + _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL); + return (DW_DLV_ERROR); + } + + dis->de_last_di_ptr = die_info_ptr; + + if (!has_die_child) { + /* Look for end of sibling chain. */ + while ( dis->de_last_di_ptr < die_info_end) { + if (*dis->de_last_di_ptr) { + break; + } + ++dis->de_last_di_ptr; + } + return (DW_DLV_NO_ENTRY); + } + + ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); + if (ret_die == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + ret_die->di_debug_ptr = die_info_ptr; + ret_die->di_cu_context = die->di_cu_context; + ret_die->di_is_info = die->di_is_info; + + DECODE_LEB128_UWORD(die_info_ptr, utmp); + abbrev_code = (Dwarf_Word) utmp; + + dis->de_last_di_ptr = die_info_ptr; + + if (abbrev_code == 0) { + /* Look for end of sibling chain */ + while ( dis->de_last_di_ptr < die_info_end) { + if (*dis->de_last_di_ptr) { + break; + } + ++dis->de_last_di_ptr; + } + + /* We have arrived at a null DIE, at the end of a CU or the end + of a list of siblings. */ + *caller_ret_die = 0; + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + return DW_DLV_NO_ENTRY; + } + ret_die->di_abbrev_code = abbrev_code; + ret_die->di_abbrev_list = + _dwarf_get_abbrev_for_code(die->di_cu_context, abbrev_code); + if (ret_die->di_abbrev_list == NULL) { + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + + *caller_ret_die = ret_die; + return (DW_DLV_OK); +} + +/* Given a (global, not cu_relative) die offset, this returns + a pointer to a DIE thru *new_die. + It is up to the caller to do a + dwarf_dealloc(dbg,*new_die,DW_DLE_DIE); + The old form only works with debug_info. + The new _b form works with debug_info or debug_types. + */ +int +dwarf_offdie(Dwarf_Debug dbg, + Dwarf_Off offset, Dwarf_Die * new_die, Dwarf_Error * error) +{ + Dwarf_Bool is_info = true; + return dwarf_offdie_b(dbg,offset,is_info,new_die,error); +} + +int +dwarf_offdie_b(Dwarf_Debug dbg, + Dwarf_Off offset, Dwarf_Bool is_info, + Dwarf_Die * new_die, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Off new_cu_offset = 0; + Dwarf_Die die = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Unsigned utmp = 0; + Dwarf_Debug_InfoTypes dis = 0; + + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + dis = is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + + cu_context = _dwarf_find_CU_Context(dbg, offset,is_info); + if (cu_context == NULL) + cu_context = _dwarf_find_offdie_CU_Context(dbg, offset,is_info); + + if (cu_context == NULL) { + Dwarf_Unsigned section_size = is_info? dbg->de_debug_info.dss_size: + dbg->de_debug_types.dss_size; + int res = is_info?_dwarf_load_debug_info(dbg, error): + _dwarf_load_debug_types(dbg,error); + + if (res != DW_DLV_OK) { + return res; + } + + if (dis->de_offdie_cu_context_end != NULL) { + Dwarf_CU_Context lcu_context = + dis->de_offdie_cu_context_end; + new_cu_offset = + lcu_context->cc_debug_offset + + lcu_context->cc_length + + lcu_context->cc_length_size + + lcu_context->cc_extension_size; + } + + + do { + if ((new_cu_offset + + _dwarf_length_of_cu_header_simple(dbg,is_info)) >= section_size) { + _dwarf_error(dbg, error, DW_DLE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + cu_context = + _dwarf_make_CU_Context(dbg, new_cu_offset,is_info, error); + if (cu_context == NULL) { + /* Error if CU Context could not be made. Since + _dwarf_make_CU_Context has already registered an + error we do not do that here: we let the lower error + pass thru. */ + + return (DW_DLV_ERROR); + } + + if (dis->de_offdie_cu_context == NULL) { + dis->de_offdie_cu_context = cu_context; + dis->de_offdie_cu_context_end = cu_context; + } else { + dis->de_offdie_cu_context_end->cc_next = cu_context; + dis->de_offdie_cu_context_end = cu_context; + } + + new_cu_offset = new_cu_offset + cu_context->cc_length + + cu_context->cc_length_size; + + } while (offset >= new_cu_offset); + } + + die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); + if (die == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + die->di_cu_context = cu_context; + die->di_is_info = is_info; + + { + Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + info_ptr = dataptr + offset; + } + die->di_debug_ptr = info_ptr; + DECODE_LEB128_UWORD(info_ptr, utmp); + abbrev_code = utmp; + if (abbrev_code == 0) { + /* we are at a null DIE (or there is a bug). */ + *new_die = 0; + dwarf_dealloc(dbg, die, DW_DLA_DIE); + return DW_DLV_NO_ENTRY; + } + die->di_abbrev_code = abbrev_code; + die->di_abbrev_list = + _dwarf_get_abbrev_for_code(cu_context, abbrev_code); + if (die->di_abbrev_list == NULL) { + dwarf_dealloc(dbg, die, DW_DLA_DIE); + _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_LIST_NULL); + return (DW_DLV_ERROR); + } + + *new_die = die; + return (DW_DLV_OK); +} diff --git a/libdwarf/dwarf_die_deliv.h b/libdwarf/dwarf_die_deliv.h new file mode 100644 index 0000000..0c4bf2a --- /dev/null +++ b/libdwarf/dwarf_die_deliv.h @@ -0,0 +1,55 @@ +/* + + Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +/* + This struct holds information about a abbreviation. + It is put in the hash table for abbreviations for + a compile-unit. +*/ +struct Dwarf_Abbrev_List_s { + Dwarf_Unsigned ab_code; + Dwarf_Half ab_tag; + Dwarf_Half ab_has_child; + + /* Points to start of attribute and form pairs in the .debug_abbrev + section for the abbrev. */ + Dwarf_Byte_Ptr ab_abbrev_ptr; + + struct Dwarf_Abbrev_List_s *ab_next; +}; diff --git a/libdwarf/dwarf_elf_access.c b/libdwarf/dwarf_elf_access.c new file mode 100644 index 0000000..4ca66ae --- /dev/null +++ b/libdwarf/dwarf_elf_access.c @@ -0,0 +1,1027 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2010 Arxan Technologies, Inc. All Rights Reserved. + Portions Copyright 2009-2011 David Anderson. All rights reserved. + Portions Copyright 2009-2010 Novell Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +#include "config.h" +#include "dwarf_incl.h" +#include "dwarf_elf_access.h" + +#ifdef HAVE_ELF_H +#include <elf.h> +#endif +#ifdef HAVE_LIBELF_H +#include <libelf.h> +#else +#ifdef HAVE_LIBELF_LIBELF_H +#include <libelf/libelf.h> +#endif +#endif + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> + +#define FALSE 0 +#define TRUE 1 + +#ifndef EM_MIPS +/* This is the standard elf value EM_MIPS. */ +#define EM_MIPS 8 +#endif + + +#ifdef HAVE_ELF64_GETEHDR +extern Elf64_Ehdr *elf64_getehdr(Elf *); +#endif +#ifdef HAVE_ELF64_GETSHDR +extern Elf64_Shdr *elf64_getshdr(Elf_Scn *); +#endif +#ifdef WORDS_BIGENDIAN +#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \ + { \ + dbg->de_copy_word(dest, \ + ((char *)source) +srclength-len_out, \ + len_out) ; \ + } + + +#else /* LITTLE ENDIAN */ + +#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \ + { \ + dbg->de_copy_word( (dest) , \ + ((char *)source) , \ + len_out) ; \ + } +#endif + + + +typedef struct { + dwarf_elf_handle elf; + int is_64bit; + Dwarf_Small length_size; + Dwarf_Small pointer_size; + Dwarf_Unsigned section_count; + Dwarf_Endianness endianness; + Dwarf_Small machine; + int libdwarf_owns_elf; + Elf32_Ehdr *ehdr32; + +#ifdef HAVE_ELF64_GETEHDR + Elf64_Ehdr *ehdr64; +#endif + /* Elf symtab and its strtab. Initialized at first + call to do relocations, the actual data is in the Dwarf_Debug + struct, not allocated locally here. */ + struct Dwarf_Section_s *symtab; + struct Dwarf_Section_s *strtab; + +} dwarf_elf_object_access_internals_t; + +struct Dwarf_Elf_Rela { + Dwarf_ufixed64 r_offset; + /*Dwarf_ufixed64 r_info; */ + Dwarf_ufixed64 r_type; + Dwarf_ufixed64 r_symidx; + Dwarf_ufixed64 r_addend; +}; + + +static int dwarf_elf_object_access_load_section(void* obj_in, + Dwarf_Half section_index, + Dwarf_Small** section_data, + int* error); + +/* dwarf_elf_object_access_internals_init() */ +static int +dwarf_elf_object_access_internals_init(void* obj_in, + dwarf_elf_handle elf, + int* error) +{ + dwarf_elf_object_access_internals_t*obj = + (dwarf_elf_object_access_internals_t*)obj_in; + char *ehdr_ident = 0; + Dwarf_Half machine = 0; + obj->elf = elf; + + if ((ehdr_ident = elf_getident(elf, NULL)) == NULL) { + *error = DW_DLE_ELF_GETIDENT_ERROR; + return DW_DLV_ERROR; + } + + obj->is_64bit = (ehdr_ident[EI_CLASS] == ELFCLASS64); + + + if(ehdr_ident[EI_DATA] == ELFDATA2LSB){ + obj->endianness = DW_OBJECT_LSB; + } else if(ehdr_ident[EI_DATA] == ELFDATA2MSB){ + obj->endianness = DW_OBJECT_MSB; + } + + if (obj->is_64bit) { +#ifdef HAVE_ELF64_GETEHDR + obj->ehdr64 = elf64_getehdr(elf); + if (obj->ehdr64 == NULL) { + *error = DW_DLE_ELF_GETEHDR_ERROR; + return DW_DLV_ERROR; + } + obj->section_count = obj->ehdr64->e_shnum; + machine = obj->ehdr64->e_machine; + obj->machine = machine; +#else + *error = DW_DLE_NO_ELF64_SUPPORT; + return DW_DLV_ERROR; +#endif + } else { + obj->ehdr32 = elf32_getehdr(elf); + if (obj->ehdr32 == NULL) { + *error = DW_DLE_ELF_GETEHDR_ERROR; + return DW_DLV_ERROR; + } + obj->section_count = obj->ehdr32->e_shnum; + machine = obj->ehdr32->e_machine; + obj->machine = machine; + } + + /* The following length_size is Not Too Significant. Only used + one calculation, and an approximate one at that. */ + obj->length_size = obj->is_64bit ? 8 : 4; + obj->pointer_size = obj->is_64bit ? 8 : 4; + + if (obj->is_64bit && machine != EM_MIPS) { + /* MIPS/IRIX makes pointer size and length size 8 for -64. + Other platforms make length 4 always. */ + /* 4 here supports 32bit-offset dwarf2, as emitted by cygnus + tools, and the dwarfv2.1 64bit extension setting. + This is not the same as the size-of-an-offset, which + is 4 in 32bit dwarf and 8 in 64bit dwarf. */ + obj->length_size = 4; + } + return DW_DLV_OK; +} + +/* dwarf_elf_object_access_get_byte_order */ +static +Dwarf_Endianness +dwarf_elf_object_access_get_byte_order(void* obj_in) +{ + dwarf_elf_object_access_internals_t*obj = + (dwarf_elf_object_access_internals_t*)obj_in; + return obj->endianness; +} + +/* dwarf_elf_object_access_get_section_count() */ +static +Dwarf_Unsigned +dwarf_elf_object_access_get_section_count(void * obj_in) +{ + dwarf_elf_object_access_internals_t*obj = + (dwarf_elf_object_access_internals_t*)obj_in; + return obj->section_count; +} + + +/* dwarf_elf_object_access_get_section() + + If writing a function vaguely like this for a non-elf object, + be sure that when section-index is passed in as zero that + you set the fields in *ret_scn to reflect an empty section + with an empty string as the section name. Adjust your + section indexes of your non-elf-reading-code + for all the necessary functions in Dwarf_Obj_Access_Methods_s + accordingly. +*/ +static +int +dwarf_elf_object_access_get_section_info( + void* obj_in, + Dwarf_Half section_index, + Dwarf_Obj_Access_Section* ret_scn, + int* error) +{ + dwarf_elf_object_access_internals_t*obj = + (dwarf_elf_object_access_internals_t*)obj_in; + + Elf32_Shdr *shdr32 = 0; + +#ifdef HAVE_ELF64_GETSHDR + Elf64_Shdr *shdr64 = 0; +#endif + Elf_Scn *scn = 0; + + + scn = elf_getscn(obj->elf, section_index); + if (scn == NULL) { + *error = DW_DLE_MDE; + return DW_DLV_ERROR; + } + if (obj->is_64bit) { +#ifdef HAVE_ELF64_GETSHDR + shdr64 = elf64_getshdr(scn); + if (shdr64 == NULL) { + *error = DW_DLE_ELF_GETSHDR_ERROR; + return DW_DLV_ERROR; + } + + ret_scn->size = shdr64->sh_size; + ret_scn->addr = shdr64->sh_addr; + ret_scn->link = shdr64->sh_link; + ret_scn->entrysize = shdr64->sh_entsize; + ret_scn->name = elf_strptr(obj->elf, obj->ehdr64->e_shstrndx, + shdr64->sh_name); + if(ret_scn->name == NULL) { + *error = DW_DLE_ELF_STRPTR_ERROR; + return DW_DLV_ERROR; + } + return DW_DLV_OK; +#else + *error = DW_DLE_MISSING_ELF64_SUPPORT; + return DW_DLV_ERROR; +#endif /* HAVE_ELF64_GETSHDR */ + } + if ((shdr32 = elf32_getshdr(scn)) == NULL) { + *error = DW_DLE_ELF_GETSHDR_ERROR; + return DW_DLV_ERROR; + } + + ret_scn->size = shdr32->sh_size; + ret_scn->addr = shdr32->sh_addr; + ret_scn->link = shdr32->sh_link; + ret_scn->entrysize = shdr32->sh_entsize; + ret_scn->name = elf_strptr(obj->elf, obj->ehdr32->e_shstrndx, + shdr32->sh_name); + if (ret_scn->name == NULL) { + *error = DW_DLE_ELF_STRPTR_ERROR; + return DW_DLV_ERROR; + } + return DW_DLV_OK; +} + +/* dwarf_elf_object_access_get_length_size */ +static +Dwarf_Small +dwarf_elf_object_access_get_length_size(void* obj_in) +{ + dwarf_elf_object_access_internals_t*obj = + (dwarf_elf_object_access_internals_t*)obj_in; + return obj->length_size; +} + +/* dwarf_elf_object_access_get_pointer_size */ +static +Dwarf_Small +dwarf_elf_object_access_get_pointer_size(void* obj_in) +{ + dwarf_elf_object_access_internals_t*obj = + (dwarf_elf_object_access_internals_t*)obj_in; + return obj->pointer_size; +} + +#define MATCH_REL_SEC(i_,s_,r_) \ +if(i_ == s_.dss_index) { \ + *r_ = &s_; \ + return DW_DLV_OK; \ +} + +static int +find_section_to_relocate(Dwarf_Debug dbg,Dwarf_Half section_index, + struct Dwarf_Section_s **relocatablesec, int *error) +{ + MATCH_REL_SEC(section_index,dbg->de_debug_info,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_abbrev,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_line,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_loc,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_aranges,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_macinfo,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_pubnames,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_ranges,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_frame,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_frame_eh_gnu,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_pubtypes,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_funcnames,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_typenames,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_varnames,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_weaknames,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_types,relocatablesec); + /* dbg-> de_debug_str,syms); */ + /* de_elf_symtab,syms); */ + /* de_elf_strtab,syms); */ + *error = DW_DLE_RELOC_SECTION_MISMATCH; + return DW_DLV_ERROR; + +} +#undef MATCH_REL_SEC + +static void +get_rela_elf32(Dwarf_Small *data, unsigned int i, + int endianness, + int machine, + struct Dwarf_Elf_Rela *relap) +{ + Elf32_Rela *relp = (Elf32_Rela*)(data + (i * sizeof(Elf32_Rela))); + relap->r_offset = relp->r_offset; + /* + relap->r_info = relp->r_info; + */ + relap->r_type = ELF32_R_TYPE(relp->r_info); + relap->r_symidx = ELF32_R_SYM(relp->r_info); + relap->r_addend = relp->r_addend; +} + +static void +get_rela_elf64(Dwarf_Small *data, unsigned int i, + int endianness, + int machine, + struct Dwarf_Elf_Rela *relap) +{ +#ifdef HAVE_ELF64_RELA + Elf64_Rela * relp = (Elf64_Rela*)(data + (i * sizeof(Elf64_Rela))); + relap->r_offset = relp->r_offset; + /* + relap->r_info = relp->r_info; + */ +#define ELF64MIPS_REL_SYM(i) ((i) & 0xffffffff) +#define ELF64MIPS_REL_TYPE(i) ((i >> 56) &0xff) + if(machine == EM_MIPS && endianness == DW_OBJECT_LSB ){ + /* This is really wierd. Treat this very specially. + The Elf64 LE MIPS object used for + testing (that has rela) wants the + values as sym ssym type3 type2 type, treating + each value as independent value. But libelf xlate + treats it as something else so we fudge here. + It is unclear + how to precisely characterize where these relocations + were used. + SGI MIPS on IRIX never used .rela relocations. + The BE 64bit elf MIPS test object with rela uses traditional + elf relocation layouts, not this special case. */ + /* We ignore the special TYPE2 and TYPE3, they should be + value R_MIPS_NONE in rela. */ + relap->r_type = ELF64MIPS_REL_TYPE(relp->r_info); + relap->r_symidx = ELF64MIPS_REL_SYM(relp->r_info); +#undef MIPS64SYM +#undef MIPS64TYPE + } else + { + relap->r_type = ELF64_R_TYPE(relp->r_info); + relap->r_symidx = ELF64_R_SYM(relp->r_info); + } + relap->r_addend = relp->r_addend; +#endif +} + +static void +get_relocations_array(Dwarf_Bool is_64bit, + int endianness, + int machine, + Dwarf_Small *data, + unsigned int num_relocations, + struct Dwarf_Elf_Rela *relap) +{ + unsigned int i = 0; + void (*get_relocations)(Dwarf_Small *data, unsigned int i, + int endianness, + int machine, + struct Dwarf_Elf_Rela *relap); + + /* Handle 32/64 bit issue */ + if (is_64bit) { + get_relocations = get_rela_elf64; + } else { + get_relocations = get_rela_elf32; + } + + for (i=0; i < num_relocations; i++) { + get_relocations(data, i,endianness,machine, + &(relap[i])); + } + +} + +static int +get_relocation_entries(Dwarf_Bool is_64bit, + int endianness, + int machine, + Dwarf_Small *relocation_section, + Dwarf_Unsigned relocation_section_size, + Dwarf_Unsigned relocation_section_entrysize, + struct Dwarf_Elf_Rela **relas, + unsigned int *nrelas, + int *error) +{ + unsigned int relocation_size = 0; + + if (is_64bit) { +#ifdef HAVE_ELF64_RELA + relocation_size = sizeof(Elf64_Rela); +#else + *error = DW_DLE_MISSING_ELF64_SUPPORT; + return DW_DLV_ERROR; +#endif + } else { + relocation_size = sizeof(Elf32_Rela); + } + if( relocation_size != relocation_section_entrysize) { + /* Means our struct definition does not match the + real object. */ + *error = DW_DLE_RELOC_SECTION_LENGTH_ODD; + return DW_DLV_ERROR; + } + + if (relocation_section == NULL) { + *error = DW_DLE_RELOC_SECTION_PTR_NULL; + return(DW_DLV_ERROR); + } + + if ((relocation_section_size != 0)) { + size_t bytescount = 0; + if(relocation_section_size%relocation_size) { + *error = DW_DLE_RELOC_SECTION_LENGTH_ODD; + return DW_DLV_ERROR; + } + *nrelas = relocation_section_size/relocation_size; + bytescount = (*nrelas) * sizeof(struct Dwarf_Elf_Rela); + *relas = malloc(bytescount); + if (!*relas) { + *error = DW_DLE_MAF; + return(DW_DLV_ERROR); + } + memset(*relas,0,bytescount); + get_relocations_array(is_64bit,endianness,machine, + relocation_section, + *nrelas, *relas); + } + return(DW_DLV_OK); +} + +/* We have a EM_QUALCOMM_DSP6 relocatable object + test case in dwarf regression tests, atefail/ig_server. + Values for QUALCOMM were derived from this executable. +*/ + +#define EM_QUALCOMM_DSP6 0xa4 +#define QUALCOMM_REL32 6 + +static Dwarf_Bool +is_32bit_abs_reloc(unsigned int type, Dwarf_Half machine) +{ + Dwarf_Bool r = 0; + switch (machine) { +#if defined(EM_MIPS) && defined (R_MIPS_32) + case EM_MIPS: + r = (type == R_MIPS_32); + break; +#endif +#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA32) + case EM_SPARC32PLUS: + r = (type == R_SPARC_UA32); + break; +#endif +#if defined(EM_SPARCV9) && defined (R_SPARC_UA32) + case EM_SPARCV9: + r = (type == R_SPARC_UA32); + break; +#endif +#if defined(EM_SPARC) && defined (R_SPARC_UA32) + case EM_SPARC: + r = (type == R_SPARC_UA32); + break; +#endif +#if defined(EM_386) && defined (R_386_32) + case EM_386: + r = (type == R_386_32); + break; +#endif +#if defined(EM_IA_64) && defined (R_IA64_SECREL32LSB) + case EM_IA_64: + r = (type == R_IA64_SECREL32LSB); + break; +#endif +#if defined(EM_PPC64) && defined (R_PPC64_ADDR32) + case EM_PPC64: + r = (type == R_PPC64_ADDR32); + break; +#endif +#if defined(EM_PPC) && defined (R_PPC_ADDR32) + case EM_PPC: + r = (type == R_PPC_ADDR32); + break; +#endif +#if defined(EM_S390) && defined (R_390_32) + case EM_S390: + r = (type == R_390_32); + break; +#endif +#if defined(EM_X86_64) && defined (R_X86_64_32) + case EM_X86_64: + r = (type == R_X86_64_32); + break; +#endif + case EM_QUALCOMM_DSP6: + r = (type == QUALCOMM_REL32); + break; + } + return r; +} + +static Dwarf_Bool +is_64bit_abs_reloc(unsigned int type, Dwarf_Half machine) +{ + Dwarf_Bool r = 0; + switch (machine) { +#if defined(EM_MIPS) && defined (R_MIPS_64) + case EM_MIPS: + r = (type == R_MIPS_64); + break; +#endif +#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA64) + case EM_SPARC32PLUS: + r = (type == R_SPARC_UA64); + break; +#endif +#if defined(EM_SPARCV9) && defined (R_SPARC_UA64) + case EM_SPARCV9: + r = (type == R_SPARC_UA64); + break; +#endif +#if defined(EM_SPARC) && defined (R_SPARC_UA64) + case EM_SPARC: + r = (type == R_SPARC_UA64); + break; +#endif +#if defined(EM_IA_64) && defined (R_IA64_SECREL32LSB) + case EM_IA_64: + r = (type == R_IA64_DIR64LSB); + break; +#endif +#if defined(EM_PPC64) && defined (R_PPC64_ADDR64) + case EM_PPC64: + r = (type == R_PPC64_ADDR64); + break; +#endif +#if defined(EM_S390) && defined (R_390_64) + case EM_S390: + r = (type == R_390_64); + break; +#endif +#if defined(EM_X86_64) && defined (R_X86_64_64) + case EM_X86_64: + r = (type == R_X86_64_64); + break; +#endif + } + return r; +} + + +/* Returns DW_DLV_OK if it works, else DW_DLV_ERROR. + The caller may decide to ignre the errors or report them. */ +static int +update_entry(Dwarf_Debug dbg, + Dwarf_Bool is_64bit, Dwarf_Endianness endianess, + Dwarf_Half machine, struct Dwarf_Elf_Rela *rela, + Dwarf_Small *target_section, + Dwarf_Small *symtab_section_data, + Dwarf_Unsigned symtab_section_size, + Dwarf_Unsigned symtab_section_entrysize, + int *error) +{ + unsigned int type = 0; + unsigned int sym_idx = 0; +#ifdef HAVE_ELF64_SYM + Elf64_Sym sym_buf; + Elf64_Sym *sym = 0; +#else + Elf32_Sym sym_buf; + Elf32_Sym *sym = 0; +#endif + Elf32_Sym *sym32 = 0; + Dwarf_ufixed64 offset = 0; + Dwarf_sfixed64 addend = 0; + Dwarf_Unsigned reloc_size = 0; + Dwarf_Unsigned symtab_entry_count = 0; + + if( symtab_section_entrysize == 0) { + *error = DW_DLE_SYMTAB_SECTION_ENTRYSIZE_ZERO; + return DW_DLV_ERROR; + } + symtab_entry_count = symtab_section_size/symtab_section_entrysize; + + /* Dwarf_Elf_Rela dereferencing */ + offset = rela->r_offset; + addend = rela->r_addend; + type = rela->r_type; + sym_idx = rela->r_symidx; + if (sym_idx >= symtab_entry_count) { + *error = DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD; + return DW_DLV_ERROR; + } + + + + if (is_64bit) { +#ifdef HAVE_ELF64_SYM + sym = &((Elf64_Sym*)symtab_section_data)[sym_idx]; +#endif + } else { + sym32 = &((Elf32_Sym*)symtab_section_data)[sym_idx]; + + /* Convert Elf32_Sym struct to Elf64_Sym struct. We point at + an Elf64_Sym local variable (sym_buf) to allow us to use the + same pointer (sym) for both 32-bit and 64-bit instances. */ + sym = &sym_buf; + sym->st_name = sym32->st_name; + sym->st_info = sym32->st_info; + sym->st_other = sym32->st_other; + sym->st_shndx = sym32->st_shndx; + sym->st_value = sym32->st_value; + sym->st_size = sym32->st_size; + } + + /* Determine relocation size */ + if (is_32bit_abs_reloc(type, machine)) { + reloc_size = 4; + } else if (is_64bit_abs_reloc(type, machine)) { + reloc_size = 8; + } else { + *error = DW_DLE_RELOC_SECTION_RELOC_TARGET_SIZE_UNKNOWN; + return DW_DLV_ERROR; + } + + + { + /* Assuming we do not need to do a READ_UNALIGNED here + at target_section + offset and add its value to + outval. Some ABIs say no read (for example MIPS), + but if some do then which ones? */ + Dwarf_Unsigned outval = sym->st_value + addend; + WRITE_UNALIGNED(dbg,target_section + offset, + &outval,sizeof(outval),reloc_size); + } + return DW_DLV_OK; +} + + + +/* Somewhat arbitrarily, we attempt to apply all the relocations we can + and still notify the caller of at least one error if we found + any errors. */ +static int +apply_rela_entries(Dwarf_Debug dbg, + Dwarf_Bool is_64bit, + Dwarf_Endianness endianess, + Dwarf_Half machine, + Dwarf_Small *target_section, + Dwarf_Small *symtab_section, + Dwarf_Unsigned symtab_section_size, + Dwarf_Unsigned symtab_section_entrysize, + struct Dwarf_Elf_Rela *relas, unsigned int nrelas, + int *error) +{ + int return_res = DW_DLV_OK; + if ((target_section != NULL) && (relas != NULL)) { + unsigned int i; + if( symtab_section_entrysize == 0) { + *error = DW_DLE_SYMTAB_SECTION_ENTRYSIZE_ZERO; + return DW_DLV_ERROR; + } + if(symtab_section_size%symtab_section_entrysize) { + *error = DW_DLE_SYMTAB_SECTION_LENGTH_ODD; + return DW_DLV_ERROR; + } + for (i = 0; i < nrelas; i++) { + int res = update_entry(dbg, is_64bit, + endianess, + machine, + &(relas)[i], + target_section, + symtab_section, + symtab_section_size, + symtab_section_entrysize, + error); + if (res != DW_DLV_OK) { + return_res = res; + } + } + } + return return_res; +} + + +static int +loop_through_relocations( + Dwarf_Debug dbg, + dwarf_elf_object_access_internals_t* obj, + struct Dwarf_Section_s *relocatablesec, + int *error) +{ + Dwarf_Small *target_section = 0; + Dwarf_Small *symtab_section = obj->symtab->dss_data; + Dwarf_Unsigned symtab_section_entrysize = obj->symtab->dss_entrysize; + Dwarf_Unsigned symtab_section_size = obj->symtab->dss_size; + Dwarf_Small *relocation_section = relocatablesec->dss_reloc_data; + Dwarf_Unsigned relocation_section_size = + relocatablesec->dss_reloc_size; + Dwarf_Unsigned relocation_section_entrysize = relocatablesec->dss_reloc_entrysize; + + int ret = DW_DLV_ERROR; + struct Dwarf_Elf_Rela *relas = 0; + unsigned int nrelas = 0; + Dwarf_Small *mspace = 0; + + ret = get_relocation_entries(obj->is_64bit, + obj->endianness, + obj->machine, + relocation_section, + relocation_section_size, + relocation_section_entrysize, + &relas, &nrelas, error); + if(ret != DW_DLV_OK) { + free(relas); + return ret; + } + + /* Some systems read Elf in read-only memory via mmap or the like. + So the only safe thing is to copy the current data into + malloc space and refer to the malloc space instead of the + space returned by the elf library */ + mspace = malloc(relocatablesec->dss_size); + if(!mspace) { + *error = DW_DLE_RELOC_SECTION_MALLOC_FAIL; + return DW_DLV_ERROR; + } + memcpy(mspace,relocatablesec->dss_data,relocatablesec->dss_size); + relocatablesec->dss_data = mspace; + target_section = relocatablesec->dss_data; + relocatablesec->dss_data_was_malloc = 1; + + ret = apply_rela_entries( + dbg, + obj->is_64bit, + obj->endianness, obj->machine, + target_section, + symtab_section, + symtab_section_size, + symtab_section_entrysize, + relas, nrelas, error); + free(relas); + return ret; +} + +/* Find the section data in dbg and find all the relevant + sections. Then do relocations. +*/ +static int +dwarf_elf_object_relocate_a_section(void* obj_in, + Dwarf_Half section_index, + Dwarf_Debug dbg, + int* error) +{ + int res = DW_DLV_ERROR; + dwarf_elf_object_access_internals_t*obj = 0; + struct Dwarf_Section_s * relocatablesec = 0; + if (section_index == 0) { + return DW_DLV_NO_ENTRY; + } + obj = (dwarf_elf_object_access_internals_t*)obj_in; + + /* The section to relocate must already be loaded into memory. */ + res = find_section_to_relocate(dbg, section_index,&relocatablesec,error); + if(res != DW_DLV_OK) { + return res; + } + + /* Sun and possibly others do not always set sh_link in .debug_* sections. + So we cannot do full consistency checks. */ + if(relocatablesec->dss_reloc_index == 0 ) { + /* Something is wrong. */ + *error = DW_DLE_RELOC_SECTION_MISSING_INDEX; + return DW_DLV_ERROR; + } + /* Now load the relocations themselves. */ + res = dwarf_elf_object_access_load_section(obj_in, + relocatablesec->dss_reloc_index, + &relocatablesec->dss_reloc_data, error); + if(res != DW_DLV_OK) { + return res; + } + + /* Now get the symtab. */ + if (!obj->symtab) { + obj->symtab = &dbg->de_elf_symtab; + obj->strtab = &dbg->de_elf_strtab; + } + if( obj->symtab->dss_index != relocatablesec->dss_reloc_link) { + /* Something is wrong. */ + *error = DW_DLE_RELOC_MISMATCH_RELOC_INDEX; + return DW_DLV_ERROR; + } + if( obj->strtab->dss_index != obj->symtab->dss_link) { + /* Something is wrong. */ + *error = DW_DLE_RELOC_MISMATCH_STRTAB_INDEX; + return DW_DLV_ERROR; + } + if(!obj->symtab->dss_data) { + /* Now load the symtab */ + res = dwarf_elf_object_access_load_section(obj_in, + obj->symtab->dss_index, + &obj->symtab->dss_data, error); + if(res != DW_DLV_OK) { + return res; + } + } + if(! obj->strtab->dss_data) { + /* Now load the strtab */ + res = dwarf_elf_object_access_load_section(obj_in, + obj->strtab->dss_index, + &obj->strtab->dss_data,error); + if(res != DW_DLV_OK){ + return res; + } + } + + /* We have all the data we need in memory. */ + res = loop_through_relocations(dbg,obj,relocatablesec,error); + + return res; +} + +/* dwarf_elf_object_access_load_section */ +static int +dwarf_elf_object_access_load_section(void* obj_in, + Dwarf_Half section_index, + Dwarf_Small** section_data, + int* error) +{ + dwarf_elf_object_access_internals_t*obj = + (dwarf_elf_object_access_internals_t*)obj_in; + if (section_index == 0) { + return DW_DLV_NO_ENTRY; + } + + { + Elf_Scn *scn = 0; + Elf_Data *data = 0; + + scn = elf_getscn(obj->elf, section_index); + if (scn == NULL) { + *error = DW_DLE_MDE; + return DW_DLV_ERROR; + } + + /* When using libelf as a producer, section data may be stored + in multiple buffers. In libdwarf however, we only use libelf + as a consumer (there is a dwarf producer API, but it doesn't + use libelf). Because of this, this single call to elf_getdata + will retrieve the entire section in a single contiguous + buffer. */ + data = elf_getdata(scn, NULL); + if (data == NULL) { + *error = DW_DLE_MDE; + return DW_DLV_ERROR; + } + *section_data = data->d_buf; + } + return DW_DLV_OK; +} + + +/* dwarf_elf_access method table. */ +static const struct Dwarf_Obj_Access_Methods_s dwarf_elf_object_access_methods = +{ + dwarf_elf_object_access_get_section_info, + dwarf_elf_object_access_get_byte_order, + dwarf_elf_object_access_get_length_size, + dwarf_elf_object_access_get_pointer_size, + dwarf_elf_object_access_get_section_count, + dwarf_elf_object_access_load_section, + dwarf_elf_object_relocate_a_section +}; + + +/* Interface for the ELF object file implementation. */ +int +dwarf_elf_object_access_init(dwarf_elf_handle elf, + int libdwarf_owns_elf, + Dwarf_Obj_Access_Interface** ret_obj, + int *err) +{ + int res = 0; + dwarf_elf_object_access_internals_t *internals = 0; + Dwarf_Obj_Access_Interface *intfc = 0; + + internals = malloc(sizeof(dwarf_elf_object_access_internals_t)); + if(!internals) { + /* Impossible case, we hope. Give up. */ + return DW_DLV_ERROR; + } + memset(internals,0,sizeof(*internals)); + res = dwarf_elf_object_access_internals_init(internals, elf, err); + if(res != DW_DLV_OK){ + free(internals); + return DW_DLV_ERROR; + } + internals->libdwarf_owns_elf = libdwarf_owns_elf; + + intfc = malloc(sizeof(Dwarf_Obj_Access_Interface)); + if(!intfc) { + /* Impossible case, we hope. Give up. */ + free(internals); + return DW_DLV_ERROR; + } + /* Initialize the interface struct */ + intfc->object = internals; + intfc->methods = &dwarf_elf_object_access_methods; + + *ret_obj = intfc; + return DW_DLV_OK; +} + + + +/* Clean up the Dwarf_Obj_Access_Interface returned by elf_access_init. */ +void +dwarf_elf_object_access_finish(Dwarf_Obj_Access_Interface* obj) +{ + if(!obj) { + return; + } + if(obj->object) { + dwarf_elf_object_access_internals_t *internals = + (dwarf_elf_object_access_internals_t *)obj->object; + if(internals->libdwarf_owns_elf){ + elf_end(internals->elf); + } + } + free(obj->object); + free(obj); +} + +/* This function returns the Elf * pointer + associated with a Dwarf_Debug. + + This function only makes sense if ELF is implied. */ +int +dwarf_get_elf(Dwarf_Debug dbg, dwarf_elf_handle * elf, + Dwarf_Error * error) +{ + struct Dwarf_Obj_Access_Interface_s * obj = 0; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + + obj = dbg->de_obj_file; + if(obj) { + dwarf_elf_object_access_internals_t *internals = + (dwarf_elf_object_access_internals_t*)obj->object; + if(internals->elf == NULL) { + _dwarf_error(dbg, error, DW_DLE_FNO); + return (DW_DLV_ERROR); + } + *elf = internals->elf; + return DW_DLV_OK; + + } + _dwarf_error(dbg, error, DW_DLE_FNO); + return DW_DLV_ERROR; +} + + diff --git a/libdwarf/dwarf_elf_access.h b/libdwarf/dwarf_elf_access.h new file mode 100644 index 0000000..4608a27 --- /dev/null +++ b/libdwarf/dwarf_elf_access.h @@ -0,0 +1,55 @@ +#ifndef _DWARF_ELF_PORT_H +#define _DWARF_ELF_PORT_H +/* + + Copyright (C) 2008-2011 David Anderson. All rights reserved. + Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +/* ELF (usually libelf) object access for the generic object file interface */ + +int +dwarf_elf_object_access_init(dwarf_elf_handle elf , + int libdwarf_owns_elf, + Dwarf_Obj_Access_Interface** ret_obj, + int *err ); + +void +dwarf_elf_object_access_finish(Dwarf_Obj_Access_Interface* obj ); + +/* End ELF object access for the generic object file interface */ + + +#endif diff --git a/libdwarf/dwarf_error.c b/libdwarf/dwarf_error.c new file mode 100644 index 0000000..69031b7 --- /dev/null +++ b/libdwarf/dwarf_error.c @@ -0,0 +1,418 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#ifdef HAVE_ELF_H +#include <elf.h> +#endif + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <stdlib.h> + +/* Array to hold string representation of errors. Any time a + define is added to the list in libdwarf.h, a string should be + added to this Array +*/ + +const char *_dwarf_errmsgs[] = { + + "No error (0)\n", + "DW_DLE_VMM 1 dwarf format/library version mismatch", + "DW_DLE_MAP 2 memory map failure", + "DW_DLE_LEE 3 libelf error", + "DW_DLE_NDS 4 no debug section", + "DW_DLE_NLS 5 no line section ", + "DW_DLE_ID 6 invalid descriptor for query ", + "DW_DLE_IOF 7 I/O failure ", + "DW_DLE_MAF 8 memory allocation failure ", + "DW_DLE_IA 9 invalid argument ", + "DW_DLE_MDE 10 mangled debugging entry ", + "DW_DLE_MLE 11 mangled line number entry ", + "DW_DLE_FNO 12 file not open ", + "DW_DLE_FNR 13 file not a regular file ", + "DW_DLE_FWA 14 file open with wrong access ", + "DW_DLE_NOB 15 not an object file ", + "DW_DLE_MOF 16 mangled object file header ", + "DW_DLE_EOLL 17 end of location list entries ", + "DW_DLE_NOLL 18 no location list section ", + "DW_DLE_BADOFF 19 Invalid offset ", + "DW_DLE_EOS 20 end of section ", + "DW_DLE_ATRUNC 21 abbreviations section appears truncated", + "DW_DLE_BADBITC 22 Address size passed to dwarf bad", + + "DW_DLE_DBG_ALLOC 23 Unable to malloc a Dwarf_Debug structure", + "DW_DLE_FSTAT_ERROR 24 The file fd passed to dwarf_init " + "cannot be fstat()ed", + "DW_DLE_FSTAT_MODE_ERROR 25 The file mode bits do not " + "indicate that the file being opened via " + "dwarf_init() is a normal file", + "DW_DLE_INIT_ACCESS_WRONG 26 A call to dwarf_init had an " + "access of other than DW_DLC_READ", + "DW_DLE_ELF_BEGIN_ERROR 27 a call to " + "elf_begin(... ELF_C_READ_MMAP... ) failed", + "DW_DLE_ELF_GETEHDR_ERROR 28 a call to " + "elf32_getehdr() or elf64_getehdr() failed", + "DW_DLE_ELF_GETSHDR_ERROR 29 a call to " + "elf32_getshdr() or elf64_getshdr() failed", + "DW_DLE_ELF_STRPTR_ERROR 30 a call to " + "elf_strptr() failed trying to get a section name", + "DW_DLE_DEBUG_INFO_DUPLICATE 31 Only one .debug_info " + "section is allowed", + "DW_DLE_DEBUG_INFO_NULL 32 .debug_info section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_ABBREV_DUPLICATE 33 Only one .debug_abbrev " + "section is allowed", + "DW_DLE_DEBUG_ABBREV_NULL 34 .debug_abbrev section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_ARANGES_DUPLICATE 35 Only one .debug_aranges " + "section is allowed", + "DW_DLE_DEBUG_ARANGES_NULL 36 .debug_aranges section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_LINE_DUPLICATE 37 Only one .debug_line " + "section is allowed", + "DW_DLE_DEBUG_LINE_NULL (38) .debug_line section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_LOC_DUPLICATE (39) Only one .debug_loc " + "section is allowed", + "DW_DLE_DEBUG_LOC_NULL (40) .debug_loc section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_MACINFO_DUPLICATE (41) Only one .debug_macinfo " + "section is allowed", + "DW_DLE_DEBUG_MACINFO_NULL (42) .debug_macinfo section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_PUBNAMES_DUPLICATE (43) Only one .debug_pubnames " + "section is allowed", + "DW_DLE_DEBUG_PUBNAMES_NULL (44) .debug_pubnames section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_STR_DUPLICATE (45) Only one .debug_str " + "section is allowed", + "DW_DLE_DEBUG_STR_NULL (46) .debug_str section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_CU_LENGTH_ERROR (47)", + "DW_DLE_VERSION_STAMP_ERROR (48)", + "DW_DLE_ABBREV_OFFSET_ERROR (49)", + "DW_DLE_ADDRESS_SIZE_ERROR (50)", + "DW_DLE_DEBUG_INFO_PTR_NULL (51)", + "DW_DLE_DIE_NULL (52)", + "DW_DLE_STRING_OFFSET_BAD (53)", + "DW_DLE_DEBUG_LINE_LENGTH_BAD (54)", + "DW_DLE_LINE_PROLOG_LENGTH_BAD (55)", + "DW_DLE_LINE_NUM_OPERANDS_BAD", + "DW_DLE_LINE_SET_ADDR_ERROR", + "DW_DLE_LINE_EXT_OPCODE_BAD", + "DW_DLE_DWARF_LINE_NULL", + "DW_DLE_INCL_DIR_NUM_BAD", + "DW_DLE_LINE_FILE_NUM_BAD", + "DW_DLE_ALLOC_FAIL", + "DW_DLE_NO_CALLBACK_FUNC", + "DW_DLE_SECT_ALLOC", + "DW_DLE_FILE_ENTRY_ALLOC", + "DW_DLE_LINE_ALLOC", + "DW_DLE_FPGM_ALLOC", + "DW_DLE_INCDIR_ALLOC", + "DW_DLE_STRING_ALLOC", + "DW_DLE_CHUNK_ALLOC", + "DW_DLE_BYTEOFF_ERR", + "DW_DLE_CIE_ALLOC", + "DW_DLE_FDE_ALLOC", + "DW_DLE_REGNO_OVFL", + "DW_DLE_CIE_OFFS_ALLOC", + "DW_DLE_WRONG_ADDRESS", + "DW_DLE_EXTRA_NEIGHBORS", + "DW_DLE_WRONG_TAG", + "DW_DLE_DIE_ALLOC", + "DW_DLE_PARENT_EXISTS", + "DW_DLE_DBG_NULL", + "DW_DLE_DEBUGLINE_ERROR", + "DW_DLE_DEBUGFRAME_ERROR", + "DW_DLE_DEBUGINFO_ERROR", + "DW_DLE_ATTR_ALLOC", + "DW_DLE_ABBREV_ALLOC", + "DW_DLE_OFFSET_UFLW", + "DW_DLE_ELF_SECT_ERR", + "DW_DLE_DEBUG_FRAME_LENGTH_BAD", + "DW_DLE_FRAME_VERSION_BAD", + "DW_DLE_CIE_RET_ADDR_REG_ERROR", + "DW_DLE_FDE_NULL", + "DW_DLE_FDE_DBG_NULL", + "DW_DLE_CIE_NULL", + "DW_DLE_CIE_DBG_NULL", + "DW_DLE_FRAME_TABLE_COL_BAD", + "DW_DLE_PC_NOT_IN_FDE_RANGE", + "DW_DLE_CIE_INSTR_EXEC_ERROR", + "DW_DLE_FRAME_INSTR_EXEC_ERROR", + "DW_DLE_FDE_PTR_NULL", + "DW_DLE_RET_OP_LIST_NULL", + "DW_DLE_LINE_CONTEXT_NULL", + "DW_DLE_DBG_NO_CU_CONTEXT", + "DW_DLE_DIE_NO_CU_CONTEXT", + "DW_DLE_FIRST_DIE_NOT_CU", + "DW_DLE_NEXT_DIE_PTR_NULL", + "DW_DLE_DEBUG_FRAME_DUPLICATE Only one .debug_frame " + "section is allowed", + "DW_DLE_DEBUG_FRAME_NULL .debug_frame section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_ABBREV_DECODE_ERROR", + "DW_DLE_DWARF_ABBREV_NULL", + "DW_DLE_ATTR_NULL", + "DW_DLE_DIE_BAD", + "DW_DLE_DIE_ABBREV_BAD", + "DW_DLE_ATTR_FORM_BAD", + "DW_DLE_ATTR_NO_CU_CONTEXT", + "DW_DLE_ATTR_FORM_SIZE_BAD", + "DW_DLE_ATTR_DBG_NULL", + "DW_DLE_BAD_REF_FORM", + "DW_DLE_ATTR_FORM_OFFSET_BAD", + "DW_DLE_LINE_OFFSET_BAD", + "DW_DLE_DEBUG_STR_OFFSET_BAD", + "DW_DLE_STRING_PTR_NULL", + "DW_DLE_PUBNAMES_VERSION_ERROR", + "DW_DLE_PUBNAMES_LENGTH_BAD", + "DW_DLE_GLOBAL_NULL", + "DW_DLE_GLOBAL_CONTEXT_NULL", + "DW_DLE_DIR_INDEX_BAD", + "DW_DLE_LOC_EXPR_BAD", + "DW_DLE_DIE_LOC_EXPR_BAD", + "DW_DLE_ADDR_ALLOC", + "DW_DLE_OFFSET_BAD", + "DW_DLE_MAKE_CU_CONTEXT_FAIL", + "DW_DLE_REL_ALLOC", + "DW_DLE_ARANGE_OFFSET_BAD", + "DW_DLE_SEGMENT_SIZE_BAD (135) Size of a segment selector should usually be less than 8 (bytes).", + "DW_DLE_ARANGE_LENGTH_BAD", + "DW_DLE_ARANGE_DECODE_ERROR", + "DW_DLE_ARANGES_NULL", + "DW_DLE_ARANGE_NULL", + "DW_DLE_NO_FILE_NAME", + "DW_DLE_NO_COMP_DIR", + "DW_DLE_CU_ADDRESS_SIZE_BAD", + "DW_DLE_INPUT_ATTR_BAD", + "DW_DLE_EXPR_NULL", + "DW_DLE_BAD_EXPR_OPCODE", + "DW_DLE_EXPR_LENGTH_BAD", + "DW_DLE_MULTIPLE_RELOC_IN_EXPR", + "DW_DLE_ELF_GETIDENT_ERROR", + "DW_DLE_NO_AT_MIPS_FDE", + "DW_DLE_NO_CIE_FOR_FDE", + "DW_DLE_DIE_ABBREV_LIST_NULL", + "DW_DLE_DEBUG_FUNCNAMES_DUPLICATE", + "DW_DLE_DEBUG_FUNCNAMES_NULL .debug_funcnames section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR", + "DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD", + "DW_DLE_FUNC_NULL", + "DW_DLE_FUNC_CONTEXT_NULL", + "DW_DLE_DEBUG_TYPENAMES_DUPLICATE", + "DW_DLE_DEBUG_TYPENAMES_NULL .debug_typenames section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR", + "DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD", + "DW_DLE_TYPE_NULL", + "DW_DLE_TYPE_CONTEXT_NULL", + "DW_DLE_DEBUG_VARNAMES_DUPLICATE", + "DW_DLE_DEBUG_VARNAMES_NULL .debug_varnames section present but " + "elf_getdata() failed or section is zero-length", + "DW_DLE_DEBUG_VARNAMES_VERSION_ERROR", + "DW_DLE_DEBUG_VARNAMES_LENGTH_BAD", + "DW_DLE_VAR_NULL", + "DW_DLE_VAR_CONTEXT_NULL", + "DW_DLE_DEBUG_WEAKNAMES_DUPLICATE", + "DW_DLE_DEBUG_WEAKNAMES_NULL .debug_weaknames section present but " + "elf_getdata() failed or section is zero-length", + + "DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR", + "DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD", + "DW_DLE_WEAK_NULL", + "DW_DLE_WEAK_CONTEXT_NULL (175)", + "DW_DLE_LOCDESC_COUNT_WRONG (176)", + "DW_DLE_MACINFO_STRING_NULL (177)", + "DW_DLE_MACINFO_STRING_EMPTY (178)", + "DW_DLE_MACINFO_INTERNAL_ERROR_SPACE (179)", + "DW_DLE_MACINFO_MALLOC_FAIL (180)", + "DW_DLE_DEBUGMACINFO_ERROR (181)", + "DW_DLE_DEBUG_MACRO_LENGTH_BAD (182)", + "DW_DLE_DEBUG_MACRO_MAX_BAD (183)", + "DW_DLE_DEBUG_MACRO_INTERNAL_ERR (184)", + "DW_DLE_DEBUG_MACRO_MALLOC_SPACE (185)", + "DW_DLE_DEBUG_MACRO_INCONSISTENT (186)", + "DW_DLE_DF_NO_CIE_AUGMENTATION(187)", + "DW_DLE_DF_REG_NUM_TOO_HIGH(188)", + "DW_DLE_DF_MAKE_INSTR_NO_INIT(189)", + "DW_DLE_DF_NEW_LOC_LESS_OLD_LOC(190)", + "DW_DLE_DF_POP_EMPTY_STACK(191)", + "DW_DLE_DF_ALLOC_FAIL(192)", + "DW_DLE_DF_FRAME_DECODING_ERROR(193)", + "DW_DLE_DEBUG_LOC_SECTION_SHORT(194)", + "DW_DLE_FRAME_AUGMENTATION_UNKNOWN(195)", + "DW_DLE_PUBTYPE_CONTEXT(196)", + "DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD(197)", + "DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR(198)", + "DW_DLE_DEBUG_PUBTYPES_DUPLICATE(199)", + "DW_DLE_FRAME_CIE_DECODE_ERROR(200)", + "DW_DLE_FRAME_REGISTER_UNREPRESENTABLE(201)", + "DW_DLE_FRAME_REGISTER_COUNT_MISMATCH(202)", + "DW_DLE_LINK_LOOP(203)", + "DW_DLE_STRP_OFFSET_BAD(204)", + "DW_DLE_DEBUG_RANGES_DUPLICATE(205)", + "DW_DLE_DEBUG_RANGES_OFFSET_BAD(206)", + "DW_DLE_DEBUG_RANGES_MISSING_END(207)", + "DW_DLE_DEBUG_RANGES_OUT_OF_MEM(208)", + "DW_DLE_DEBUG_SYMTAB_ERR(209)", + "DW_DLE_DEBUG_STRTAB_ERR(210)", + "DW_DLE_RELOC_MISMATCH_INDEX(211)", + "DW_DLE_RELOC_MISMATCH_RELOC_INDEX(212)", + "DW_DLE_RELOC_MISMATCH_STRTAB_INDEX(213)", + "DW_DLE_RELOC_SECTION_MISMATCH(214)", + "DW_DLE_RELOC_SECTION_MISSING_INDEX(215)", + "DW_DLE_RELOC_SECTION_LENGTH_ODD(216)", + "DW_DLE_RELOC_SECTION_PTR_NULL(217)", + "DW_DLE_RELOC_SECTION_MALLOC_FAIL(218)", + "DW_DLE_NO_ELF64_SUPPORT(219)", + "DW_DLE_MISSING_ELF64_SUPPORT(220)", + "DW_DLE_ORPHAN_FDE(221)", + "DW_DLE_DUPLICATE_INST_BLOCK(222)", + "DW_DLE_BAD_REF_SIG8_FORM(223)", + "DW_DLE_ATTR_EXPRLOC_FORM_BAD(224)", + "DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD(225)", + "DW_DLE_NOT_REF_FORM(226)", + "DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE(227)", + "DW_DLE_REF_SIG8_NOT_HANDLED (228)", + "DW_DLE_DEBUG_FRAME_POSSIBLE_ADDRESS_BOTCH (229)", + "DW_DLE_LOC_BAD_TERMINATION (230) the last location operator in an expression is missing some associated data, an operator ended too soon", + "DW_DLE_SYMTAB_SECTION_LENGTH_ODD (231) so doing relocations seems unsafe", + "DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD (232) so doing a relocation seems unsafe", + "DW_DLE_RELOC_SECTION_RELOC_TARGET_SIZE_UNKNOWN (233) so doing a relocation is unsafe", + "DW_DLE_SYMTAB_SECTION_ENTRYSIZE_ZERO(234)", + "DW_DLE_LINE_NUMBER_HEADER_ERROR (235), a line number program header seems incomplete (perhaps the header_length is wrong?).", + "DW_DLE_DEBUG_TYPES_NULL (236)", + "DW_DLE_DEBUG_TYPES_DUPLICATE (237)", + "DW_DLE_DEBUG_TYPES_ONLY_DWARF4 (238)", + "DW_DLE_DEBUG_TYPEOFFSET_BAD (239)", + "DW_DLE_GNU_OPCODE_ERROR (240)", +}; + + + + +/* This function performs error handling as described in the + libdwarf consumer document section 3. Dbg is the Dwarf_debug + structure being processed. Error is a pointer to the pointer + to the error descriptor that will be returned. Errval is an + error code listed in dwarf_error.h. */ +void +_dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, Dwarf_Sword errval) +{ + Dwarf_Error errptr; + + /* Allow NULL dbg on entry, since sometimes that can happen and we + want to report the upper-level error, not this one. */ + if (error != NULL) { + /* If dbg is NULL, use the alternate error struct. However, + this will overwrite the earlier error. */ + if (dbg != NULL) { + errptr = + (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1); + if (errptr == NULL) { + fprintf(stderr, + "Could not allocate Dwarf_Error structure, " + "abort() in libdwarf.\n"); + abort(); + } + } else { + /* We have no dbg to work with. dwarf_init failed. We hack + up a special area. */ + errptr = _dwarf_special_no_dbg_error_malloc(); + if (errptr == NULL) { + fprintf(stderr, + "Could not allocate Dwarf_Error structure, " + "abort() in libdwarf..\n"); + abort(); + } + } + + errptr->er_errval = errval; + *error = errptr; + return; + } + + if (dbg != NULL && dbg->de_errhand != NULL) { + errptr = (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1); + if (errptr == NULL) { + fprintf(stderr, "Could not allocate Dwarf_Error structure," + " abort() in libdwarf.\n"); + abort(); + } + errptr->er_errval = errval; + dbg->de_errhand(errptr, dbg->de_errarg); + return; + } + fprintf(stderr, + "abort() in libdwarf. No error argument, no handler.\n"); + abort(); +} + + +Dwarf_Unsigned +dwarf_errno(Dwarf_Error error) +{ + if (error == NULL) { + return (0); + } + + return (error->er_errval); +} + + +/* +*/ +char * +dwarf_errmsg(Dwarf_Error error) +{ + if (error == NULL) { + return "Dwarf_Error is NULL"; + } + + if (error->er_errval >= (sizeof(_dwarf_errmsgs) / sizeof(char *))) { + return "Dwarf_Error value out of range"; + } + + return ((char *) _dwarf_errmsgs[error->er_errval]); +} diff --git a/libdwarf/dwarf_error.h b/libdwarf/dwarf_error.h new file mode 100644 index 0000000..4a4923e --- /dev/null +++ b/libdwarf/dwarf_error.h @@ -0,0 +1,44 @@ +/* + + Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +void _dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, + Dwarf_Sword errval); + +struct Dwarf_Error_s { + Dwarf_Sword er_errval; +}; diff --git a/libdwarf/dwarf_form.c b/libdwarf/dwarf_form.c new file mode 100644 index 0000000..c09b610 --- /dev/null +++ b/libdwarf/dwarf_form.c @@ -0,0 +1,931 @@ +/* + + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2011 David Anderson. All rights reserved. + Portions Copyright 2010 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include "dwarf_die_deliv.h" + +/* This code was repeated many times, now it + is all in one place. */ +static int +get_attr_dbg(Dwarf_Debug *dbg, + Dwarf_CU_Context * cu_context, + Dwarf_Attribute attr, + Dwarf_Error *error) +{ + Dwarf_CU_Context cup; + if (attr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return (DW_DLV_ERROR); + } + + cup = attr->ar_cu_context; + if (cup == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return (DW_DLV_ERROR); + } + + if (cup->cc_dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL); + return (DW_DLV_ERROR); + } + *cu_context = cup; + *dbg = cup->cc_dbg; + return DW_DLV_OK; + +} + +int +dwarf_hasform(Dwarf_Attribute attr, + Dwarf_Half form, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_bool = (attr->ar_attribute_form == form); + return DW_DLV_OK; +} + +/* Not often called, we do not worry about efficiency here. + The dwarf_whatform() call does the sanity checks for us. +*/ +int +dwarf_whatform_direct(Dwarf_Attribute attr, + Dwarf_Half * return_form, Dwarf_Error * error) +{ + int res = dwarf_whatform(attr, return_form, error); + + if (res != DW_DLV_OK) { + return res; + } + + *return_form = attr->ar_attribute_form_direct; + return (DW_DLV_OK); +} +void * +dwarf_uncompress_integer_block( + Dwarf_Debug dbg, + Dwarf_Bool unit_is_signed, + Dwarf_Small unit_length_in_bits, + void* input_block, + Dwarf_Unsigned input_length_in_bytes, + Dwarf_Unsigned* output_length_in_units_ptr, + Dwarf_Error* error +) +{ + Dwarf_Unsigned output_length_in_units = 0; + void * output_block = 0; + int i = 0; + char * ptr = 0; + int remain = 0; + Dwarf_sfixed * array = 0; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return((void *)DW_DLV_BADADDR); + } + + if (unit_is_signed == false || + unit_length_in_bits != 32 || + input_block == NULL || + input_length_in_bytes == 0 || + output_length_in_units_ptr == NULL) { + + _dwarf_error(NULL, error, DW_DLE_BADBITC); + return ((void *) DW_DLV_BADADDR); + } + + /* At this point we assume the format is: signed 32 bit */ + + /* first uncompress everything to find the total size. */ + + output_length_in_units = 0; + remain = input_length_in_bytes; + ptr = input_block; + while (remain > 0) { + Dwarf_Signed num; + Dwarf_Word len; + num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len); + ptr += len; + remain -= len; + output_length_in_units++; + } + + if (remain != 0) { + _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL); + return((void *)DW_DLV_BADADDR); + } + + /* then alloc */ + + output_block = (void *) + _dwarf_get_alloc(dbg, + DW_DLA_STRING, + output_length_in_units * (unit_length_in_bits / 8)); + if (output_block == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((void*)DW_DLV_BADADDR); + } + + /* then uncompress again and copy into new buffer */ + + array = (Dwarf_sfixed *) output_block; + remain = input_length_in_bytes; + ptr = input_block; + for (i=0; i<output_length_in_units && remain>0; i++) { + Dwarf_Signed num; + Dwarf_Word len; + num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len); + ptr += len; + remain -= len; + array[i] = num; + } + + if (remain != 0) { + dwarf_dealloc(dbg, (unsigned char *)output_block, DW_DLA_STRING); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + *output_length_in_units_ptr = output_length_in_units; + return output_block; +} + +void +dwarf_dealloc_uncompressed_block(Dwarf_Debug dbg, void * space) +{ + dwarf_dealloc(dbg, space, DW_DLA_STRING); +} + + +int +dwarf_whatform(Dwarf_Attribute attr, + Dwarf_Half * return_form, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_form = attr->ar_attribute_form; + return (DW_DLV_OK); +} + + +/* + This function is analogous to dwarf_whatform. + It returns the attribute in attr instead of + the form. +*/ +int +dwarf_whatattr(Dwarf_Attribute attr, + Dwarf_Half * return_attr, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_attr = (attr->ar_attribute); + return DW_DLV_OK; +} + + +/* Convert an offset within the local CU into a section-relative + debug_info offset. See dwarf_global_formref() and dwarf_formref() + for additional information on conversion rules. +*/ +int +dwarf_convert_to_global_offset(Dwarf_Attribute attr, + Dwarf_Off offset, Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + + switch (attr->ar_attribute_form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + /* It would be nice to put some code to check + legality of the offset */ + /* globalize the offset */ + offset += cu_context->cc_debug_offset; + break; + + case DW_FORM_ref_addr: + /* This offset is defined to be debug_info global already, so + use this value unaltered. */ + break; + + default: + _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM); + return (DW_DLV_ERROR); + } + + *ret_offset = (offset); + return DW_DLV_OK; +} + + +/* A global offset cannot be returned by this interface: + see dwarf_global_formref(). + + DW_FORM_ref_addr is considered an incorrect form + for this call because DW_FORM_ref_addr is a global-offset into + the debug_info section. + + For the same reason DW_FORM_data4/data8 are not returned + from this function. + + For the same reason DW_FORM_sec_offset is not returned + from this function, DW_FORM_sec_offset is a global offset + (to various sections, not a CU relative offset. + + DW_FORM_ref_addr has a value which was documented in + DWARF2 as address-size but which was always an offset + so should have always been offset size (wording + corrected in DWARF3). + + November, 2010: *ret_offset is always set now. + Even in case of error. + Set to zero for most errors, but for + DW_DLE_ATTR_FORM_OFFSET_BAD + *ret_offset is set to the bad offset. */ +int +dwarf_formref(Dwarf_Attribute attr, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Unsigned maximumoffset = 0; + int res = DW_DLV_ERROR; + + + *ret_offset = 0; + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_ref1: + offset = *(Dwarf_Small *) attr->ar_debug_ptr; + break; + + case DW_FORM_ref2: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + break; + + case DW_FORM_ref4: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + break; + + case DW_FORM_ref8: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + break; + + case DW_FORM_ref_udata: + offset = _dwarf_decode_u_leb128(attr->ar_debug_ptr, NULL); + break; + case DW_FORM_ref_sig8: + /* We cannot handle this here. + The reference is to .debug_types + not a .debug_info CU local offset. */ + _dwarf_error(dbg, error, DW_DLE_REF_SIG8_NOT_HANDLED); + return (DW_DLV_ERROR); + default: + _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM); + return (DW_DLV_ERROR); + } + + /* Check that offset is within current cu portion of .debug_info. */ + + maximumoffset = cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size; + if (offset >= maximumoffset) { + /* For the DW_TAG_compile_unit is legal to have the + DW_AT_sibling attribute outside the current cu portion of + .debug_info. + In other words, sibling points to the end of the CU. + It is used for precompiled headers. + The valid condition will be: 'offset == maximumoffset'. */ + Dwarf_Half tag = 0; + if (DW_DLV_OK != dwarf_tag(attr->ar_die,&tag,error)) { + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + + if (DW_TAG_compile_unit != tag && + DW_AT_sibling != attr->ar_attribute && + offset > maximumoffset) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + /* Return the incorrect offset for better error reporting */ + *ret_offset = (offset); + return (DW_DLV_ERROR); + } + } + *ret_offset = (offset); + return DW_DLV_OK; +} + +/* dwarf_formsig8 returns in the caller-provided 8 byte area + the 8 bytes of a DW_FORM_ref_sig8 (copying the bytes + directly to the caller). Not a string, an 8 byte + MD5 hash. This function is new in DWARF4 libdwarf. +*/ +int dwarf_formsig8(Dwarf_Attribute attr, + Dwarf_Sig8 * returned_sig_bytes, + Dwarf_Error* error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned field_end_offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Small *dataptr = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + + if(attr->ar_attribute_form != DW_FORM_ref_sig8 ) { + _dwarf_error(dbg, error, DW_DLE_BAD_REF_SIG8_FORM); + return (DW_DLV_ERROR); + } + + dataptr = cu_context->cc_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + field_end_offset = attr->ar_debug_ptr + sizeof(Dwarf_Sig8) - + (dataptr + cu_context->cc_debug_offset); + /* Check that offset is within current cu portion of .debug_info. */ + if (field_end_offset > cu_context->cc_length + + cu_context->cc_length_size + cu_context->cc_extension_size) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + memcpy(returned_sig_bytes, attr->ar_debug_ptr, + sizeof(Dwarf_Sig8)); + return DW_DLV_OK; +} + +/* Since this returns section-relative debug_info offsets, + this can represent all REFERENCE forms correctly + and allows all applicable forms. + + DW_FORM_ref_addr has a value which was documented in + DWARF2 as address-size but which was always an offset + so should have always been offset size (wording + corrected in DWARF3). + + See the DWARF4 document for the 3 cases fitting + reference forms. The caller must determine which section the + reference 'points' to. The function added in November 2009, + dwarf_get_form_class(), helps in this regard. */ +int +dwarf_global_formref(Dwarf_Attribute attr, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Half context_version = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + context_version = cu_context->cc_version_stamp; + switch (attr->ar_attribute_form) { + + case DW_FORM_ref1: + offset = *(Dwarf_Small *) attr->ar_debug_ptr; + goto fixoffset; + + case DW_FORM_ref2: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + goto fixoffset; + + case DW_FORM_ref4: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + goto fixoffset; + + case DW_FORM_ref8: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + goto fixoffset; + + case DW_FORM_ref_udata: + offset = _dwarf_decode_u_leb128(attr->ar_debug_ptr, NULL); + + fixoffset: /* we have a local offset, make it global */ + + /* check legality of offset */ + if (offset >= cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + /* globalize the offset */ + offset += cu_context->cc_debug_offset; + break; + + /* The DWARF2 document did not make clear that + DW_FORM_data4( and 8) were references with + global offsets to some section. + That was first clearly documented in DWARF3. + In DWARF4 these two forms are no longer references. */ + case DW_FORM_data4: + if(context_version == DW_CU_VERSION4) { + _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM); + return (DW_DLV_ERROR); + } + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + /* The offset is global. */ + break; + case DW_FORM_data8: + if(context_version == DW_CU_VERSION4) { + _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM); + return (DW_DLV_ERROR); + } + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + /* The offset is global. */ + break; + case DW_FORM_ref_addr: + case DW_FORM_sec_offset: + { + /* DW_FORM_sec_offset first exists in DWARF4.*/ + /* It is up to the caller to know what the offset + of DW_FORM_sec_offset refers to, + the offset is not going to refer to .debug_info! */ + unsigned length_size = cu_context->cc_length_size; + if(length_size == 4) { + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + } else if (length_size == 8) { + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + } else { + _dwarf_error(dbg, error, DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD); + return (DW_DLV_ERROR); + } + } + break; + case DW_FORM_ref_sig8: /* FIXME */ + /* We cannot handle this yet. + The reference is to .debug_types, and + this function only returns an offset in + .debug_info at this point. */ + _dwarf_error(dbg, error, DW_DLE_REF_SIG8_NOT_HANDLED); + return (DW_DLV_ERROR); + default: + _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM); + return (DW_DLV_ERROR); + } + + /* We do not know what section the offset refers to, so + we have no way to check it for correctness. */ + *ret_offset = offset; + return DW_DLV_OK; +} + + +int +dwarf_formaddr(Dwarf_Attribute attr, + Dwarf_Addr * return_addr, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Addr ret_addr = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + if (attr->ar_attribute_form == DW_FORM_addr + /* || attr->ar_attribute_form == DW_FORM_ref_addr Allowance of + DW_FORM_ref_addr was a mistake. The value returned in that + case is NOT an address it is a global debug_info offset (ie, + not CU-relative offset within the CU in debug_info). The + Dwarf document refers to it as an address (misleadingly) in + sec 6.5.4 where it describes the reference form. It is + address-sized so that the linker can easily update it, but + it is a reference inside the debug_info section. No longer + allowed. */ + ) { + + READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr, + attr->ar_debug_ptr, + cu_context->cc_address_size); + *return_addr = ret_addr; + return (DW_DLV_OK); + } + + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formflag(Dwarf_Attribute attr, + Dwarf_Bool * ret_bool, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + + if (attr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return (DW_DLV_ERROR); + } + + cu_context = attr->ar_cu_context; + if (cu_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return (DW_DLV_ERROR); + } + + if (cu_context->cc_dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL); + return (DW_DLV_ERROR); + } + if (attr->ar_attribute_form == DW_FORM_flag_present) { + /* Implicit means we don't read any data at all. Just + the existence of the Form does it. DWARF4. */ + *ret_bool = 1; + return (DW_DLV_OK); + } + + if (attr->ar_attribute_form == DW_FORM_flag) { + *ret_bool = (*(Dwarf_Small *) attr->ar_debug_ptr != 0); + return (DW_DLV_OK); + } + _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formudata(Dwarf_Attribute attr, + Dwarf_Unsigned * return_uval, Dwarf_Error * error) +{ + Dwarf_Unsigned ret_value = 0; + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_data1: + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Small)); + *return_uval = ret_value; + return DW_DLV_OK; + + /* READ_UNALIGNED does the right thing as it reads + the right number bits and generates host order. + So we can just assign to *return_uval. */ + case DW_FORM_data2:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + *return_uval = ret_value; + return DW_DLV_OK; + } + + case DW_FORM_data4:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, + sizeof(Dwarf_ufixed)); + *return_uval = ret_value; + return DW_DLV_OK; + } + + case DW_FORM_data8:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, + sizeof(Dwarf_Unsigned)); + *return_uval = ret_value; + return DW_DLV_OK; + } + break; + case DW_FORM_udata: + ret_value = + (_dwarf_decode_u_leb128(attr->ar_debug_ptr, NULL)); + *return_uval = ret_value; + return DW_DLV_OK; + + + /* IRIX bug 583450. We do not allow reading sdata from a udata + value. Caller can retry, calling sdata */ + + + default: + break; + } + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formsdata(Dwarf_Attribute attr, + Dwarf_Signed * return_sval, Dwarf_Error * error) +{ + Dwarf_Signed ret_value = 0; + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_data1: + *return_sval = (*(Dwarf_Sbyte *) attr->ar_debug_ptr); + return DW_DLV_OK; + + /* READ_UNALIGNED does not sign extend. + So we have to use a cast to get the + value sign extended in the right way for each case. */ + case DW_FORM_data2:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + sizeof(Dwarf_Shalf)); + *return_sval = (Dwarf_Shalf) ret_value; + return DW_DLV_OK; + + } + + case DW_FORM_data4:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + sizeof(Dwarf_sfixed)); + *return_sval = (Dwarf_sfixed) ret_value; + return DW_DLV_OK; + } + + case DW_FORM_data8:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + sizeof(Dwarf_Signed)); + *return_sval = (Dwarf_Signed) ret_value; + return DW_DLV_OK; + } + + case DW_FORM_sdata: + ret_value = + (_dwarf_decode_s_leb128(attr->ar_debug_ptr, NULL)); + *return_sval = ret_value; + return DW_DLV_OK; + + /* IRIX bug 583450. We do not allow reading sdata from a udata + value. Caller can retry, calling udata */ + + default: + break; + } + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formblock(Dwarf_Attribute attr, + Dwarf_Block ** return_block, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + Dwarf_Unsigned length = 0; + Dwarf_Small *data = 0; + Dwarf_Word leb128_length = 0; + Dwarf_Block *ret_block = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_block1: + length = *(Dwarf_Small *) attr->ar_debug_ptr; + data = attr->ar_debug_ptr + sizeof(Dwarf_Small); + break; + + case DW_FORM_block2: + READ_UNALIGNED(dbg, length, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + data = attr->ar_debug_ptr + sizeof(Dwarf_Half); + break; + + case DW_FORM_block4: + READ_UNALIGNED(dbg, length, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + data = attr->ar_debug_ptr + sizeof(Dwarf_ufixed); + break; + + case DW_FORM_block: + length = _dwarf_decode_u_leb128(attr->ar_debug_ptr, + &leb128_length); + data = attr->ar_debug_ptr + leb128_length; + break; + + default: + _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); + } + + /* Check that block lies within current cu in .debug_info. */ + if (attr->ar_debug_ptr + length >= + dbg->de_debug_info.dss_data + cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD); + return (DW_DLV_ERROR); + } + + ret_block = (Dwarf_Block *) _dwarf_get_alloc(dbg, DW_DLA_BLOCK, 1); + if (ret_block == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + ret_block->bl_len = length; + ret_block->bl_data = (Dwarf_Ptr) data; + ret_block->bl_from_loclist = 0; + ret_block->bl_section_offset = data - dbg->de_debug_info.dss_data; + + + *return_block = ret_block; + return (DW_DLV_OK); +} + + +/* Contrary to long standing documentation, + The string pointer returned thru return_str must + never have dwarf_dealloc() applied to it. + Documentation fixed July 2005. +*/ +int +dwarf_formstring(Dwarf_Attribute attr, + char **return_str, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + int res = DW_DLV_ERROR; + + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + if (attr->ar_attribute_form == DW_FORM_string) { + + void *begin = attr->ar_debug_ptr; + + if (0 == dbg->de_assume_string_in_bounds) { + /* Check that string lies within current cu in .debug_info. + */ + void *end = dbg->de_debug_info.dss_data + + cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size; + if (0 == _dwarf_string_valid(begin, end)) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD); + return (DW_DLV_ERROR); + } + } + *return_str = (char *) (begin); + return DW_DLV_OK; + } + + if (attr->ar_attribute_form == DW_FORM_strp) { + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, + cu_context->cc_length_size); + + res = _dwarf_load_section(dbg, &dbg->de_debug_str,error); + if (res != DW_DLV_OK) { + return res; + } + if (0 == dbg->de_assume_string_in_bounds) { + /* Check that string lies within current cu in .debug_info. + */ + void *end = dbg->de_debug_str.dss_data + + dbg->de_debug_str.dss_size; + void*begin = dbg->de_debug_str.dss_data + offset; + if (0 == _dwarf_string_valid(begin, end)) { + _dwarf_error(dbg, error, DW_DLE_STRP_OFFSET_BAD); + return (DW_DLV_ERROR); + } + } + + /* Ensure the offset lies within the .debug_str */ + if (offset >= dbg->de_debug_str.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + *return_str = (char *) (dbg->de_debug_str.dss_data + offset); + return DW_DLV_OK; + } + + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + +int +dwarf_formexprloc(Dwarf_Attribute attr, + Dwarf_Unsigned * return_exprlen, + Dwarf_Ptr * block_ptr, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL); + return (DW_DLV_ERROR); + } + if (attr->ar_attribute_form == DW_FORM_exprloc ) { + Dwarf_Word leb_len = 0; + Dwarf_Unsigned exprlen = + (_dwarf_decode_u_leb128(attr->ar_debug_ptr, &leb_len)); + Dwarf_Small * addr = attr->ar_debug_ptr; + *return_exprlen = exprlen; + *block_ptr = addr + leb_len; + return DW_DLV_OK; + + } + _dwarf_error(dbg, error, DW_DLE_ATTR_EXPRLOC_FORM_BAD); + return (DW_DLV_ERROR); +} diff --git a/libdwarf/dwarf_frame.c b/libdwarf/dwarf_frame.c new file mode 100644 index 0000000..1d327f0 --- /dev/null +++ b/libdwarf/dwarf_frame.c @@ -0,0 +1,2431 @@ +/* + + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <stdlib.h> +#include "dwarf_frame.h" +#include "dwarf_arange.h" /* Using Arange as a way to build a list */ + +#define FDE_NULL_CHECKS_AND_SET_DBG(fde,dbg ) \ + do { \ + if ((fde) == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_FDE_NULL);\ + return (DW_DLV_ERROR); \ + } \ + (dbg)= (fde)->fd_dbg; \ + if ((dbg) == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);\ + return (DW_DLV_ERROR); \ + } } while (0) + + +#define MIN(a,b) (((a) < (b))? a:b) + +static int dwarf_initialize_fde_table(Dwarf_Debug dbg, + struct Dwarf_Frame_s *fde_table, + unsigned table_real_data_size, + Dwarf_Error * error); +static void dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table); +static void dwarf_init_reg_rules_ru(struct Dwarf_Reg_Rule_s *base, + unsigned first, unsigned last,int initial_value); +static void dwarf_init_reg_rules_dw(struct Dwarf_Regtable_Entry_s *base, + unsigned first, unsigned last,int initial_value); +static void dwarf_init_reg_rules_dw3(struct Dwarf_Regtable_Entry3_s *base, + unsigned first, unsigned last,int initial_value); + + +#if 0 +/* Only used for debugging libdwarf. */ +static void dump_frame_rule(char *msg, + struct Dwarf_Reg_Rule_s *reg_rule); +#endif + + + +/* + This function is the heart of the debug_frame stuff. Don't even + think of reading this without reading both the Libdwarf and + consumer API carefully first. This function basically executes + frame instructions contained in a Cie or an Fde, but does in a + number of different ways depending on the information sought. + Start_instr_ptr points to the first byte of the frame instruction + stream, and final_instr_ptr to the to the first byte after the + last. + + The offsets returned in the frame instructions are factored. That + is they need to be multiplied by either the code_alignment_factor + or the data_alignment_factor, as appropriate to obtain the actual + offset. This makes it possible to expand an instruction stream + without the corresponding Cie. However, when an Fde frame instr + sequence is being expanded there must be a valid Cie with a pointer + to an initial table row. + + + If successful, returns DW_DLV_OK + And sets returned_count thru the pointer + if make_instr is true. + If make_instr is false returned_count + should NOT be used by the caller (returned_count + is set to 0 thru the pointer by this routine...) + If unsuccessful, returns DW_DLV_ERROR + and sets returned_error to the error code + + It does not do a whole lot of input validation being a private + function. Please make sure inputs are valid. + + (1) If make_instr is true, it makes a list of pointers to + Dwarf_Frame_Op structures containing the frame instructions + executed. A pointer to this list is returned in ret_frame_instr. + Make_instr is true only when a list of frame instructions is to be + returned. In this case since we are not interested in the contents + of the table, the input Cie can be NULL. This is the only case + where the inpute Cie can be NULL. + + (2) If search_pc is true, frame instructions are executed till + either a location is reached that is greater than the search_pc_val + provided, or all instructions are executed. At this point the + last row of the table generated is returned in a structure. + A pointer to this structure is supplied in table. + + (3) This function is also used to create the initial table row + defined by a Cie. In this case, the Dwarf_Cie pointer cie, is + NULL. For an FDE, however, cie points to the associated Cie. + + make_instr - make list of frame instr? 0/1 + ret_frame_instr - Ptr to list of ptrs to frame instrs + search_pc - Search for a pc value? 0/1 + search_pc_val - Search for this pc value + initial_loc - Initial code location value. + start_instr_ptr - Ptr to start of frame instrs. + final_instr_ptr - Ptr just past frame instrs. + table - Ptr to struct with last row. + cie - Ptr to Cie used by the Fde. + + Different cies may have distinct address-sizes, so the cie + is used, not de_pointer_size. + +*/ + +int +_dwarf_exec_frame_instr(Dwarf_Bool make_instr, + Dwarf_Frame_Op ** ret_frame_instr, + Dwarf_Bool search_pc, + Dwarf_Addr search_pc_val, + Dwarf_Addr initial_loc, + Dwarf_Small * start_instr_ptr, + Dwarf_Small * final_instr_ptr, + Dwarf_Frame table, + Dwarf_Cie cie, + Dwarf_Debug dbg, + Dwarf_Half reg_num_of_cfa, + Dwarf_Sword * returned_count, + int *returned_error) +{ +#define ERROR_IF_REG_NUM_TOO_HIGH(macreg,machigh_reg) \ + do { \ + if ((macreg) >= (machigh_reg) || (macreg) < 0) { \ + SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH); \ + } \ + } /*CONSTCOND */ while(0) +#define SIMPLE_ERROR_RETURN(code) \ + free(localregtab); \ + *returned_error = code; \ + return DW_DLV_ERROR + + /* Sweeps the frame instructions. */ + Dwarf_Small *instr_ptr; + + /* Register numbers not limited to just 255, thus not using + Dwarf_Small. */ + typedef int reg_num_type; + + Dwarf_Unsigned factored_N_value; + Dwarf_Signed signed_factored_N_value; + Dwarf_Addr current_loc = initial_loc; /* code location/ + pc-value corresponding to the frame instructions. + Starts at zero when the caller has no value to pass in. */ + + /* Must be min de_pointer_size bytes and must be at least sizeof + Dwarf_ufixed */ + Dwarf_Unsigned adv_loc = 0; + + int reg_count = dbg->de_frame_reg_rules_entry_count; + struct Dwarf_Reg_Rule_s *localregtab = calloc(reg_count, + sizeof(struct Dwarf_Reg_Rule_s)); + + struct Dwarf_Reg_Rule_s cfa_reg; + + + /* This is used to end executing frame instructions. */ + /* Becomes true when search_pc is true and current_loc */ + /* is greater than search_pc_val. */ + Dwarf_Bool search_over = false; + + /* Used by the DW_FRAME_advance_loc instr */ + /* to hold the increment in pc value. */ + Dwarf_Addr adv_pc; + + /* Contains the length in bytes of */ + /* an leb128 encoded number. */ + Dwarf_Word leb128_length; + + Dwarf_Half address_size = (cie)? cie->ci_address_size: + dbg->de_pointer_size; + + /* Counts the number of frame instructions executed. */ + Dwarf_Word instr_count = 0; + + /* These contain the current fields of the current frame + instruction. */ + Dwarf_Small fp_base_op = 0; + Dwarf_Small fp_extended_op; + reg_num_type fp_register; + + /* The value in fp_offset may be signed, though we call it + unsigned. This works ok for 2-s complement arithmetic. */ + Dwarf_Unsigned fp_offset; + Dwarf_Off fp_instr_offset; + + /* Stack_table points to the row (Dwarf_Frame ie) being pushed or + popped by a remember or restore instruction. Top_stack points to + the top of the stack of rows. */ + Dwarf_Frame stack_table = NULL; + Dwarf_Frame top_stack = NULL; + + /* These are used only when make_instr is true. Curr_instr is a + pointer to the current frame instruction executed. + Curr_instr_ptr, head_instr_list, and curr_instr_list are used to + form a chain of Dwarf_Frame_Op structs. Dealloc_instr_ptr is + used to deallocate the structs used to form the chain. + Head_instr_block points to a contiguous list of pointers to the + Dwarf_Frame_Op structs executed. */ + Dwarf_Frame_Op *curr_instr; + Dwarf_Chain curr_instr_item, dealloc_instr_item; + Dwarf_Chain head_instr_chain = NULL; + Dwarf_Chain tail_instr_chain = NULL; + Dwarf_Frame_Op *head_instr_block; + + /* These are the alignment_factors taken from the Cie provided. + When no input Cie is provided they are set to 1, because only + factored offsets are required. */ + Dwarf_Sword code_alignment_factor = 1; + Dwarf_Sword data_alignment_factor = 1; + + /* This flag indicates when an actual alignment factor is needed. + So if a frame instruction that computes an offset using an + alignment factor is encountered when this flag is set, an error + is returned because the Cie did not have a valid augmentation. */ + Dwarf_Bool need_augmentation = false; + + Dwarf_Word i; + + /* Initialize first row from associated Cie. Using temp regs + explicity */ + + if (localregtab == 0) { + SIMPLE_ERROR_RETURN(DW_DLE_ALLOC_FAIL); + } + { + struct Dwarf_Reg_Rule_s *t1reg = localregtab; + if (cie != NULL && cie->ci_initial_table != NULL) { + unsigned minregcount = 0; + unsigned curreg = 0; + struct Dwarf_Reg_Rule_s *t2reg = cie->ci_initial_table->fr_reg; + + if (reg_count != cie->ci_initial_table->fr_reg_count) { + /* Should never happen, it makes no sense to have the + table sizes change. There is no real allowance for + the set of registers to change dynamically in a + single Dwarf_Debug (except the size can be set near + initial Dwarf_Debug creation time). */ + SIMPLE_ERROR_RETURN + (DW_DLE_FRAME_REGISTER_COUNT_MISMATCH); + } + minregcount = MIN(reg_count,cie->ci_initial_table->fr_reg_count); + for (; curreg < minregcount ;curreg++, t1reg++, t2reg++) { + *t1reg = *t2reg; + } + cfa_reg = cie->ci_initial_table->fr_cfa_rule; + } else { + dwarf_init_reg_rules_ru(localregtab,0,reg_count, + dbg->de_frame_rule_initial_value); + dwarf_init_reg_rules_ru(&cfa_reg,0, 1, + dbg->de_frame_rule_initial_value); + } + } + + /* The idea here is that the code_alignment_factor and + data_alignment_factor which are needed for certain instructions + are valid only when the Cie has a proper augmentation string. So + if the augmentation is not right, only Frame instruction can be + read. */ + if (cie != NULL && cie->ci_augmentation != NULL) { + code_alignment_factor = cie->ci_code_alignment_factor; + data_alignment_factor = cie->ci_data_alignment_factor; + } else { + need_augmentation = !make_instr; + } + + instr_ptr = start_instr_ptr; + while ((instr_ptr < final_instr_ptr) && (!search_over)) { + Dwarf_Small instr = 0; + Dwarf_Small opcode = 0; + reg_num_type reg_no = 0; + + fp_instr_offset = instr_ptr - start_instr_ptr; + instr = *(Dwarf_Small *) instr_ptr; + instr_ptr += sizeof(Dwarf_Small); + + fp_base_op = (instr & 0xc0) >> 6; + if ((instr & 0xc0) == 0x00) { + opcode = instr; /* is really extended op */ + fp_extended_op = (instr & (~(0xc0))) & 0xff; + } else { + opcode = instr & 0xc0; /* is base op */ + fp_extended_op = 0; + } + + fp_register = 0; + fp_offset = 0; + switch (opcode) { + case DW_CFA_advance_loc: + { + /* base op */ + fp_offset = adv_pc = instr & DW_FRAME_INSTR_OFFSET_MASK; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_pc = adv_pc * code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_pc > search_pc_val); + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = current_loc + adv_pc; + } + break; + } + + case DW_CFA_offset: + { /* base op */ + reg_no = + (reg_num_type) (instr & DW_FRAME_INSTR_OFFSET_MASK); + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr = instr_ptr + leb128_length; + + fp_register = reg_no; + fp_offset = factored_N_value; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset_or_block_len = + factored_N_value * data_alignment_factor; + + break; + } + + case DW_CFA_restore: + { /* base op */ + reg_no = (instr & DW_FRAME_INSTR_OFFSET_MASK); + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + fp_register = reg_no; + + if (cie != NULL && cie->ci_initial_table != NULL) + localregtab[reg_no] = + cie->ci_initial_table->fr_reg[reg_no]; + else if (!make_instr) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_MAKE_INSTR_NO_INIT); + } + + break; + } + case DW_CFA_set_loc: + { + Dwarf_Addr new_loc = 0; + + READ_UNALIGNED(dbg, new_loc, Dwarf_Addr, + instr_ptr, address_size); + instr_ptr += address_size; + if (new_loc != 0 && current_loc != 0) { + /* Pre-relocation or before current_loc is set the + test comparing new_loc and current_loc makes no + sense. Testing for non-zero (above) is a way + (fallible) to check that current_loc, new_loc + are already relocated. */ + if (new_loc <= current_loc) { + /* Within a frame, address must increase. + Seemingly it has not. Seems to be an error. */ + + SIMPLE_ERROR_RETURN + (DW_DLE_DF_NEW_LOC_LESS_OLD_LOC); + } + } + + search_over = search_pc && (new_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = new_loc; + } + fp_offset = new_loc; + break; + } + + case DW_CFA_advance_loc1: + { + fp_offset = adv_loc = *(Dwarf_Small *) instr_ptr; + instr_ptr += sizeof(Dwarf_Small); + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_loc *= code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = current_loc + adv_loc; + } + break; + } + + case DW_CFA_advance_loc2: + { + READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned, + instr_ptr, sizeof(Dwarf_Half)); + instr_ptr += sizeof(Dwarf_Half); + fp_offset = adv_loc; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_loc *= code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = current_loc + adv_loc; + } + break; + } + + case DW_CFA_advance_loc4: + { + READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned, + instr_ptr, sizeof(Dwarf_ufixed)); + instr_ptr += sizeof(Dwarf_ufixed); + fp_offset = adv_loc; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adv_loc *= code_alignment_factor; + + search_over = search_pc && + (current_loc + adv_loc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = current_loc + adv_loc; + } + break; + } + + case DW_CFA_offset_extended: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);; + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset_or_block_len = factored_N_value * + data_alignment_factor; + + fp_register = reg_no; + fp_offset = factored_N_value; + break; + } + + case DW_CFA_restore_extended: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + if (cie != NULL && cie->ci_initial_table != NULL) { + localregtab[reg_no] = cie->ci_initial_table->fr_reg[reg_no]; + } else { + if (!make_instr) { + SIMPLE_ERROR_RETURN + (DW_DLE_DF_MAKE_INSTR_NO_INIT); + } + } + + fp_register = reg_no; + break; + } + + case DW_CFA_undefined: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + localregtab[reg_no].ru_is_off = 0; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = + dbg->de_frame_undefined_value_number; + localregtab[reg_no].ru_offset_or_block_len = 0; + + fp_register = reg_no; + break; + } + + case DW_CFA_same_value: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + localregtab[reg_no].ru_is_off = 0; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = + dbg->de_frame_same_value_number; + localregtab[reg_no].ru_offset_or_block_len = 0; + fp_register = reg_no; + break; + } + + case DW_CFA_register: + { + Dwarf_Unsigned lreg; + reg_num_type reg_noA = 0; + reg_num_type reg_noB = 0; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_noA = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_noA, reg_count); + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_noB = (reg_num_type) lreg; + + if (reg_noB > reg_count) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH); + } + + + localregtab[reg_noA].ru_is_off = 0; + localregtab[reg_noA].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_noA].ru_register = reg_noB; + localregtab[reg_noA].ru_offset_or_block_len = 0; + + fp_register = reg_noA; + fp_offset = reg_noB; + break; + } + + case DW_CFA_remember_state: + { + stack_table = (Dwarf_Frame) + _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1); + if (stack_table == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + for (i = 0; i < reg_count; i++) + stack_table->fr_reg[i] = localregtab[i]; + stack_table->fr_cfa_rule = cfa_reg; + + if (top_stack != NULL) + stack_table->fr_next = top_stack; + top_stack = stack_table; + + break; + } + + case DW_CFA_restore_state: + { + if (top_stack == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_POP_EMPTY_STACK); + } + stack_table = top_stack; + top_stack = stack_table->fr_next; + + for (i = 0; i < reg_count; i++) + localregtab[i] = stack_table->fr_reg[i]; + cfa_reg = stack_table->fr_cfa_rule; + + dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME); + break; + } + + case DW_CFA_def_cfa: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_register = reg_no; + cfa_reg.ru_offset_or_block_len = factored_N_value; + + fp_register = reg_no; + fp_offset = factored_N_value; + break; + } + + case DW_CFA_def_cfa_register: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + cfa_reg.ru_register = reg_no; + /* Do NOT set ru_offset_or_block_len or ru_is_off here. + See dwarf2/3 spec. */ + fp_register = reg_no; + break; + } + + case DW_CFA_def_cfa_offset: + { + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_offset_or_block_len = factored_N_value; + + fp_offset = factored_N_value; + break; + } + case DW_CFA_nop: + { + break; + } + /* DWARF3 ops begin here. */ + case DW_CFA_def_cfa_expression: + { + /* A single DW_FORM_block representing a dwarf + expression. The form block establishes the way to + compute the CFA. */ + Dwarf_Unsigned block_len = 0; + + DECODE_LEB128_UWORD(instr_ptr, block_len); + cfa_reg.ru_is_off = 0; /* arbitrary */ + cfa_reg.ru_value_type = DW_EXPR_EXPRESSION; + cfa_reg.ru_offset_or_block_len = block_len; + cfa_reg.ru_block = instr_ptr; + fp_offset = (Dwarf_Unsigned) instr_ptr; + instr_ptr += block_len; + } + break; + case DW_CFA_expression: + { + /* An unsigned leb128 value is the first operand (a + register number). The second operand is single + DW_FORM_block representing a dwarf expression. The + evaluator pushes the CFA on the evaluation stack + then evaluates the expression to compute the value + of the register contents. */ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned block_len = 0; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + DECODE_LEB128_UWORD(instr_ptr, block_len); + localregtab[lreg].ru_is_off = 0; /* arbitrary */ + localregtab[lreg].ru_value_type = DW_EXPR_EXPRESSION; + localregtab[lreg].ru_offset_or_block_len = block_len; + localregtab[lreg].ru_block = instr_ptr; + fp_offset = (Dwarf_Unsigned) instr_ptr; + fp_register = reg_no; + instr_ptr += block_len; + } + break; + case DW_CFA_offset_extended_sf: + { + /* The first operand is an unsigned leb128 register + number. The second is a signed factored offset. + Identical to DW_CFA_offset_extended except the + second operand is signed */ + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_register = reg_no; + fp_offset = signed_factored_N_value; + } + break; + case DW_CFA_def_cfa_sf: + { + /* The first operand is an unsigned leb128 register + number. The second is a signed leb128 factored + offset. Identical to DW_CFA_def_cfa except that the + second operand is signed and factored. */ + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_register = reg_no; + cfa_reg.ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_register = reg_no; + fp_offset = signed_factored_N_value; + } + break; + case DW_CFA_def_cfa_offset_sf: + { + /* The operand is a signed leb128 operand representing + a factored offset. Identical to + DW_CFA_def_cfa_offset excep the operand is signed + and factored. */ + + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + cfa_reg.ru_is_off = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_offset = signed_factored_N_value; + } + break; + case DW_CFA_val_offset: + { + /* The first operand is an unsigned leb128 register + number. The second is a factored unsigned offset. + Makes the register be a val_offset(N) rule with N = + factored_offset*data_alignment_factor. */ + + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + factored_N_value = + _dwarf_decode_u_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET; + localregtab[reg_no].ru_offset_or_block_len = + factored_N_value * data_alignment_factor; + + fp_offset = factored_N_value; + break; + } + case DW_CFA_val_offset_sf: + { + /* The first operand is an unsigned leb128 register + number. The second is a factored signed offset. + Makes the register be a val_offset(N) rule with N = + factored_offset*data_alignment_factor. */ + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + signed_factored_N_value = + _dwarf_decode_s_leb128(instr_ptr, &leb128_length); + instr_ptr += leb128_length; + + if (need_augmentation) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + localregtab[reg_no].ru_is_off = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET; + localregtab[reg_no].ru_offset_or_block_len = + signed_factored_N_value * data_alignment_factor; + + fp_offset = signed_factored_N_value; + + } + break; + case DW_CFA_val_expression: + { + /* The first operand is an unsigned leb128 register + number. The second is a DW_FORM_block representing a + DWARF expression. The rule for the register number + becomes a val_expression(E) rule. */ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned block_len = 0; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + DECODE_LEB128_UWORD(instr_ptr, block_len); + localregtab[lreg].ru_is_off = 0; /* arbitrary */ + localregtab[lreg].ru_value_type = DW_EXPR_VAL_EXPRESSION; + localregtab[lreg].ru_offset_or_block_len = block_len; + localregtab[lreg].ru_block = instr_ptr; + fp_offset = (Dwarf_Unsigned) instr_ptr; + + instr_ptr += block_len; + fp_register = reg_no; + + } + break; + + /* END DWARF3 new ops. */ + + +#ifdef DW_CFA_GNU_window_save + case DW_CFA_GNU_window_save: + { + /* No information: this just tells unwinder to restore + the window registers from the previous frame's + window save area */ + break; + } +#endif +#ifdef DW_CFA_GNU_args_size + /* Single uleb128 is the current arg area size in bytes. No + register exists yet to save this in */ + case DW_CFA_GNU_args_size: + { + Dwarf_Unsigned lreg; + + DECODE_LEB128_UWORD(instr_ptr, lreg); + reg_no = (reg_num_type) lreg; + + break; + } +#endif + default: + /* ERROR, we have an opcode we know nothing about. Memory + leak here, but an error like this is not supposed to + happen so we ignore the leak. These used to be ignored, + now we notice and report. */ + SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR); + + } + + if (make_instr) { + instr_count++; + + curr_instr = (Dwarf_Frame_Op *) + _dwarf_get_alloc(dbg, DW_DLA_FRAME_OP, 1); + if (curr_instr == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + curr_instr->fp_base_op = fp_base_op; + curr_instr->fp_extended_op = fp_extended_op; + curr_instr->fp_register = fp_register; + curr_instr->fp_offset = fp_offset; + curr_instr->fp_instr_offset = fp_instr_offset; + + curr_instr_item = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_instr_item == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + curr_instr_item->ch_item = curr_instr; + if (head_instr_chain == NULL) + head_instr_chain = tail_instr_chain = curr_instr_item; + else { + tail_instr_chain->ch_next = curr_instr_item; + tail_instr_chain = curr_instr_item; + } + } + } + + /* If frame instruction decoding was right we would stop exactly at + final_instr_ptr. */ + if (instr_ptr > final_instr_ptr) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR); + } + + /* Fill in the actual output table, the space the caller passed in. */ + if (table != NULL) { + + struct Dwarf_Reg_Rule_s *t2reg = table->fr_reg; + struct Dwarf_Reg_Rule_s *t3reg = localregtab; + unsigned minregcount = MIN(table->fr_reg_count,reg_count); + unsigned curreg = 0; + + table->fr_loc = current_loc; + for (; curreg < minregcount ; curreg++, t3reg++, t2reg++) { + *t2reg = *t3reg; + } + + /* CONSTCOND */ + /* Do not update the main table with the cfa_reg. + Just leave cfa_reg as cfa_reg. */ + table->fr_cfa_rule = cfa_reg; + } + + /* Dealloc anything remaining on stack. */ + for (; top_stack != NULL;) { + stack_table = top_stack; + top_stack = top_stack->fr_next; + dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME); + } + + if (make_instr) { + /* Allocate list of pointers to Dwarf_Frame_Op's. */ + head_instr_block = (Dwarf_Frame_Op *) + _dwarf_get_alloc(dbg, DW_DLA_FRAME_BLOCK, instr_count); + if (head_instr_block == NULL) { + SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL); + } + + /* Store pointers to Dwarf_Frame_Op's in this list and + deallocate the structs that chain the Dwarf_Frame_Op's. */ + curr_instr_item = head_instr_chain; + for (i = 0; i < instr_count; i++) { + *(head_instr_block + i) = + *(Dwarf_Frame_Op *) curr_instr_item->ch_item; + dealloc_instr_item = curr_instr_item; + curr_instr_item = curr_instr_item->ch_next; + dwarf_dealloc(dbg, dealloc_instr_item->ch_item, + DW_DLA_FRAME_OP); + dwarf_dealloc(dbg, dealloc_instr_item, DW_DLA_CHAIN); + } + *ret_frame_instr = head_instr_block; + *returned_count = (Dwarf_Sword) instr_count; + } else { + *returned_count = 0; + } + free(localregtab); + return DW_DLV_OK; +#undef ERROR_IF_REG_NUM_TOO_HIGH +#undef SIMPLE_ERROR_RETURN +} + +/* Depending on version, either read the return address register + as a ubyte or as an leb number. + The form of this value changed for DWARF3. +*/ +Dwarf_Unsigned +_dwarf_get_return_address_reg(Dwarf_Small * frame_ptr, + int version, unsigned long *size) +{ + Dwarf_Unsigned uvalue = 0; + Dwarf_Word leb128_length = 0; + + if (version == 1) { + *size = 1; + uvalue = *(unsigned char *) frame_ptr; + return uvalue; + } + uvalue = _dwarf_decode_u_leb128(frame_ptr, &leb128_length); + *size = leb128_length; + return uvalue; +} + + +/* Trivial consumer function. +*/ +int +dwarf_get_cie_of_fde(Dwarf_Fde fde, + Dwarf_Cie * cie_returned, Dwarf_Error * error) +{ + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + *cie_returned = fde->fd_cie; + return DW_DLV_OK; + +} + +int dwarf_get_cie_index( + Dwarf_Cie cie, + Dwarf_Signed* index, + Dwarf_Error* error ) +{ + if( cie == NULL ) + { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return (DW_DLV_ERROR); + } + + *index = cie->ci_index; + return (DW_DLV_OK); +} + +/* For g++ .eh_frame fde and cie. + the cie id is different as the + definition of the cie_id in an fde + is the distance back from the address of the + value to the cie. + Or 0 if this is a true cie. + Non standard dwarf, designed this way to be + convenient at run time for an allocated + (mapped into memory as part of the running image) section. +*/ +int +dwarf_get_fde_list_eh(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_frame_eh_gnu,error); + if (res != DW_DLV_OK) { + return res; + } + + res = _dwarf_get_fde_list_internal(dbg, + cie_data, + cie_element_count, + fde_data, + fde_element_count, + dbg->de_debug_frame_eh_gnu.dss_data, + dbg->de_debug_frame_eh_gnu.dss_index, + dbg->de_debug_frame_eh_gnu.dss_size, + /* cie_id_value */ 0, + /* use_gnu_cie_calc= */ 1, + error); + return res; +} + + + +/* For standard dwarf .debug_frame + cie_id is -1 in a cie, and + is the section offset in the .debug_frame section + of the cie otherwise. Standard dwarf +*/ +int +dwarf_get_fde_list(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error); + if (res != DW_DLV_OK) { + return res; + } + + res = _dwarf_get_fde_list_internal(dbg, cie_data, + cie_element_count, + fde_data, + fde_element_count, + dbg->de_debug_frame.dss_data, + dbg->de_debug_frame.dss_index, + dbg->de_debug_frame.dss_size, + DW_CIE_ID, + /* use_gnu_cie_calc= */ 0, + error); + + return res; +} + + +/* Only works on dwarf sections, not eh_frame + Given a Dwarf_Die, see if it has a + DW_AT_MIPS_fde attribute and if so use that + to get an fde offset. + Then create a Dwarf_Fde to return thru the ret_fde pointer. + Also creates a cie (pointed at from the Dwarf_Fde). */ +int +dwarf_get_fde_for_die(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Fde * ret_fde, Dwarf_Error * error) +{ + Dwarf_Attribute attr; + Dwarf_Unsigned fde_offset = 0; + Dwarf_Signed signdval = 0; + Dwarf_Fde new_fde = 0; + unsigned char *fde_ptr = 0; + unsigned char *cie_ptr = 0; + Dwarf_Unsigned cie_id = 0; + + /* Fields for the current Cie being read. */ + int res = 0; + int resattr = 0; + int sdatares = 0; + + struct cie_fde_prefix_s prefix; + struct cie_fde_prefix_s prefix_c; + + if (die == NULL) { + _dwarf_error(NULL, error, DW_DLE_DIE_NULL); + return (DW_DLV_ERROR); + } + + resattr = dwarf_attr(die, DW_AT_MIPS_fde, &attr, error); + if (resattr != DW_DLV_OK) { + return resattr; + } + + /* why is this formsdata? FIX */ + sdatares = dwarf_formsdata(attr, &signdval, error); + if (sdatares != DW_DLV_OK) { + return sdatares; + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error); + if (res != DW_DLV_OK) { + return res; + } + + fde_offset = signdval; + fde_ptr = (dbg->de_debug_frame.dss_data + fde_offset); + + + /* First read in the 'common prefix' to figure out what * we are to + do with this entry. */ + memset(&prefix_c, 0, sizeof(prefix_c)); + memset(&prefix, 0, sizeof(prefix)); + res = dwarf_read_cie_fde_prefix(dbg, fde_ptr, + dbg->de_debug_frame.dss_data, + dbg->de_debug_frame.dss_index, + dbg->de_debug_frame.dss_size, + &prefix, + error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) + return res; + fde_ptr = prefix.cf_addr_after_prefix; + cie_id = prefix.cf_cie_id; + /* Pass NULL, not section pointer, for 3rd argument. + de_debug_frame.dss_data has no eh_frame relevance. */ + res = dwarf_create_fde_from_after_start(dbg, &prefix, + (Dwarf_Small *) NULL, + fde_ptr, + /* use_gnu_cie_calc= */ 0, + /* Dwarf_Cie = */ 0, + &new_fde, error); + if (res == DW_DLV_ERROR) { + return res; + } else if (res == DW_DLV_NO_ENTRY) { + return res; + } + /* DW_DLV_OK */ + + /* now read the cie corresponding to the fde */ + cie_ptr = new_fde->fd_section_ptr + cie_id; + res = dwarf_read_cie_fde_prefix(dbg, cie_ptr, + dbg->de_debug_frame.dss_data, + dbg->de_debug_frame.dss_index, + dbg->de_debug_frame.dss_size, + &prefix_c, error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) + return res; + + cie_ptr = prefix_c.cf_addr_after_prefix; + cie_id = prefix_c.cf_cie_id; + + if (cie_id == DW_CIE_ID) { + int res2 = 0; + Dwarf_Cie new_cie = 0; + + /* Pass NULL, not section pointer, for 3rd argument. + de_debug_frame.dss_data has no eh_frame relevance. */ + res2 = dwarf_create_cie_from_after_start(dbg, + &prefix_c, + (Dwarf_Small *) NULL, + cie_ptr, + /* cie_count= */ 0, + /* use_gnu_cie_calc= */ + 0, &new_cie, error); + if (res2 == DW_DLV_ERROR) { + dwarf_dealloc(dbg, new_fde, DW_DLA_FDE); + return res; + } else if (res2 == DW_DLV_NO_ENTRY) { + dwarf_dealloc(dbg, new_fde, DW_DLA_FDE); + return res; + } + new_fde->fd_cie = new_cie; + } else { + _dwarf_error(dbg, error, DW_DLE_NO_CIE_FOR_FDE); + return (DW_DLV_ERROR); + } + + *ret_fde = new_fde; + return DW_DLV_OK; +} + +/* A dwarf consumer operation, see the consumer library documentation. +*/ +int +dwarf_get_fde_range(Dwarf_Fde fde, + Dwarf_Addr * low_pc, + Dwarf_Unsigned * func_length, + Dwarf_Ptr * fde_bytes, + Dwarf_Unsigned * fde_byte_length, + Dwarf_Off * cie_offset, + Dwarf_Signed * cie_index, + Dwarf_Off * fde_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + + + /* We have always already done the section load here, so no need to + load the section. We did the section load in order to create the + Dwarf_Fde pointer passed in here. */ + + + if (low_pc != NULL) + *low_pc = fde->fd_initial_location; + if (func_length != NULL) + *func_length = fde->fd_address_range; + if (fde_bytes != NULL) + *fde_bytes = fde->fd_fde_start; + if (fde_byte_length != NULL) + *fde_byte_length = fde->fd_length; + if (cie_offset != NULL) + *cie_offset = fde->fd_cie_offset; + if (cie_index != NULL) + *cie_index = fde->fd_cie_index; + if (fde_offset != NULL) + *fde_offset = fde->fd_fde_start - fde->fd_section_ptr; + + return DW_DLV_OK; +} + +/* IRIX specific function. The exception tables + have C++ destructor information and are + at present undocumented. */ +int +dwarf_get_fde_exception_info(Dwarf_Fde fde, + Dwarf_Signed * + offset_into_exception_tables, + Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + *offset_into_exception_tables = + fde->fd_offset_into_exception_tables; + return DW_DLV_OK; +} + + +/* A consumer code function. + Given a CIE pointer, return the normal CIE data thru + pointers. + Special augmentation data is not returned here. +*/ +int +dwarf_get_cie_info(Dwarf_Cie cie, + Dwarf_Unsigned * bytes_in_cie, + Dwarf_Small * ptr_to_version, + char **augmenter, + Dwarf_Unsigned * code_alignment_factor, + Dwarf_Signed * data_alignment_factor, + Dwarf_Half * return_address_register, + Dwarf_Ptr * initial_instructions, + Dwarf_Unsigned * initial_instructions_length, + Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return (DW_DLV_ERROR); + } + + dbg = cie->ci_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_DBG_NULL); + return (DW_DLV_ERROR); + } + + if (ptr_to_version != NULL) + *ptr_to_version = cie->ci_cie_version_number; + if (augmenter != NULL) + *augmenter = cie->ci_augmentation; + if (code_alignment_factor != NULL) + *code_alignment_factor = cie->ci_code_alignment_factor; + if (data_alignment_factor != NULL) + *data_alignment_factor = cie->ci_data_alignment_factor; + if (return_address_register != NULL) + *return_address_register = cie->ci_return_address_register; + if (initial_instructions != NULL) + *initial_instructions = cie->ci_cie_instr_start; + if (initial_instructions_length != NULL) { + *initial_instructions_length = cie->ci_length + + cie->ci_length_size + + cie->ci_extension_size - + (cie->ci_cie_instr_start - cie->ci_cie_start); + + } + *bytes_in_cie = (cie->ci_length); + return (DW_DLV_OK); +} + +/* Return the register rules for all registers at a given pc. +*/ +static int +_dwarf_get_fde_info_for_a_pc_row(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Frame table, + Dwarf_Half cfa_reg_col_num, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Cie cie = 0; + int dw_err = 0; + Dwarf_Sword icount = 0; + int res = 0; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + + if (pc_requested < fde->fd_initial_location || + pc_requested >= + fde->fd_initial_location + fde->fd_address_range) { + _dwarf_error(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); + return (DW_DLV_ERROR); + } + + cie = fde->fd_cie; + if (cie->ci_initial_table == NULL) { + cie->ci_initial_table = _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1); + + if (cie->ci_initial_table == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + dwarf_init_reg_rules_ru(cie->ci_initial_table->fr_reg, + 0, cie->ci_initial_table->fr_reg_count,dbg->de_frame_rule_initial_value); + dwarf_init_reg_rules_ru(&cie->ci_initial_table->fr_cfa_rule, + 0,1,dbg->de_frame_rule_initial_value); + res = _dwarf_exec_frame_instr( /* make_instr= */ false, + /* ret_frame_instr= */ NULL, + /* search_pc */ false, + /* search_pc_val */ 0, + /* location */ 0, + cie->ci_cie_instr_start, + cie->ci_cie_instr_start + (cie->ci_length + + cie->ci_length_size + + cie->ci_extension_size - + (cie->ci_cie_instr_start - + cie->ci_cie_start)), + cie->ci_initial_table, cie, dbg, + cfa_reg_col_num, &icount, + &dw_err); + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, error, dw_err); + return (res); + } else if (res == DW_DLV_NO_ENTRY) { + return res; + } + } + + { + Dwarf_Small *instr_end = fde->fd_fde_instr_start + + fde->fd_length + + fde->fd_length_size + + fde->fd_extension_size - (fde->fd_fde_instr_start - + fde->fd_fde_start); + + res = _dwarf_exec_frame_instr( /* make_instr= */ false, + /* ret_frame_instr= */ NULL, + /* search_pc */ true, + /* search_pc_val */ pc_requested, + fde->fd_initial_location, + fde->fd_fde_instr_start, + instr_end, + table, + cie, dbg, + cfa_reg_col_num, &icount, + &dw_err); + } + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, error, dw_err); + return (res); + } else if (res == DW_DLV_NO_ENTRY) { + return res; + } + + return DW_DLV_OK; +} + +/* A consumer call for efficiently getting the register info + for all registers in one call. + + The output table rules array is size DW_REG_TABLE_SIZE. + The frame info rules array in fde_table is of size + DW_REG_TABLE_SIZE too. + + This interface really only works well with MIPS/IRIX + where DW_FRAME_CFA_COL is zero (in that case it's safe). + + It is also restricted to the case where + DW_REG_TABLE_SIZE == DW_FRAME_LAST_REG_NUM == + dbg->de_frame_reg_rules_entry_count (true for MIPS/IRIX). + If this condition is not met calling this routine can result in + incorrect output or in memory corruption. + + It is much better to use dwarf_get_fde_info_for_all_regs3() + instead of this interface. +*/ +int +dwarf_get_fde_info_for_all_regs(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Regtable * reg_table, + Dwarf_Addr * row_pc, + Dwarf_Error * error) +{ + + /* Table size: DW_REG_TABLE_SIZE */ + struct Dwarf_Frame_s fde_table; + Dwarf_Sword i = 0; + struct Dwarf_Reg_Rule_s *rule = NULL; + struct Dwarf_Regtable_Entry_s *out_rule = NULL; + int res = 0; + Dwarf_Debug dbg = 0; + + /* For this interface the size is fixed at compile time. */ + int output_table_real_data_size = DW_REG_TABLE_SIZE; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + res = dwarf_initialize_fde_table(dbg, &fde_table, + output_table_real_data_size, + error); + if (res != DW_DLV_OK) + return res; + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, + &fde_table, dbg->de_frame_cfa_col_number, error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + out_rule = ®_table->rules[0]; + rule = &fde_table.fr_reg[0]; + for (i = 0; i < output_table_real_data_size; + i++, ++out_rule, ++rule) { + out_rule->dw_offset_relevant = rule->ru_is_off; + out_rule->dw_value_type = rule->ru_value_type; + out_rule->dw_regnum = rule->ru_register; + out_rule->dw_offset = rule->ru_offset_or_block_len; + } + dwarf_init_reg_rules_dw(®_table->rules[0],i,DW_REG_TABLE_SIZE, + dbg->de_frame_undefined_value_number); + + /* The test is just in case it's not inside the table. For non-MIPS + it could be outside the table and that is just fine, it was + really a mistake to put it in the table in 1993. */ + /* CONSTCOND */ + if (dbg->de_frame_cfa_col_number < DW_REG_TABLE_SIZE) { + out_rule = ®_table->rules[dbg->de_frame_cfa_col_number]; + out_rule->dw_offset_relevant = fde_table.fr_cfa_rule.ru_is_off; + out_rule->dw_value_type = fde_table.fr_cfa_rule.ru_value_type; + out_rule->dw_regnum = fde_table.fr_cfa_rule.ru_register; + out_rule->dw_offset = + fde_table.fr_cfa_rule.ru_offset_or_block_len; + } + + if (row_pc != NULL) + *row_pc = fde_table.fr_loc; + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + +/* A consumer call for efficiently getting the register info + for all registers in one call. + + The output table rules array is size output_table_real_data_size. + (normally DW_REG_TABLE_SIZE). + The frame info rules array in fde_table is normally of size + DW_FRAME_LAST_REG_NUM. */ +int +dwarf_get_fde_info_for_all_regs3(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Regtable3 * reg_table, + Dwarf_Addr * row_pc, + Dwarf_Error * error) +{ + + struct Dwarf_Frame_s fde_table; + Dwarf_Sword i = 0; + int res = 0; + struct Dwarf_Reg_Rule_s *rule = NULL; + struct Dwarf_Regtable_Entry3_s *out_rule = NULL; + Dwarf_Debug dbg = 0; + int output_table_real_data_size = reg_table->rt3_reg_table_size; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + output_table_real_data_size = + MIN(output_table_real_data_size, + dbg->de_frame_reg_rules_entry_count); + + res = dwarf_initialize_fde_table(dbg, &fde_table, + output_table_real_data_size, + error); + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, + &fde_table, + dbg->de_frame_cfa_col_number, + error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + out_rule = ®_table->rt3_rules[0]; + rule = &fde_table.fr_reg[0]; + for (i = 0; i < output_table_real_data_size; + i++, ++out_rule, ++rule) { + out_rule->dw_offset_relevant = rule->ru_is_off; + out_rule->dw_value_type = rule->ru_value_type; + out_rule->dw_regnum = rule->ru_register; + out_rule->dw_offset_or_block_len = rule->ru_offset_or_block_len; + out_rule->dw_block_ptr = rule->ru_block; + } + dwarf_init_reg_rules_dw3(®_table->rt3_rules[0],i,reg_table->rt3_reg_table_size, + dbg->de_frame_undefined_value_number); + + reg_table->rt3_cfa_rule.dw_offset_relevant = + fde_table.fr_cfa_rule.ru_is_off; + reg_table->rt3_cfa_rule.dw_value_type = + fde_table.fr_cfa_rule.ru_value_type; + reg_table->rt3_cfa_rule.dw_regnum = + fde_table.fr_cfa_rule.ru_register; + reg_table->rt3_cfa_rule.dw_offset_or_block_len = + fde_table.fr_cfa_rule.ru_offset_or_block_len; + reg_table->rt3_cfa_rule.dw_block_ptr = + fde_table.fr_cfa_rule.ru_block; + + if (row_pc != NULL) + *row_pc = fde_table.fr_loc; + + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + + +/* Gets the register info for a single register at a given PC value + for the FDE specified. + + This is the old MIPS interface and should no longer be used. + Use dwarf_get_fde_info_for_reg3() instead. */ +int +dwarf_get_fde_info_for_reg(Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr pc_requested, + Dwarf_Signed * offset_relevant, + Dwarf_Signed * register_num, + Dwarf_Signed * offset, + Dwarf_Addr * row_pc, Dwarf_Error * error) +{ + struct Dwarf_Frame_s fde_table; + int res = DW_DLV_ERROR; + Dwarf_Debug dbg = 0; + int output_table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + output_table_real_data_size = dbg->de_frame_reg_rules_entry_count; + + res = dwarf_initialize_fde_table(dbg, &fde_table, + output_table_real_data_size, + error); + if (res != DW_DLV_OK) + return res; + + if (table_column >= output_table_real_data_size) { + dwarf_free_fde_table(&fde_table); + _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD); + return (DW_DLV_ERROR); + } + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = + _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table, + dbg->de_frame_cfa_col_number, error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + if (fde_table.fr_reg[table_column].ru_value_type != DW_EXPR_OFFSET) { + /* The problem here is that this interface cannot deal with + other sorts of (newer) dwarf frame values. Code must + use dwarf_get_fde_info_for_reg3() to get these + values correctly. We error rather than return + misleading incomplete data. */ + dwarf_free_fde_table(&fde_table); + _dwarf_error(NULL, error, + DW_DLE_FRAME_REGISTER_UNREPRESENTABLE); + return (DW_DLV_ERROR); + } + if(table_column == dbg->de_frame_cfa_col_number) { + if (register_num != NULL) + *register_num = fde_table.fr_cfa_rule.ru_register; + if (offset != NULL) + *offset = fde_table.fr_cfa_rule.ru_offset_or_block_len; + if (row_pc != NULL) + *row_pc = fde_table.fr_loc; + *offset_relevant = fde_table.fr_cfa_rule.ru_is_off; + + } else { + if (register_num != NULL) + *register_num = fde_table.fr_reg[table_column].ru_register; + if (offset != NULL) + *offset = fde_table.fr_reg[table_column].ru_offset_or_block_len; + if (row_pc != NULL) + *row_pc = fde_table.fr_loc; + + *offset_relevant = fde_table.fr_reg[table_column].ru_is_off; + } + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + +/* In this interface, table_column of DW_FRAME_CFA_COL + is not meaningful. + Use dwarf_get_fde_info_for_cfa_reg3() to get the CFA. + Call dwarf_set_frame_cfa_value() to set the correct column + after calling dwarf_init() + (DW_FRAME_CFA_COL3 is a sensible column to use). +*/ +int +dwarf_get_fde_info_for_reg3(Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr pc_requested, + Dwarf_Small * value_type, + Dwarf_Signed * offset_relevant, + Dwarf_Signed * register_num, + Dwarf_Signed * offset_or_block_len, + Dwarf_Ptr * block_ptr, + Dwarf_Addr * row_pc_out, + Dwarf_Error * error) +{ + struct Dwarf_Frame_s fde_table; + int res = DW_DLV_ERROR; + + Dwarf_Debug dbg = 0; + int table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + table_real_data_size = dbg->de_frame_reg_rules_entry_count; + res = dwarf_initialize_fde_table(dbg, &fde_table, + table_real_data_size, error); + if (res != DW_DLV_OK) + return res; + if (table_column >= table_real_data_size) { + dwarf_free_fde_table(&fde_table); + _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD); + return (DW_DLV_ERROR); + } + + /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks + */ + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table, + dbg->de_frame_cfa_col_number, + error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + if (register_num != NULL) + *register_num = fde_table.fr_reg[table_column].ru_register; + if (offset_or_block_len != NULL) + *offset_or_block_len = + fde_table.fr_reg[table_column].ru_offset_or_block_len; + if (row_pc_out != NULL) + *row_pc_out = fde_table.fr_loc; + if (block_ptr) + *block_ptr = fde_table.fr_reg[table_column].ru_block; + + /* Without value_type the data cannot be understood, so we insist + on it being present, we don't test it. */ + *value_type = fde_table.fr_reg[table_column].ru_value_type; + *offset_relevant = (fde_table.fr_reg[table_column].ru_is_off); + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; + +} + +/* For latest DWARF, this is the preferred interface. + It more portably deals with the CFA by not + making the CFA a column number, which means + DW_FRAME_CFA_COL3 becomes, like DW_CFA_SAME_VALUE, + a special value, not something one uses as an index. + + Call dwarf_set_frame_cfa_value() to set the correct column + after calling dwarf_init() + (DW_FRAME_CFA_COL3 is a sensible column to use, and + is the default unless '--enable-oldframecol' + is used to configure libdwarf). */ +int +dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Small * value_type, + Dwarf_Signed * offset_relevant, + Dwarf_Signed * register_num, + Dwarf_Signed * offset_or_block_len, + Dwarf_Ptr * block_ptr, + Dwarf_Addr * row_pc_out, + Dwarf_Error * error) +{ + struct Dwarf_Frame_s fde_table; + int res = DW_DLV_ERROR; + Dwarf_Debug dbg = 0; + + int table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + table_real_data_size = dbg->de_frame_reg_rules_entry_count; + res = dwarf_initialize_fde_table(dbg, &fde_table, + table_real_data_size, error); + if (res != DW_DLV_OK) + return res; + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table, + dbg->de_frame_cfa_col_number,error); + if (res != DW_DLV_OK) { + dwarf_free_fde_table(&fde_table); + return res; + } + + if (register_num != NULL) + *register_num = fde_table.fr_cfa_rule.ru_register; + if (offset_or_block_len != NULL) + *offset_or_block_len = + fde_table.fr_cfa_rule.ru_offset_or_block_len; + if (row_pc_out != NULL) + *row_pc_out = fde_table.fr_loc; + if (block_ptr) + *block_ptr = fde_table.fr_cfa_rule.ru_block; + + /* Without value_type the data cannot be understood, so we insist + on it being present, we don't test it. */ + *value_type = fde_table.fr_cfa_rule.ru_value_type; + *offset_relevant = fde_table.fr_cfa_rule.ru_is_off; + dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + + + +/* Return pointer to the instructions in the dwarf fde. */ +int +dwarf_get_fde_instr_bytes(Dwarf_Fde inFde, Dwarf_Ptr * outinstraddr, + Dwarf_Unsigned * outaddrlen, + Dwarf_Error * error) +{ + Dwarf_Unsigned len = 0; + unsigned char *instrs = 0; + Dwarf_Debug dbg = 0; + + if (inFde == NULL) { + _dwarf_error(dbg, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + + dbg = inFde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(dbg, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + + instrs = inFde->fd_fde_instr_start; + + len = (inFde->fd_fde_start + inFde->fd_length + + inFde->fd_length_size + inFde->fd_extension_size) - instrs; + + *outinstraddr = instrs; + *outaddrlen = len; + return DW_DLV_OK; +} + +/* Allows getting an fde from its table via an index. + With more error checking than simply indexing oneself. */ +int +dwarf_get_fde_n(Dwarf_Fde * fde_data, + Dwarf_Unsigned fde_index, + Dwarf_Fde * returned_fde, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Signed fdecount = 0; + + if (fde_data == NULL) { + _dwarf_error(dbg, error, DW_DLE_FDE_PTR_NULL); + return (DW_DLV_ERROR); + } + + FDE_NULL_CHECKS_AND_SET_DBG(*fde_data, dbg); + /* Assumes fde_data table has at least one entry. */ + fdecount = fde_data[0]->fd_is_eh? + dbg->de_fde_count_eh:dbg->de_fde_count; + if (fde_index >= fdecount) { + return (DW_DLV_NO_ENTRY); + } + *returned_fde = (*(fde_data + fde_index)); + return DW_DLV_OK; +} + + +/* Lopc and hipc are extensions to the interface to + return the range of addresses that are described + by the returned fde. */ +int +dwarf_get_fde_at_pc(Dwarf_Fde * fde_data, + Dwarf_Addr pc_of_interest, + Dwarf_Fde * returned_fde, + Dwarf_Addr * lopc, + Dwarf_Addr * hipc, Dwarf_Error * error) +{ + Dwarf_Debug dbg = NULL; + Dwarf_Fde fde = NULL; + Dwarf_Fde entryfde = NULL; + Dwarf_Signed fdecount = 0; + + if (fde_data == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_PTR_NULL); + return (DW_DLV_ERROR); + } + + /* Assumes fde_data table has at least one entry. */ + entryfde = *fde_data; + FDE_NULL_CHECKS_AND_SET_DBG(entryfde, dbg); + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return (DW_DLV_ERROR); + } + fdecount = entryfde->fd_is_eh? + dbg->de_fde_count_eh:dbg->de_fde_count; + { + /* The fdes are sorted by their addresses. Binary search to + find correct fde. */ + Dwarf_Signed low = 0; + Dwarf_Signed high = fdecount - 1L; + Dwarf_Signed middle = 0; + Dwarf_Fde cur_fde; + + while (low <= high) { + middle = (low + high) / 2; + cur_fde = fde_data[middle]; + if (pc_of_interest < cur_fde->fd_initial_location) { + high = middle - 1; + } else if (pc_of_interest >= + (cur_fde->fd_initial_location + + cur_fde->fd_address_range)) { + low = middle + 1; + } else { + fde = fde_data[middle]; + break; + } + } + } + + if (fde) { + if (lopc != NULL) + *lopc = fde->fd_initial_location; + if (hipc != NULL) + *hipc = + fde->fd_initial_location + fde->fd_address_range - 1; + *returned_fde = fde; + return (DW_DLV_OK); + } + + return (DW_DLV_NO_ENTRY); +} + + +/* Expands a single frame instruction block + from a specific cie + into a n array of Dwarf_Frame_Op-s. + This depends on having the cfa column set sensibly. + + Call dwarf_set_frame_cfa_value() to set the correct column + after calling dwarf_init() unless you are using + the old MIPS frame interfaces (in which case the default + will be ok). (DW_FRAME_CFA_COL3 is a sensible column to use ). +*/ +int +dwarf_expand_frame_instructions(Dwarf_Cie cie, + Dwarf_Ptr instruction, + Dwarf_Unsigned i_length, + Dwarf_Frame_Op ** returned_op_list, + Dwarf_Signed * returned_op_count, + Dwarf_Error * error) +{ + Dwarf_Sword instr_count; + int res = DW_DLV_ERROR; + int dw_err; + Dwarf_Debug dbg = 0; + + if (cie == 0) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + dbg = cie->ci_dbg; + + if (returned_op_list == 0 || returned_op_count == 0) { + _dwarf_error(dbg, error, DW_DLE_RET_OP_LIST_NULL); + return (DW_DLV_ERROR); + } + + /* The cast to Dwarf_Ptr may get a compiler warning, but it is safe + as it is just an i_length offset from 'instruction' itself. A + caller has made a big mistake if the result is not a valid + pointer. */ + res = _dwarf_exec_frame_instr( /* make_instr= */ true, + returned_op_list, + /* search_pc */ false, + /* search_pc_val */ 0, + /* location */ 0, + instruction, + (Dwarf_Ptr) ((Dwarf_Unsigned) instruction + i_length), + /* Dwarf_Frame */ NULL, + cie, + dbg, + dbg->de_frame_cfa_col_number, &instr_count, + &dw_err); + if (res != DW_DLV_OK) { + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, error, dw_err); + } + return (res); + } + + *returned_op_count = instr_count; + return DW_DLV_OK; +} + + +/* Used by dwarfdump -v to print offsets, for debugging + dwarf info. + The dwarf_ version is preferred over the obsolete _dwarf version. + _dwarf version kept for compatibility. +*/ +/* ARGSUSED 4 */ +int +_dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde, + Dwarf_Off * fde_off, Dwarf_Off * cie_off, + Dwarf_Error * err) +{ + return dwarf_fde_section_offset(dbg,in_fde,fde_off, + cie_off,err); +} +/* ARGSUSED 4 */ +int +dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde, + Dwarf_Off * fde_off, Dwarf_Off * cie_off, + Dwarf_Error * err) +{ + char *start = 0; + char *loc = 0; + + + + start = (char *) in_fde->fd_section_ptr; + loc = (char *) in_fde->fd_fde_start; + + *fde_off = (loc - start); + *cie_off = in_fde->fd_cie_offset; + return DW_DLV_OK; +} + +/* Used by dwarfdump -v to print offsets, for debugging + dwarf info. + The dwarf_ version is preferred over the obsolete _dwarf version. + _dwarf version kept for compatibility. +*/ +/* ARGSUSED 4 */ +int +_dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie, + Dwarf_Off * cie_off, Dwarf_Error * err) +{ + return dwarf_cie_section_offset(dbg,in_cie,cie_off,err); +} +/* ARGSUSED 4 */ +int +dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie, + Dwarf_Off * cie_off, Dwarf_Error * err) +{ + char *start = 0; + char *loc = 0; + + start = (char *) in_cie->ci_section_ptr; + loc = (char *) in_cie->ci_cie_start; + + *cie_off = (loc - start); + return DW_DLV_OK; +} + +/* Returns a pointer to target-specific augmentation data thru augdata + and returns the length of the data thru augdata_len. + + It's up to the consumer code to know how to interpret the bytes + of target-specific data (endian issues apply too, these + are just raw bytes pointed to). + See Linux Standard Base Core Specification version 3.0 for + the details on .eh_frame info. + + Returns DW_DLV_ERROR if fde is NULL or some other serious + error. + Returns DW_DLV_NO_ENTRY if there is no target-specific + augmentation data. + + The bytes pointed to are in the Dwarf_Cie, and as long as that + is valid the bytes are there. No 'dealloc' call is needed + for the bytes. */ +int +dwarf_get_cie_augmentation_data(Dwarf_Cie cie, + Dwarf_Small ** augdata, + Dwarf_Unsigned * augdata_len, + Dwarf_Error * error) +{ + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return (DW_DLV_ERROR); + } + if (cie->ci_gnu_eh_augmentation_len == 0) { + return DW_DLV_NO_ENTRY; + } + *augdata = (Dwarf_Small *) (cie->ci_gnu_eh_augmentation_bytes); + *augdata_len = cie->ci_gnu_eh_augmentation_len; + return DW_DLV_OK; +} + + +/* Returns a pointer to target-specific augmentation data thru augdata + and returns the length of the data thru augdata_len. + + It's up to the consumer code to know how to interpret the bytes + of target-specific data (endian issues apply too, these + are just raw bytes pointed to). + See Linux Standard Base Core Specification version 3.0 for + the details on .eh_frame info. + + Returns DW_DLV_ERROR if fde is NULL or some other serious + error. + Returns DW_DLV_NO_ENTRY if there is no target-specific + augmentation data. + + The bytes pointed to are in the Dwarf_Fde, and as long as that + is valid the bytes are there. No 'dealloc' call is needed + for the bytes. */ +int +dwarf_get_fde_augmentation_data(Dwarf_Fde fde, + Dwarf_Small * *augdata, + Dwarf_Unsigned * augdata_len, + Dwarf_Error * error) +{ + Dwarf_Cie cie = 0; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return (DW_DLV_ERROR); + } + cie = fde->fd_cie; + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return (DW_DLV_ERROR); + } + if (cie->ci_gnu_eh_augmentation_len == 0) { + return DW_DLV_NO_ENTRY; + } + *augdata = (Dwarf_Small *) fde->fd_gnu_eh_augmentation_bytes; + *augdata_len = fde->fd_gnu_eh_augmentation_len; + return DW_DLV_OK; +} + + +#if 0 +/* Used solely for debugging libdwarf. */ +static void +dump_frame_rule(char *msg, struct Dwarf_Reg_Rule_s *reg_rule) +{ + printf + ("%s type %s (0x%" DW_PR_XZEROS DW_PR_DUx + "), is_off %" DW_PR_DUu + " reg %" DW_PR_DUu " offset 0x%" DW_PR_XZEROS DW_PR_DUx + " blockp 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + msg, + (reg_rule->ru_value_type == DW_EXPR_OFFSET) ? + "DW_EXPR_OFFSET" : + (reg_rule->ru_value_type == DW_EXPR_VAL_OFFSET) ? + "DW_EXPR_VAL_OFFSET" : + (reg_rule->ru_value_type == DW_EXPR_VAL_EXPRESSION) ? + "DW_EXPR_VAL_EXPRESSION" : + (reg_rule->ru_value_type == DW_EXPR_EXPRESSION) ? + "DW_EXPR_EXPRESSION" : "Unknown", + (Dwarf_Unsigned) reg_rule->ru_value_type, + (Dwarf_Unsigned) reg_rule->ru_is_off, + (Dwarf_Unsigned) reg_rule->ru_register, + (Dwarf_Unsigned) reg_rule->ru_offset_or_block_len, + (Dwarf_Unsigned) reg_rule->ru_block); + return; +} +#endif + +/* This allows consumers to set the 'initial value' so that + an ISA/ABI specific default can be used, dynamically, + at run time. Useful for dwarfdump and non-MIPS architectures.. + The value defaults to one of + DW_FRAME_SAME_VALUE or DW_FRAME_UNKNOWN_VALUE + but dwarfdump can dump multiple ISA/ABI objects so + we may want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. */ +Dwarf_Half +dwarf_set_frame_rule_initial_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_rule_initial_value; + dbg->de_frame_rule_initial_value = value; + return orig; +} + +/* The following spelling for backwards compatibility. */ +Dwarf_Half +dwarf_set_frame_rule_inital_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + return dwarf_set_frame_rule_initial_value(dbg,value); +} + +/* This allows consumers to set the array size of the reg rules + table so that + an ISA/ABI specific value can be used, dynamically, + at run time. Useful for non-MIPS archtectures. + The value defaults to DW_FRAME_LAST_REG_NUM. + but dwarfdump can dump multiple ISA/ABI objects so + consumers want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. +*/ + +Dwarf_Half +dwarf_set_frame_rule_table_size(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_reg_rules_entry_count; + dbg->de_frame_reg_rules_entry_count = value; + + /* Take the caller-specified value, but do not + let the value be too small. Keep it at least to + DW_FRAME_LAST_REG_NUM. + This helps prevent libdwarf (mistakenly) indexing outside + of of a register array when the ABI reg count is really small. */ + if (value < DW_FRAME_LAST_REG_NUM) { + dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM; + } + return orig; +} +/* This allows consumers to set the CFA register value + so that an ISA/ABI specific value can be used, dynamically, + at run time. Useful for non-MIPS archtectures. + The value defaults to DW_FRAME_CFA_COL3 and should be + higher than any real register in the ABI. + Dwarfdump can dump multiple ISA/ABI objects so + consumers want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. */ + +Dwarf_Half +dwarf_set_frame_cfa_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_cfa_col_number; + dbg->de_frame_cfa_col_number = value; + return orig; +} +/* Similar to above, but for the other crucial fields for frames. */ +Dwarf_Half +dwarf_set_frame_same_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_same_value_number; + dbg->de_frame_same_value_number = value; + return orig; +} +Dwarf_Half +dwarf_set_frame_undefined_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_same_value_number; + dbg->de_frame_undefined_value_number = value; + return orig; +} + +/* Does something only if value passed in is greater than 0 and + a size than we can handle (in number of bytes). */ +Dwarf_Small dwarf_set_default_address_size(Dwarf_Debug dbg, + Dwarf_Small value ) +{ + Dwarf_Small orig = dbg->de_pointer_size; + if (value > 0 && value <= sizeof(Dwarf_Addr)) { + dbg->de_pointer_size = value; + } + return orig; +} + +static int +init_reg_rules_alloc(Dwarf_Debug dbg,struct Dwarf_Frame_s *f, + unsigned count, Dwarf_Error * error) +{ + f->fr_reg_count = count; + f->fr_reg = (struct Dwarf_Reg_Rule_s *) + calloc(sizeof(struct Dwarf_Reg_Rule_s), count); + if (f->fr_reg == 0) { + if(error) { + _dwarf_error(dbg, error, DW_DLE_DF_ALLOC_FAIL); + } + return (DW_DLV_ERROR); + } + dwarf_init_reg_rules_ru(f->fr_reg,0, count, + dbg->de_frame_rule_initial_value); + return DW_DLV_OK; +} +static int +dwarf_initialize_fde_table(Dwarf_Debug dbg, + struct Dwarf_Frame_s *fde_table, + unsigned table_real_data_size, + Dwarf_Error * error) +{ + unsigned entry_size = sizeof(struct Dwarf_Frame_s); + memset(fde_table,0,entry_size); + fde_table->fr_loc = 0; + fde_table->fr_next = 0; + + return init_reg_rules_alloc(dbg,fde_table,table_real_data_size,error); +} +static void +dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table) +{ + free(fde_table->fr_reg); + fde_table->fr_reg_count = 0; + fde_table->fr_reg = 0; +} + + +/* Return DW_DLV_OK if we succeed. else return DW_DLV_ERROR. +*/ +int +_dwarf_frame_constructor(Dwarf_Debug dbg, void *frame) +{ + struct Dwarf_Frame_s *fp = frame; + + if (!dbg) { + return DW_DLV_ERROR; + } + return init_reg_rules_alloc(dbg,fp,dbg->de_frame_reg_rules_entry_count, 0); +} + +void +_dwarf_frame_destructor(void *frame) +{ + struct Dwarf_Frame_s *fp = frame; + dwarf_free_fde_table(fp); +} + +static void +dwarf_init_reg_rules_ru(struct Dwarf_Reg_Rule_s *base, + unsigned first, unsigned last,int initial_value) +{ + struct Dwarf_Reg_Rule_s *r = base+first; + unsigned i = first; + for( ; i < last; ++i,++r) { + r->ru_is_off = 0; + r->ru_value_type = DW_EXPR_OFFSET; + r->ru_register = initial_value; + r->ru_offset_or_block_len = 0; + r->ru_block = 0; + } +} +static void +dwarf_init_reg_rules_dw(struct Dwarf_Regtable_Entry_s *base, + unsigned first, unsigned last,int initial_value) +{ + struct Dwarf_Regtable_Entry_s *r = base+first; + unsigned i = first; + for( ; i < last; ++i,++r) { + r->dw_offset_relevant = 0; + r->dw_value_type = DW_EXPR_OFFSET; + r->dw_regnum = initial_value; + r->dw_offset = 0; + } +} +static void +dwarf_init_reg_rules_dw3(struct Dwarf_Regtable_Entry3_s *base, + unsigned first, unsigned last,int initial_value) +{ + struct Dwarf_Regtable_Entry3_s *r = base+first; + unsigned i = first; + for( ; i < last; ++i,++r) { + r->dw_offset_relevant = 0; + r->dw_value_type = DW_EXPR_OFFSET; + r->dw_regnum = initial_value; + r->dw_offset_or_block_len = 0; + r->dw_block_ptr = 0; + } +} diff --git a/libdwarf/dwarf_frame.h b/libdwarf/dwarf_frame.h new file mode 100644 index 0000000..61d2a56 --- /dev/null +++ b/libdwarf/dwarf_frame.h @@ -0,0 +1,419 @@ +/* + + Copyright (C) 2000, 2004, 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +/* The dwarf 2.0 standard dictates that only the following + fields can be read when an unexpected augmentation string + (in the cie) is encountered: CIE length, CIE_id, version and + augmentation; FDE: length, CIE pointer, initial location and + address range. Unfortunately, with the above restrictions, it + is impossible to read the instruction table from a CIE or a FDE + when a new augmentation string is encountered. + To fix this problem, the following layout is used, if the + augmentation string starts with the string "z". + CIE FDE + length length + CIE_id CIE_pointer + version initial_location + augmentation address_range + + - length_of_augmented_fields (*NEW*) + code_alignment_factor Any new fields as necessary + data_alignment_factor instruction_table + return_address + length_of_augmented fields + Any new fields as necessary + initial_instructions + + The type of all the old data items are the same as what is + described in dwarf 2.0 standard. The length_of_augmented_fields + is an LEB128 data item that denotes the size (in bytes) of + the augmented fields (not including the size of + "length_of_augmented_fields" itself). + + Handling of cie augmentation strings is necessarly a heuristic. + See dwarf_frame.c for the currently known augmentation strings. + + + ---START SGI-ONLY COMMENT: + SGI-IRIX versions of cie or fde were intended to use "z1", "z2" as the + augmenter strings if required for new augmentation. + However, that never happened (as of March 2005). + + The fde's augmented by the string "z" have a new field + (signed constant, 4 byte field) + called offset_into_exception_tables, following the + length_of_augmented field. This field contains an offset + into the "_MIPS_eh_region", which describes + the IRIX CC exception handling tables. + ---END SGI-ONLY COMMENT + + + GNU .eh_frame has an augmentation string of z[RLP]* (gcc 3.4) + The similarity to IRIX 'z' (and proposed but never + implemented IRIX z1, z2 etc) was confusing things. + If the section is .eh_frame then 'z' means GNU exception + information 'Augmentation Data' not IRIX 'z'. + See The Linux Standard Base Core Specification version 3.0 +*/ + +#define DW_DEBUG_FRAME_VERSION 1 /* DWARF2 */ +#define DW_DEBUG_FRAME_VERSION3 3 /* DWARF3 */ +#define DW_DEBUG_FRAME_VERSION4 4 /* DWARF4 */ +/* The following is SGI/IRIX specific, and probably no longer + in use anywhere. */ +#define DW_DEBUG_FRAME_AUGMENTER_STRING "mti v1" + +/* The value of the offset field for Cie's. */ +#define DW_CIE_OFFSET ~(0x0) + +/* The augmentation string may be NULL. */ +#define DW_EMPTY_STRING "" + +#define DW_FRAME_INSTR_OPCODE_SHIFT 6 +#define DW_FRAME_INSTR_OFFSET_MASK 0x3f + +/* + This struct denotes the rule for a register in a row of + the frame table. In other words, it is one element of + the table. +*/ +struct Dwarf_Reg_Rule_s { + + /* Is a flag indicating whether the rule includes the offset + field, ie whether the ru_offset field is valid or not. + Applies only if DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET. + It is important, since reg+offset (offset of 0) is different from + just 'register' since the former means 'read memory at address + given by the sum of register contents plus offset to get the + value'. whereas the latter means 'the value is in the register'. + + The 'register' numbers are either real registers (ie, table + columns defined as real registers) or defined entries that are + not really hardware registers, such as DW_FRAME_SAME_VAL or + DW_FRAME_CFA_COL. */ + Dwarf_Sbyte ru_is_off; + + /* DW_EXPR_OFFSET (0, DWARF2) + DW_EXPR_VAL_OFFSET 1 (dwarf2/3) + DW_EXPR_EXPRESSION 2 (dwarf2/3) + DW_EXPR_VAL_EXPRESSION 3 (dwarf2/3) + See dwarf_frame.h. */ + Dwarf_Sbyte ru_value_type; + + /* Register involved in this rule. */ + Dwarf_Half ru_register; + + /* Offset to add to register, if indicated by ru_is_offset + and if DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET. + If DW_EXPR_EXPRESSION or DW_EXPR_VAL_EXPRESSION + this is DW_FORM_block block-length, not offset. */ + Dwarf_Unsigned ru_offset_or_block_len; + + /* For DW_EXPR_EXPRESSION DW_EXPR_VAL_EXPRESSION these is set, + else 0. */ + Dwarf_Small *ru_block; +}; + +typedef struct Dwarf_Frame_s *Dwarf_Frame; + +/* + This structure represents a row of the frame table. + Fr_loc is the pc value for this row, and Fr_reg + contains the rule for each column. + + Entry DW_FRAME_CFA_COL of fr_reg was the tradional MIPS + way of setting CFA. cfa_rule is the new one. +*/ +struct Dwarf_Frame_s { + + /* Pc value corresponding to this row of the frame table. */ + Dwarf_Addr fr_loc; + + /* Rules for all the registers in this row. */ + struct Dwarf_Reg_Rule_s fr_cfa_rule; + + /* fr_reg_count is the the number of + entries of the fr_reg array. */ + unsigned long fr_reg_count; + struct Dwarf_Reg_Rule_s *fr_reg; + + Dwarf_Frame fr_next; +}; + +typedef struct Dwarf_Frame_Op_List_s *Dwarf_Frame_Op_List; + +/* This is used to chain together Dwarf_Frame_Op structures. */ +struct Dwarf_Frame_Op_List_s { + Dwarf_Frame_Op *fl_frame_instr; + Dwarf_Frame_Op_List fl_next; +}; + +/* See dwarf_frame.c for the heuristics used to set the + Dwarf_Cie ci_augmentation_type. + + This succinctly helps interpret the size and meaning of .debug_frame + and (for gcc) .eh_frame. + + In the case of gcc .eh_frame (gcc 3.3, 3.4) + z may be followed by one or more of + L R P. + +*/ +enum Dwarf_augmentation_type { + aug_empty_string, /* Default empty augmentation string. */ + aug_irix_exception_table, /* IRIX plain "z", + for exception handling, IRIX CC compiler. + Proposed z1 z2 ... never implemented. */ + aug_gcc_eh_z, /* gcc z augmentation, (including + L R P variations). gcc 3.3 3.4 exception + handling in eh_frame. */ + aug_irix_mti_v1, /* IRIX "mti v1" augmentation string. Probably + never in any released SGI-IRIX compiler. */ + aug_eh, /* For gcc .eh_frame, "eh" is the string., + gcc 1,2, egcs. Older values. */ + aug_armcc, /* "armcc+" meaning the cfa calculation + is corrected to be standard (output by + Arm C RVCT 3.0 SP1 and later). See + http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html + for details. */ + aug_unknown, /* Unknown augmentation, we cannot do much. */ + aug_past_last +}; + + +/* + This structure contains all the pertinent info for a Cie. Most + of the fields are taken straight from the definition of a Cie. + Ci_cie_start points to the address (in .debug_frame) where this + Cie begins. Ci_cie_instr_start points to the first byte of the + frame instructions for this Cie. Ci_dbg points to the associated + Dwarf_Debug structure. Ci_initial_table is a pointer to the table + row generated by the instructions for this Cie. +*/ +struct Dwarf_Cie_s { + Dwarf_Unsigned ci_length; + char *ci_augmentation; + Dwarf_Small ci_code_alignment_factor; + Dwarf_Sbyte ci_data_alignment_factor; + Dwarf_Small ci_return_address_register; + Dwarf_Small *ci_cie_start; + Dwarf_Small *ci_cie_instr_start; + Dwarf_Debug ci_dbg; + Dwarf_Frame ci_initial_table; + Dwarf_Cie ci_next; + Dwarf_Small ci_length_size; + Dwarf_Small ci_extension_size; + Dwarf_Half ci_cie_version_number; + enum Dwarf_augmentation_type ci_augmentation_type; + + /* The following 2 for GNU .eh_frame exception handling + Augmentation Data. Set if ci_augmentation_type + is aug_gcc_eh_z. Zero if unused. */ + Dwarf_Unsigned ci_gnu_eh_augmentation_len; + Dwarf_Ptr ci_gnu_eh_augmentation_bytes; + + /* These are extracted from the gnu eh_frame + augmentation if the + augmentation begins with 'z'. See Linux LSB documents. + Otherwize these are zero. */ + unsigned char ci_gnu_personality_handler_encoding; + unsigned char ci_gnu_lsda_encoding; + unsigned char ci_gnu_fde_begin_encoding; + + /* If 'P' augmentation present, is handler addr. Else + is zero. */ + Dwarf_Addr ci_gnu_personality_handler_addr; + + + /* In creating list of cie's (which will become an array) + record the position so fde can get it on fde creation. */ + Dwarf_Unsigned ci_index; + Dwarf_Small * ci_section_ptr; + /* DWARF4 adds address size and segment size to the CIE: the .debug_info + section may not always be present to allow libdwarf to + find address_size from the compilation-unit. */ + Dwarf_Half ci_address_size; + Dwarf_Half ci_segment_size; + +}; + +/* + This structure contains all the pertinent info for a Fde. + Most of the fields are taken straight from the definition. + fd_cie_index is the index of the Cie associated with this + Fde in the list of Cie's for this debug_frame. Fd_cie + points to the corresponsing Dwarf_Cie structure. Fd_fde_start + points to the start address of the Fde. Fd_fde_instr_start + points to the start of the instructions for this Fde. Fd_dbg + points to the associated Dwarf_Debug structure. +*/ +struct Dwarf_Fde_s { + Dwarf_Unsigned fd_length; + Dwarf_Addr fd_cie_offset; + Dwarf_Unsigned fd_cie_index; + Dwarf_Cie fd_cie; + Dwarf_Addr fd_initial_location; + Dwarf_Small *fd_initial_loc_pos; + Dwarf_Addr fd_address_range; + Dwarf_Small *fd_fde_start; + Dwarf_Small *fd_fde_instr_start; + Dwarf_Debug fd_dbg; + + /* fd_offset_into_exception_tables is SGI/IRIX exception table + offset. Unused and zero if not IRIX .debug_frame. */ + Dwarf_Signed fd_offset_into_exception_tables; + + Dwarf_Fde fd_next; + Dwarf_Small fd_length_size; + Dwarf_Small fd_extension_size; + /* So we know from an fde which 'count' of fde-s in + Dwarf_Debug applies: eh or standard. */ + Dwarf_Small fd_is_eh; + /* The following 2 for GNU .eh_frame exception handling + Augmentation Data. Set if CIE ci_augmentation_type + is aug_gcc_eh_z. Zero if unused. */ + Dwarf_Unsigned fd_gnu_eh_augmentation_len; + Dwarf_Ptr fd_gnu_eh_augmentation_bytes; + Dwarf_Addr fd_gnu_eh_lsda; /* If 'L' augmentation letter + present: is address of the + Language Specific Data Area (LSDA). If not 'L" is zero. */ + + /* The following 3 are about the Elf section the FDEs come from. */ + Dwarf_Small * fd_section_ptr; + Dwarf_Unsigned fd_section_length; + Dwarf_Unsigned fd_section_index; + +}; + + +int +_dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist, + Dwarf_Off ** offsetlist, + Dwarf_Signed * returncount, + Dwarf_Error * err); + +int +_dwarf_get_fde_list_internal(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Unsigned cie_id_value, + int use_gnu_cie_calc, /* If non-zero, + this is gcc eh_frame. */ + Dwarf_Error * error); + +enum Dwarf_augmentation_type +_dwarf_get_augmentation_type(Dwarf_Debug dbg, + Dwarf_Small *augmentation_string, + int is_gcc_eh_frame); + +Dwarf_Unsigned _dwarf_get_return_address_reg(Dwarf_Small *frame_ptr, + int version, + unsigned long *size); + +/* Temporary recording of crucial cie/fde prefix data. + Vastly simplifies some argument lists. */ +struct cie_fde_prefix_s { + /* cf_start_addr is a pointer to the first byte of this fde/cie + we are reading now. */ + Dwarf_Small * cf_start_addr; + Dwarf_Small * cf_addr_after_prefix; + Dwarf_Unsigned cf_length; + int cf_local_length_size; + int cf_local_extension_size; + Dwarf_Unsigned cf_cie_id; + Dwarf_Small * cf_cie_id_addr; /* used for eh_frame calculations. */ + + /* Simplifies passing around these values to create fde having + these here. */ + /* cf_section_ptr is a pointer to the first byte + of the object section the prefix is read from. */ + Dwarf_Small * cf_section_ptr; + Dwarf_Unsigned cf_section_index; + Dwarf_Unsigned cf_section_length; +}; + +int +_dwarf_exec_frame_instr(Dwarf_Bool make_instr, + Dwarf_Frame_Op ** ret_frame_instr, + Dwarf_Bool search_pc, + Dwarf_Addr search_pc_val, + Dwarf_Addr initial_loc, + Dwarf_Small * start_instr_ptr, + Dwarf_Small * final_instr_ptr, + Dwarf_Frame table, + Dwarf_Cie cie, + Dwarf_Debug dbg, + Dwarf_Half reg_num_of_cfa, + Dwarf_Sword * returned_count, + int *returned_error); + + +int dwarf_read_cie_fde_prefix(Dwarf_Debug dbg, + Dwarf_Small *frame_ptr_in, + Dwarf_Small *section_ptr_in, + Dwarf_Unsigned section_index_in, + Dwarf_Unsigned section_length_in, + struct cie_fde_prefix_s *prefix_out, + Dwarf_Error *error); + +int dwarf_create_fde_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s * prefix, + Dwarf_Small *section_pointer, + Dwarf_Small *frame_ptr, + int use_gnu_cie_calc, + Dwarf_Cie cie_ptr_in, + Dwarf_Fde *fde_ptr_out, + Dwarf_Error *error); + +int dwarf_create_cie_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s *prefix, + Dwarf_Small* section_pointer, + Dwarf_Small* frame_ptr, + Dwarf_Unsigned cie_count, + int use_gnu_cie_calc, + Dwarf_Cie *cie_ptr_out, + Dwarf_Error *error); + + +int _dwarf_frame_constructor(Dwarf_Debug dbg,void * ); +void _dwarf_frame_destructor (void *); diff --git a/libdwarf/dwarf_frame2.c b/libdwarf/dwarf_frame2.c new file mode 100644 index 0000000..870442d --- /dev/null +++ b/libdwarf/dwarf_frame2.c @@ -0,0 +1,1531 @@ +/* + + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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. +*/ + + +/* This implements _dwarf_get_fde_list_internal() + and related helper functions for reading cie/fde data. */ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <stdlib.h> +#include "dwarf_frame.h" +#include "dwarf_arange.h" /* using Arange as a way to build a list */ + + +static int dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr, + Dwarf_Cie cur_cie_ptr, + Dwarf_Cie * cie_ptr_to_use_out, + Dwarf_Cie head_cie_ptr); +static void dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr, + Dwarf_Cie head_cie_ptr); +static int dwarf_create_cie_from_start(Dwarf_Debug dbg, + Dwarf_Small * cie_ptr_val, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Small * frame_ptr_end, + Dwarf_Unsigned cie_id_value, + Dwarf_Unsigned cie_count, +int use_gnu_cie_calc, +Dwarf_Cie * cie_ptr_to_use_out, +Dwarf_Error * error); + +static Dwarf_Small *get_cieptr_given_offset(Dwarf_Unsigned cie_id_value, + int use_gnu_cie_calc, + Dwarf_Small * section_ptr, + Dwarf_Small * cie_id_addr); +static int get_gcc_eh_augmentation(Dwarf_Debug dbg, + Dwarf_Small * frame_ptr, + unsigned long + *size_of_augmentation_data, + enum Dwarf_augmentation_type augtype, + Dwarf_Small * section_pointer, + Dwarf_Small * fde_eh_encoding_out, + char *augmentation); + +static int +gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation, + Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len, + Dwarf_Half address_size, + unsigned char *pers_hand_enc_out, + unsigned char *lsda_enc_out, + unsigned char *fde_begin_enc_out, + Dwarf_Addr * gnu_pers_addr_out); + + +static int read_encoded_ptr(Dwarf_Debug dbg, + Dwarf_Small * section_pointer, + Dwarf_Small * input_field, + int gnu_encoding, + Dwarf_Half address_size, + Dwarf_Unsigned * addr, + Dwarf_Small ** input_field_out); + + + +static int qsort_compare(const void *elem1, const void *elem2); + + +/* Adds 'newone' to the end of the list starting at 'head' + and makes the new one 'cur'rent. */ +static void +chain_up_fde(Dwarf_Fde newone, Dwarf_Fde * head, Dwarf_Fde * cur) +{ + if (*head == NULL) + *head = newone; + else { + (*cur)->fd_next = newone; + } + *cur = newone; + +} + +/* Adds 'newone' to the end of the list starting at 'head' + and makes the new one 'cur'rent. */ +static void +chain_up_cie(Dwarf_Cie newone, Dwarf_Cie * head, Dwarf_Cie * cur) +{ + if (*head == NULL) { + *head = newone; + } else { + (*cur)->ci_next = newone; + } + *cur = newone; +} + +/* The size of the length field plus the + value of length must be an integral + multiple of the address size. Dwarf4 standard. + + A constant that gives the number of bytes of the CIE + structure, not including the length field itself + (where length mod <size of an address> == 0) + (see Section 7.2.2). Dwarf3 standard. + + A uword constant that gives the number of bytes of + the CIE structure, not including the + length field, itself (length mod <addressing unit size> == 0). + Dwarf2 standard.*/ +static void +validate_length(Dwarf_Debug dbg, + Dwarf_Cie cieptr, Dwarf_Unsigned length, + Dwarf_Unsigned length_size, + Dwarf_Unsigned extension_size, + Dwarf_Small * section_ptr, + Dwarf_Small * ciefde_start, + const char * cieorfde) +{ + Dwarf_Unsigned address_size = cieptr->ci_address_size; + Dwarf_Unsigned length_field_summed = length_size + extension_size; + Dwarf_Unsigned total_len = length + length_field_summed; + Dwarf_Unsigned mod = total_len % address_size; + + if (mod != 0) { + char msg[DW_HARMLESS_ERROR_MSG_STRING_SIZE]; + Dwarf_Unsigned sectionoffset = ciefde_start - section_ptr; + snprintf(msg,sizeof(msg), + "DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE" + " len=0x%" DW_PR_XZEROS DW_PR_DUx + ", len size=0x%" DW_PR_XZEROS DW_PR_DUx + ", extn size=0x%" DW_PR_XZEROS DW_PR_DUx + ", totl length=0x%" DW_PR_XZEROS DW_PR_DUx + ", addr size=0x%" DW_PR_XZEROS DW_PR_DUx + ", mod=0x%" DW_PR_XZEROS DW_PR_DUx " must be zero" + " in %s" + ", offset 0x%" DW_PR_XZEROS DW_PR_DUx ".", + length, + length_size, + extension_size, + total_len,address_size, mod, + cieorfde, + sectionoffset); + dwarf_insert_harmless_error(dbg,msg); + } + return; +} + + +#if 0 +/* For debugging only. */ +static void +print_prefix(struct cie_fde_prefix_s *prefix, int line) +{ + printf("prefix-print, prefix at 0x%lx, line %d\n", + (long) prefix, line); + printf(" start addr 0x%lx after prefix 0x%lx\n", + (long) prefix->cf_start_addr, + (long) prefix->cf_addr_after_prefix); + printf(" length 0x%" DW_PR_DUx ", len size %d ext size %d\n", + (Dwarf_Unsigned) prefix->cf_length, + prefix->cf_local_length_size, + prefix->cf_local_extension_size); + printf(" cie_id 0x%" DW_PR_DUx " cie_id cie_id_addr 0x%lx\n", + (Dwarf_Unsigned) prefix->cf_cie_id, + (long) prefix->cf_cie_id_addr); + printf + (" sec ptr 0x%lx sec index %" DW_PR_DSd " sec len 0x%" DW_PR_DUx " sec past end 0x%lx\n", + (long) prefix->cf_section_ptr, + (Dwarf_Signed) prefix->cf_section_index, + (Dwarf_Unsigned) prefix->cf_section_length, + (long) prefix->cf_section_ptr + prefix->cf_section_length); +} +#endif + + + +/* Internal function called from various places to create + lists of CIEs and FDEs. Not directly called + by consumer code */ +int +_dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Unsigned cie_id_value, + int use_gnu_cie_calc, Dwarf_Error * error) +{ + /* Scans the debug_frame section. */ + Dwarf_Small *frame_ptr = section_ptr; + Dwarf_Small *frame_ptr_end = section_ptr + section_length; + + + + /* New_cie points to the Cie being read, and head_cie_ptr and + cur_cie_ptr are used for chaining them up in sequence. + In case cie's are reused aggressively we need tail_cie_ptr + to add to the chain. If we re-use an early cie + later on, that does not mean we chain a new cie to the early one, + we always chain it to the tail. */ + Dwarf_Cie head_cie_ptr = NULL; + Dwarf_Cie cur_cie_ptr = NULL; + Dwarf_Cie tail_cie_ptr = NULL; + Dwarf_Word cie_count = 0; + + /* Points to a list of contiguous pointers to Dwarf_Cie structures. + */ + Dwarf_Cie *cie_list_ptr = 0; + + + /* New_fde points to the Fde being created, and head_fde_ptr and + cur_fde_ptr are used to chain them up. */ + Dwarf_Fde head_fde_ptr = NULL; + Dwarf_Fde cur_fde_ptr = NULL; + Dwarf_Word fde_count = 0; + + /* Points to a list of contiguous pointers to Dwarf_Fde structures. + */ + Dwarf_Fde *fde_list_ptr = NULL; + + Dwarf_Word i = 0; + int res = DW_DLV_ERROR; + + if (frame_ptr == 0) { + return DW_DLV_NO_ENTRY; + } + + /* We create the fde and cie arrays. Processing each CIE as we come + to it or as an FDE refers to it. We cannot process 'late' CIEs + late as GNU .eh_frame complexities mean we need the whole CIE + before we can process the FDE correctly. */ + while (frame_ptr < frame_ptr_end) { + + struct cie_fde_prefix_s prefix; + + /* First read in the 'common prefix' to figure out what we are + to do with this entry. */ + memset(&prefix, 0, sizeof(prefix)); + res = dwarf_read_cie_fde_prefix(dbg, + frame_ptr, section_ptr, + section_index, + section_length, &prefix, error); + if (res == DW_DLV_ERROR) { + dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr); + return res; + } + if (res == DW_DLV_NO_ENTRY) + break; + frame_ptr = prefix.cf_addr_after_prefix; + if (frame_ptr >= frame_ptr_end) { + dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr); + _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + + } + + if (prefix.cf_cie_id == cie_id_value) { + /* This is a CIE. */ + Dwarf_Cie cie_ptr_to_use = 0; + + int res = dwarf_find_existing_cie_ptr(prefix.cf_start_addr, + cur_cie_ptr, + &cie_ptr_to_use, + head_cie_ptr); + if (res == DW_DLV_OK) { + cur_cie_ptr = cie_ptr_to_use; + /* Ok. Seen already. */ + } else if (res == DW_DLV_NO_ENTRY) { + /* CIE before its FDE in this case. */ + res = dwarf_create_cie_from_after_start(dbg, + &prefix, + section_ptr, + frame_ptr, + cie_count, + use_gnu_cie_calc, + &cie_ptr_to_use, + error); + /* ASSERT: res==DW_DLV_NO_ENTRY impossible. */ + if (res == DW_DLV_ERROR) { + dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return res; + } + /* ASSERT res != DW_DLV_NO_ENTRY */ + cie_count++; + chain_up_cie(cie_ptr_to_use, &head_cie_ptr, + &tail_cie_ptr); + cur_cie_ptr = tail_cie_ptr; + } else { /* res == DW_DLV_ERROR */ + + dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return res; + } + frame_ptr = cie_ptr_to_use->ci_cie_start + + cie_ptr_to_use->ci_length + + cie_ptr_to_use->ci_length_size + + cie_ptr_to_use->ci_extension_size; + continue; + } else { + /* This is an FDE, Frame Description Entry, see the Dwarf + Spec, section 6.4.1 */ + int res = DW_DLV_ERROR; + Dwarf_Cie cie_ptr_to_use = 0; + Dwarf_Fde fde_ptr_to_use = 0; + + /* Do not call this twice on one prefix, as + prefix.cf_cie_id_addr is altered as a side effect. */ + Dwarf_Small *cieptr_val = + get_cieptr_given_offset(prefix.cf_cie_id, + use_gnu_cie_calc, + section_ptr, + prefix.cf_cie_id_addr); + + res = dwarf_find_existing_cie_ptr(cieptr_val, + cur_cie_ptr, + &cie_ptr_to_use, + head_cie_ptr); + if (res == DW_DLV_OK) { + cur_cie_ptr = cie_ptr_to_use; + /* Ok. Seen CIE already. */ + } else if (res == DW_DLV_NO_ENTRY) { + res = dwarf_create_cie_from_start(dbg, + cieptr_val, + section_ptr, + section_index, + section_length, + frame_ptr_end, + cie_id_value, + cie_count, + use_gnu_cie_calc, + &cie_ptr_to_use, + error); + if (res == DW_DLV_ERROR) { + dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return res; + } else if (res == DW_DLV_NO_ENTRY) { + return res; + } + ++cie_count; + chain_up_cie(cie_ptr_to_use, &head_cie_ptr, + &tail_cie_ptr); + cur_cie_ptr = tail_cie_ptr; + + } else { + /* DW_DLV_ERROR */ + return res; + } + + res = dwarf_create_fde_from_after_start(dbg, + &prefix, + section_ptr, + frame_ptr, + use_gnu_cie_calc, + cie_ptr_to_use, + &fde_ptr_to_use, + error); + if (res == DW_DLV_ERROR) { + return res; + } + chain_up_fde(fde_ptr_to_use, &head_fde_ptr, &cur_fde_ptr); + fde_count++; + /* ASSERT: DW_DLV_OK. */ + frame_ptr = fde_ptr_to_use->fd_fde_start + + fde_ptr_to_use->fd_length + + fde_ptr_to_use->fd_length_size + + fde_ptr_to_use->fd_extension_size; + if (frame_ptr < fde_ptr_to_use->fd_fde_instr_start) { + /* Sanity check. With a really short fde instruction + set and address_size we think is 8 + as it is ELF64 (but is + really 4, as in DWARF{2,3} where we have + no FDE address_size) we emit an error. + This error means things will not go well. */ + _dwarf_error(dbg,error, + DW_DLE_DEBUG_FRAME_POSSIBLE_ADDRESS_BOTCH); + return DW_DLV_ERROR; + } + + + continue; + } + } + /* Now build list of CIEs from the list. If there are no CIEs + there should be no FDEs. */ + if (cie_count > 0) { + cie_list_ptr = (Dwarf_Cie *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, cie_count); + } else { + if(fde_count > 0) { + dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr); + _dwarf_error(dbg, error, DW_DLE_ORPHAN_FDE); + return DW_DLV_ERROR; + } + dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr); + return DW_DLV_NO_ENTRY; + } + if (cie_list_ptr == NULL) { + dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + cur_cie_ptr = head_cie_ptr; + for (i = 0; i < cie_count; i++) { + *(cie_list_ptr + i) = cur_cie_ptr; + cur_cie_ptr = cur_cie_ptr->ci_next; + } + + /* Now build array of FDEs from the list. + With orphan CIEs (meaning no FDEs) + lets not return DW_DLV_NO_ENTRY */ + if (fde_count > 0) { + fde_list_ptr = (Dwarf_Fde *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, fde_count); + } + + // It is ok if fde_list_ptr is NULL, we just have no fdes. + cur_fde_ptr = head_fde_ptr; + for (i = 0; i < fde_count; i++) { + *(fde_list_ptr + i) = cur_fde_ptr; + cur_fde_ptr = cur_fde_ptr->fd_next; + } + + + /* Return arguments. */ + *cie_data = cie_list_ptr; + *cie_element_count = cie_count; + + *fde_data = fde_list_ptr; + *fde_element_count = fde_count; + if(use_gnu_cie_calc) { + dbg->de_fde_data_eh = fde_list_ptr; + dbg->de_fde_count_eh = fde_count; + dbg->de_cie_data_eh = cie_list_ptr; + dbg->de_cie_count_eh = cie_count; + } else { + dbg->de_fde_data = fde_list_ptr; + dbg->de_fde_count = fde_count; + dbg->de_cie_data = cie_list_ptr; + dbg->de_cie_count = cie_count; + } + + /* Sort the list by the address so that dwarf_get_fde_at_pc() can + binary search this list. */ + if(fde_count > 0) { + qsort((void *) fde_list_ptr, fde_count, sizeof(Dwarf_Ptr), + qsort_compare); + } + + return (DW_DLV_OK); +} + +/* Internal function, not called by consumer code. + 'prefix' has accumulated the info up thru the cie-id + and now we consume the rest and build a Dwarf_Cie_s structure. +*/ +int +dwarf_create_cie_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s *prefix, + Dwarf_Small * section_pointer, + Dwarf_Small * frame_ptr, + Dwarf_Unsigned cie_count, + int use_gnu_cie_calc, + Dwarf_Cie * cie_ptr_out, + Dwarf_Error * error) +{ + Dwarf_Cie new_cie = 0; + + /* egcs-1.1.2 .eh_frame uses 0 as the distinguishing id. sgi uses + -1 (in .debug_frame). .eh_frame not quite identical to + .debug_frame */ + /* We here default the address size as it is not present + in DWARF2 or DWARF3 cie data, below we set it right if + it is present. */ + Dwarf_Half address_size = dbg->de_pointer_size; + Dwarf_Small eh_fde_encoding = 0; + Dwarf_Small *augmentation = 0; + Dwarf_Half segment_size = 0; + Dwarf_Sword data_alignment_factor = -1; + Dwarf_Word code_alignment_factor = 4; + Dwarf_Unsigned return_address_register = 31; + int local_length_size = 0; + Dwarf_Word leb128_length = 0; + Dwarf_Unsigned cie_aug_data_len = 0; + Dwarf_Small *cie_aug_data = 0; + Dwarf_Addr gnu_personality_handler_addr = 0; + unsigned char gnu_personality_handler_encoding = 0; + unsigned char gnu_lsda_encoding = 0; + unsigned char gnu_fde_begin_encoding = 0; + + + enum Dwarf_augmentation_type augt = aug_unknown; + + + /* This is a CIE, Common Information Entry: See the dwarf spec, + section 6.4.1 */ + Dwarf_Small version = *(Dwarf_Small *) frame_ptr; + + frame_ptr++; + if (version != DW_CIE_VERSION && version != DW_CIE_VERSION3 && + version != DW_CIE_VERSION4) { + _dwarf_error(dbg, error, DW_DLE_FRAME_VERSION_BAD); + return (DW_DLV_ERROR); + } + + augmentation = frame_ptr; + frame_ptr = frame_ptr + strlen((char *) frame_ptr) + 1; + augt = _dwarf_get_augmentation_type(dbg, + augmentation, use_gnu_cie_calc); + if (augt == aug_eh) { + /* REFERENCED *//* Not used in this instance */ + Dwarf_Unsigned exception_table_addr; + + /* this is per egcs-1.1.2 as on RH 6.0 */ + READ_UNALIGNED(dbg, exception_table_addr, + Dwarf_Unsigned, frame_ptr, local_length_size); + frame_ptr += local_length_size; + } + { + Dwarf_Unsigned lreg = 0; + unsigned long size = 0; + + if( version == DW_CIE_VERSION4) { + address_size = *((unsigned char *)frame_ptr); + if(address_size > sizeof(Dwarf_Addr)) { + _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR); + return (DW_DLV_ERROR); + } + ++frame_ptr; + segment_size = *((unsigned char *)frame_ptr); + ++frame_ptr; + if(segment_size > sizeof(Dwarf_Addr)) { + _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD); + return (DW_DLV_ERROR); + } + } + + DECODE_LEB128_UWORD(frame_ptr, lreg); + code_alignment_factor = (Dwarf_Word) lreg; + data_alignment_factor = + (Dwarf_Sword) _dwarf_decode_s_leb128(frame_ptr, + &leb128_length); + frame_ptr = frame_ptr + leb128_length; + return_address_register = + _dwarf_get_return_address_reg(frame_ptr, version, &size); + if (return_address_register > dbg->de_frame_reg_rules_entry_count) { + _dwarf_error(dbg, error, DW_DLE_CIE_RET_ADDR_REG_ERROR); + return (DW_DLV_ERROR); + } + frame_ptr += size; + } + switch (augt) { + case aug_empty_string: + break; + case aug_irix_mti_v1: + break; + case aug_irix_exception_table:{ + Dwarf_Unsigned lreg = 0; + Dwarf_Word length_of_augmented_fields; + + /* Decode the length of augmented fields. */ + DECODE_LEB128_UWORD(frame_ptr, lreg); + length_of_augmented_fields = (Dwarf_Word) lreg; + /* set the frame_ptr to point at the instruction start. */ + frame_ptr += length_of_augmented_fields; + } + break; + + case aug_eh:{ + int err = 0; + unsigned long increment = 0; + + if (!use_gnu_cie_calc) { + /* This should be impossible. */ + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + + err = get_gcc_eh_augmentation(dbg, frame_ptr, &increment, + augt, + prefix->cf_section_ptr, + &eh_fde_encoding, + (char *) augmentation); + if (err == DW_DLV_ERROR) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + frame_ptr += increment; + } + break; + case aug_gcc_eh_z:{ + /* Here we have Augmentation Data Length (uleb128) followed + by Augmentation Data bytes. */ + int res = DW_DLV_ERROR; + Dwarf_Unsigned adlen = 0; + + DECODE_LEB128_UWORD(frame_ptr, adlen); + cie_aug_data_len = adlen; + cie_aug_data = frame_ptr; + res = gnu_aug_encodings(dbg, + (char *) augmentation, + cie_aug_data, + cie_aug_data_len, + address_size, + &gnu_personality_handler_encoding, + &gnu_lsda_encoding, + &gnu_fde_begin_encoding, + &gnu_personality_handler_addr); + if (res != DW_DLV_OK) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return res; + } + frame_ptr += adlen; + } + break; + case aug_armcc: + break; + default:{ + /* We do not understand the augmentation string. No + assumption can be made about any fields other than what + we have already read. */ + frame_ptr = prefix->cf_start_addr + + prefix->cf_length + prefix->cf_local_length_size + + prefix->cf_local_extension_size; + /* FIX -- What are the values of data_alignment_factor, + code_alignement_factor, return_address_register and + instruction start? They were clearly uninitalized in the + previous version and I am leaving them the same way. */ + } + break; + } /* End switch on augmentation type. */ + + new_cie = (Dwarf_Cie) _dwarf_get_alloc(dbg, DW_DLA_CIE, 1); + if (new_cie == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + new_cie->ci_cie_version_number = version; + new_cie->ci_initial_table = NULL; + new_cie->ci_length = (Dwarf_Word) prefix->cf_length; + new_cie->ci_length_size = prefix->cf_local_length_size; + new_cie->ci_extension_size = prefix->cf_local_extension_size; + new_cie->ci_augmentation = (char *) augmentation; + + new_cie->ci_data_alignment_factor = + (Dwarf_Sbyte) data_alignment_factor; + new_cie->ci_code_alignment_factor = + (Dwarf_Small) code_alignment_factor; + new_cie->ci_return_address_register = return_address_register; + new_cie->ci_cie_start = prefix->cf_start_addr; + new_cie->ci_cie_instr_start = frame_ptr; + new_cie->ci_dbg = dbg; + new_cie->ci_augmentation_type = augt; + new_cie->ci_gnu_eh_augmentation_len = cie_aug_data_len; + new_cie->ci_gnu_eh_augmentation_bytes = cie_aug_data; + new_cie->ci_gnu_personality_handler_encoding = + gnu_personality_handler_encoding; + new_cie->ci_gnu_personality_handler_addr = + gnu_personality_handler_addr; + new_cie->ci_gnu_lsda_encoding = gnu_lsda_encoding; + new_cie->ci_gnu_fde_begin_encoding = gnu_fde_begin_encoding; + + new_cie->ci_index = cie_count; + new_cie->ci_section_ptr = prefix->cf_section_ptr; + /* The Following new in DWARF4 */ + new_cie->ci_address_size = address_size; + new_cie->ci_segment_size = segment_size; + validate_length(dbg,new_cie,new_cie->ci_length, + new_cie->ci_length_size, new_cie->ci_extension_size, + new_cie->ci_section_ptr, + new_cie->ci_cie_start,"cie"); + + *cie_ptr_out = new_cie; + return DW_DLV_OK; + +} + + +/* Internal function, not called by consumer code. + 'prefix' has accumulated the info up thru the cie-id + and now we consume the rest and build a Dwarf_Fde_s structure. */ + +int +dwarf_create_fde_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s *prefix, + Dwarf_Small * section_pointer, + Dwarf_Small * frame_ptr, + int use_gnu_cie_calc, + Dwarf_Cie cie_ptr_in, + Dwarf_Fde * fde_ptr_out, + Dwarf_Error * error) +{ + Dwarf_Fde new_fde = 0; + Dwarf_Cie cieptr = cie_ptr_in; + Dwarf_Small *saved_frame_ptr = 0; + + Dwarf_Small *initloc = frame_ptr; + Dwarf_Signed offset_into_exception_tables + /* must be min dwarf_sfixed in size */ + = (Dwarf_Signed) DW_DLX_NO_EH_OFFSET; + Dwarf_Small *fde_aug_data = 0; + Dwarf_Unsigned fde_aug_data_len = 0; + Dwarf_Addr cie_base_offset = prefix->cf_cie_id; + Dwarf_Addr initial_location = 0; /* must be min de_pointer_size + bytes in size */ + Dwarf_Addr address_range = 0; /* must be min de_pointer_size + bytes in size */ + Dwarf_Half address_size = cie_ptr_in->ci_address_size; + + enum Dwarf_augmentation_type augt = cieptr->ci_augmentation_type; + + if (augt == aug_gcc_eh_z) { + /* If z augmentation this is eh_frame, and initial_location and + address_range in the FDE are read according to the CIE + augmentation string instructions. */ + + { + Dwarf_Small *fp_updated = 0; + int res = read_encoded_ptr(dbg, + section_pointer, + frame_ptr, + cieptr-> ci_gnu_fde_begin_encoding, + address_size, + &initial_location, + &fp_updated); + if (res != DW_DLV_OK) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + frame_ptr = fp_updated; + /* For the address-range it makes no sense to be + pc-relative, so we turn it off with a section_pointer of + NULL. Masking off DW_EH_PE_pcrel from the + ci_gnu_fde_begin_encoding in this call would also work + to turn off DW_EH_PE_pcrel. */ + res = read_encoded_ptr(dbg, (Dwarf_Small *) NULL, + frame_ptr, + cieptr->ci_gnu_fde_begin_encoding, + address_size, + &address_range, &fp_updated); + if (res != DW_DLV_OK) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + frame_ptr = fp_updated; + } + { + Dwarf_Unsigned adlen = 0; + + DECODE_LEB128_UWORD(frame_ptr, adlen); + fde_aug_data_len = adlen; + fde_aug_data = frame_ptr; + frame_ptr += adlen; + } + + } else { + READ_UNALIGNED(dbg, initial_location, Dwarf_Addr, + frame_ptr, address_size); + frame_ptr += address_size; + READ_UNALIGNED(dbg, address_range, Dwarf_Addr, + frame_ptr, address_size); + frame_ptr += address_size; + } + switch (augt) { + case aug_irix_mti_v1: + case aug_empty_string: + break; + case aug_irix_exception_table:{ + Dwarf_Unsigned lreg = 0; + Dwarf_Word length_of_augmented_fields = 0; + + DECODE_LEB128_UWORD(frame_ptr, lreg); + length_of_augmented_fields = (Dwarf_Word) lreg; + + saved_frame_ptr = frame_ptr; + /* The first word is an offset into exception tables. + Defined as a 32bit offset even for CC -64. */ + READ_UNALIGNED(dbg, offset_into_exception_tables, + Dwarf_Addr, frame_ptr, sizeof(Dwarf_sfixed)); + SIGN_EXTEND(offset_into_exception_tables, + sizeof(Dwarf_sfixed)); + frame_ptr = saved_frame_ptr + length_of_augmented_fields; + } + break; + case aug_eh:{ + Dwarf_Unsigned eh_table_value = 0; + + if (!use_gnu_cie_calc) { + /* This should be impossible. */ + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + + /* gnu eh fde case. we do not need to do anything */ + /*REFERENCED*/ /* Not used in this instance of the macro */ + READ_UNALIGNED(dbg, eh_table_value, + Dwarf_Unsigned, frame_ptr, + address_size); + frame_ptr += address_size; + } + break; + + case aug_gcc_eh_z:{ + /* The Augmentation Data Length is here, followed by the + Augmentation Data bytes themselves. */ + } + break; + case aug_armcc: + break; + case aug_past_last: + break; + case aug_unknown: + _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } /* End switch on augmentation type */ + new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1); + if (new_fde == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + new_fde->fd_length = prefix->cf_length; + new_fde->fd_length_size = prefix->cf_local_length_size; + new_fde->fd_extension_size = prefix->cf_local_extension_size; + new_fde->fd_is_eh = use_gnu_cie_calc; + new_fde->fd_cie_offset = cie_base_offset; + new_fde->fd_cie_index = cieptr->ci_index; + new_fde->fd_cie = cieptr; + new_fde->fd_initial_location = initial_location; + new_fde->fd_initial_loc_pos = initloc; + new_fde->fd_address_range = address_range; + new_fde->fd_fde_start = prefix->cf_start_addr; + new_fde->fd_fde_instr_start = frame_ptr; + new_fde->fd_dbg = dbg; + new_fde->fd_offset_into_exception_tables = + offset_into_exception_tables; + + new_fde->fd_section_ptr = prefix->cf_section_ptr; + new_fde->fd_section_index = prefix->cf_section_index; + new_fde->fd_section_length = prefix->cf_section_length; + + new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data; + new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len; + validate_length(dbg,cieptr,new_fde->fd_length, + new_fde->fd_length_size, new_fde->fd_extension_size, + new_fde->fd_section_ptr,new_fde->fd_fde_start,"fde"); + + + *fde_ptr_out = new_fde; + return DW_DLV_OK; +} + +/* Called by qsort to compare FDE entries. + Consumer code expects the array of FDE pointers to be + in address order. +*/ +static int +qsort_compare(const void *elem1, const void *elem2) +{ + Dwarf_Fde fde1 = *(Dwarf_Fde *) elem1; + Dwarf_Fde fde2 = *(Dwarf_Fde *) elem2; + Dwarf_Addr addr1 = fde1->fd_initial_location; + Dwarf_Addr addr2 = fde2->fd_initial_location; + + if (addr1 < addr2) { + return -1; + } else if (addr1 > addr2) { + return 1; + } + return 0; +} + + +/* Read in the common cie/fde prefix, including reading + the cie-value which shows which this is: cie or fde. */ +int +dwarf_read_cie_fde_prefix(Dwarf_Debug dbg, + Dwarf_Small * frame_ptr_in, + Dwarf_Small * section_ptr_in, + Dwarf_Unsigned section_index_in, + Dwarf_Unsigned section_length_in, + struct cie_fde_prefix_s *data_out, + Dwarf_Error * error) +{ + Dwarf_Unsigned length = 0; + int local_length_size = 0; + int local_extension_size = 0; + Dwarf_Small *frame_ptr = frame_ptr_in; + Dwarf_Small *cie_ptr_addr = 0; + Dwarf_Unsigned cie_id = 0; + + /* READ_AREA_LENGTH updates frame_ptr for consumed bytes */ + READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, + frame_ptr, local_length_size, + local_extension_size); + + if (length == 0) { + /* nul bytes at end of section, seen at end of egcs eh_frame + sections (in a.out). Take this as meaning no more CIE/FDE + data. We should be very close to end of section. */ + return DW_DLV_NO_ENTRY; + } + + cie_ptr_addr = frame_ptr; + READ_UNALIGNED(dbg, cie_id, Dwarf_Unsigned, + frame_ptr, local_length_size); + SIGN_EXTEND(cie_id, local_length_size); + frame_ptr += local_length_size; + + data_out->cf_start_addr = frame_ptr_in; + data_out->cf_addr_after_prefix = frame_ptr; + + data_out->cf_length = length; + data_out->cf_local_length_size = local_length_size; + data_out->cf_local_extension_size = local_extension_size; + data_out->cf_cie_id = cie_id; + data_out->cf_cie_id_addr = cie_ptr_addr; + data_out->cf_section_ptr = section_ptr_in; + data_out->cf_section_index = section_index_in; + data_out->cf_section_length = section_length_in; + return DW_DLV_OK; +} + +/* On various errors previously-allocated CIEs and FDEs + must be cleaned up. + This helps avoid leaks in case of errors. +*/ +static void +dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr, + Dwarf_Cie head_cie_ptr) +{ + Dwarf_Fde curfde = 0; + Dwarf_Cie curcie = 0; + Dwarf_Fde nextfde = 0; + Dwarf_Cie nextcie = 0; + + for (curfde = head_fde_ptr; curfde; curfde = nextfde) { + nextfde = curfde->fd_next; + dwarf_dealloc(curfde->fd_dbg, curfde, DW_DLA_FDE); + } + for (curcie = head_cie_ptr; curcie; curcie = nextcie) { + Dwarf_Frame frame = curcie->ci_initial_table; + + nextcie = curcie->ci_next; + if (frame) + dwarf_dealloc(curcie->ci_dbg, frame, DW_DLA_FRAME); + dwarf_dealloc(curcie->ci_dbg, curcie, DW_DLA_CIE); + } +} + +/* Find the cie whose id value is given: the id + value is, per DWARF2/3, an offset in the section. + For .debug_frame, zero is a legal offset. For + GNU .eh_frame it is not a legal offset. + 'cie_ptr' is a pointer into our section, not an offset. */ +static int +dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr, + Dwarf_Cie cur_cie_ptr, + Dwarf_Cie * cie_ptr_to_use_out, + Dwarf_Cie head_cie_ptr) +{ + Dwarf_Cie next = 0; + + if (cur_cie_ptr && cie_ptr == cur_cie_ptr->ci_cie_start) { + /* Usually, we use the same cie again and again. */ + *cie_ptr_to_use_out = cur_cie_ptr; + return DW_DLV_OK; + } + for (next = head_cie_ptr; next; next = next->ci_next) { + if (cie_ptr == next->ci_cie_start) { + *cie_ptr_to_use_out = next; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + + +/* We have a valid cie_ptr_val that has not been + turned into an internal Cie yet. Do so now. + Returns DW_DLV_OK or DW_DLV_ERROR, never + DW_DLV_NO_ENTRY. + + 'section_ptr' - Points to first byte of section data. + 'section_length' - Length of the section, in bytes. + 'frame_ptr_end' - Points 1-past last byte of section data. */ +static int +dwarf_create_cie_from_start(Dwarf_Debug dbg, + Dwarf_Small * cie_ptr_val, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Small * frame_ptr_end, + Dwarf_Unsigned cie_id_value, + Dwarf_Unsigned cie_count, + int use_gnu_cie_calc, + Dwarf_Cie * cie_ptr_to_use_out, + Dwarf_Error * error) +{ + struct cie_fde_prefix_s prefix; + int res = DW_DLV_ERROR; + Dwarf_Small *frame_ptr = cie_ptr_val; + + if (frame_ptr < section_ptr || frame_ptr > frame_ptr_end) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + /* First read in the 'common prefix' to figure out what * we are to + do with this entry. If it is not a cie * we are in big trouble. */ + memset(&prefix, 0, sizeof(prefix)); + res = dwarf_read_cie_fde_prefix(dbg, frame_ptr, section_ptr, + section_index, section_length, + &prefix, error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + /* error. */ + _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR); + return DW_DLV_ERROR; + + } + + if (prefix.cf_cie_id != cie_id_value) { + _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR); + return DW_DLV_ERROR; + } + frame_ptr = prefix.cf_addr_after_prefix; + res = dwarf_create_cie_from_after_start(dbg, + &prefix, + section_ptr, + frame_ptr, + cie_count, + use_gnu_cie_calc, + cie_ptr_to_use_out, error); + return res; + +} + + +/* This is for gnu eh frames, the 'z' case. + We find the letter involved + Return the augmentation character and, if applicable, + the personality routine address. + + personality_routine_out - + if 'P' is augchar, is personality handler addr. + Otherwise is not set. + aug_data - if 'P' points to data space of the + aug_data_len - length of areas aug_data points to. + +*/ +#if 0 +/* For debugging only. */ +void +dump_bytes(Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + for (; cur < end; cur++) { + printf(" byte %d, data %02x\n", (int) (cur - start), *cur); + } + +} +#endif +static int +gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation, + Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len, + Dwarf_Half address_size, + unsigned char *pers_hand_enc_out, + unsigned char *lsda_enc_out, + unsigned char *fde_begin_enc_out, + Dwarf_Addr * gnu_pers_addr_out) +{ + char *nc = 0; + Dwarf_Small *cur_aug_p = aug_data; + Dwarf_Small *end_aug_p = aug_data + aug_data_len; + + for (nc = augmentation; *nc; ++nc) { + char c = *nc; + + switch (c) { + case 'z': + /* Means that the augmentation data is present. */ + continue; + + case 'S': + /* Indicates this is a signal stack frame. + Debuggers have to do + special handling. We don't need to do more than + print this flag at the right time, though + (see dwarfdump where it prints the augmentation + string). + A signal stack frame (in some OS's) can only be + unwound (backtraced) by knowing it is a signal + stack frame (perhaps by noticing the name of the + function for the stack frame if the name can be + found somehow) and figuring + out (or knowing) how the kernel and libc + pushed a structure + onto the stack and loading registers from that structure. + Totally different from normal stack unwinding. + This flag gives an unwinder a big leg up by + decoupling the 'hint: this is a stack frame' + from knowledge like + the function name (the name might be + unavailable at unwind time). + */ + break; + + case 'L': + if (cur_aug_p > end_aug_p) { + return DW_DLV_ERROR; + } + *lsda_enc_out = *(unsigned char *) cur_aug_p; + ++cur_aug_p; + break; + case 'R': + /* Followed by a one byte argument giving the + pointer encoding for the address pointers in the fde. */ + if (cur_aug_p >= end_aug_p) { + return DW_DLV_ERROR; + } + *fde_begin_enc_out = *(unsigned char *) cur_aug_p; + ++cur_aug_p; + break; + case 'P':{ + int res = DW_DLV_ERROR; + Dwarf_Small *updated_aug_p = 0; + unsigned char encoding = 0; + + if (cur_aug_p >= end_aug_p) { + return DW_DLV_ERROR; + } + encoding = *(unsigned char *) cur_aug_p; + *pers_hand_enc_out = encoding; + ++cur_aug_p; + if (cur_aug_p > end_aug_p) { + return DW_DLV_ERROR; + } + /* DW_EH_PE_pcrel makes no sense here, so we turn it + off via a section pointer of NULL. */ + res = read_encoded_ptr(dbg, + (Dwarf_Small *) NULL, + cur_aug_p, + encoding, + address_size, + gnu_pers_addr_out, + &updated_aug_p); + if (res != DW_DLV_OK) { + return res; + } + cur_aug_p = updated_aug_p; + if (cur_aug_p > end_aug_p) { + return DW_DLV_ERROR; + } + } + break; + default: + return DW_DLV_ERROR; + + } + } + + return DW_DLV_OK; +} + +/* Given augmentation character (the encoding) giving the + address format, read the address from input_field + and return an incremented value 1 past the input bytes of the + address. + Push the address read back thru the *addr pointer. + See LSB (Linux Standard Base) exception handling documents. */ +static int +read_encoded_ptr(Dwarf_Debug dbg, + Dwarf_Small * section_pointer, + Dwarf_Small * input_field, + int gnu_encoding, + Dwarf_Half address_size, + Dwarf_Unsigned * addr, + Dwarf_Small ** input_field_updated) +{ + Dwarf_Word length = 0; + int value_type = gnu_encoding & 0xf; + Dwarf_Small *input_field_original = input_field; + + if (gnu_encoding == 0xff) { + /* There is no data here. */ + + *addr = 0; + *input_field_updated = input_field; + /* Should we return DW_DLV_NO_ENTRY? */ + return DW_DLV_OK; + } + switch (value_type) { + case DW_EH_PE_absptr:{ + /* value_type is zero. Treat as pointer size of the object. + */ + Dwarf_Unsigned ret_value = 0; + + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + input_field, address_size); + *addr = ret_value; + *input_field_updated = input_field + address_size; + } + break; + case DW_EH_PE_uleb128:{ + Dwarf_Unsigned val = _dwarf_decode_u_leb128(input_field, + &length); + + *addr = val; + *input_field_updated = input_field + length; + } + break; + case DW_EH_PE_udata2:{ + Dwarf_Unsigned ret_value = 0; + + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + input_field, 2); + *addr = ret_value; + *input_field_updated = input_field + 2; + } + break; + + case DW_EH_PE_udata4:{ + Dwarf_Unsigned ret_value = 0; + + /* ASSERT: sizeof(Dwarf_ufixed) == 4 */ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + input_field, sizeof(Dwarf_ufixed)); + *addr = ret_value; + *input_field_updated = input_field + sizeof(Dwarf_ufixed); + } + break; + + case DW_EH_PE_udata8:{ + Dwarf_Unsigned ret_value = 0; + + /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + input_field, sizeof(Dwarf_Unsigned)); + *addr = ret_value; + *input_field_updated = input_field + sizeof(Dwarf_Unsigned); + } + break; + + case DW_EH_PE_sleb128:{ + Dwarf_Signed val = _dwarf_decode_s_leb128(input_field, + &length); + + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field + length; + } + break; + case DW_EH_PE_sdata2:{ + Dwarf_Unsigned val = 0; + + READ_UNALIGNED(dbg, val, Dwarf_Unsigned, input_field, 2); + SIGN_EXTEND(val, 2); + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field + 2; + } + break; + + case DW_EH_PE_sdata4:{ + Dwarf_Unsigned val = 0; + + /* ASSERT: sizeof(Dwarf_ufixed) == 4 */ + READ_UNALIGNED(dbg, val, + Dwarf_Unsigned, input_field, + sizeof(Dwarf_ufixed)); + SIGN_EXTEND(val, sizeof(Dwarf_ufixed)); + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field + sizeof(Dwarf_ufixed); + } + break; + case DW_EH_PE_sdata8:{ + Dwarf_Unsigned val = 0; + + /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */ + READ_UNALIGNED(dbg, val, + Dwarf_Unsigned, input_field, + sizeof(Dwarf_Unsigned)); + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field + sizeof(Dwarf_Unsigned); + } + break; + default: + return DW_DLV_ERROR; + + }; + /* The ELF ABI for gnu does not document the meaning of + DW_EH_PE_pcrel, which is awkward. It apparently means the value + we got above is pc-relative (meaning section-relative), so we + adjust the value. Section_pointer may be null if it is known + DW_EH_PE_pcrel cannot apply, such as for .debug_frame or for an + address-range value. */ + if (section_pointer && ((gnu_encoding & 0x70) == DW_EH_PE_pcrel)) { + /* Address (*addr) above is pc relative with respect to a + section. Add to the offset the base address (from elf) of + section and the distance of the field we are reading from + the section-beginning to get the actual address. */ + /* ASSERT: input_field_original >= section_pointer */ + Dwarf_Unsigned distance = + input_field_original - section_pointer; + *addr += dbg->de_debug_frame_eh_gnu.dss_addr + distance; + } + return DW_DLV_OK; +} + + + + +/* All augmentation string checking done here now. + + For .eh_frame, gcc from 3.3 uses the z style, earlier used + only "eh" as augmentation. We don't yet handle + decoding .eh_frame with the z style extensions like L P. + + These are nasty heuristics, but then that's life + as augmentations are implementation specific. */ +/* ARGSUSED */ +enum Dwarf_augmentation_type +_dwarf_get_augmentation_type(Dwarf_Debug dbg, + Dwarf_Small * augmentation_string, + int is_gcc_eh_frame) +{ + enum Dwarf_augmentation_type t = aug_unknown; + char *ag_string = (char *) augmentation_string; + + if (ag_string[0] == 0) { + /* Empty string. We'll just guess that we know what this means: + standard dwarf2/3 with no implementation-defined fields. */ + t = aug_empty_string; + } else if (strcmp(ag_string, DW_DEBUG_FRAME_AUGMENTER_STRING) == 0) { + /* The string is "mti v1". Used internally at SGI, probably + never shipped. Replaced by "z". Treat like 'nothing + special'. */ + t = aug_irix_mti_v1; + } else if (ag_string[0] == 'z') { + /* If it's IRIX cc, z means aug_irix_exception_table. z1 z2 + were designed as for IRIX CC, but never implemented */ + /* If it's gcc, z may be any of several things. "z" or z + followed optionally followed by one or more of L R P, each + of which means a value may be present. Should be in eh_frame + only, I think. */ + if (is_gcc_eh_frame) { + t = aug_gcc_eh_z; + } else if (ag_string[1] == 0) { + /* This is the normal IRIX C++ case, where there is an + offset into a table in each fde. The table being for + IRIX CC exception handling. */ + /* DW_CIE_AUGMENTER_STRING_V0 "z" */ + t = aug_irix_exception_table; + } /* Else unknown. */ + } else if (strncmp(ag_string, "eh", 2) == 0) { + /* gcc .eh_frame augmentation for egcs and gcc 2.x, at least + for x86. */ + t = aug_eh; + } else if (strcmp(ag_string, "armcc+") == 0) { + /* Arm uses this string to mean a bug in + in Arm compilers was fixed, changing to the standard + calculation of the CFA. See + http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html + for details. */ + t = aug_armcc; + } else { + + } + return t; +} + +/* Using augmentation, and version + read in the augmentation data for GNU eh. + + Return DW_DLV_OK if we succeeded, + DW_DLV_ERR if we fail. + + On success, update 'size_of_augmentation_data' with + the length of the fields that are part of augmentation (so the + caller can increment frame_ptr appropriately). + + 'frame_ptr' points within section. + 'section_pointer' points to section base address in memory. +*/ +/* ARGSUSED */ +static int +get_gcc_eh_augmentation(Dwarf_Debug dbg, Dwarf_Small * frame_ptr, + unsigned long *size_of_augmentation_data, + enum Dwarf_augmentation_type augtype, + Dwarf_Small * section_pointer, + Dwarf_Small * fde_eh_encoding_out, + char *augmentation) +{ + char *suffix = 0; + unsigned long augdata_size = 0; + + if (augtype == aug_gcc_eh_z) { + /* Has leading 'z'. */ + Dwarf_Word leb128_length = 0; + + /* Dwarf_Unsigned eh_value = */ + _dwarf_decode_u_leb128(frame_ptr, &leb128_length); + augdata_size += leb128_length; + frame_ptr += leb128_length; + suffix = augmentation + 1; + } else { + /* Prefix is 'eh'. As in gcc 3.2. No suffix present + apparently. */ + suffix = augmentation + 2; + } + for (; *suffix; ++suffix) { + /* We have no idea what this is as yet. Some extensions beyond + dwarf exist which we do not yet handle. */ + return DW_DLV_ERROR; + + } + + *size_of_augmentation_data = augdata_size; + return DW_DLV_OK; +} + + +/* Make the 'cie_id_addr' consistent across .debug_frame and .eh_frame. + Calculate a pointer into section bytes given a cie_id, which is + trivial for .debug_frame, but a bit more work for .eh_frame. +*/ +static Dwarf_Small * +get_cieptr_given_offset(Dwarf_Unsigned cie_id_value, + int use_gnu_cie_calc, + Dwarf_Small * section_ptr, + Dwarf_Small * cie_id_addr) +{ + Dwarf_Small *cieptr = 0; + + if (use_gnu_cie_calc) { + /* cie_id value is offset, in section, of the cie_id itself, to + use vm ptr of the value, less the value, to get to the cie + itself. In addition, munge *cie_id_addr to look *as if* it + was from real dwarf. */ + cieptr = (Dwarf_Small *) ((Dwarf_Unsigned) cie_id_addr) - + ((Dwarf_Unsigned) cie_id_value); + } else { + /* Traditional dwarf section offset is in cie_id */ + cieptr = (section_ptr + cie_id_value); + } + return cieptr; +} + +/* To properly release all spaced used. + Earlier approaches (before July 15, 2005) + letting client do the dealloc directly left + some data allocated. + This is directly called by consumer code. +*/ +void +dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg, + Dwarf_Cie * cie_data, + Dwarf_Signed cie_element_count, + Dwarf_Fde * fde_data, + Dwarf_Signed fde_element_count) +{ + Dwarf_Signed i = 0; + + for (i = 0; i < cie_element_count; ++i) { + Dwarf_Frame frame = cie_data[i]->ci_initial_table; + + if (frame) + dwarf_dealloc(dbg, frame, DW_DLA_FRAME); + dwarf_dealloc(dbg, cie_data[i], DW_DLA_CIE); + } + for (i = 0; i < fde_element_count; ++i) { + dwarf_dealloc(dbg, fde_data[i], DW_DLA_FDE); + } + if (cie_data) + dwarf_dealloc(dbg, cie_data, DW_DLA_LIST); + if (fde_data) + dwarf_dealloc(dbg, fde_data, DW_DLA_LIST); +} diff --git a/libdwarf/dwarf_frame3.c b/libdwarf/dwarf_frame3.c new file mode 100644 index 0000000..6f6e25d --- /dev/null +++ b/libdwarf/dwarf_frame3.c @@ -0,0 +1,292 @@ +/* + + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <stdlib.h> +#include "dwarf_frame.h" +#include "dwarf_arange.h" /* using Arange as a way to build a list */ + +/* Used by rqs (an IRIX application). + Not needed except for that one application. + Should be moved to its own source file since + it is so rarely needed. + Returns DW_DLV_OK if returns the arrays. + Returns DW_DLV_NO_ENTRY if no section. ?? (How do I tell?) + Returns DW_DLV_ERROR if there is an error. + + Uses DW_FRAME_CFA_COL because IRIX is only DWARF2 + and that is what IRIX compilers and compatible + compilers support on IRIX. +*/ +int +_dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist, + Dwarf_Off ** offsetlist, + Dwarf_Signed * returncount, + Dwarf_Error * err) +{ + int retval = DW_DLV_OK; + int res = DW_DLV_ERROR; + Dwarf_Cie *cie_data; + Dwarf_Signed cie_count; + Dwarf_Fde *fde_data; + Dwarf_Signed fde_count; + Dwarf_Signed i; + Dwarf_Frame_Op *frame_inst; + Dwarf_Fde fdep; + Dwarf_Cie ciep; + Dwarf_Chain curr_chain = 0; + Dwarf_Chain head_chain = 0; + Dwarf_Chain prev_chain = 0; + Dwarf_Arange arange; + Dwarf_Unsigned arange_count = 0; + Dwarf_Addr *arange_addrs = 0; + Dwarf_Off *arange_offsets = 0; + + res = dwarf_get_fde_list(dbg, &cie_data, &cie_count, + &fde_data, &fde_count, err); + if (res != DW_DLV_OK) { + return res; + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_frame, err); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_frame.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + for (i = 0; i < cie_count; i++) { + Dwarf_Off instoff = 0; + Dwarf_Signed initial_instructions_length = 0; + Dwarf_Small *instr_end = 0; + Dwarf_Sword icount = 0; + int j = 0; + int dw_err; + + ciep = cie_data[i]; + instoff = ciep->ci_cie_instr_start - dbg->de_debug_frame.dss_data; + initial_instructions_length = ciep->ci_length + + ciep->ci_length_size + ciep->ci_extension_size - + (ciep->ci_cie_instr_start - ciep->ci_cie_start); + instr_end = ciep->ci_cie_instr_start + + initial_instructions_length; + res = _dwarf_exec_frame_instr( /* make_instr */ true, + &frame_inst, + /* search_pc= */ false, + /* search_pc_val= */ 0, + /* location */ 0, + ciep->ci_cie_instr_start, + instr_end, + /* Dwarf_frame= */ 0, + /* cie= */ 0, + dbg, + DW_FRAME_CFA_COL, + &icount, &dw_err); + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, err, dw_err); + return (res); + } else if (res == DW_DLV_NO_ENTRY) { + continue; + } + + for (j = 0; j < icount; ++j) { + Dwarf_Frame_Op *finst = frame_inst + j; + + if (finst->fp_base_op == 0 && finst->fp_extended_op == 1) { + /* is DW_CFA_set_loc */ + Dwarf_Addr add = (Dwarf_Addr) finst->fp_offset; + Dwarf_Off off = finst->fp_instr_offset + instoff; + + arange = (Dwarf_Arange) + _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); + if (arange == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + arange->ar_address = add; + arange->ar_info_offset = off; + arange_count++; + curr_chain = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + curr_chain->ch_item = arange; + if (head_chain == NULL) + head_chain = prev_chain = curr_chain; + else { + prev_chain->ch_next = curr_chain; + prev_chain = curr_chain; + } + } + } + dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK); + + } + for (i = 0; i < fde_count; i++) { + Dwarf_Small *instr_end = 0; + Dwarf_Sword icount = 0; + Dwarf_Signed instructions_length = 0; + Dwarf_Off instoff = 0; + Dwarf_Off off = 0; + Dwarf_Addr addr = 0; + int j = 0; + int dw_err; + + fdep = fde_data[i]; + off = fdep->fd_initial_loc_pos - dbg->de_debug_frame.dss_data; + addr = fdep->fd_initial_location; + arange = (Dwarf_Arange) + _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); + if (arange == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + arange->ar_address = addr; + arange->ar_info_offset = off; + arange_count++; + curr_chain = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + curr_chain->ch_item = arange; + if (head_chain == NULL) + head_chain = prev_chain = curr_chain; + else { + prev_chain->ch_next = curr_chain; + prev_chain = curr_chain; + } + + + instoff = fdep->fd_fde_instr_start - dbg->de_debug_frame.dss_data; + instructions_length = fdep->fd_length + + fdep->fd_length_size + fdep->fd_extension_size - + (fdep->fd_fde_instr_start - fdep->fd_fde_start); + instr_end = fdep->fd_fde_instr_start + instructions_length; + res = _dwarf_exec_frame_instr( /* make_instr */ true, + &frame_inst, + /* search_pc= */ false, + /* search_pc_val= */ 0, + /* location */ 0, + fdep->fd_fde_instr_start, + instr_end, + /* Dwarf_frame= */ 0, + /* cie= */ 0, + dbg, + DW_FRAME_CFA_COL, + &icount, &dw_err); + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, err, dw_err); + return (res); + } else if (res == DW_DLV_NO_ENTRY) { + continue; + } + + for (j = 0; j < icount; ++j) { + Dwarf_Frame_Op *finst2 = frame_inst + j; + + if (finst2->fp_base_op == 0 && finst2->fp_extended_op == 1) { + /* is DW_CFA_set_loc */ + Dwarf_Addr add = (Dwarf_Addr) finst2->fp_offset; + Dwarf_Off off = finst2->fp_instr_offset + instoff; + + arange = (Dwarf_Arange) + _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); + if (arange == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + arange->ar_address = add; + arange->ar_info_offset = off; + arange_count++; + curr_chain = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + curr_chain->ch_item = arange; + if (head_chain == NULL) + head_chain = prev_chain = curr_chain; + else { + prev_chain->ch_next = curr_chain; + prev_chain = curr_chain; + } + + } + } + dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK); + + } + dwarf_dealloc(dbg, fde_data, DW_DLA_LIST); + dwarf_dealloc(dbg, cie_data, DW_DLA_LIST); + arange_addrs = (Dwarf_Addr *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); + if (arange_addrs == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + arange_offsets = (Dwarf_Off *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); + if (arange_offsets == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + curr_chain = head_chain; + for (i = 0; i < arange_count; i++) { + Dwarf_Arange ar = curr_chain->ch_item; + + arange_addrs[i] = ar->ar_address; + arange_offsets[i] = ar->ar_info_offset; + prev_chain = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, ar, DW_DLA_ARANGE); + dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); + } + *returncount = arange_count; + *offsetlist = arange_offsets; + *addrlist = arange_addrs; + return retval; +} diff --git a/libdwarf/dwarf_funcs.c b/libdwarf/dwarf_funcs.c new file mode 100644 index 0000000..83ebb58 --- /dev/null +++ b/libdwarf/dwarf_funcs.c @@ -0,0 +1,134 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_funcs.h" +#include "dwarf_global.h" + +int +dwarf_get_funcs(Dwarf_Debug dbg, + Dwarf_Func ** funcs, + Dwarf_Signed * ret_func_count, Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_funcnames,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_funcnames.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + return _dwarf_internal_get_pubnames_like_data(dbg, + dbg->de_debug_funcnames.dss_data, + dbg->de_debug_funcnames.dss_size, + (Dwarf_Global **) funcs, /* Type punning for sections with identical format. */ + ret_func_count, + error, + DW_DLA_FUNC_CONTEXT, + DW_DLA_FUNC, + DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD, + DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR); +} + +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. +*/ + +void +dwarf_funcs_dealloc(Dwarf_Debug dbg, Dwarf_Func * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl, + count, + DW_DLA_FUNC_CONTEXT, + DW_DLA_FUNC, DW_DLA_LIST); + return; +} + + + +int +dwarf_funcname(Dwarf_Func func_in, char **ret_name, Dwarf_Error * error) +{ + Dwarf_Global func = (Dwarf_Global) func_in; + + if (func == NULL) { + _dwarf_error(NULL, error, DW_DLE_FUNC_NULL); + return (DW_DLV_ERROR); + } + + *ret_name = (char *) (func->gl_name); + return DW_DLV_OK; +} + +int +dwarf_func_die_offset(Dwarf_Func func_in, + Dwarf_Off * return_offset, Dwarf_Error * error) +{ + Dwarf_Global func = (Dwarf_Global) func_in; + + return dwarf_global_die_offset(func, return_offset, error); +} + + +int +dwarf_func_cu_offset(Dwarf_Func func_in, + Dwarf_Off * return_offset, Dwarf_Error * error) +{ + Dwarf_Global func = (Dwarf_Global) func_in; + + return dwarf_global_cu_offset(func, return_offset, error); +} + + +int +dwarf_func_name_offsets(Dwarf_Func func_in, + char **ret_func_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_die_offset, Dwarf_Error * error) +{ + Dwarf_Global func = (Dwarf_Global) func_in; + + return dwarf_global_name_offsets(func, + ret_func_name, + die_offset, cu_die_offset, error); +} diff --git a/libdwarf/dwarf_funcs.h b/libdwarf/dwarf_funcs.h new file mode 100644 index 0000000..bf91c32 --- /dev/null +++ b/libdwarf/dwarf_funcs.h @@ -0,0 +1,42 @@ +/* + + Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +typedef struct Dwarf_Func_Context_s *Dwarf_Func_Context; + + +/* struct never completed: see dwarf_global.h */ diff --git a/libdwarf/dwarf_global.c b/libdwarf/dwarf_global.c new file mode 100644 index 0000000..1b4486b --- /dev/null +++ b/libdwarf/dwarf_global.c @@ -0,0 +1,614 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_global.h" + + +#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */ +/* The 'fixup' here intended for IRIX targets only. + With a 2+GB Elf64 IRIX executable (under 4GB in size), + some DIE offsets wrongly + got the 32bit upper bit sign extended. For the cu-header + offset in the .debug_pubnames section and in the + .debug_aranges section. + the 'varp' here is a pointer to an offset into .debug_info. + We fix up the offset here if it seems advisable.. + + As of June 2005 we have identified a series of mistakes + in ldx64 that can cause this (64 bit values getting passed + thru 32-bit signed knothole). +*/ +void +_dwarf_fix_up_offset_irix(Dwarf_Debug dbg, + Dwarf_Unsigned * varp, char *caller_site_name) +{ + + Dwarf_Unsigned var = *varp; + +#define UPPER33 0xffffffff80000000LL +#define LOWER32 0xffffffffLL + /* Restrict the hack to the known case. Upper 32 bits erroneously + sign extended from lower 32 upper bit. */ + if ((var & UPPER33) == UPPER33) { + var &= LOWER32; + /* Apply the fix. Dreadful hack. */ + *varp = var; + } +#undef UPPER33 +#undef LOWER32 + return; +} +#endif + + +int +dwarf_get_globals(Dwarf_Debug dbg, + Dwarf_Global ** globals, + Dwarf_Signed * return_count, Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_pubnames,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_pubnames.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + return _dwarf_internal_get_pubnames_like_data(dbg, + dbg->de_debug_pubnames.dss_data, + dbg->de_debug_pubnames.dss_size, + globals, + return_count, + error, + DW_DLA_GLOBAL_CONTEXT, + DW_DLA_GLOBAL, + DW_DLE_PUBNAMES_LENGTH_BAD, + DW_DLE_PUBNAMES_VERSION_ERROR); + +} + +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. +*/ + +void +dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, dwgl, + count, + DW_DLA_GLOBAL_CONTEXT, + DW_DLA_GLOBAL, DW_DLA_LIST); + return; +} + +void +_dwarf_internal_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl, + Dwarf_Signed count, + int context_code, + int global_code, int list_code) +{ + Dwarf_Signed i; + struct Dwarf_Global_Context_s *gcp = 0; + struct Dwarf_Global_Context_s *lastgcp = 0; + + for (i = 0; i < count; i++) { + Dwarf_Global dgb = dwgl[i]; + + gcp = dgb->gl_context; + + if (lastgcp != gcp) { + lastgcp = gcp; + dwarf_dealloc(dbg, gcp, context_code); + } + dwarf_dealloc(dbg, dgb, global_code); + } + dwarf_dealloc(dbg, dwgl, list_code); + return; +} + + +/* Sweeps the complete section. */ +int +_dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, + Dwarf_Small * section_data_ptr, + Dwarf_Unsigned section_length, + Dwarf_Global ** globals, + Dwarf_Signed * return_count, + Dwarf_Error * error, + int context_code, + int global_code, + int length_err_num, + int version_err_num) +{ + Dwarf_Small *pubnames_like_ptr = 0; + + /* Points to the context for the current set of global names, and + contains information to identify the compilation-unit that the + set refers to. */ + Dwarf_Global_Context pubnames_context = 0; + + Dwarf_Half version = 0; + + /* Offset from the start of compilation-unit for the current + global. */ + Dwarf_Off die_offset_in_cu = 0; + + Dwarf_Unsigned global_count = 0; + + /* Points to the current global read. */ + Dwarf_Global global = 0; + + /* Used to chain the Dwarf_Global_s structs for creating contiguous + list of pointers to the structs. */ + Dwarf_Chain curr_chain = 0; + Dwarf_Chain prev_chain = 0; + Dwarf_Chain head_chain = 0; + + /* Points to contiguous block of Dwarf_Global's to be returned. */ + Dwarf_Global *ret_globals = 0; + + /* Temporary counter. */ + Dwarf_Unsigned i = 0; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + /* We will eventually need the .debug_info data. Load it now. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + } + if (section_data_ptr == NULL) { + return (DW_DLV_NO_ENTRY); + } + pubnames_like_ptr = section_data_ptr; + do { + Dwarf_Unsigned length = 0; + int local_extension_size = 0; + int local_length_size = 0; + + /* Some compilers emit padding at the end of each cu's area. + pubnames_ptr_past_end_cu records the true area end for this + cu's data. Essentially the length in the header and the 0 + terminator of the data are redundant information. The + dwarf2/3 spec does not mention what to do if the length is + past the 0 terminator. So we take any bytes left after the 0 + as padding and ignore them. */ + Dwarf_Small *pubnames_ptr_past_end_cu = 0; + + + pubnames_context = (Dwarf_Global_Context) + _dwarf_get_alloc(dbg, context_code, 1); + if (pubnames_context == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed + bytes. */ + READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, + pubnames_like_ptr, local_length_size, + local_extension_size); + pubnames_context->pu_length_size = local_length_size; + pubnames_context->pu_extension_size = local_extension_size; + pubnames_context->pu_dbg = dbg; + + pubnames_ptr_past_end_cu = pubnames_like_ptr + length; + + READ_UNALIGNED(dbg, version, Dwarf_Half, + pubnames_like_ptr, sizeof(Dwarf_Half)); + pubnames_like_ptr += sizeof(Dwarf_Half); + if (version != CURRENT_VERSION_STAMP) { + _dwarf_error(dbg, error, version_err_num); + return (DW_DLV_ERROR); + } + + /* Offset of CU header in debug section. */ + READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header, + Dwarf_Off, pubnames_like_ptr, + pubnames_context->pu_length_size); + pubnames_like_ptr += pubnames_context->pu_length_size; + + FIX_UP_OFFSET_IRIX_BUG(dbg, + pubnames_context->pu_offset_of_cu_header, + "pubnames cu header offset"); + + + READ_UNALIGNED(dbg, pubnames_context->pu_info_length, + Dwarf_Unsigned, pubnames_like_ptr, + pubnames_context->pu_length_size); + pubnames_like_ptr += pubnames_context->pu_length_size; + + if (pubnames_like_ptr > (section_data_ptr + section_length)) { + _dwarf_error(dbg, error, length_err_num); + return (DW_DLV_ERROR); + } + + /* Read initial offset (of DIE within CU) of a pubname, final + entry is not a pair, just a zero offset. */ + READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, + pubnames_like_ptr, + pubnames_context->pu_length_size); + pubnames_like_ptr += pubnames_context->pu_length_size; + FIX_UP_OFFSET_IRIX_BUG(dbg, + die_offset_in_cu, "offset of die in cu"); + + /* Loop thru pairs. DIE off with CU followed by string. */ + while (die_offset_in_cu != 0) { + + /* Already read offset, pubnames_like_ptr now points to the + string. */ + global = + (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1); + if (global == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + global_count++; + + global->gl_context = pubnames_context; + + global->gl_named_die_offset_within_cu = die_offset_in_cu; + + global->gl_name = pubnames_like_ptr; + + pubnames_like_ptr = pubnames_like_ptr + + strlen((char *) pubnames_like_ptr) + 1; + + + /* Finish off current entry chain */ + curr_chain = + (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* Put current global on singly_linked list. */ + curr_chain->ch_item = (Dwarf_Global) global; + + if (head_chain == NULL) + head_chain = prev_chain = curr_chain; + else { + prev_chain->ch_next = curr_chain; + prev_chain = curr_chain; + } + + /* Fead offset for the *next* entry */ + READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, + pubnames_like_ptr, pubnames_context->pu_length_size); + + pubnames_like_ptr += pubnames_context->pu_length_size; + FIX_UP_OFFSET_IRIX_BUG(dbg, + die_offset_in_cu, "offset of next die in cu"); + + if (pubnames_like_ptr > (section_data_ptr + section_length)) { + _dwarf_error(dbg, error, length_err_num); + return (DW_DLV_ERROR); + } + } + /* ASSERT: die_offset_in_cu == 0 */ + if (pubnames_like_ptr > pubnames_ptr_past_end_cu) { + /* This is some kind of error. This simply cannot happen. + The encoding is wrong or the length in the header for + this cu's contribution is wrong. */ + _dwarf_error(dbg, error, length_err_num); + return (DW_DLV_ERROR); + } + /* If there is some kind of padding at the end of the section, + as emitted by some compilers, skip over that padding and + simply ignore the bytes thus passed-over. With most + compilers, pubnames_like_ptr == pubnames_ptr_past_end_cu at + this point */ + pubnames_like_ptr = pubnames_ptr_past_end_cu; + + } while (pubnames_like_ptr < (section_data_ptr + section_length)); + + /* Points to contiguous block of Dwarf_Global's. */ + ret_globals = (Dwarf_Global *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count); + if (ret_globals == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* Store pointers to Dwarf_Global_s structs in contiguous block, + and deallocate the chain. */ + curr_chain = head_chain; + for (i = 0; i < global_count; i++) { + *(ret_globals + i) = curr_chain->ch_item; + prev_chain = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); + } + + *globals = ret_globals; + *return_count = (Dwarf_Signed) global_count; + return DW_DLV_OK; +} + + +/* Given a pubnames entry (or other like section entry) + return thru the ret_name pointer + a pointer to the string which is the entry name. */ +int +dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error) +{ + if (glob == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); + } + + *ret_name = (char *) (glob->gl_name); + return DW_DLV_OK; +} + + +/* Given a pubnames entry (or other like section entry) + return thru the ret_off pointer the + global offset of the DIE for this entry. + The global offset is the offset within the .debug_info + section as a whole. */ +int +dwarf_global_die_offset(Dwarf_Global global, + Dwarf_Off * ret_off, Dwarf_Error * error) +{ + if (global == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); + } + + if (global->gl_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return (DW_DLV_ERROR); + } + + *ret_off = (global->gl_named_die_offset_within_cu + + global->gl_context->pu_offset_of_cu_header); + return DW_DLV_OK; +} + +/* Given a pubnames entry (or other like section entry) + return thru the ret_off pointer the + offset of the compilation unit header of the + compilation unit the global is part of. + + In early versions of this, the value returned was + the offset of the compilation unit die, and + other cu-local die offsets were faked so adding this to + such a cu-local offset got a true section offset. + Now things do as they say (adding *cu_header_offset to + a cu-local offset gets the section offset). */ +int +dwarf_global_cu_offset(Dwarf_Global global, + Dwarf_Off * cu_header_offset, + Dwarf_Error * error) +{ + Dwarf_Global_Context con = 0; + + if (global == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); + } + + con = global->gl_context; + + if (con == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return (DW_DLV_ERROR); + } + + /* In early libdwarf, this incorrectly returned the offset of the + CU DIE. Now correctly returns the header offset. */ + *cu_header_offset = con->pu_offset_of_cu_header; + + return DW_DLV_OK; +} + +/* + Give back the pubnames entry (or any other like section) + name, symbol DIE offset, and the cu-DIE offset. + + Various errors are possible. + + The string pointer returned thru ret_name is not + dwarf_get_alloc()ed, so no dwarf_dealloc() + DW_DLA_STRING should be applied to it. + +*/ +int +dwarf_global_name_offsets(Dwarf_Global global, + char **ret_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_die_offset, + Dwarf_Error * error) +{ + Dwarf_Global_Context con = 0; + Dwarf_Debug dbg = 0; + Dwarf_Off off = 0; + + if (global == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); + } + + con = global->gl_context; + + if (con == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return (DW_DLV_ERROR); + } + + off = con->pu_offset_of_cu_header; + /* The offset had better not be too close to the end. If it is, + _dwarf_length_of_cu_header() will step off the end and therefore + must not be used. 10 is a meaningless heuristic, but no CU + header is that small so it is safe. An erroneous offset is due + to a bug in the tool chain. A bug like this has been seen on + IRIX with MIPSpro 7.3.1.3 and an executable > 2GB in size and + with 2 million pubnames entries. */ +#define MIN_CU_HDR_SIZE 10 + dbg = con->pu_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + /* Cannot refer to debug_types */ + if (dbg->de_debug_info.dss_size && + ((off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) { + _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD); + return (DW_DLV_ERROR); + } +#undef MIN_CU_HDR_SIZE + if (die_offset != NULL) { + *die_offset = global->gl_named_die_offset_within_cu + off; + } + + *ret_name = (char *) global->gl_name; + + if (cu_die_offset != NULL) { + /* Globals cannot refer to debug_types */ + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + /* The offset had better not be too close to the end. If it is, + _dwarf_length_of_cu_header() will step off the end and + therefore must not be used. 10 is a meaningless heuristic, + but no CU header is that small so it is safe. */ + /* Globals cannot refer to debug_types */ + if ((off + 10) >= dbg->de_debug_info.dss_size) { + _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off,true); + } + + + return DW_DLV_OK; +} + +/* We have the offset to a CU header. + Return thru outFileOffset the offset of the CU DIE. + + New June, 2001. + Used by SGI IRIX debuggers. + No error is possible. + + See also dwarf_CU_dieoffset_given_die(). + + This is assumed to never apply to data in .debug_types, it + only refers to .debug_info. + +*/ + +/* ARGSUSED */ +int +dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, + Dwarf_Off * out_cu_die_offset, + Dwarf_Error * err) +{ + Dwarf_Off len = + _dwarf_length_of_cu_header(dbg, in_cu_header_offset,true); + + Dwarf_Off newoff = in_cu_header_offset + len; + + *out_cu_die_offset = newoff; + return DW_DLV_OK; +} + +/* The following version new in October 2011, does allow finding + the offset if one knows whether debug_info or debug_types. + */ +int +dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, + Dwarf_Bool is_info, + Dwarf_Off * out_cu_die_offset, + Dwarf_Error * err) +{ + Dwarf_Off len = + _dwarf_length_of_cu_header(dbg, in_cu_header_offset,is_info); + + Dwarf_Off newoff = in_cu_header_offset + len; + + *out_cu_die_offset = newoff; + return DW_DLV_OK; +} +/* dwarf_CU_dieoffset_given_die returns + the global debug_info section offset of the CU die + that is the CU containing the given (passed-in) die. + This information makes it possible for a consumer to + find and print context information for any die. + + Use dwarf_offdie() passing in the offset this returns + to get a die pointer to the CU die. */ +int +dwarf_CU_dieoffset_given_die(Dwarf_Die die, + Dwarf_Off* return_offset, + Dwarf_Error* error) +{ + Dwarf_Off dieoff = 0; + Dwarf_CU_Context cucontext = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + cucontext = die->di_cu_context; + dieoff = cucontext->cc_debug_offset; + /* The following call cannot fail, so no error check. */ + dwarf_get_cu_die_offset_given_cu_header_offset_b( + cucontext->cc_dbg, dieoff, + die->di_is_info, return_offset,error); + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_global.h b/libdwarf/dwarf_global.h new file mode 100644 index 0000000..f1a8e93 --- /dev/null +++ b/libdwarf/dwarf_global.h @@ -0,0 +1,126 @@ +/* + + Copyright (C) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2011 David Anderson. All Rights Reserved. + + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +typedef struct Dwarf_Global_Context_s *Dwarf_Global_Context; + +/* + This struct contains header information for a set of pubnames. + Essentially, they contain the context for a set of pubnames + belonging to a compilation-unit. + + This is also used for the sgi-specific + weaknames, typenames, varnames, funcnames data: + the structs for those are incomplete and + instances of this are used instead. + + Also used for DWARF3 .debug_pubtypes. + + These never refer to .debug_types, only to .debug_info. + +*/ +struct Dwarf_Global_Context_s { + + /* Length in .debug_pubnames (etc) of a set of names for a + compilation-unit. Dwarf_Word pu_length; The value is not made + available outside libdwarf and not used inside, so no need to + record it. */ + + /* For this context, size of a length. 4 or 8 */ + unsigned char pu_length_size; + + /* For this CU, size of the extension 0 except for dwarf2 extension + 64bit, in which case is 4. */ + unsigned char pu_extension_size; + + /* Offset into .debug_info of the compilation-unit header (not DIE) + for this set of pubnames. */ + Dwarf_Off pu_offset_of_cu_header; + + /* Size of compilation-unit that these pubnames are in. */ + Dwarf_Unsigned pu_info_length; + + Dwarf_Debug pu_dbg; +}; + + +/* This struct contains information for a single pubname. */ +struct Dwarf_Global_s { + + /* Offset from the start of the corresponding compilation-unit of + the DIE for the given pubname CU. */ + Dwarf_Off gl_named_die_offset_within_cu; + + /* Points to the given pubname. */ + Dwarf_Small *gl_name; + + /* Context for this pubname. */ + Dwarf_Global_Context gl_context; +}; + +int _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, + Dwarf_Small * + section_data_ptr, + Dwarf_Unsigned + section_length, + Dwarf_Global ** globals, + Dwarf_Signed * return_count, + Dwarf_Error * error, + int context_code, + int global_code, + int length_err_num, + int version_err_num); + +void +_dwarf_internal_globals_dealloc( Dwarf_Debug dbg, Dwarf_Global *dwgl, + Dwarf_Signed count, + int context_code, + int global_code, + int list_code); + + +#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */ +void _dwarf_fix_up_offset_irix(Dwarf_Debug dbg, + Dwarf_Unsigned *varp, + char *caller_site_name); +#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name) _dwarf_fix_up_offset_irix(ldbg,&var,name) +#else +#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name) +#endif + diff --git a/libdwarf/dwarf_harmless.c b/libdwarf/dwarf_harmless.c new file mode 100644 index 0000000..0329bc9 --- /dev/null +++ b/libdwarf/dwarf_harmless.c @@ -0,0 +1,226 @@ +/* + + Copyright (C) 2010-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + +*/ + +/* This implements _dwarf_insert_harmless_error + and related helper functions for recording + compiler errors that need not make the input + unusable. + + Applications can use dwarf_get_harmless_error_list to + find (and possibly print) a warning about such errors. + + The initial error reported here is + DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE which was a + bug in a specific compiler. + + It is a fixed length circular list to constrain + the space used for errors. + + The assumption is that these errors are exceedingly + rare, and indicate a broken compiler (the one that + produced the object getting the error(s)). + + dh_maxcount is recorded internally as 1 greater than + requested. Hiding the fact we always leave one + slot unused (at least). So a user request for + N slots really gives the user N usable slots. */ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <stdlib.h> +#include "dwarf_frame.h" +#include "dwarf_harmless.h" + + +/* The pointers returned here through errmsg_ptrs_array + become invalidated by any call to libdwarf. Any call. +*/ +int dwarf_get_harmless_error_list(Dwarf_Debug dbg, + unsigned count, + const char ** errmsg_ptrs_array, + unsigned * errs_count) +{ + struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors; + if(!dhp->dh_errors) { + dhp->dh_errs_count = 0; + return DW_DLV_NO_ENTRY; + } + if(dhp->dh_errs_count == 0) { + return DW_DLV_NO_ENTRY; + } + if(errs_count) { + *errs_count = dhp->dh_errs_count; + } + if(count) { + /* NULL terminate the array of pointers */ + --count; + errmsg_ptrs_array[count] = 0; + + if(dhp->dh_next_to_use != dhp->dh_first) { + unsigned i = 0; + unsigned cur = dhp->dh_first; + for(i = 0; cur != dhp->dh_next_to_use; ++i) { + if(i >= count ) { + /* All output spaces are used. */ + break; + } + errmsg_ptrs_array[i] = dhp->dh_errors[cur]; + cur = (cur +1) % dhp->dh_maxcount; + } + errmsg_ptrs_array[i] = 0; + } + } + dhp->dh_next_to_use = 0; + dhp->dh_first = 0; + dhp->dh_errs_count = 0; + return DW_DLV_OK; +} + +/* strncpy does not null-terminate, this does it. */ +static void +safe_strncpy(char *targ, char *src, unsigned spaceavail) +{ + unsigned goodcount = spaceavail-1; + if(spaceavail < 1) { + return; /* impossible */ + } + strncpy(targ,src,goodcount); + targ[goodcount] = 0; +} + +/* Insertion made public is only for testing the harmless error code, + it is not necessarily useful for libdwarf client code aside + from code testing libdwarf. */ +void dwarf_insert_harmless_error(Dwarf_Debug dbg, + char *newerror) +{ + struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors; + unsigned next = 0; + unsigned cur = dhp->dh_next_to_use; + char *msgspace; + if(!dhp->dh_errors) { + dhp->dh_errs_count++; + return; + } + msgspace = dhp->dh_errors[cur]; + safe_strncpy(msgspace, newerror,DW_HARMLESS_ERROR_MSG_STRING_SIZE); + next = (cur+1) % dhp->dh_maxcount; + dhp->dh_errs_count++; + dhp->dh_next_to_use = next; + if (dhp->dh_next_to_use == dhp->dh_first) { + /* Array is full set full invariant. */ + dhp->dh_first = (dhp->dh_first+1) % dhp->dh_maxcount; + } +} + +/* The size of the circular list of strings may be set + and reset as desired. Returns the previous size of + the list. If the list is shortened excess error entries + are simply dropped. + If the reallocation fails the list size is left unchanged. + Do not make this a long list! + + Remember the maxcount we record is 1 > the user count, + so we adjust it so it looks like the user count. +*/ +unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg, + unsigned maxcount ) +{ + struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors; + unsigned prevcount = dhp->dh_maxcount; + if(maxcount != 0) { + ++maxcount; + if(maxcount != dhp->dh_maxcount) { + /* Assign transfers 'ownership' of the malloc areas + to oldarray. */ + struct Dwarf_Harmless_s oldarray = *dhp; + /* Do not double increment the max, the init() func + increments it too. */ + dwarf_harmless_init(dhp,maxcount-1); + if(oldarray.dh_next_to_use != oldarray.dh_first) { + unsigned i = 0; + for(i = oldarray.dh_first; i != oldarray.dh_next_to_use; + i = (i+1)%oldarray.dh_maxcount) { + dwarf_insert_harmless_error(dbg,oldarray.dh_errors[i]); + } + if( oldarray.dh_errs_count > dhp->dh_errs_count) { + dhp->dh_errs_count = oldarray.dh_errs_count; + } + } + dwarf_harmless_cleanout(&oldarray); + } + } + return prevcount-1; +} + +/* Only callable from within libdwarf (as a practical matter) +*/ +void +dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size) +{ + unsigned i = 0; + memset(dhp,0,sizeof(*dhp)); + dhp->dh_maxcount = size +1; + dhp->dh_errors = (char **)malloc(sizeof( char *) *dhp->dh_maxcount); + if (!dhp->dh_errors) { + dhp->dh_maxcount = 0; + return; + } + + for(i = 0; i < dhp->dh_maxcount; ++i) { + char *newstr = + (char *)malloc(DW_HARMLESS_ERROR_MSG_STRING_SIZE); + dhp->dh_errors[i] = newstr; + if(!newstr) { + dhp->dh_maxcount = 0; + /* Let it leak, the leak is a constrained amount. */ + dhp->dh_errors = 0; + return; + } + /* We make the string content well-defined by an initial + NUL byte, but this is not really necessary. */ + newstr[0] = 0; + } +} + +void +dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp) +{ + unsigned i = 0; + if(!dhp->dh_errors) { + return; + } + for(i = 0; i < dhp->dh_maxcount; ++i) { + free(dhp->dh_errors[i]); + } + free(dhp->dh_errors); + dhp->dh_errors = 0; + dhp->dh_maxcount = 0; +} + diff --git a/libdwarf/dwarf_harmless.h b/libdwarf/dwarf_harmless.h new file mode 100644 index 0000000..3d4d910 --- /dev/null +++ b/libdwarf/dwarf_harmless.h @@ -0,0 +1,31 @@ +/* + + Copyright (C) 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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + +*/ + + + +void dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size); +void dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp); + diff --git a/libdwarf/dwarf_incl.h b/libdwarf/dwarf_incl.h new file mode 100644 index 0000000..58208e1 --- /dev/null +++ b/libdwarf/dwarf_incl.h @@ -0,0 +1,69 @@ +/* + + Copyright (C) 2000, 2002, 2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2008-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#ifndef DWARF_INCL_H +#define DWARF_INCL_H +#if (!defined(HAVE_RAW_LIBELF_OK) && defined(HAVE_LIBELF_OFF64_OK) ) +/* At a certain point libelf.h requires _GNU_SOURCE. + here we assume the criteria in configure determine that + usefully. +*/ +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_STDAFX_H /* Windows specific. */ +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "libdwarfdefs.h" +#include <string.h> + +#ifdef HAVE_ELF_H +#include <elf.h> +#endif + +#include <limits.h> +#include <dwarf.h> +#include <libdwarf.h> + +#include "dwarf_base_types.h" +#include "dwarf_alloc.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#endif /* DWARF_INCL_H */ diff --git a/libdwarf/dwarf_init_finish.c b/libdwarf/dwarf_init_finish.c new file mode 100644 index 0000000..ce73979 --- /dev/null +++ b/libdwarf/dwarf_init_finish.c @@ -0,0 +1,732 @@ +/* + + Copyright (C) 2000,2002,2003,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +#include "config.h" +#include "dwarf_incl.h" + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> + +#include "dwarf_incl.h" +#include "dwarf_harmless.h" +#include "malloc_check.h" + +#define DWARF_DBG_ERROR(dbg,errval,retval) \ + _dwarf_error(dbg, error, errval); return(retval); + +#define FALSE 0 +#define TRUE 1 + + + +/* This static is copied to the dbg on dbg init + so that the static need not be referenced at + run time, preserving better locality of + reference. + Value is 0 means do the string check. + Value non-zero means do not do the check. +*/ +static Dwarf_Small _dwarf_assume_string_bad; +static Dwarf_Small _dwarf_apply_relocs = 1; + +/* Call this after calling dwarf_init but before doing anything else. + It applies to all objects, not just the current object. */ +int +dwarf_set_reloc_application(int apply) +{ + int oldval = _dwarf_apply_relocs; + _dwarf_apply_relocs = apply; + return oldval; +} + +int +dwarf_set_stringcheck(int newval) +{ + int oldval = _dwarf_assume_string_bad; + + _dwarf_assume_string_bad = newval; + return oldval; +} + +/* Unifies the basic duplicate/empty testing and section + data setting to one place. */ +static int +get_basic_section_data(Dwarf_Debug dbg, + struct Dwarf_Section_s *secdata, + struct Dwarf_Obj_Access_Section_s *doas, + Dwarf_Half section_index, + Dwarf_Error* error, + int duperr, int emptyerr ) +{ + /* There is an elf convention that section index 0 is reserved, + and that section is always empty. + Non-elf object formats must honor that by ensuring that + (when they assign numbers to 'sections' or 'section-like-things') + they never assign a real section section-number 0 to dss_index. */ + if (secdata->dss_index != 0) { + DWARF_DBG_ERROR(dbg, duperr, DW_DLV_ERROR); + } + if (doas->size == 0) { + if (emptyerr == 0 ) { + /* Allow empty section. */ + return DW_DLV_OK; + } + /* Know no reason to allow section */ + DWARF_DBG_ERROR(dbg, emptyerr, DW_DLV_ERROR); + } + secdata->dss_index = section_index; + secdata->dss_size = doas->size; + secdata->dss_addr = doas->addr; + secdata->dss_link = doas->link; + secdata->dss_entrysize = doas->entrysize; + return DW_DLV_OK; +} + + +static void +add_rela_data( struct Dwarf_Section_s *secdata, + struct Dwarf_Obj_Access_Section_s *doas, + Dwarf_Half section_index) +{ + secdata->dss_reloc_index = section_index; + secdata->dss_reloc_size = doas->size; + secdata->dss_reloc_entrysize = doas->entrysize; + secdata->dss_reloc_addr = doas->addr; + secdata->dss_reloc_symtab = doas->link; + secdata->dss_reloc_link = doas->link; +} + +/* Given an Elf ptr, set up dbg with pointers + to all the Dwarf data sections. + Return NULL on error. + + This function is also responsible for determining + whether the given object contains Dwarf information + or not. The test currently used is that it contains + either a .debug_info or a .debug_frame section. If + not, it returns DW_DLV_NO_ENTRY causing dwarf_init() also to + return DW_DLV_NO_ENTRY. Earlier, we had thought of using only + the presence/absence of .debug_info to test, but we + added .debug_frame since there could be stripped objects + that have only a .debug_frame section for exception + processing. + DW_DLV_NO_ENTRY or DW_DLV_OK or DW_DLV_ERROR */ +static int +_dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error) +{ + const char *scn_name = 0; + int foundDwarf = 0; + struct Dwarf_Obj_Access_Interface_s * obj = 0; + + Dwarf_Endianness endianness; + + Dwarf_Unsigned section_size = 0; + Dwarf_Unsigned section_count = 0; + Dwarf_Half section_index = 0; + Dwarf_Addr section_addr = 0; + + foundDwarf = FALSE; + + dbg->de_assume_string_in_bounds = _dwarf_assume_string_bad; + + dbg->de_same_endian = 1; + dbg->de_copy_word = memcpy; + obj = dbg->de_obj_file; + endianness = obj->methods->get_byte_order(obj->object); +#ifdef WORDS_BIGENDIAN + dbg->de_big_endian_object = 1; + if (endianness == DW_OBJECT_LSB ) { + dbg->de_same_endian = 0; + dbg->de_big_endian_object = 0; + dbg->de_copy_word = _dwarf_memcpy_swap_bytes; + } +#else /* little endian */ + dbg->de_big_endian_object = 0; + if (endianness == DW_OBJECT_MSB ) { + dbg->de_same_endian = 0; + dbg->de_big_endian_object = 1; + dbg->de_copy_word = _dwarf_memcpy_swap_bytes; + } +#endif /* !WORDS_BIGENDIAN */ + + + /* The following de_length_size is Not Too Significant. Only used + one calculation, and an approximate one at that. */ + dbg->de_length_size = obj->methods->get_length_size(obj->object); + dbg->de_pointer_size = obj->methods->get_pointer_size(obj->object); + + /* For windows always is 4 ? */ +#ifdef WIN32 + dbg->de_pointer_size = 4; +#endif /* WIN32 */ + + section_count = obj->methods->get_section_count(obj->object); + + /* We can skip index 0 when considering ELF files, but not other + object types. Indeed regardless of the object type we should + skip section 0 here. + This is a convention. We depend on it. + Non-elf object access code should + (in itself) understand we will index beginning at 1 and adjust + itself to deal with this Elf convention. Without this + convention various parts of the code in this file won't work correctly. + A dss_index of 0 must not be used, even though we start at 0 + here. So the get_section_info() must adapt to the situation + (the elf version does automatically as a result of Elf having + a section zero with zero length and an empty name). */ + for (section_index = 0; section_index < section_count; + ++section_index) { + + struct Dwarf_Obj_Access_Section_s doas; + int res = DW_DLV_ERROR; + int err = 0; + + memset(&doas,0,sizeof(doas)); + res = obj->methods->get_section_info(obj->object, + section_index, + &doas, &err); + if(res == DW_DLV_ERROR){ + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + + section_addr = doas.addr; + section_size = doas.size; + scn_name = doas.name; + + if (strncmp(scn_name, ".debug_", 7) + && strcmp(scn_name, ".eh_frame") + && strcmp(scn_name, ".symtab") + && strcmp(scn_name, ".strtab") + && strncmp(scn_name, ".rela.",6)) { + continue; + } + else if (strcmp(scn_name, ".debug_info") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_info, &doas, + section_index,error, + DW_DLE_DEBUG_INFO_DUPLICATE,DW_DLE_DEBUG_INFO_NULL); + if(res != DW_DLV_OK) { + return res; + } + foundDwarf = TRUE; + } + else if (strcmp(scn_name, ".debug_types") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_types, &doas, + section_index,error, + DW_DLE_DEBUG_TYPES_DUPLICATE,DW_DLE_DEBUG_TYPES_NULL); + if(res != DW_DLV_OK) { + return res; + } + foundDwarf = TRUE; + } + else if (strcmp(scn_name, ".debug_abbrev") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_abbrev, &doas, + section_index,error, + DW_DLE_DEBUG_ABBREV_DUPLICATE,DW_DLE_DEBUG_ABBREV_NULL); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_aranges") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_aranges, &doas, + section_index,error, DW_DLE_DEBUG_ARANGES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + + else if (strcmp(scn_name, ".debug_line") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_line, &doas, + section_index,error, DW_DLE_DEBUG_LINE_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_frame") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_frame, &doas, + section_index,error, DW_DLE_DEBUG_FRAME_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + foundDwarf = TRUE; + } else if (strcmp(scn_name, ".eh_frame") == 0) { + /* gnu egcs-1.1.2 data */ + res = get_basic_section_data(dbg,&dbg->de_debug_frame_eh_gnu, + &doas, + section_index,error, DW_DLE_DEBUG_FRAME_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + foundDwarf = TRUE; + } + else if (strcmp(scn_name, ".debug_loc") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_loc, &doas, + section_index,error, DW_DLE_DEBUG_LOC_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_pubnames") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_pubnames, &doas, + section_index,error, DW_DLE_DEBUG_PUBNAMES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + + else if (strcmp(scn_name, ".debug_str") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_str, &doas, + section_index,error, DW_DLE_DEBUG_STR_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_funcnames") == 0) { + /* SGI IRIX-only. */ + res = get_basic_section_data(dbg,&dbg->de_debug_funcnames, + &doas, + section_index,error, DW_DLE_DEBUG_FUNCNAMES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_typenames") == 0) { + /* SGI IRIX-only, created years before DWARF3. Content + essentially identical to .debug_pubtypes. */ + res = get_basic_section_data(dbg,&dbg->de_debug_typenames, + &doas, + section_index,error, DW_DLE_DEBUG_TYPENAMES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } else if (strcmp(scn_name, ".debug_pubtypes") == 0) { + /* Section new in DWARF3. */ + res = get_basic_section_data(dbg,&dbg->de_debug_pubtypes, &doas, + section_index,error, DW_DLE_DEBUG_PUBTYPES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_varnames") == 0) { + /* SGI IRIX-only. */ + res = get_basic_section_data(dbg,&dbg->de_debug_varnames, &doas, + section_index,error, DW_DLE_DEBUG_VARNAMES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_weaknames") == 0) { + /* SGI IRIX-only. */ + res = get_basic_section_data(dbg,&dbg->de_debug_weaknames, + &doas, section_index,error, + DW_DLE_DEBUG_WEAKNAMES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } else if (strcmp(scn_name, ".debug_macinfo") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_macinfo, &doas, + section_index,error, DW_DLE_DEBUG_MACINFO_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".debug_ranges") == 0) { + res = get_basic_section_data(dbg,&dbg->de_debug_ranges, &doas, + section_index,error, DW_DLE_DEBUG_RANGES_DUPLICATE,0); + if(res != DW_DLV_OK) { + return res; + } + foundDwarf = TRUE; + } + else if (strcmp(scn_name, ".symtab") == 0) { + res = get_basic_section_data(dbg,&dbg->de_elf_symtab, &doas, + section_index,error, DW_DLE_DEBUG_SYMTAB_ERR,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strcmp(scn_name, ".strtab") == 0) { + res = get_basic_section_data(dbg,&dbg->de_elf_strtab, &doas, + section_index,error, DW_DLE_DEBUG_STRTAB_ERR,0); + if(res != DW_DLV_OK) { + return res; + } + } + else if (strncmp(scn_name, ".rela.debug_",12) == 0) { + const char *rcn_name = scn_name + 5; + if (strcmp(rcn_name, ".debug_info") == 0) { + add_rela_data(&dbg->de_debug_info,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_abbrev") == 0) { + add_rela_data(&dbg->de_debug_abbrev,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_aranges") == 0) { + add_rela_data(&dbg->de_debug_aranges,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_line") == 0) { + add_rela_data(&dbg->de_debug_line,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_frame") == 0) { + add_rela_data(&dbg->de_debug_frame,&doas,section_index); + } else if (strcmp(rcn_name, ".eh_frame") == 0) { + add_rela_data(&dbg->de_debug_frame_eh_gnu,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_loc") == 0) { + add_rela_data(&dbg->de_debug_loc,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_pubnames") == 0) { + add_rela_data(&dbg->de_debug_pubnames,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_str") == 0) { + add_rela_data(&dbg->de_debug_str,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_funcnames") == 0) { + add_rela_data(&dbg->de_debug_funcnames,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_typenames") == 0) { + add_rela_data(&dbg->de_debug_typenames,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_pubtypes") == 0) { + add_rela_data(&dbg->de_debug_pubtypes,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_varnames") == 0) { + add_rela_data(&dbg->de_debug_varnames,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_weaknames") == 0) { + add_rela_data(&dbg->de_debug_weaknames,&doas,section_index); + } else if (strcmp(rcn_name, ".debug_macinfo") == 0) { + add_rela_data(&dbg->de_debug_macinfo,&doas,section_index); + } + } + } + if (foundDwarf) { + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + + +/* + Use a Dwarf_Obj_Access_Interface to kick things off. All other + init routines eventually use this one. + The returned Dwarf_Debug contains a copy of *obj + the callers copy of *obj may be freed whenever the caller + wishes. +*/ +int +dwarf_object_init(Dwarf_Obj_Access_Interface* obj, Dwarf_Handler errhand, + Dwarf_Ptr errarg, Dwarf_Debug* ret_dbg, + Dwarf_Error* error) +{ + Dwarf_Debug dbg = 0; + int setup_result = DW_DLV_OK; + + dbg = _dwarf_get_debug(); + if (dbg == NULL) { + DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR); + } + dbg->de_errhand = errhand; + dbg->de_errarg = errarg; + dbg->de_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE; + dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM; +#ifdef HAVE_OLD_FRAME_CFA_COL + /* DW_FRAME_CFA_COL is really only suitable for old libdwarf frame + interfaces and its value of 0 there is only usable where + (as in MIPS) register 0 has no value other than 0 so + we can use the frame table column 0 for the CFA value + (and rely on client software to know when 'register 0' + is the cfa and when to just use a value 0 for register 0). + */ + dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL; +#else + dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL3; +#endif + dbg->de_frame_same_value_number = DW_FRAME_SAME_VAL; + dbg->de_frame_undefined_value_number = DW_FRAME_UNDEFINED_VAL; + + dbg->de_obj_file = obj; + + setup_result = _dwarf_setup(dbg, error); + if (setup_result != DW_DLV_OK) { + /* The status we want to return here is of _dwarf_setup, + not of the _dwarf_free_all_of_one_debug(dbg) call. + So use a local status variable for the free. */ + int freeresult = _dwarf_free_all_of_one_debug(dbg); + if (freeresult == DW_DLV_ERROR) { + DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR); + } + dwarf_malloc_check_complete("After Final free"); + return setup_result; + } + + dwarf_harmless_init(&dbg->de_harmless_errors, + DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE); + + /* This call cannot fail: allocates nothing, releases nothing */ + _dwarf_setup_debug(dbg); + + + *ret_dbg = dbg; + return DW_DLV_OK; +} + + +/* A finish routine that is completely unaware of ELF. + + Frees all memory that was not previously freed by + dwarf_dealloc. + Aside frmo certain categories. */ +int +dwarf_object_finish(Dwarf_Debug dbg, Dwarf_Error * error) +{ + int res = DW_DLV_OK; + + res = _dwarf_free_all_of_one_debug(dbg); + if (res == DW_DLV_ERROR) { + DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR); + } + dwarf_malloc_check_complete("After Final free"); + + return res; +} + + +/* Load the ELF section with the specified index and set the + pointer pointed to by section_data to the memory where it + was loaded. */ +int +_dwarf_load_section(Dwarf_Debug dbg, + struct Dwarf_Section_s *section, + Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + int err = 0; + struct Dwarf_Obj_Access_Interface_s *o = 0; + + /* check to see if the section is already loaded */ + if (section->dss_data != NULL) { + return DW_DLV_OK; + } + o = dbg->de_obj_file; + /* There is an elf convention that section index 0 is reserved, + and that section is always empty. + Non-elf object formats must honor that by ensuring that + (when they assign numbers to 'sections' or 'section-like-things') + they never assign a real section section-number 0 to dss_index. */ + res = o->methods->load_section( + o->object, section->dss_index, + §ion->dss_data, &err); + if(res == DW_DLV_ERROR){ + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + if(_dwarf_apply_relocs == 0) { + return res; + } + if(section->dss_reloc_size == 0) { + return res; + } + if(!o->methods->relocate_a_section) { + return res; + } + /*apply relocations */ + res = o->methods->relocate_a_section( o->object, section->dss_index, + dbg, &err); + if(res == DW_DLV_ERROR) { + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + return res; +} + +/* This is a hack so clients can verify offsets. + Added April 2005 so that debugger can detect broken offsets + (which happened in an IRIX -64 executable larger than 2GB + using MIPSpro 7.3.1.3 compilers. A couple .debug_pubnames + offsets were wrong.). +*/ +int +dwarf_get_section_max_offsets(Dwarf_Debug dbg, + Dwarf_Unsigned * debug_info_size, + Dwarf_Unsigned * debug_abbrev_size, + Dwarf_Unsigned * debug_line_size, + Dwarf_Unsigned * debug_loc_size, + Dwarf_Unsigned * debug_aranges_size, + Dwarf_Unsigned * debug_macinfo_size, + Dwarf_Unsigned * debug_pubnames_size, + Dwarf_Unsigned * debug_str_size, + Dwarf_Unsigned * debug_frame_size, + Dwarf_Unsigned * debug_ranges_size, + Dwarf_Unsigned * debug_typenames_size) +{ + *debug_info_size = dbg->de_debug_info.dss_size; + *debug_abbrev_size = dbg->de_debug_abbrev.dss_size; + *debug_line_size = dbg->de_debug_line.dss_size; + *debug_loc_size = dbg->de_debug_loc.dss_size; + *debug_aranges_size = dbg->de_debug_aranges.dss_size; + *debug_macinfo_size = dbg->de_debug_macinfo.dss_size; + *debug_pubnames_size = dbg->de_debug_pubnames.dss_size; + *debug_str_size = dbg->de_debug_str.dss_size; + *debug_frame_size = dbg->de_debug_frame.dss_size; + *debug_ranges_size = dbg->de_debug_ranges.dss_size; + *debug_typenames_size = dbg->de_debug_typenames.dss_size; + return DW_DLV_OK; +} +/* This adds the new types size (new section) to the output data. + Oct 27, 2011. */ +int +dwarf_get_section_max_offsets_b(Dwarf_Debug dbg, + Dwarf_Unsigned * debug_info_size, + Dwarf_Unsigned * debug_abbrev_size, + Dwarf_Unsigned * debug_line_size, + Dwarf_Unsigned * debug_loc_size, + Dwarf_Unsigned * debug_aranges_size, + Dwarf_Unsigned * debug_macinfo_size, + Dwarf_Unsigned * debug_pubnames_size, + Dwarf_Unsigned * debug_str_size, + Dwarf_Unsigned * debug_frame_size, + Dwarf_Unsigned * debug_ranges_size, + Dwarf_Unsigned * debug_typenames_size, + Dwarf_Unsigned * debug_types_size) +{ + *debug_info_size = dbg->de_debug_info.dss_size; + *debug_abbrev_size = dbg->de_debug_abbrev.dss_size; + *debug_line_size = dbg->de_debug_line.dss_size; + *debug_loc_size = dbg->de_debug_loc.dss_size; + *debug_aranges_size = dbg->de_debug_aranges.dss_size; + *debug_macinfo_size = dbg->de_debug_macinfo.dss_size; + *debug_pubnames_size = dbg->de_debug_pubnames.dss_size; + *debug_str_size = dbg->de_debug_str.dss_size; + *debug_frame_size = dbg->de_debug_frame.dss_size; + *debug_ranges_size = dbg->de_debug_ranges.dss_size; + *debug_typenames_size = dbg->de_debug_typenames.dss_size; + *debug_types_size = dbg->de_debug_types.dss_size; + return DW_DLV_OK; +} + + +/* Given a section name, get its size and address */ +int +dwarf_get_section_info_by_name(Dwarf_Debug dbg, + const char *section_name, + Dwarf_Addr *section_addr, + Dwarf_Unsigned *section_size, + Dwarf_Error * error) +{ + struct Dwarf_Obj_Access_Section_s doas; + struct Dwarf_Obj_Access_Interface_s * obj = 0; + Dwarf_Unsigned section_count = 0; + Dwarf_Half section_index = 0; + + *section_addr = 0; + *section_size = 0; + + obj = dbg->de_obj_file; + if (NULL == obj) { + return DW_DLV_NO_ENTRY; + } + + section_count = obj->methods->get_section_count(obj->object); + + /* We can skip index 0 when considering ELF files, but not other + object types. */ + for (section_index = 0; section_index < section_count; + ++section_index) { + int err = 0; + int res = obj->methods->get_section_info(obj->object, + section_index, &doas, &err); + if (res == DW_DLV_ERROR) { + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + + if (!strcmp(section_name,doas.name)) { + *section_addr = doas.addr; + *section_size = doas.size; + return DW_DLV_OK; + } + } + + return DW_DLV_NO_ENTRY; +} + +/* Given a section index, get its size and address */ +int +dwarf_get_section_info_by_index(Dwarf_Debug dbg, + int section_index, + const char **section_name, + Dwarf_Addr *section_addr, + Dwarf_Unsigned *section_size, + Dwarf_Error * error) +{ + *section_addr = 0; + *section_size = 0; + *section_name = NULL; + + /* Check if we have a valid section index */ + if (section_index >= 0 && section_index < dwarf_get_section_count(dbg)) { + int res = 0; + int err = 0; + struct Dwarf_Obj_Access_Section_s doas; + struct Dwarf_Obj_Access_Interface_s * obj = dbg->de_obj_file; + if (NULL == obj) { + return DW_DLV_NO_ENTRY; + } + res = obj->methods->get_section_info(obj->object, + section_index, &doas, &err); + if (res == DW_DLV_ERROR){ + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + + *section_addr = doas.addr; + *section_size = doas.size; + *section_name = doas.name; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +/* Get section count */ +int +dwarf_get_section_count(Dwarf_Debug dbg) +{ + struct Dwarf_Obj_Access_Interface_s * obj = dbg->de_obj_file; + if (NULL == obj) { + return DW_DLV_NO_ENTRY; + } + return obj->methods->get_section_count(obj->object); +} + +Dwarf_Cmdline_Options dwarf_cmdline_options = { + FALSE /* Use quiet mode by default. */ +}; + +/* Lets libdwarf reflect a command line option, so we can get details + of some errors printed using libdwarf-internal information. */ +void +dwarf_record_cmdline_options(Dwarf_Cmdline_Options options) +{ + dwarf_cmdline_options = options; +} diff --git a/libdwarf/dwarf_leb.c b/libdwarf/dwarf_leb.c new file mode 100644 index 0000000..7e01d84 --- /dev/null +++ b/libdwarf/dwarf_leb.c @@ -0,0 +1,146 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> + + +/* Decode ULEB */ +Dwarf_Unsigned +_dwarf_decode_u_leb128(Dwarf_Small * leb128, Dwarf_Word * leb128_length) +{ + unsigned char byte; + Dwarf_Word word_number; + Dwarf_Unsigned number; + Dwarf_Sword shift; + Dwarf_Sword byte_length; + + /* The following unrolls-the-loop for the first few bytes and + unpacks into 32 bits to make this as fast as possible. + word_number is assumed big enough that the shift has a defined + result. */ + if ((*leb128 & 0x80) == 0) { + if (leb128_length != NULL) + *leb128_length = 1; + return (*leb128); + } else if ((*(leb128 + 1) & 0x80) == 0) { + if (leb128_length != NULL) + *leb128_length = 2; + + word_number = *leb128 & 0x7f; + word_number |= (*(leb128 + 1) & 0x7f) << 7; + return (word_number); + } else if ((*(leb128 + 2) & 0x80) == 0) { + if (leb128_length != NULL) + *leb128_length = 3; + + word_number = *leb128 & 0x7f; + word_number |= (*(leb128 + 1) & 0x7f) << 7; + word_number |= (*(leb128 + 2) & 0x7f) << 14; + return (word_number); + } else if ((*(leb128 + 3) & 0x80) == 0) { + if (leb128_length != NULL) + *leb128_length = 4; + + word_number = *leb128 & 0x7f; + word_number |= (*(leb128 + 1) & 0x7f) << 7; + word_number |= (*(leb128 + 2) & 0x7f) << 14; + word_number |= (*(leb128 + 3) & 0x7f) << 21; + return (word_number); + } + + /* The rest handles long numbers Because the 'number' may be larger + than the default int/unsigned, we must cast the 'byte' before + the shift for the shift to have a defined result. */ + number = 0; + shift = 0; + byte_length = 1; + byte = *(leb128); + for (;;) { + number |= ((Dwarf_Unsigned) (byte & 0x7f)) << shift; + + if ((byte & 0x80) == 0) { + if (leb128_length != NULL) + *leb128_length = byte_length; + return (number); + } + shift += 7; + + byte_length++; + ++leb128; + byte = *leb128; + } +} + +#define BITSINBYTE 8 + +/* decode SLEB */ +Dwarf_Signed +_dwarf_decode_s_leb128(Dwarf_Small * leb128, Dwarf_Word * leb128_length) +{ + Dwarf_Signed number = 0; + Dwarf_Bool sign = 0; + Dwarf_Sword shift = 0; + unsigned char byte = *leb128; + Dwarf_Sword byte_length = 1; + + /* byte_length being the number of bytes of data absorbed so far in + turning the leb into a Dwarf_Signed. */ + + for (;;) { + sign = byte & 0x40; + number |= ((Dwarf_Signed) ((byte & 0x7f))) << shift; + shift += 7; + + if ((byte & 0x80) == 0) { + break; + } + ++leb128; + byte = *leb128; + byte_length++; + } + + if ((shift < sizeof(Dwarf_Signed) * BITSINBYTE) && sign) { + number |= -((Dwarf_Signed) 1 << shift); + } + + if (leb128_length != NULL) + *leb128_length = byte_length; + return (number); +} diff --git a/libdwarf/dwarf_line.c b/libdwarf/dwarf_line.c new file mode 100644 index 0000000..5f81e7c --- /dev/null +++ b/libdwarf/dwarf_line.c @@ -0,0 +1,2059 @@ +/* . + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <stdlib.h> +#include "dwarf_line.h" + +static int +is_path_separator(Dwarf_Small s) +{ + if(s == '/') { + return 1; + } +#ifdef HAVE_WINDOWS_PATH + if(s == '\\') { + return 1; + } +#endif + return 0; +} + +/* Return 0 if false, 1 if true. + If HAVE_WINDOWS_PATH is defined we + attempt to handle windows full paths: + \\something or C:cwdpath.c +*/ +static int +file_name_is_full_path(Dwarf_Small *fname) +{ + Dwarf_Small firstc = *fname; + if(is_path_separator(firstc)) { + /* Full path. */ + return 1; + } + if(!firstc) { + return 0; + } +#ifdef HAVE_WINDOWS_PATH + if((firstc >= 'A' && firstc <= 'Z') || + (firstc >= 'a' && firstc <= 'z')) { + + Dwarf_Small secondc = fname[1]; + if (secondc == ':') { + return 1; + } + } +#endif + return 0; +} + +/* Although source files is supposed to return the + source files in the compilation-unit, it does + not look for any in the statement program. In + other words, it ignores those defined using the + extended opcode DW_LNE_define_file. */ +int +dwarf_srcfiles(Dwarf_Die die, + char ***srcfiles, + Dwarf_Signed * srcfilecount, Dwarf_Error * error) +{ + /* This pointer is used to scan the portion of the .debug_line + section for the current cu. */ + Dwarf_Small *line_ptr; + + /* Pointer to a DW_AT_stmt_list attribute in case it exists in the + die. */ + Dwarf_Attribute stmt_list_attr; + + /* Pointer to DW_AT_comp_dir attribute in die. */ + Dwarf_Attribute comp_dir_attr; + + /* Pointer to name of compilation directory. */ + Dwarf_Small *comp_dir = 0; + + /* Offset into .debug_line specified by a DW_AT_stmt_list + attribute. */ + Dwarf_Unsigned line_offset = 0; + + /* This points to a block of char *'s, each of which points to a + file name. */ + char **ret_files = 0; + + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg = 0; + + /* Used to chain the file names. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain prev_chain = NULL; + Dwarf_Chain head_chain = NULL; + Dwarf_Half attrform = 0; + int resattr = DW_DLV_ERROR; + int lres = DW_DLV_ERROR; + struct Line_Table_Prefix_s line_prefix; + int i = 0; + int res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + /* Reset error. */ + if (error != NULL) { + *error = NULL; + } + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + + resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error); + if (resattr != DW_DLV_OK) { + return resattr; + } + + if (dbg->de_debug_line.dss_index == 0) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL); + return (DW_DLV_ERROR); + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_line.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + lres = dwarf_whatform(stmt_list_attr,&attrform,error); + if (lres != DW_DLV_OK) { + return lres; + } + if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 && + attrform != DW_FORM_sec_offset ) { + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + lres = dwarf_global_formref(stmt_list_attr, &line_offset, error); + if (lres != DW_DLV_OK) { + return lres; + } + if (line_offset >= dbg->de_debug_line.dss_size) { + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + line_ptr = dbg->de_debug_line.dss_data + line_offset; + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + + /* If die has DW_AT_comp_dir attribute, get the string that names + the compilation directory. */ + resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + if (resattr == DW_DLV_OK) { + int cres = DW_DLV_ERROR; + char *cdir = 0; + + cres = dwarf_formstring(comp_dir_attr, &cdir, error); + if (cres == DW_DLV_ERROR) { + return cres; + } else if (cres == DW_DLV_OK) { + comp_dir = (Dwarf_Small *) cdir; + } + } + if (resattr == DW_DLV_OK) { + dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); + } + dwarf_init_line_table_prefix(&line_prefix); + { + Dwarf_Small *line_ptr_out = 0; + int dres = dwarf_read_line_table_prefix(dbg, + line_ptr, + dbg->de_debug_line.dss_size, + &line_ptr_out, + &line_prefix, + NULL, NULL,error, + 0); + + if (dres == DW_DLV_ERROR) { + dwarf_free_line_table_prefix(&line_prefix); + return dres; + } + if (dres == DW_DLV_NO_ENTRY) { + dwarf_free_line_table_prefix(&line_prefix); + return dres; + } + + line_ptr = line_ptr_out; + } + + for (i = 0; i < line_prefix.pf_files_count; ++i) { + struct Line_Table_File_Entry_s *fe = + line_prefix.pf_line_table_file_entries + i; + char *file_name = (char *) fe->lte_filename; + char *dir_name = 0; + char *full_name = 0; + Dwarf_Unsigned dir_index = fe->lte_directory_index; + + if (dir_index == 0) { + dir_name = (char *) comp_dir; + } else { + dir_name = + (char *) line_prefix.pf_include_directories[ + fe->lte_directory_index - 1]; + } + + /* dir_name can be NULL if there is no DW_AT_comp_dir. + file_name == fe->lte_filename aside from char signedness. + */ + if(dir_name == 0 || file_name_is_full_path(fe->lte_filename)) { + /* This is safe because dwarf_dealloc is careful to not + dealloc strings which are part of the raw .debug_* data. + */ + full_name = file_name; + } else { + full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING, + strlen(dir_name) + 1 + + strlen(file_name) + + 1); + if (full_name == NULL) { + dwarf_free_line_table_prefix(&line_prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* This is not careful to avoid // in the output, Nothing + forces a 'canonical' name format here. Unclear if this + needs to be fixed. */ +#if defined (HAVE_WINDOWS_PATH) + /* Always '/' instead of '\\', this is a Windows -> Unix + issue. */ + { + int index = 0; + int len = strlen(dir_name); + for (index = 0; index < len; ++index) { + full_name[index] = dir_name[index]; + if (full_name[index] == '\\') { + full_name[index] = '/'; + } + } + } +#else + strcpy(full_name, dir_name); +#endif /* HAVE_WINDOWS_PATH */ + strcat(full_name, "/"); + strcat(full_name, file_name); + } + curr_chain = + (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + dwarf_free_line_table_prefix(&line_prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + curr_chain->ch_item = full_name; + if (head_chain == NULL) + head_chain = prev_chain = curr_chain; + else { + prev_chain->ch_next = curr_chain; + prev_chain = curr_chain; + } + } + + curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + dwarf_free_line_table_prefix(&line_prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + if (line_prefix.pf_files_count == 0) { + *srcfiles = NULL; + *srcfilecount = 0; + dwarf_free_line_table_prefix(&line_prefix); + return (DW_DLV_NO_ENTRY); + } + + ret_files = (char **) + _dwarf_get_alloc(dbg, DW_DLA_LIST, line_prefix.pf_files_count); + if (ret_files == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + dwarf_free_line_table_prefix(&line_prefix); + return (DW_DLV_ERROR); + } + + curr_chain = head_chain; + for (i = 0; i < line_prefix.pf_files_count; i++) { + *(ret_files + i) = curr_chain->ch_item; + prev_chain = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); + } + + *srcfiles = ret_files; + *srcfilecount = line_prefix.pf_files_count; + dwarf_free_line_table_prefix(&line_prefix); + return (DW_DLV_OK); +} + +/* A function as this code is used twice. */ +static void +update_file_entry(Dwarf_File_Entry cur_file_entry, + Dwarf_File_Entry *file_entries, + Dwarf_File_Entry *prev_file_entry, + Dwarf_Sword *file_entry_count) +{ + if (*file_entries == NULL) { + *file_entries = cur_file_entry; + } else { + (*prev_file_entry)->fi_next = cur_file_entry; + } + *prev_file_entry = cur_file_entry; + (*file_entry_count)++; +} + +static void +update_chain_list( Dwarf_Chain chain_line, + Dwarf_Chain *head_chain, Dwarf_Chain *curr_chain) +{ + if (*head_chain == NULL) { + *head_chain = chain_line; + } else { + (*curr_chain)->ch_next = chain_line; + } + *curr_chain = chain_line; +} + + +/* Feturn DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR */ +int +_dwarf_internal_srclines(Dwarf_Die die, + Dwarf_Line ** linebuf, + Dwarf_Signed * count, + Dwarf_Bool doaddrs, + Dwarf_Bool dolines, Dwarf_Error * error) +{ + /* This pointer is used to scan the portion of the .debug_line + section for the current cu. */ + Dwarf_Small *line_ptr = 0; + + /* This points to the last byte of the .debug_line portion for the + current cu. */ + Dwarf_Small *line_ptr_end = 0; + + /* Pointer to a DW_AT_stmt_list attribute in case it exists in the + die. */ + Dwarf_Attribute stmt_list_attr = 0; + + /* Pointer to DW_AT_comp_dir attribute in die. */ + Dwarf_Attribute comp_dir_attr = 0; + + /* Pointer to name of compilation directory. */ + Dwarf_Small *comp_dir = NULL; + + /* Offset into .debug_line specified by a DW_AT_stmt_list + attribute. */ + Dwarf_Unsigned line_offset = 0; + + Dwarf_File_Entry file_entries = 0; + + /* These are the state machine state variables. */ + Dwarf_Addr address = 0; + Dwarf_Word file = 1; + Dwarf_Word line = 1; + Dwarf_Word column = 0; + + /* Phony init. See below for true initialization. */ + Dwarf_Bool is_stmt = false; + /* DWARF4: operation within a VLIW instruction. */ + Dwarf_Unsigned op_index = 0; + + Dwarf_Bool basic_block = false; + Dwarf_Bool prologue_end = false; + Dwarf_Bool epilogue_begin = false; + Dwarf_Small isa = 0; + Dwarf_Unsigned discriminator = 0; + Dwarf_Bool end_sequence = false; + + /* These pointers are used to build the list of files names by this + cu. cur_file_entry points to the file name being added, and + prev_file_entry to the previous one. */ + Dwarf_File_Entry cur_file_entry = 0; + Dwarf_File_Entry prev_file_entry = 0; + + Dwarf_Sword i = 0; + Dwarf_Sword file_entry_count = 0; + + /* This is the current opcode read from the statement program. */ + Dwarf_Small opcode = 0; + + /* Pointer to a Dwarf_Line_Context_s structure that contains the + context such as file names and include directories for the set + of lines being generated. */ + Dwarf_Line_Context line_context = 0; + + /* This is a pointer to the current line being added to the line + matrix. */ + Dwarf_Line curr_line = 0; + + /* These variables are used to decode leb128 numbers. Leb128_num + holds the decoded number, and leb128_length is its length in + bytes. */ + Dwarf_Word leb128_num = 0; + Dwarf_Word leb128_length = 0; + Dwarf_Sword advance_line = 0; + + /* This is the operand of the latest fixed_advance_pc extended + opcode. */ + Dwarf_Half fixed_advance_pc = 0; + + /* Counts the number of lines in the line matrix. */ + Dwarf_Sword line_count = 0; + + /* This is the length of an extended opcode instr. */ + Dwarf_Word instr_length = 0; + Dwarf_Small ext_opcode = 0; + struct Line_Table_Prefix_s prefix; + + /* Used to chain together pointers to line table entries that are + later used to create a block of Dwarf_Line entries. */ + Dwarf_Chain chain_line = NULL; + Dwarf_Chain head_chain = NULL; + Dwarf_Chain curr_chain = NULL; + + /* This points to a block of Dwarf_Lines, a pointer to which is + returned in linebuf. */ + Dwarf_Line *block_line = 0; + + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg = 0; + int resattr = DW_DLV_ERROR; + int lres = DW_DLV_ERROR; + Dwarf_Half address_size = 0; + + int res = DW_DLV_ERROR; + + /* Mark a line record as being DW_LNS_set_address */ + Dwarf_Bool is_addr_set = false; + + /* ***** BEGIN CODE ***** */ + if (error != NULL) + *error = NULL; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + + res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_line.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + address_size = _dwarf_get_address_size(dbg, die); + resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error); + if (resattr != DW_DLV_OK) { + return resattr; + } + + lres = dwarf_global_formref(stmt_list_attr, &line_offset, error); + if (lres != DW_DLV_OK) { + return lres; + } + + if (line_offset >= dbg->de_debug_line.dss_size) { + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + line_ptr = dbg->de_debug_line.dss_data + line_offset; + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + + /* If die has DW_AT_comp_dir attribute, get the string that names + the compilation directory. */ + resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + if (resattr == DW_DLV_OK) { + int cres = DW_DLV_ERROR; + char *cdir = 0; + + cres = dwarf_formstring(comp_dir_attr, &cdir, error); + if (cres == DW_DLV_ERROR) { + return cres; + } else if (cres == DW_DLV_OK) { + comp_dir = (Dwarf_Small *) cdir; + } + } + if (resattr == DW_DLV_OK) { + dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); + } + dwarf_init_line_table_prefix(&prefix); + + { + Dwarf_Small *newlinep = 0; + int res = dwarf_read_line_table_prefix(dbg, + line_ptr, + dbg->de_debug_line.dss_size, + &newlinep, + &prefix, + NULL,NULL, + error, + 0); + + if (res == DW_DLV_ERROR) { + dwarf_free_line_table_prefix(&prefix); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + dwarf_free_line_table_prefix(&prefix); + return res; + } + line_ptr_end = prefix.pf_line_ptr_end; + line_ptr = newlinep; + } + + + /* Set up context structure for this set of lines. */ + line_context = (Dwarf_Line_Context) + _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); + if (line_context == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* Fill out a Dwarf_File_Entry list as we use that to implement the + define_file operation. */ + file_entries = prev_file_entry = NULL; + for (i = 0; i < prefix.pf_files_count; ++i) { + struct Line_Table_File_Entry_s *pfxfile = + prefix.pf_line_table_file_entries + i; + + cur_file_entry = (Dwarf_File_Entry) + _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1); + if (cur_file_entry == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + cur_file_entry->fi_file_name = pfxfile->lte_filename; + cur_file_entry->fi_dir_index = pfxfile->lte_directory_index; + cur_file_entry->fi_time_last_mod = + pfxfile->lte_last_modification_time; + + cur_file_entry->fi_file_length = pfxfile->lte_length_of_file; + + update_file_entry(cur_file_entry,&file_entries, + &prev_file_entry,&file_entry_count); + } + + + /* Initialize the one state machine variable that depends on the + prefix. */ + is_stmt = prefix.pf_default_is_stmt; + + + /* Start of statement program. */ + while (line_ptr < line_ptr_end) { + int type = 0; + + opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + /* 'type' is the output */ + WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base, + prefix.pf_opcode_length_table, line_ptr, + prefix.pf_std_op_count); + + if (type == LOP_DISCARD) { + int oc = 0; + int opcnt = prefix.pf_opcode_length_table[opcode]; + + for (oc = 0; oc < opcnt; oc++) { + /* Read and discard operands we don't + understand. + arbitrary choice of unsigned read. + signed read would work as well. */ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + } + } else if (type == LOP_SPECIAL) { + /* This op code is a special op in the object, no matter + that it might fall into the standard op range in this + compile. That is, these are special opcodes between + opcode_base and MAX_LINE_OP_CODE. (including + opcode_base and MAX_LINE_OP_CODE) */ + Dwarf_Unsigned operation_advance = 0; + + opcode = opcode - prefix.pf_opcode_base; + operation_advance = (opcode / prefix.pf_line_range); + + if (prefix.pf_maximum_ops_per_instruction < 2) { + address = address + (operation_advance * + prefix.pf_minimum_instruction_length); + } else { + address = address + (prefix.pf_minimum_instruction_length * + ((op_index + operation_advance)/ + prefix.pf_maximum_ops_per_instruction)); + op_index = (op_index +operation_advance)% + prefix.pf_maximum_ops_per_instruction; + } + + line = line + prefix.pf_line_base + + opcode % prefix.pf_line_range; + + if (dolines) { + curr_line = + (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1); + if (curr_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* Mark a line record as being DW_LNS_set_address */ + curr_line->li_addr_line.li_l_data.li_is_addr_set = is_addr_set; + is_addr_set = false; + + curr_line->li_address = address; + curr_line->li_addr_line.li_l_data.li_file = + (Dwarf_Sword) file; + curr_line->li_addr_line.li_l_data.li_line = + (Dwarf_Sword) line; + curr_line->li_addr_line.li_l_data.li_column = + (Dwarf_Half) column; + curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt; + curr_line->li_addr_line.li_l_data.li_basic_block = + basic_block; + curr_line->li_addr_line.li_l_data.li_end_sequence = + curr_line->li_addr_line.li_l_data. + li_epilogue_begin = epilogue_begin; + curr_line->li_addr_line.li_l_data.li_prologue_end = + prologue_end; + curr_line->li_addr_line.li_l_data.li_isa = isa; + curr_line->li_addr_line.li_l_data.li_discriminator = discriminator; + curr_line->li_context = line_context; + line_count++; + + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + chain_line->ch_item = curr_line; + update_chain_list(chain_line,&head_chain,&curr_chain); + } + + basic_block = false; + prologue_end = false; + epilogue_begin = false; + discriminator = 0; + } else if (type == LOP_STANDARD) { + switch (opcode) { + + case DW_LNS_copy:{ + if (dolines) { + curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, + DW_DLA_LINE, 1); + if (curr_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* Mark a line record as being DW_LNS_set_address */ + curr_line->li_addr_line.li_l_data.li_is_addr_set = + is_addr_set; + is_addr_set = false; + + curr_line->li_address = address; + curr_line->li_addr_line.li_l_data.li_file = + (Dwarf_Sword) file; + curr_line->li_addr_line.li_l_data.li_line = + (Dwarf_Sword) line; + curr_line->li_addr_line.li_l_data.li_column = + (Dwarf_Half) column; + curr_line->li_addr_line.li_l_data.li_is_stmt = + is_stmt; + curr_line->li_addr_line.li_l_data. + li_basic_block = basic_block; + curr_line->li_addr_line.li_l_data. + li_end_sequence = end_sequence; + curr_line->li_context = line_context; + curr_line->li_addr_line.li_l_data. + li_epilogue_begin = epilogue_begin; + curr_line->li_addr_line.li_l_data. + li_prologue_end = prologue_end; + curr_line->li_addr_line.li_l_data.li_isa = isa; + curr_line->li_addr_line.li_l_data.li_discriminator = discriminator; + line_count++; + + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + chain_line->ch_item = curr_line; + update_chain_list(chain_line,&head_chain,&curr_chain); + } + + basic_block = false; + prologue_end = false; + epilogue_begin = false; + discriminator = 0; + } + break; + case DW_LNS_advance_pc:{ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + leb128_num = (Dwarf_Word) utmp2; + address = address + + prefix.pf_minimum_instruction_length * + leb128_num; + } + break; + case DW_LNS_advance_line:{ + Dwarf_Signed stmp = 0; + + DECODE_LEB128_SWORD(line_ptr, stmp); + advance_line = (Dwarf_Sword) stmp; + line = line + advance_line; + } + break; + case DW_LNS_set_file:{ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + file = (Dwarf_Word) utmp2; + } + break; + case DW_LNS_set_column:{ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + column = (Dwarf_Word) utmp2; + } + break; + case DW_LNS_negate_stmt:{ + is_stmt = !is_stmt; + } + break; + case DW_LNS_set_basic_block:{ + basic_block = true; + } + break; + + case DW_LNS_const_add_pc:{ + opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base; + if (prefix.pf_maximum_ops_per_instruction < 2) { + Dwarf_Unsigned operation_advance = + (opcode / prefix.pf_line_range); + address = address + + prefix.pf_minimum_instruction_length * + operation_advance; + } else { + Dwarf_Unsigned operation_advance = + (opcode / prefix.pf_line_range); + address = address + prefix.pf_minimum_instruction_length * + ((op_index + operation_advance)/ + prefix.pf_maximum_ops_per_instruction); + op_index = (op_index +operation_advance)% + prefix.pf_maximum_ops_per_instruction; + } + } + break; + case DW_LNS_fixed_advance_pc:{ + READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half, + line_ptr, sizeof(Dwarf_Half)); + line_ptr += sizeof(Dwarf_Half); + address = address + fixed_advance_pc; + op_index = 0; + } + break; + + /* New in DWARF3 */ + case DW_LNS_set_prologue_end:{ + prologue_end = true; + } + break; + /* New in DWARF3 */ + case DW_LNS_set_epilogue_begin:{ + epilogue_begin = true; + } + break; + + /* New in DWARF3 */ + case DW_LNS_set_isa:{ + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + isa = utmp2; + if (isa != utmp2) { + /* The value of the isa did not fit in our + local so we record it wrong. declare an + error. */ + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, + DW_DLE_LINE_NUM_OPERANDS_BAD); + return (DW_DLV_ERROR); + } + } + break; + } /* End switch(opcode) */ + + } else if (type == LOP_EXTENDED) { + Dwarf_Unsigned utmp3 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp3); + instr_length = (Dwarf_Word) utmp3; + /* Dwarf_Small is a ubyte and the extended opcode is a + ubyte, though not stated as clearly in the 2.0.0 spec as + one might hope. */ + ext_opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + switch (ext_opcode) { + + case DW_LNE_end_sequence:{ + end_sequence = true; + if (dolines) { + curr_line = (Dwarf_Line) + _dwarf_get_alloc(dbg, DW_DLA_LINE, 1); + if (curr_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + curr_line->li_address = address; + curr_line->li_addr_line.li_l_data.li_file = + (Dwarf_Sword) file; + curr_line->li_addr_line.li_l_data.li_line = + (Dwarf_Sword) line; + curr_line->li_addr_line.li_l_data.li_column = + (Dwarf_Half) column; + curr_line->li_addr_line.li_l_data.li_is_stmt = + is_stmt; + curr_line->li_addr_line.li_l_data. + li_basic_block = basic_block; + curr_line->li_addr_line.li_l_data. + li_end_sequence = end_sequence; + curr_line->li_context = line_context; + curr_line->li_addr_line.li_l_data. + li_epilogue_begin = epilogue_begin; + curr_line->li_addr_line.li_l_data. + li_prologue_end = prologue_end; + curr_line->li_addr_line.li_l_data.li_isa = isa; + curr_line->li_addr_line.li_l_data.li_discriminator = discriminator; + line_count++; + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + chain_line->ch_item = curr_line; + + update_chain_list(chain_line,&head_chain,&curr_chain); + } + + address = 0; + file = 1; + line = 1; + column = 0; + is_stmt = prefix.pf_default_is_stmt; + basic_block = false; + end_sequence = false; + prologue_end = false; + epilogue_begin = false; + isa = 0; + discriminator = 0; + op_index = 0; + } + break; + + case DW_LNE_set_address:{ + READ_UNALIGNED(dbg, address, Dwarf_Addr, + line_ptr, address_size); + /* Mark a line record as being DW_LNS_set_address */ + is_addr_set = true; + + if (doaddrs) { + curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, + DW_DLA_LINE, 1); + if (curr_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* Mark a line record as being DW_LNS_set_address */ + curr_line->li_addr_line.li_l_data.li_is_addr_set = + is_addr_set; + is_addr_set = false; + curr_line->li_address = address; + curr_line->li_addr_line.li_offset = + line_ptr - dbg->de_debug_line.dss_data; + line_count++; + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + chain_line->ch_item = curr_line; + + update_chain_list(chain_line,&head_chain,&curr_chain); + } + op_index = 0; + line_ptr += address_size; + } + break; + + case DW_LNE_define_file:{ + if (dolines) { + cur_file_entry = (Dwarf_File_Entry) + _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1); + if (cur_file_entry == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + cur_file_entry->fi_file_name = (Dwarf_Small *) line_ptr; + line_ptr = line_ptr + strlen((char *) line_ptr) + 1; + cur_file_entry->fi_dir_index = (Dwarf_Sword) + _dwarf_decode_u_leb128(line_ptr, &leb128_length); + line_ptr = line_ptr + leb128_length; + cur_file_entry->fi_time_last_mod = + _dwarf_decode_u_leb128(line_ptr, &leb128_length); + line_ptr = line_ptr + leb128_length; + cur_file_entry->fi_file_length = + _dwarf_decode_u_leb128(line_ptr, &leb128_length); + line_ptr = line_ptr + leb128_length; + update_file_entry(cur_file_entry,&file_entries, + &prev_file_entry,&file_entry_count); + } + } + break; + case DW_LNE_set_discriminator:{ + /* New in DWARF4 */ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + discriminator = (Dwarf_Word) utmp2; + } + break; + default:{ + /* This is an extended op code we do not know about, + other than we know now many bytes it is + and the op code and the bytes of operand. */ + Dwarf_Unsigned remaining_bytes = instr_length -1; + if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, + DW_DLE_LINE_EXT_OPCODE_BAD); + return (DW_DLV_ERROR); + } + line_ptr += remaining_bytes; + } + break; + } /* End switch. */ + } + } + + block_line = (Dwarf_Line *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, line_count); + if (block_line == NULL) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + curr_chain = head_chain; + for (i = 0; i < line_count; i++) { + *(block_line + i) = curr_chain->ch_item; + head_chain = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN); + } + + line_context->lc_file_entries = file_entries; + line_context->lc_file_entry_count = file_entry_count; + line_context->lc_include_directories_count = + prefix.pf_include_directories_count; + if (prefix.pf_include_directories_count > 0) { + /* This gets a pointer to the *first* include dir. The others + follow directly with the standard DWARF2/3 NUL byte + following the last. */ + line_context->lc_include_directories = + prefix.pf_include_directories[0]; + } + + line_context->lc_line_count = line_count; + line_context->lc_compilation_directory = comp_dir; + line_context->lc_version_number = prefix.pf_version; + line_context->lc_dbg = dbg; + *count = line_count; + + *linebuf = block_line; + dwarf_free_line_table_prefix(&prefix); + return (DW_DLV_OK); +} + +int +dwarf_srclines(Dwarf_Die die, + Dwarf_Line ** linebuf, + Dwarf_Signed * linecount, Dwarf_Error * error) +{ + Dwarf_Signed count = 0; + int res = _dwarf_internal_srclines(die, linebuf, &count, + /* addrlist= */ false, + /* linelist= */ true, error); + if (res != DW_DLV_OK) { + return res; + } + *linecount = count; + return res; +} + + + +/* Every line table entry (except DW_DLE_end_sequence, + which is returned using dwarf_lineendsequence()) + potentially has the begin-statement + flag marked 'on'. This returns thru *return_bool, + the begin-statement flag. */ + +int +dwarf_linebeginstatement(Dwarf_Line line, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + if (line == NULL || return_bool == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + + *return_bool = (line->li_addr_line.li_l_data.li_is_stmt); + return DW_DLV_OK; +} + +/* At the end of any contiguous line-table there may be + a DW_LNE_end_sequence operator. + This returns non-zero thru *return_bool + if and only if this 'line' entry was a DW_LNE_end_sequence. + + Within a compilation unit or function there may be multiple + line tables, each ending with a DW_LNE_end_sequence. + Each table describes a contiguous region. + Because compilers may split function code up in arbitrary ways + compilers may need to emit multiple contigous regions (ie + line tables) for a single function. + See the DWARF3 spec section 6.2. */ +int +dwarf_lineendsequence(Dwarf_Line line, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + + *return_bool = (line->li_addr_line.li_l_data.li_end_sequence); + return DW_DLV_OK; +} + + +/* Each 'line' entry has a line-number. + If the entry is a DW_LNE_end_sequence the line-number is + meaningless (see dwarf_lineendsequence(), just above). */ +int +dwarf_lineno(Dwarf_Line line, + Dwarf_Unsigned * ret_lineno, Dwarf_Error * error) +{ + if (line == NULL || ret_lineno == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + + *ret_lineno = (line->li_addr_line.li_l_data.li_line); + return DW_DLV_OK; +} + +/* Each 'line' entry has a file-number, and index into the file table. + If the entry is a DW_LNE_end_sequence the index is + meaningless (see dwarf_lineendsequence(), just above). + The file number returned is an index into the file table + produced by dwarf_srcfiles(), but care is required: the + li_file begins with 1 for real files, so that the li_file returned here + is 1 greater than its index into the dwarf_srcfiles() output array. + And entries from DW_LNE_define_file don't appear in + the dwarf_srcfiles() output so file indexes from here may exceed + the size of the dwarf_srcfiles() output array size. +*/ +int +dwarf_line_srcfileno(Dwarf_Line line, + Dwarf_Unsigned * ret_fileno, Dwarf_Error * error) +{ + if (line == NULL || ret_fileno == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + /* li_file must be <= line->li_context->lc_file_entry_count else it + is trash. li_file 0 means not attributable to any source file + per dwarf2/3 spec. */ + + *ret_fileno = (line->li_addr_line.li_l_data.li_file); + return DW_DLV_OK; +} + +/* Each 'line' entry has an is_addr_set attribute. + If the entry is a DW_LNE_set_address, return TRUE through + the *is_addr_set pointer. */ +int +dwarf_line_is_addr_set(Dwarf_Line line, + Dwarf_Bool *is_addr_set, Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + + *is_addr_set = (line->li_addr_line.li_l_data.li_is_addr_set); + return DW_DLV_OK; +} + +/* Each 'line' entry has a line-address. + If the entry is a DW_LNE_end_sequence the adddress + is one-beyond the last address this contigous region + covers, so the address is not inside the region, + but is just outside it. */ +int +dwarf_lineaddr(Dwarf_Line line, + Dwarf_Addr * ret_lineaddr, Dwarf_Error * error) +{ + if (line == NULL || ret_lineaddr == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + + *ret_lineaddr = (line->li_address); + return DW_DLV_OK; +} + + +/* Obsolete: do not use this function. + December 2011: For reasons lost in the mists of history, + this returned -1, not zero (through the pointer + ret_lineoff), if the column was zero. + That was always bogus, even in DWARF2. + It is also bogus that the column value is signed, but + it is painful to change the argument type in 2011, so leave it. + */ +int +dwarf_lineoff(Dwarf_Line line, + Dwarf_Signed * ret_lineoff, Dwarf_Error * error) +{ + if (line == NULL || ret_lineoff == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + *ret_lineoff = ( + (line->li_addr_line.li_l_data.li_column == 0) ? + -1 : line->li_addr_line.li_l_data.li_column); + return DW_DLV_OK; +} +/* Each 'line' entry has a column-within-line (offset + within the line) where the + source text begins. + If the entry is a DW_LNE_end_sequence the line-number is + meaningless (see dwarf_lineendsequence(), just above). + Lines of text begin at column 1. The value 0 + means the line begins at the left edge of the line. + (See the DWARF3 spec, section 6.2.2). + So 0 and 1 mean essentially the same thing. + dwarf_lineoff_b() is new in December 2011. + */ +int +dwarf_lineoff_b(Dwarf_Line line, + Dwarf_Unsigned * ret_lineoff, Dwarf_Error * error) +{ + if (line == NULL || ret_lineoff == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + + *ret_lineoff = line->li_addr_line.li_l_data.li_column; + return DW_DLV_OK; +} + + +int +dwarf_linesrc(Dwarf_Line line, char **ret_linesrc, Dwarf_Error * error) +{ + Dwarf_Signed i = 0; + Dwarf_File_Entry file_entry; + Dwarf_Small *name_buffer = 0; + Dwarf_Small *include_directories = 0; + Dwarf_Small include_direc_full_path = 0; + Dwarf_Small file_name_full_path = 0; + Dwarf_Debug dbg = 0; + unsigned int comp_dir_len = 0; + + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + + if (line->li_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL); + return (DW_DLV_ERROR); + } + dbg = line->li_context->lc_dbg; + + if (line->li_addr_line.li_l_data.li_file > + line->li_context->lc_file_entry_count) { + _dwarf_error(dbg, error, DW_DLE_LINE_FILE_NUM_BAD); + return (DW_DLV_ERROR); + } + + if (line->li_addr_line.li_l_data.li_file == 0) { + /* No file name known: see dwarf2/3 spec. */ + _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME); + return (DW_DLV_ERROR); + } + file_entry = line->li_context->lc_file_entries; + /* ASSERT: li_file > 0, dwarf correctness issue, see line table + definition of dwarf2/3 spec. */ + /* Example: if li_file is 2 and lc_file_entry_count is 3, + file_entry is file 3 (1 based), aka 2( 0 based) file_entry->next + is file 2 (1 based), aka 1( 0 based) file_entry->next->next is + file 1 (1 based), aka 0( 0 based) file_entry->next->next->next + is NULL. + + and this loop finds the file_entry we need (2 (1 based) in this + case). Because lc_file_entries are in reverse order and + effectively zero based as a count whereas li_file is 1 based. */ + for (i = line->li_addr_line.li_l_data.li_file - 1; i > 0; i--) { + file_entry = file_entry->fi_next; + } + + if (file_entry->fi_file_name == NULL) { + _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME); + return (DW_DLV_ERROR); + } + + file_name_full_path = file_name_is_full_path(file_entry->fi_file_name); + if (file_name_full_path) { + *ret_linesrc = ((char *) file_entry->fi_file_name); + return DW_DLV_OK; + } + + if (file_entry->fi_dir_index == 0) { + + /* dir_index of 0 means that the compilation was in the + 'current directory of compilation' */ + if (line->li_context->lc_compilation_directory == NULL) { + /* We don't actually *have* a current directory of + compilation: DW_AT_comp_dir was not present Rather than + emitting DW_DLE_NO_COMP_DIR lets just make an empty name + here. In other words, do the best we can with what we do + have instead of reporting an error. _dwarf_error(dbg, + error, DW_DLE_NO_COMP_DIR); return(DW_DLV_ERROR); */ + comp_dir_len = 0; + } else { + comp_dir_len = strlen((char *) + (line->li_context->lc_compilation_directory)); + } + + name_buffer = + _dwarf_get_alloc(line->li_context->lc_dbg, DW_DLA_STRING, + comp_dir_len + 1 + + strlen((char *) file_entry->fi_file_name) + 1); + if (name_buffer == NULL) { + _dwarf_error(line->li_context->lc_dbg, error, + DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + if (comp_dir_len > 0) { + /* If comp_dir_len is 0 we do not want to put a / in front + of the fi_file_name as we just don't know anything. */ + strcpy((char *) name_buffer, + (char *) (line->li_context->lc_compilation_directory)); + strcat((char *) name_buffer, "/"); + } + strcat((char *) name_buffer, (char *) file_entry->fi_file_name); + *ret_linesrc = ((char *) name_buffer); + return DW_DLV_OK; + } + + if (file_entry->fi_dir_index > + line->li_context->lc_include_directories_count) { + _dwarf_error(dbg, error, DW_DLE_INCL_DIR_NUM_BAD); + return (DW_DLV_ERROR); + } + + include_directories = line->li_context->lc_include_directories; + for (i = file_entry->fi_dir_index - 1; i > 0; i--) + include_directories += strlen((char *) include_directories) + 1; + + if (line->li_context->lc_compilation_directory) { + comp_dir_len = strlen((char *) + (line->li_context->lc_compilation_directory)); + } else { + /* No DW_AT_comp_dir present. Do the best we can without it. */ + comp_dir_len = 0; + } + + include_direc_full_path = file_name_is_full_path(include_directories); + name_buffer = _dwarf_get_alloc(dbg, DW_DLA_STRING, + (include_direc_full_path ? 0 : comp_dir_len + 1) + + strlen((char *)include_directories) + 1 + + strlen((char *)file_entry->fi_file_name) + 1); + if (name_buffer == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + if (!include_direc_full_path) { + if (comp_dir_len > 0) { + strcpy((char *)name_buffer, + (char *)line->li_context->lc_compilation_directory); + /* Who provides the / needed after the compilation + directory? */ + if (!is_path_separator(name_buffer[comp_dir_len - 1])) { + /* Here we provide the / separator. It + should work ok for Windows */ + /* Overwrite previous nul terminator with needed / */ + name_buffer[comp_dir_len] = '/'; + name_buffer[comp_dir_len + 1] = 0; + } + } + } else { + strcpy((char *) name_buffer, ""); + } + strcat((char *) name_buffer, (char *) include_directories); + strcat((char *) name_buffer, "/"); + strcat((char *) name_buffer, (char *) file_entry->fi_file_name); + *ret_linesrc = ((char *) name_buffer); + return DW_DLV_OK; +} + +/* Every line table entry potentially has the basic-block-start + flag marked 'on'. This returns thru *return_bool, + the basic-block-start flag. +*/ +int +dwarf_lineblock(Dwarf_Line line, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + *return_bool = (line->li_addr_line.li_l_data.li_basic_block); + return DW_DLV_OK; +} + +/* We gather these into one call as it's likely one + will want all or none of them. */ +int dwarf_prologue_end_etc(Dwarf_Line line, + Dwarf_Bool * prologue_end, + Dwarf_Bool * epilogue_begin, + Dwarf_Unsigned * isa, + Dwarf_Unsigned * discriminator, + Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return (DW_DLV_ERROR); + } + *prologue_end = (line->li_addr_line.li_l_data.li_prologue_end); + *epilogue_begin = (line->li_addr_line.li_l_data.li_epilogue_begin); + *isa = (line->li_addr_line.li_l_data.li_isa); + *discriminator = (line->li_addr_line.li_l_data.li_discriminator); + return DW_DLV_OK; +} + + + +#if 0 /* Ignore this. This needs major re-work. */ +/* This routine works by looking for exact matches between + the current line address and pc, and crossovers from + from less than pc value to greater than. At each line + that satisfies the above, it records a pointer to the + line, and the difference between the address and pc. + It then scans these pointers and picks out those with + the smallest difference between pc and address. +*/ +int +dwarf_pclines(Dwarf_Debug dbg, + Dwarf_Addr pc, + Dwarf_Line ** linebuf, + Dwarf_Signed slide, + Dwarf_Signed * linecount, Dwarf_Error * error) +{ + /* Scans the line matrix for the current cu to which a pointer + exists in dbg. */ + Dwarf_Line line; + Dwarf_Line prev_line; + + /* These flags are for efficiency reasons. Check_line is true + initially, but set false when the address of the current line is + greater than pc. It is set true only when the address of the + current line falls below pc. This assumes that addresses within + the same segment increase, and we are only interested in the + switch from a less than pc address to a greater than. First_line + is set true initially, but set false after the first line is + scanned. This is to prevent looking at the address of previous + line when slide is DW_DLS_BACKWARD, and the first line is being + scanned. */ + Dwarf_Bool check_line, first_line; + + /* Diff tracks the smallest difference a line address and the input + pc value. */ + Dwarf_Signed diff, i; + + /* For the slide = DW_DLS_BACKWARD case, pc_less is the value of + the address of the line immediately preceding the first line + that has value greater than pc. For the slide = DW_DLS_FORWARD + case, pc_more is the values of address for the first line that + is greater than pc. Diff is the difference between either of the + these values and pc. */ + Dwarf_Addr pc_less, pc_more; + + /* Pc_line_buf points to a chain of pointers to lines of which + those with a diff equal to the smallest difference will be + returned. */ + Dwarf_Line *pc_line_buf, *pc_line; + + /* Chain_count counts the number of lines in the above chain for + which the diff is equal to the smallest difference This is the + number returned by this routine. */ + Dwarf_Signed chain_count; + + chain_head = NULL; + + check_line = true; + first_line = true; + diff = MAX_LINE_DIFF; + + for (i = 0; i < dbg->de_cu_line_count; i++) { + + line = *(dbg->de_cu_line_ptr + i); + prev_line = first_line ? NULL : *(dbg->de_cu_line_ptr + i - 1); + + if (line->li_address == pc) { + chain_ptr = (struct chain *) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_ptr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + chain_ptr->line = line; + chain_ptr->diff = diff = 0; + chain_ptr->next = chain_head; + chain_head = chain_ptr; + } else { + /* Look for crossover from less than pc address to greater + than. */ + if (check_line && line->li_address > pc && + (first_line ? 0 : prev_line->li_address) < pc) { + if (slide == DW_DLS_BACKWARD && !first_line) { + pc_less = prev_line->li_address; + if (pc - pc_less <= diff) { + chain_ptr = (struct chain *) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_ptr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + chain_ptr->line = prev_line; + chain_ptr->diff = diff = pc - pc_less; + chain_ptr->next = chain_head; + chain_head = chain_ptr; + } + check_line = false; + } else if (slide == DW_DLS_FORWARD) { + pc_more = line->li_address; + if (pc_more - pc <= diff) { + chain_ptr = (struct chain *) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_ptr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + chain_ptr->line = line; + chain_ptr->diff = diff = pc_more - pc; + chain_ptr->next = chain_head; + chain_head = chain_ptr; + } + check_line = false; + } else { + /* Check addresses only when they go */ + /* below pc. */ + if (line->li_address < pc) { + check_line = true; + } + } + } + } + first_line = false; + } + chain_count = 0; + for (chain_ptr = chain_head; chain_ptr != NULL; + chain_ptr = chain_ptr->next) { + if (chain_ptr->diff == diff) { + chain_count++; + } + } + pc_line_buf = pc_line = (Dwarf_Line) + _dwarf_get_alloc(dbg, DW_DLA_LIST, chain_count); + for (chain_ptr = chain_head; chain_ptr != NULL; + chain_ptr = chain_ptr->next) { + if (chain_ptr->diff == diff) { + *pc_line = chain_ptr->line; + pc_line++; + } + } + for (chain_ptr = chain_head; chain_ptr != NULL;) { + chain_head = chain_ptr; + chain_ptr = chain_ptr->next; + dwarf_dealloc(dbg, chain_head, DW_DLA_CHAIN); + } + *linebuf = pc_line_buf; + return (chain_count); +} +#endif + + + +/* + It's impossible for callers of dwarf_srclines() to get to and + free all the resources (in particular, the li_context and its + lc_file_entries). + So this function, new July 2005, does it. +*/ + +void +dwarf_srclines_dealloc(Dwarf_Debug dbg, Dwarf_Line * linebuf, + Dwarf_Signed count) +{ + + Dwarf_Signed i = 0; + struct Dwarf_Line_Context_s *context = 0; + + if (count > 0) { + /* All these entries share a single context */ + context = linebuf[0]->li_context; + } + for (i = 0; i < count; ++i) { + dwarf_dealloc(dbg, linebuf[i], DW_DLA_LINE); + } + dwarf_dealloc(dbg, linebuf, DW_DLA_LIST); + + if (context) { + Dwarf_File_Entry fe = context->lc_file_entries; + + while (fe) { + Dwarf_File_Entry fenext = fe->fi_next; + + dwarf_dealloc(dbg, fe, DW_DLA_FILE_ENTRY); + fe = fenext; + } + dwarf_dealloc(dbg, context, DW_DLA_LINE_CONTEXT); + } + + return; +} + +/* Operand counts per standard operand. + The initial zero is for DW_LNS_copy. + This is an economical way to verify we understand the table + of standard-opcode-lengths in the line table prologue. */ +#define STANDARD_OPERAND_COUNT_DWARF2 9 +#define STANDARD_OPERAND_COUNT_DWARF3 12 +static unsigned char +dwarf_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = { + /* DWARF2 */ + 0, + 1, 1, 1, 1, + 0, 0, 0, + 1, + /* Following are new for DWARF3. */ + 0, 0, 1 +}; + +/* We have a normal standard opcode base, but + an arm compiler emitted a non-standard table! + This could lead to problems... + ARM C/C++ Compiler, RVCT4.0 [Build 4 + 00] seems to get the table wrong . */ +static unsigned char +dwarf_arm_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = { + /* DWARF2 */ + 0, + 1, 1, 1, 1, + 0, 0, 0, + 0, /* <<< --- this is wrong */ + /* Following are new for DWARF3. */ + 0, 0, 1 +}; + +/* There is an error, so count it. If we are printing + errors by command line option, print the details. */ +static void +print_header_issue(Dwarf_Debug dbg, + char *specific_msg, + Dwarf_Small *data_start, + int *err_count_out) +{ + if(!err_count_out) { + return; + } + /* Are we in verbose mode */ + if (dwarf_cmdline_options.check_verbose_mode) { + /* When redirecting stderr into stdout or vice versa, + ensure lines come out at the 'right time' with fflush. */ + fflush(stderr); + fflush(stdout); + printf("\n*** DWARF CHECK: " + ".debug_line: %s", specific_msg); + if( data_start >= dbg->de_debug_line.dss_data && + (data_start < (dbg->de_debug_line.dss_data + + dbg->de_debug_line.dss_size))) { + Dwarf_Unsigned off = data_start - dbg->de_debug_line.dss_data; + printf(" at offset 0x%" DW_PR_XZEROS DW_PR_DUx + " ( %" DW_PR_DUu " ) ", + off,off); + } else { + printf(" (unknown section location) "); + } + printf("***\n"); + fflush(stdout); + } + *err_count_out += 1; +} + + + +/* Common line table prefix reading code. + Returns DW_DLV_OK, DW_DLV_ERROR. + DW_DLV_NO_ENTRY cannot be returned, but callers should + assume it is possible. + + The prefix_out area must be initialized properly before calling this. + + Has the side effect of allocating arrays which + must be freed (see the Line_Table_Prefix_s struct which + holds the pointers to space we allocate here). + + bogus_bytes_ptr and bogus_bytes are output values which + let a print-program notify the user of some surprising bytes + after a line table header and before the line table instructions. + These can be ignored unless one is printing. + And are ignored if NULL passed as the pointer. +*/ + +/* err_count_out may be NULL, in which case we + make no attempt to count checking-type errors. + Checking-type errors do not stop us, we just report them. +*/ +int +dwarf_read_line_table_prefix(Dwarf_Debug dbg, + Dwarf_Small * data_start, + Dwarf_Unsigned data_length, + Dwarf_Small ** updated_data_start_out, + struct Line_Table_Prefix_s *prefix_out, + Dwarf_Small ** bogus_bytes_ptr, + Dwarf_Unsigned *bogus_bytes, + Dwarf_Error * err, + int *err_count_out) +{ + Dwarf_Small *line_ptr = data_start; + Dwarf_Unsigned total_length = 0; + int local_length_size = 0; + int local_extension_size = 0; + Dwarf_Unsigned prologue_length = 0; + Dwarf_Half version = 0; + Dwarf_Unsigned directories_count = 0; + Dwarf_Unsigned directories_malloc = 0; + Dwarf_Unsigned files_count = 0; + Dwarf_Unsigned files_malloc = 0; + Dwarf_Small *line_ptr_end = 0; + Dwarf_Small *lp_begin = 0; + if(bogus_bytes_ptr) *bogus_bytes_ptr = 0; + if(bogus_bytes) *bogus_bytes= 0; + + prefix_out->pf_line_ptr_start = line_ptr; + /* READ_AREA_LENGTH updates line_ptr for consumed bytes */ + READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned, + line_ptr, local_length_size, local_extension_size); + + + line_ptr_end = line_ptr + total_length; + prefix_out->pf_line_ptr_end = line_ptr_end; + prefix_out->pf_length_field_length = local_length_size + + local_extension_size; + /* ASSERT: prefix_out->pf_length_field_length == line_ptr + -prefix_out->pf_line_ptr_start; */ + if (line_ptr_end > dbg->de_debug_line.dss_data + + dbg->de_debug_line.dss_size) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return (DW_DLV_ERROR); + } + if (line_ptr_end > data_start + data_length) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return (DW_DLV_ERROR); + } + prefix_out->pf_total_length = total_length; + + READ_UNALIGNED(dbg, version, Dwarf_Half, + line_ptr, sizeof(Dwarf_Half)); + prefix_out->pf_version = version; + line_ptr += sizeof(Dwarf_Half); + if (version != CURRENT_VERSION_STAMP && + version != CURRENT_VERSION_STAMP3 && + version != CURRENT_VERSION_STAMP4) { + _dwarf_error(dbg, err, DW_DLE_VERSION_STAMP_ERROR); + return (DW_DLV_ERROR); + } + + READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned, + line_ptr, local_length_size); + prefix_out->pf_prologue_length = prologue_length; + line_ptr += local_length_size; + prefix_out->pf_line_prologue_start = line_ptr; + + prefix_out->pf_minimum_instruction_length = + *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + + prefix_out->pf_default_is_stmt = *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + + if(version == CURRENT_VERSION_STAMP4) { + prefix_out->pf_maximum_ops_per_instruction = + *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + } + + prefix_out->pf_line_base = *(signed char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Sbyte); + + prefix_out->pf_line_range = *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + + prefix_out->pf_opcode_base = *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + + /* Set up the array of standard opcode lengths. */ + /* We think this works ok even for cross-endian processing of + objects. It might be wrong, we might need to specially process + the array of ubyte into host order. */ + prefix_out->pf_opcode_length_table = line_ptr; + + /* pf_opcode_base is one greater than the size of the array. */ + line_ptr += prefix_out->pf_opcode_base - 1; + + { + /* Determine (as best we can) whether the + pf_opcode_length_table holds 9 or 12 standard-conforming + entries. gcc4 upped to DWARF3's 12 without updating the + version number. */ + int operand_ck_fail = true; + + if (prefix_out->pf_opcode_base >= STANDARD_OPERAND_COUNT_DWARF3) { + int mismatch = memcmp(dwarf_standard_opcode_operand_count, + prefix_out->pf_opcode_length_table, + STANDARD_OPERAND_COUNT_DWARF3); + if(mismatch) { + if(err_count_out) { + print_header_issue(dbg, + "standard-operands did not match", + data_start,err_count_out); + } + mismatch = memcmp(dwarf_arm_standard_opcode_operand_count, + prefix_out->pf_opcode_length_table, + STANDARD_OPERAND_COUNT_DWARF3); + if(!mismatch && err_count_out) { + print_header_issue(dbg, + "arm (incorrect) operands in use", + data_start,err_count_out); + } + } + if (!mismatch) { + if (version == 2) { + if(err_count_out) { + print_header_issue(dbg, + "standard DWARF3 operands matched, but is DWARF2 linetable", + data_start,err_count_out); + } + } + operand_ck_fail = false; + prefix_out->pf_std_op_count = + STANDARD_OPERAND_COUNT_DWARF3; + } + } + if (operand_ck_fail) { + if (prefix_out->pf_opcode_base >= + STANDARD_OPERAND_COUNT_DWARF2) { + int mismatch = memcmp(dwarf_standard_opcode_operand_count, + prefix_out->pf_opcode_length_table, + STANDARD_OPERAND_COUNT_DWARF2); + + if(mismatch) { + if(err_count_out) { + print_header_issue(dbg, + "standard-operands-lengths did not match", + data_start,err_count_out); + } + mismatch = memcmp(dwarf_arm_standard_opcode_operand_count, + prefix_out->pf_opcode_length_table, + STANDARD_OPERAND_COUNT_DWARF2); + if(!mismatch && err_count_out) { + print_header_issue(dbg, + "arm (incorrect) operand in use", + data_start,err_count_out); + } + } + + if (!mismatch) { + operand_ck_fail = false; + prefix_out->pf_std_op_count = + STANDARD_OPERAND_COUNT_DWARF2; + } + } + } + if (operand_ck_fail) { + /* Here we are not sure what the pf_std_op_count is. */ + _dwarf_error(dbg, err, DW_DLE_LINE_NUM_OPERANDS_BAD); + return (DW_DLV_ERROR); + } + } + /* At this point we no longer need to check operand counts. */ + + + directories_count = 0; + directories_malloc = 5; + prefix_out->pf_include_directories = malloc(sizeof(Dwarf_Small *) * + directories_malloc); + if (prefix_out->pf_include_directories == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + memset(prefix_out->pf_include_directories, 0, + sizeof(Dwarf_Small *) * directories_malloc); + + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return (DW_DLV_ERROR); + } + while ((*(char *) line_ptr) != '\0') { + if (directories_count >= directories_malloc) { + Dwarf_Unsigned expand = 2 * directories_malloc; + Dwarf_Unsigned bytesalloc = sizeof(Dwarf_Small *) * expand; + Dwarf_Small **newdirs = + realloc(prefix_out->pf_include_directories, + bytesalloc); + + if (!newdirs) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + /* Doubled size, zero out second half. */ + memset(newdirs + directories_malloc, 0, + sizeof(Dwarf_Small *) * directories_malloc); + directories_malloc = expand; + prefix_out->pf_include_directories = newdirs; + } + prefix_out->pf_include_directories[directories_count] = + line_ptr; + line_ptr = line_ptr + strlen((char *) line_ptr) + 1; + directories_count++; + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return (DW_DLV_ERROR); + } + } + prefix_out->pf_include_directories_count = directories_count; + line_ptr++; + + files_count = 0; + files_malloc = 5; + prefix_out->pf_line_table_file_entries = + malloc(sizeof(struct Line_Table_File_Entry_s) * files_malloc); + if (prefix_out->pf_line_table_file_entries == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + memset(prefix_out->pf_line_table_file_entries, 0, + sizeof(struct Line_Table_File_Entry_s) * files_malloc); + + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return (DW_DLV_ERROR); + } + while (*(char *) line_ptr != '\0') { + Dwarf_Unsigned utmp; + Dwarf_Unsigned dir_index = 0; + Dwarf_Unsigned lastmod = 0; + Dwarf_Unsigned file_length = 0; + struct Line_Table_File_Entry_s *curline; + Dwarf_Word leb128_length = 0; + + + if (files_count >= files_malloc) { + Dwarf_Unsigned expand = 2 * files_malloc; + struct Line_Table_File_Entry_s *newfiles = + realloc(prefix_out->pf_line_table_file_entries, + sizeof(struct Line_Table_File_Entry_s) * + expand); + if (!newfiles) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + memset(newfiles + files_malloc, 0, + sizeof(struct Line_Table_File_Entry_s) * + files_malloc); + files_malloc = expand; + prefix_out->pf_line_table_file_entries = newfiles; + } + curline = prefix_out->pf_line_table_file_entries + files_count; + + curline->lte_filename = line_ptr; + line_ptr = line_ptr + strlen((char *) line_ptr) + 1; + + DECODE_LEB128_UWORD(line_ptr, utmp); + dir_index = (Dwarf_Sword) utmp; + if (dir_index > directories_count) { + _dwarf_error(dbg, err, DW_DLE_DIR_INDEX_BAD); + return (DW_DLV_ERROR); + } + curline->lte_directory_index = dir_index; + + lastmod = _dwarf_decode_u_leb128(line_ptr, &leb128_length); + line_ptr = line_ptr + leb128_length; + curline->lte_last_modification_time = lastmod; + + /* Skip over file length. */ + file_length = _dwarf_decode_u_leb128(line_ptr, &leb128_length); + line_ptr = line_ptr + leb128_length; + curline->lte_length_of_file = file_length; + + ++files_count; + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return (DW_DLV_ERROR); + } + + } + prefix_out->pf_files_count = files_count; + /* Skip trailing nul byte */ + ++line_ptr; + + + lp_begin = prefix_out->pf_line_prologue_start + + prefix_out->pf_prologue_length; + if (line_ptr != lp_begin) { + if(line_ptr > lp_begin) { + _dwarf_error(dbg, err, DW_DLE_LINE_PROLOG_LENGTH_BAD); + return (DW_DLV_ERROR); + } else { + /* Bug in compiler. These + bytes are really part of the instruction + stream. The prefix_out->pf_prologue_length is + wrong (12 too high). */ + if(bogus_bytes_ptr) { + *bogus_bytes_ptr = line_ptr; + } + if(bogus_bytes) { + /* How far off things are. We expect the + value 12 ! */ + *bogus_bytes = (lp_begin - line_ptr); + } + } + /* Ignore the lp_begin calc. Assume line_ptr right. + Making up for compiler bug. */ + lp_begin = line_ptr; + + } + + *updated_data_start_out = lp_begin; + return DW_DLV_OK; +} + + +/* Initialize the Line_Table_Prefix_s struct. + memset is not guaranteed a portable initializer, but works + fine for current architectures. AFAIK. +*/ +void +dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf) +{ + memset(pf, 0, sizeof(*pf)); +} + +/* Free any malloc'd area. of the Line_Table_Prefix_s struct. */ +void +dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf) +{ + if (pf->pf_include_directories) { + free(pf->pf_include_directories); + pf->pf_include_directories = 0; + } + if (pf->pf_line_table_file_entries) { + free(pf->pf_line_table_file_entries); + pf->pf_line_table_file_entries = 0; + } + return; +} diff --git a/libdwarf/dwarf_line.h b/libdwarf/dwarf_line.h new file mode 100644 index 0000000..7bbcd5b --- /dev/null +++ b/libdwarf/dwarf_line.h @@ -0,0 +1,326 @@ +/* + + Copyright (C) 2000, 2004, 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#define DW_EXTENDED_OPCODE 0 + +/* + This is used as the starting value for an algorithm + to get the minimum difference between 2 values. + UINT_MAX is used as our approximation to infinity. +*/ +#define MAX_LINE_DIFF UINT_MAX + +/* This is for a sanity check on line + table extended opcodes. + It is entirely arbitrary, and 100 is surely too small if + someone was inserting strings in the opcode. */ +#define DW_LNE_LEN_MAX 100 + + +/* + This structure is used to build a list of all the + files that are used in the current compilation unit. + All of the fields execpt fi_next have meanings that + are obvious from section 6.2.4 of the Libdwarf Doc. +*/ +struct Dwarf_File_Entry_s { + /* Points to string naming the file. */ + Dwarf_Small *fi_file_name; + + /* Index into the list of directories of the directory in which + this file exits. */ + Dwarf_Sword fi_dir_index; + + /* Time of last modification of the file. */ + Dwarf_Unsigned fi_time_last_mod; + + /* Length in bytes of the file. */ + Dwarf_Unsigned fi_file_length; + + /* Pointer for chaining file entries. */ + Dwarf_File_Entry fi_next; +}; + + +typedef struct Dwarf_Line_Context_s *Dwarf_Line_Context; + +/* + This structure provides the context in which the fields of + a Dwarf_Line structure are interpreted. They come from the + statement program prologue. **Updated by dwarf_srclines in + dwarf_line.c. +*/ +struct Dwarf_Line_Context_s { + /* Points to a chain of entries providing info about source files + for the current set of Dwarf_Line structures. File number + 'li_file 1' is last on the list, the first list entry is the + file numbered lc_file_entry_count. The numbering of the file + names matches the dwarf2/3 line table specification file table + and DW_LNE_define_file numbering rules. */ + Dwarf_File_Entry lc_file_entries; + /* Count of number of source files for this set of Dwarf_Line + structures. */ + Dwarf_Sword lc_file_entry_count; + /* Points to the portion of .debug_line section that contains a + list of strings naming the included directories. */ + Dwarf_Small *lc_include_directories; + + /* Count of the number of included directories. */ + Dwarf_Sword lc_include_directories_count; + + /* Count of the number of lines for this cu. */ + Dwarf_Sword lc_line_count; + + /* Points to name of compilation directory. */ + Dwarf_Small *lc_compilation_directory; + + Dwarf_Debug lc_dbg; + + Dwarf_Half lc_version_number; /* DWARF2/3 version number, 2 + for DWARF2, 3 for DWARF3. */ +}; + + +/* + This structure defines a row of the line table. + All of the fields except li_offset have the exact + same meaning that is defined in Section 6.2.2 + of the Libdwarf Document. + + li_offset is used by _dwarf_addr_finder() which is called + by rqs(1), an sgi utility for 'moving' shared libraries + as if the static linker (ld) had linked the shared library + at the newly-specified address. Most libdwarf-using + apps will ignore li_offset and _dwarf_addr_finder(). + +*/ +struct Dwarf_Line_s { + Dwarf_Addr li_address; /* pc value of machine instr */ + union addr_or_line_s { + struct li_inner_s { + Dwarf_Unsigned li_discriminator; /* New as of DWARF4 */ + Dwarf_Sword li_file; /* int identifying src file */ + /* li_file is a number 1-N, indexing into a conceptual + source file table as described in dwarf2/3 spec line + table doc. (see Dwarf_File_Entry lc_file_entries; and + Dwarf_Sword lc_file_entry_count;) */ + Dwarf_Sword li_line; /* source file line number. */ + Dwarf_Half li_column; /* source file column number */ + Dwarf_Small li_isa; /* New as of DWARF4. */ + + /* To save space, use bit flags. */ + /* indicate start of stmt */ + unsigned char li_is_stmt:1; + + /* indicate start basic block */ + unsigned char li_basic_block:1; + + /* first post sequence instr */ + unsigned char li_end_sequence:1; + + unsigned char li_prologue_end:1; + unsigned char li_epilogue_begin:1; + + /* Mark a line record as being DW_LNS_set_address. */ + unsigned char li_is_addr_set:1; + } li_l_data; + Dwarf_Off li_offset; /* for rqs */ + } li_addr_line; + Dwarf_Line_Context li_context; /* assoc Dwarf_Line_Context_s */ +}; + + +int _dwarf_line_address_offsets(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Addr ** addrs, + Dwarf_Off ** offs, + Dwarf_Unsigned * returncount, + Dwarf_Error * err); +int _dwarf_internal_srclines(Dwarf_Die die, + Dwarf_Line ** linebuf, + Dwarf_Signed * count, + Dwarf_Bool doaddrs, + Dwarf_Bool dolines, Dwarf_Error * error); + + + +/* The LOP, WHAT_IS_OPCODE stuff is here so it can + be reused in 3 places. Seemed hard to keep + the 3 places the same without an inline func or + a macro. + + Handling the line section where the header and the + file being processed do not match (unusual, but + planned for in the design of .debug_line) + is too tricky to recode this several times and keep + it right. + + As it is the code starting up line-reading is duplicated + and that is just wrong to do. FIXME! +*/ +#define LOP_EXTENDED 1 +#define LOP_DISCARD 2 +#define LOP_STANDARD 3 +#define LOP_SPECIAL 4 + +#define WHAT_IS_OPCODE(type,opcode,base,opcode_length,line_ptr,highest_std) \ + if( (opcode) < (base) ) { \ + /* we know we must treat as a standard op \ + or a special case. */ \ + if((opcode) == DW_EXTENDED_OPCODE) { \ + type = LOP_EXTENDED; \ + } else if( ((highest_std)+1) >= (base)) { \ + /* == Standard case: compile of \ + dwarf_line.c and object \ + have same standard op codes set. \ + == Special case: compile of dwarf_line.c \ + has things in standard op codes list \ + in dwarf.h header not \ + in the object: handle this as a standard \ + op code in switch below. \ + The header special ops overlap the \ + object standard ops. \ + The new standard op codes will not \ + appear in the object. */ \ + type = LOP_STANDARD; \ + } else { \ + /* These are standard opcodes in the object \ + ** that were not defined in the header \ + ** at the time dwarf_line.c \ + ** was compiled. Provides the ability of \ + ** out-of-date dwarf reader to read newer \ + ** line table data transparently. \ + */ \ + type = LOP_DISCARD; \ + } \ + } else { \ + /* Is a special op code. */ \ + type = LOP_SPECIAL; \ + } + +/* The following is from the dwarf definition of 'ubyte' + and is specifically mentioned in section 6.2.5.1, page 54 + of the Rev 2.0.0 dwarf specification. +*/ + +#define MAX_LINE_OP_CODE 255 + + +/* The following structs (Line_Table_File_Entry_s,Line_Table_Prefix_s) + and functions allow refactoring common code into a single + reader routine. +*/ +/* There can be zero of more of these needed for 1 line prologue. */ +struct Line_Table_File_Entry_s { + Dwarf_Small *lte_filename; + Dwarf_Unsigned lte_directory_index; + Dwarf_Unsigned lte_last_modification_time; + Dwarf_Unsigned lte_length_of_file; +}; + +/* Data picked up from the line table prologue for a single +CU. */ +struct Line_Table_Prefix_s { + + /* pf_total_length is the value of the length field for the line + table of this CU. So it does not count the length of itself (the + length value) for consistency with the say lenghts recorded in + DWARF2/3. */ + Dwarf_Unsigned pf_total_length; + + /* Length of the initial length field itself. */ + Dwarf_Half pf_length_field_length; + + /* The version is 2 for DWARF2, 3 for DWARF3 */ + Dwarf_Half pf_version; + + Dwarf_Unsigned pf_prologue_length; + Dwarf_Small pf_minimum_instruction_length; + + /* Start and end of this CU line area. pf_line_ptr_start + + pf_total_length + pf_length_field_length == pf_line_ptr_end. + Meaning pf_line_ptr_start is before the length info. */ + Dwarf_Small *pf_line_ptr_start; + Dwarf_Small *pf_line_ptr_end; + + /* Used to check that decoding of the line prologue is done right. */ + Dwarf_Small *pf_line_prologue_start; + + Dwarf_Small pf_default_is_stmt; + Dwarf_Ubyte pf_maximum_ops_per_instruction; + Dwarf_Sbyte pf_line_base; + Dwarf_Small pf_line_range; + + /* Highest std opcode (+1). */ + Dwarf_Small pf_opcode_base; + /* pf_opcode_base -1 entries (each a count, normally the value of + each entry is 0 or 1). */ + Dwarf_Small *pf_opcode_length_table; + + Dwarf_Unsigned pf_include_directories_count; + /* Array of pointers to dir strings. pf_include_directories_count + entriesin the array. */ + Dwarf_Small **pf_include_directories; + + /* Count of entries in line_table_file_entries array. */ + Dwarf_Unsigned pf_files_count; + struct Line_Table_File_Entry_s *pf_line_table_file_entries; + + /* The number to treat as standard ops. This is a special + accomodation of gcc using the new standard opcodes but not + updating the version number. It's legal dwarf2, but much better + for the user to understand as dwarf3 when 'it looks ok'. */ + Dwarf_Bool pf_std_op_count; + +}; + +void dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf); +void dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf); + +int dwarf_read_line_table_prefix(Dwarf_Debug dbg, + Dwarf_Small * data_start, + Dwarf_Unsigned data_length, + Dwarf_Small ** updated_data_start_out, + struct Line_Table_Prefix_s *prefix_out, + /* The following 2 arguments are solely for warning users + when there is a surprising 'gap' in the .debug_line info. */ + Dwarf_Small ** bogus_bytes_ptr, + Dwarf_Unsigned * bogus_bytes_count, + Dwarf_Error * err, + int * err_count_out); diff --git a/libdwarf/dwarf_line2.c b/libdwarf/dwarf_line2.c new file mode 100644 index 0000000..ba384c7 --- /dev/null +++ b/libdwarf/dwarf_line2.c @@ -0,0 +1,107 @@ +/* + + Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2008-2011 David Anderson, Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +/* This source file used for SGI-IRIX rqs processing. + Unused otherwise. +*/ + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_line.h" + +/* Return DW_DLV_OK or, if error, + DW_DLV_ERROR. + + Thru pointers, return 2 arrays and a count + for rqs (IRIX run-time linker). */ +int +_dwarf_line_address_offsets(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Addr ** addrs, + Dwarf_Off ** offs, + Dwarf_Unsigned * returncount, + Dwarf_Error * err) +{ + Dwarf_Addr *laddrs; + Dwarf_Off *loffsets; + Dwarf_Signed lcount; + Dwarf_Signed i; + int res; + Dwarf_Line *linebuf; + + res = _dwarf_internal_srclines(die, &linebuf, &lcount, + /* addrlist= */ true, /* linelist= */ false, err); + if (res != DW_DLV_OK) { + return res; + } + laddrs = (Dwarf_Addr *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount); + if (laddrs == NULL) { + dwarf_srclines_dealloc(dbg, linebuf, lcount); + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + loffsets = (Dwarf_Off *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount); + if (loffsets == NULL) { + dwarf_srclines_dealloc(dbg, linebuf, lcount); + /* We already allocated what laddrs points at, so we'e better + deallocate that space since we are not going to return the + pointer to the caller. */ + dwarf_dealloc(dbg, laddrs, DW_DLA_ADDR); + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + for (i = 0; i < lcount; i++) { + laddrs[i] = linebuf[i]->li_address; + loffsets[i] = linebuf[i]->li_addr_line.li_offset; + } + dwarf_srclines_dealloc(dbg, linebuf, lcount); + *returncount = lcount; + *offs = loffsets; + *addrs = laddrs; + return DW_DLV_OK; +} + +/* + It's impossible for callers of dwarf_srclines() to get to and + free all the resources (in particular, the li_context and its + lc_file_entries). + So this function, new July 2005, does it. +*/ diff --git a/libdwarf/dwarf_loc.c b/libdwarf/dwarf_loc.c new file mode 100644 index 0000000..3a2025a --- /dev/null +++ b/libdwarf/dwarf_loc.c @@ -0,0 +1,1197 @@ +/* + + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include "dwarf_loc.h" +#include <stdio.h> /* for debugging only. */ + +/* Richard Henderson: The operand is an absolute + address. The first byte of the value + is an encoding length: 0 2 4 or 8. If zero + it means the following is address-size. + The address then follows immediately for + that number of bytes. */ +static int +read_encoded_addr(Dwarf_Small *loc_ptr, Dwarf_Debug dbg, + Dwarf_Unsigned * val_out, + int * len_out, + Dwarf_Error *error) +{ + int totallen = 0; + int oplen = 0; + int len = 0; + Dwarf_Small op = *loc_ptr; + Dwarf_Unsigned operand = 0; + len++; + if(op == 0) { + /* FIXME: should be CU specific. */ + op = dbg->de_pointer_size; + } + switch(op) { + case 1: + *val_out = *loc_ptr; + len++; + break; + + case 2: + READ_UNALIGNED(dbg, operand, Dwarf_Unsigned, loc_ptr, 2); + *val_out = operand; + len +=2; + break; + case 4: + READ_UNALIGNED(dbg, operand, Dwarf_Unsigned, loc_ptr, 4); + *val_out = operand; + len +=4; + break; + case 8: + READ_UNALIGNED(dbg, operand, Dwarf_Unsigned, loc_ptr, 8); + *val_out = operand; + len +=8; + break; + default: + /* We do not know how much to read. */ + _dwarf_error(dbg, error, DW_DLE_GNU_OPCODE_ERROR); + return DW_DLV_ERROR; + }; + *len_out = len; + return DW_DLV_OK; +} + + + +/* Given a Dwarf_Block that represents a location expression, + this function returns a pointer to a Dwarf_Locdesc struct + that has its ld_cents field set to the number of location + operators in the block, and its ld_s field pointing to a + contiguous block of Dwarf_Loc structs. However, the + ld_lopc and ld_hipc values are uninitialized. Returns + NULL on error. This function assumes that the length of + the block is greater than 0. Zero length location expressions + to represent variables that have been optimized away are + handled in the calling function. +*/ +static Dwarf_Locdesc * +_dwarf_get_locdesc(Dwarf_Debug dbg, + Dwarf_Block * loc_block, + Dwarf_Half address_size, + Dwarf_Addr lowpc, + Dwarf_Addr highpc, + Dwarf_Error * error) +{ + /* Size of the block containing the location expression. */ + Dwarf_Unsigned loc_len = 0; + + /* Sweeps the block containing the location expression. */ + Dwarf_Small *loc_ptr = 0; + + /* Offset of current operator from start of block. */ + Dwarf_Unsigned offset = 0; + + /* Used to chain the Dwarf_Loc_Chain_s structs. */ + Dwarf_Loc_Chain curr_loc = NULL; + Dwarf_Loc_Chain prev_loc = NULL; + Dwarf_Loc_Chain head_loc = NULL; + + /* Count of the number of location operators. */ + Dwarf_Unsigned op_count = 0; + + /* Contiguous block of Dwarf_Loc's for Dwarf_Locdesc. */ + Dwarf_Loc *block_loc = 0; + + /* Dwarf_Locdesc pointer to be returned. */ + Dwarf_Locdesc *locdesc = 0; + + Dwarf_Word leb128_length = 0; + Dwarf_Unsigned i = 0; + + /* ***** BEGIN CODE ***** */ + + loc_len = loc_block->bl_len; + loc_ptr = loc_block->bl_data; + + offset = 0; + op_count = 0; + while (offset < loc_len) { + Dwarf_Unsigned operand1 = 0; + Dwarf_Unsigned operand2 = 0; + Dwarf_Small atom = 0; + + op_count++; + atom = *(Dwarf_Small *) loc_ptr; + loc_ptr++; + offset++; + curr_loc = + (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN, + 1); + if (curr_loc == NULL) { + /* Some memory may leak here. */ + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (NULL); + } + curr_loc->lc_offset = offset; + curr_loc->lc_atom = atom; + switch (atom) { + + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + break; + + case DW_OP_regx: + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + operand1 = atom - DW_OP_lit0; + break; + + case DW_OP_addr: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, + loc_ptr, address_size); + loc_ptr += address_size; + offset += address_size; + break; + + case DW_OP_const1u: + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + offset = offset + 1; + break; + + case DW_OP_const1s: + operand1 = *(Dwarf_Sbyte *) loc_ptr; + SIGN_EXTEND(operand1,1); + loc_ptr = loc_ptr + 1; + offset = offset + 1; + break; + + case DW_OP_const2u: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_const2s: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2); + SIGN_EXTEND(operand1,2); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_const4u: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4); + loc_ptr = loc_ptr + 4; + offset = offset + 4; + break; + + case DW_OP_const4s: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4); + SIGN_EXTEND(operand1,4); + loc_ptr = loc_ptr + 4; + offset = offset + 4; + break; + + case DW_OP_const8u: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8); + loc_ptr = loc_ptr + 8; + offset = offset + 8; + break; + + case DW_OP_const8s: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8); + loc_ptr = loc_ptr + 8; + offset = offset + 8; + break; + + case DW_OP_constu: + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_consts: + operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_fbreg: + operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_bregx: + /* uleb reg num followed by sleb offset */ + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + + operand2 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_dup: + case DW_OP_drop: + break; + + case DW_OP_pick: + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + offset = offset + 1; + break; + + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_deref: + break; + + case DW_OP_deref_size: + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + offset = offset + 1; + break; + + case DW_OP_xderef: + break; + + case DW_OP_xderef_size: + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + offset = offset + 1; + break; + + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + break; + + case DW_OP_plus_uconst: + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + break; + + case DW_OP_le: + case DW_OP_ge: + case DW_OP_eq: + case DW_OP_lt: + case DW_OP_gt: + case DW_OP_ne: + break; + + case DW_OP_skip: + case DW_OP_bra: + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_piece: + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + case DW_OP_nop: + break; + case DW_OP_push_object_address: /* DWARF3 */ + break; + case DW_OP_call2: /* DWARF3 */ + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_call4: /* DWARF3 */ + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4); + loc_ptr = loc_ptr + 4; + offset = offset + 4; + break; + case DW_OP_call_ref: /* DWARF3 */ + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, + dbg->de_length_size); + loc_ptr = loc_ptr + dbg->de_length_size; + offset = offset + dbg->de_length_size; + break; + + case DW_OP_form_tls_address: /* DWARF3f */ + break; + case DW_OP_call_frame_cfa: /* DWARF3f */ + break; + case DW_OP_bit_piece: /* DWARF3f */ + /* uleb size in bits followed by uleb offset in bits */ + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + + operand2 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + break; + + /* The operator means: push the currently computed + (by the operations encountered so far in this + expression) onto the expression stack as the offset + in thread-local-storage of the variable. */ + case DW_OP_GNU_push_tls_address: + break; + + case DW_OP_implicit_value: /* DWARF4 */ + /* uleb length of value bytes followed by that + number of bytes of the value. */ + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + + /* Second operand is block of 'operand1' bytes of stuff. */ + /* This using the second operand as a pointer + is quite ugly. */ + /* This gets an ugly compiler warning. Sorry. */ + operand2 = (Dwarf_Unsigned)loc_ptr; + offset = offset + operand1; + loc_ptr = loc_ptr + operand1; + break; + case DW_OP_stack_value: /* DWARF4 */ + break; + case DW_OP_GNU_uninit: /* 0xf0 GNU */ + /* Carolyn Tice: Follws a DW_OP_reg or DW_OP_regx + and marks the reg as being uninitialized. */ + break; + case DW_OP_GNU_encoded_addr: { /* 0xf1 GNU */ + /* Richard Henderson: The operand is an absolute + address. The first byte of the value + is an encoding length: 0 2 4 or 8. If zero + it means the following is address-size. + The address then follows immediately for + that number of bytes. */ + int length = 0; + int reares = read_encoded_addr(loc_ptr,dbg,&operand1, + &length,error); + if(reares != DW_DLV_OK) { + /* Oops. The caller will notice and + will issue DW_DLV_ERROR. */ + return NULL; + } + loc_ptr += length; + offset += length; + } + break; + case DW_OP_GNU_implicit_pointer: /* 0xf2 GNU */ + /* Jakub Jelinek: The value is an optimized-out + pointer value. Represented as + an offset_size (address_size) DIE offset + (as simple unsigned integer) followed by + a signed leb128 offset. + http://www.dwarfstd.org/ShowIssue.php?issue=100831.1 */ + READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, + dbg->de_length_size); + loc_ptr = loc_ptr + dbg->de_length_size; + offset = offset + dbg->de_length_size; + + operand2 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + + break; + case DW_OP_GNU_entry_value: /* 0xf3 GNU */ + /* Jakub Jelinek: A register reused really soon, + but the value is unchanged. So to represent + that value we have a uleb128 size followed + by a DWARF expression block that size. + http://www.dwarfstd.org/ShowIssue.php?issue=100909.1 */ + + /* uleb length of value bytes followed by that + number of bytes of the value. */ + operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length); + loc_ptr = loc_ptr + leb128_length; + offset = offset + leb128_length; + + /* Second operand is block of 'operand1' bytes of stuff. */ + /* This using the second operand as a pointer + is quite ugly. */ + /* This gets an ugly compiler warning. Sorry. */ + operand2 = (Dwarf_Unsigned)loc_ptr; + offset = offset + operand1; + loc_ptr = loc_ptr + operand1; + break; + + default: + /* Some memory does leak here. */ + + _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD); + return (NULL); + } + + /* If offset == loc_len this would be normal end-of-expression. */ + if (offset > loc_len) { + /* We stepped past the end of the expression. + This has to be a compiler bug. + Operators missing their values cannot be detected + as such except at the end of an expression (like this). + The results would be wrong if returned. + Some memory may leak here. + */ + _dwarf_error(dbg, error, DW_DLE_LOC_BAD_TERMINATION); + return (NULL); + } + + curr_loc->lc_number = operand1; + curr_loc->lc_number2 = operand2; + + if (head_loc == NULL) + head_loc = prev_loc = curr_loc; + else { + prev_loc->lc_next = curr_loc; + prev_loc = curr_loc; + } + } + + block_loc = + (Dwarf_Loc *) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK, op_count); + if (block_loc == NULL) { + /* Some memory does leak here. */ + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (NULL); + } + + curr_loc = head_loc; + for (i = 0; i < op_count; i++) { + (block_loc + i)->lr_atom = curr_loc->lc_atom; + (block_loc + i)->lr_number = curr_loc->lc_number; + (block_loc + i)->lr_number2 = curr_loc->lc_number2; + (block_loc + i)->lr_offset = curr_loc->lc_offset; + + prev_loc = curr_loc; + curr_loc = curr_loc->lc_next; + dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN); + } + + locdesc = + (Dwarf_Locdesc *) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC, 1); + if (locdesc == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (NULL); + } + + locdesc->ld_cents = op_count; + locdesc->ld_s = block_loc; + locdesc->ld_from_loclist = loc_block->bl_from_loclist; + locdesc->ld_section_offset = loc_block->bl_section_offset; + locdesc->ld_lopc = lowpc; + locdesc->ld_hipc = highpc; + + return (locdesc); +} + +/* Using a loclist offset to get the in-memory + address of .debug_loc data to read, returns the loclist + 'header' info in return_block. +*/ + +#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff) + +static int +_dwarf_read_loc_section(Dwarf_Debug dbg, + Dwarf_Block * return_block, + Dwarf_Addr * lowpc, Dwarf_Addr * hipc, + Dwarf_Off sec_offset, + Dwarf_Half address_size, + Dwarf_Error * error) +{ + Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset; + + Dwarf_Addr start_addr = 0; + Dwarf_Addr end_addr = 0; + Dwarf_Half exprblock_size = 0; + Dwarf_Unsigned exprblock_off = + 2 * address_size + sizeof(Dwarf_Half); + + if (sec_offset >= dbg->de_debug_loc.dss_size) { + /* We're at the end. No more present. */ + return DW_DLV_NO_ENTRY; + } + + /* If it goes past end, error */ + if (exprblock_off > dbg->de_debug_loc.dss_size) { + _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); + return DW_DLV_ERROR; + } + + READ_UNALIGNED(dbg, start_addr, Dwarf_Addr, beg, address_size); + READ_UNALIGNED(dbg, end_addr, Dwarf_Addr, + beg + address_size, address_size); + if (start_addr == 0 && end_addr == 0) { + /* If start_addr and end_addr are 0, it's the end and no + exprblock_size field follows. */ + exprblock_size = 0; + exprblock_off -= sizeof(Dwarf_Half); + } else if (start_addr == MAX_ADDR) { + /* End address is a base address, no exprblock_size field here + either */ + exprblock_size = 0; + exprblock_off -= sizeof(Dwarf_Half); + } else { + + READ_UNALIGNED(dbg, exprblock_size, Dwarf_Half, + beg + 2 * address_size, sizeof(Dwarf_Half)); + /* exprblock_size can be zero, means no expression */ + if ((exprblock_off + exprblock_size) > dbg->de_debug_loc.dss_size) { + _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); + return DW_DLV_ERROR; + } + } +#undef MAX_ADDR + *lowpc = start_addr; + *hipc = end_addr; + + return_block->bl_len = exprblock_size; + return_block->bl_from_loclist = 1; + return_block->bl_data = beg + exprblock_off; + return_block->bl_section_offset = + ((Dwarf_Small *) return_block->bl_data) - dbg->de_debug_loc.dss_data; + + return DW_DLV_OK; + +} +static int +_dwarf_get_loclist_count(Dwarf_Debug dbg, + Dwarf_Off loclist_offset, + Dwarf_Half address_size, + int *loclist_count, Dwarf_Error * error) +{ + int count = 0; + Dwarf_Off offset = loclist_offset; + + + for (;;) { + Dwarf_Block b; + Dwarf_Addr lowpc; + Dwarf_Addr highpc; + int res = _dwarf_read_loc_section(dbg, &b, + &lowpc, &highpc, + offset, address_size,error); + if (res != DW_DLV_OK) { + return res; + } + offset = b.bl_len + b.bl_section_offset; + if (lowpc == 0 && highpc == 0) { + break; + } + count++; + } + *loclist_count = count; + return DW_DLV_OK; +} + +/* Helper routine to avoid code duplication. +*/ +static int +_dwarf_setup_loc(Dwarf_Attribute attr, + Dwarf_Debug * dbg_ret, + Dwarf_CU_Context *cucontext_ret, + Dwarf_Half * form_ret, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Half form = 0; + int blkres = DW_DLV_ERROR; + + if (attr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return (DW_DLV_ERROR); + } + if (attr->ar_cu_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return (DW_DLV_ERROR); + } + *cucontext_ret = attr->ar_cu_context; + + dbg = attr->ar_cu_context->cc_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL); + return (DW_DLV_ERROR); + } + *dbg_ret = dbg; + blkres = dwarf_whatform(attr, &form, error); + if (blkres != DW_DLV_OK) { + _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD); + return blkres; + } + *form_ret = form; + return DW_DLV_OK; +} + +/* Helper routine to avoid code duplication. +*/ +static int +_dwarf_get_loclist_header_start(Dwarf_Debug dbg, + Dwarf_Attribute attr, + Dwarf_Unsigned * loclist_offset, + Dwarf_Error * error) +{ + int blkres = dwarf_global_formref(attr, loclist_offset, error); + if (blkres != DW_DLV_OK) { + return (blkres); + } + + if (!dbg->de_debug_loc.dss_data) { + int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error); + if (secload != DW_DLV_OK) { + return secload; + } + if (!dbg->de_debug_loc.dss_size) { + return (DW_DLV_NO_ENTRY); + } + } + return DW_DLV_OK; +} + +/* When llbuf (see dwarf_loclist_n) is partially set up + and an error is encountered, tear it down as it + won't be used. +*/ +static void +_dwarf_cleanup_llbuf(Dwarf_Debug dbg, Dwarf_Locdesc ** llbuf, int count) +{ + int i; + for (i = 0; i < count; ++i) { + dwarf_dealloc(dbg, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(dbg, llbuf[i], DW_DLA_LOCDESC); + } + dwarf_dealloc(dbg, llbuf, DW_DLA_LIST); +} + +/* Handles simple location entries and loclists. + Returns all the Locdesc's thru llbuf. */ +int +dwarf_loclist_n(Dwarf_Attribute attr, + Dwarf_Locdesc *** llbuf_out, + Dwarf_Signed * listlen_out, Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + /* Dwarf_Attribute that describes the DW_AT_location in die, if + present. */ + Dwarf_Attribute loc_attr = attr; + + /* Dwarf_Block that describes a single location expression. */ + Dwarf_Block loc_block; + + /* A pointer to the current Dwarf_Locdesc read. */ + Dwarf_Locdesc *locdesc = 0; + + Dwarf_Half form = 0; + Dwarf_Addr lowpc = 0; + Dwarf_Addr highpc = 0; + Dwarf_Signed listlen = 0; + Dwarf_Locdesc **llbuf = 0; + Dwarf_CU_Context cucontext = 0; + unsigned address_size = 0; + + int blkres = DW_DLV_ERROR; + int setup_res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error); + if (setup_res != DW_DLV_OK) { + return setup_res; + } + address_size = cucontext->cc_address_size; + /* If this is a form_block then it's a location expression. If it's + DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */ + if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP || + cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) && + (form == DW_FORM_data4 || form == DW_FORM_data8)) || + (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 && + form == DW_FORM_sec_offset)) { + + + /* A reference to .debug_loc, with an offset in .debug_loc of a + loclist */ + Dwarf_Unsigned loclist_offset = 0; + int off_res = DW_DLV_ERROR; + int count_res = DW_DLV_ERROR; + int loclist_count; + int lli; + + off_res = _dwarf_get_loclist_header_start(dbg, + attr, &loclist_offset, error); + if (off_res != DW_DLV_OK) { + return off_res; + } + count_res = _dwarf_get_loclist_count(dbg, loclist_offset, + address_size, &loclist_count, error); + listlen = loclist_count; + if (count_res != DW_DLV_OK) { + return count_res; + } + if (loclist_count == 0) { + return DW_DLV_NO_ENTRY; + } + + llbuf = (Dwarf_Locdesc **) + _dwarf_get_alloc(dbg, DW_DLA_LIST, loclist_count); + if (!llbuf) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + for (lli = 0; lli < loclist_count; ++lli) { + blkres = _dwarf_read_loc_section(dbg, &loc_block, + &lowpc, + &highpc, + loclist_offset, + address_size, + error); + if (blkres != DW_DLV_OK) { + _dwarf_cleanup_llbuf(dbg, llbuf, lli); + return (blkres); + } + locdesc = _dwarf_get_locdesc(dbg, &loc_block, + address_size, + lowpc, highpc, error); + if (locdesc == NULL) { + _dwarf_cleanup_llbuf(dbg, llbuf, lli); + /* low level error already set: let it be passed back */ + return (DW_DLV_ERROR); + } + llbuf[lli] = locdesc; + + /* Now get to next loclist entry offset. */ + loclist_offset = loc_block.bl_section_offset + + loc_block.bl_len; + } + + + } else { + Dwarf_Block *tblock = 0; + + blkres = dwarf_formblock(loc_attr, &tblock, error); + if (blkres != DW_DLV_OK) { + return (blkres); + } + loc_block = *tblock; + /* We copied tblock contents to the stack var, so can dealloc + tblock now. Avoids leaks. */ + dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK); + listlen = 1; /* One by definition of a location entry. */ + lowpc = 0; /* HACK */ + highpc = (Dwarf_Unsigned) (-1LL); /* HACK */ + + /* An empty location description (block length 0) means the + code generator emitted no variable, the variable was not + generated, it was unused or perhaps never tested after being + set. Dwarf2, section 2.4.1 In other words, it is not an + error, and we don't test for block length 0 specially here. */ + locdesc = _dwarf_get_locdesc(dbg, &loc_block, + address_size, + lowpc, highpc, error); + if (locdesc == NULL) { + /* low level error already set: let it be passed back */ + return (DW_DLV_ERROR); + } + llbuf = (Dwarf_Locdesc **) + _dwarf_get_alloc(dbg, DW_DLA_LIST, listlen); + if (!llbuf) { + /* Free the locdesc we allocated but won't use. */ + dwarf_dealloc(dbg, locdesc, DW_DLA_LOCDESC); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + llbuf[0] = locdesc; + } + + *llbuf_out = llbuf; + *listlen_out = listlen; + return (DW_DLV_OK); +} + + +/* Handles only a location expression. + If called on a loclist, just returns one of those. + Cannot not handle a real loclist. + It returns the location expression as a loclist with + a single entry. + See dwarf_loclist_n() which handles any number + of location list entries. + + This is the original definition, and it simply + does not work for loclists. Kept for compatibility. +*/ +int +dwarf_loclist(Dwarf_Attribute attr, + Dwarf_Locdesc ** llbuf, + Dwarf_Signed * listlen, Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + /* Dwarf_Attribute that describes the DW_AT_location in die, if + present. */ + Dwarf_Attribute loc_attr = attr; + + /* Dwarf_Block that describes a single location expression. */ + Dwarf_Block loc_block; + + /* A pointer to the current Dwarf_Locdesc read. */ + Dwarf_Locdesc *locdesc = 0; + + Dwarf_Half form = 0; + Dwarf_Addr lowpc = 0; + Dwarf_Addr highpc = 0; + Dwarf_CU_Context cucontext = 0; + unsigned address_size = 0; + + int blkres = DW_DLV_ERROR; + int setup_res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + setup_res = _dwarf_setup_loc(attr, &dbg, &cucontext, &form, error); + if (setup_res != DW_DLV_OK) { + return setup_res; + } + address_size = cucontext->cc_address_size; + /* If this is a form_block then it's a location expression. If it's + DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */ + if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP || + cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) && + (form == DW_FORM_data4 || form == DW_FORM_data8)) || + (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 && + form == DW_FORM_sec_offset)) + { + + /* A reference to .debug_loc, with an offset in .debug_loc of a + loclist. */ + Dwarf_Unsigned loclist_offset = 0; + int off_res = DW_DLV_ERROR; + + off_res = _dwarf_get_loclist_header_start(dbg, + attr, &loclist_offset, + error); + if (off_res != DW_DLV_OK) { + return off_res; + } + + /* With dwarf_loclist, just read a single entry */ + blkres = _dwarf_read_loc_section(dbg, &loc_block, + &lowpc, + &highpc, + loclist_offset, + address_size, + error); + if (blkres != DW_DLV_OK) { + return (blkres); + } + } else { + Dwarf_Block *tblock = 0; + + blkres = dwarf_formblock(loc_attr, &tblock, error); + if (blkres != DW_DLV_OK) { + return (blkres); + } + loc_block = *tblock; + /* We copied tblock contents to the stack var, so can dealloc + tblock now. Avoids leaks. */ + dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK); + lowpc = 0; /* HACK */ + highpc = (Dwarf_Unsigned) (-1LL); /* HACK */ + } + + /* An empty location description (block length 0) means the code + generator emitted no variable, the variable was not generated, + it was unused or perhaps never tested after being set. Dwarf2, + section 2.4.1 In other words, it is not an error, and we don't + test for block length 0 specially here. + See *dwarf_loclist_n() which handles the general case, this case + handles only a single location expression. */ + locdesc = _dwarf_get_locdesc(dbg, &loc_block, + address_size, + lowpc, highpc, error); + if (locdesc == NULL) { + /* low level error already set: let it be passed back */ + return (DW_DLV_ERROR); + } + + *llbuf = locdesc; + *listlen = 1; + return (DW_DLV_OK); +} + + + +/* Handles only a location expression. + It returns the location expression as a loclist with + a single entry. + + Usable to access dwarf expressions from any source, but + specifically from + DW_CFA_def_cfa_expression + DW_CFA_expression + DW_CFA_val_expression + + expression_in must point to a valid dwarf expression + set of bytes of length expression_length. Not + a DW_FORM_block*, just the expression bytes. + + If the address_size != de_pointer_size this will not work + right. FIXME. +*/ +int +dwarf_loclist_from_expr(Dwarf_Debug dbg, + Dwarf_Ptr expression_in, + Dwarf_Unsigned expression_length, + Dwarf_Locdesc ** llbuf, + Dwarf_Signed * listlen, Dwarf_Error * error) +{ + int res = 0; + Dwarf_Half addr_size = dbg->de_pointer_size; + res = dwarf_loclist_from_expr_a(dbg,expression_in, + expression_length, addr_size,llbuf,listlen,error); + return res; +} + +/* New April 27 2009. Adding addr_size argument for the rare + cases where an object has CUs with a different address_size. */ +int +dwarf_loclist_from_expr_a(Dwarf_Debug dbg, + Dwarf_Ptr expression_in, + Dwarf_Unsigned expression_length, + Dwarf_Half addr_size, + Dwarf_Locdesc ** llbuf, + Dwarf_Signed * listlen, Dwarf_Error * error) +{ + /* Dwarf_Block that describes a single location expression. */ + Dwarf_Block loc_block; + + /* A pointer to the current Dwarf_Locdesc read. */ + Dwarf_Locdesc *locdesc = 0; + Dwarf_Addr lowpc = 0; + Dwarf_Addr highpc = (Dwarf_Unsigned) (-1LL); + + memset(&loc_block,0,sizeof(loc_block)); + loc_block.bl_len = expression_length; + loc_block.bl_data = expression_in; + loc_block.bl_from_loclist = 0; /* Not from loclist. */ + loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */ + + /* An empty location description (block length 0) means the code + generator emitted no variable, the variable was not generated, + it was unused or perhaps never tested after being set. Dwarf2, + section 2.4.1 In other words, it is not an error, and we don't + test for block length 0 specially here. */ + locdesc = _dwarf_get_locdesc(dbg, &loc_block, + addr_size,lowpc, highpc, error); + if (locdesc == NULL) { + /* low level error already set: let it be passed back */ + return (DW_DLV_ERROR); + } + + *llbuf = locdesc; + *listlen = 1; + return (DW_DLV_OK); +} + +/* Usable to read a single loclist or to read a block of them + or to read an entire section's loclists. + + It's broken because it's not safe to read a loclist entry + when we do not know the address size (in any object where + address size can vary by compilation unit). +*/ + +/*ARGSUSED*/ int +dwarf_get_loclist_entry(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Addr * hipc_offset, + Dwarf_Addr * lopc_offset, + Dwarf_Ptr * data, + Dwarf_Unsigned * entry_len, + Dwarf_Unsigned * next_entry, + Dwarf_Error * error) +{ + Dwarf_Block b; + Dwarf_Addr lowpc = 0; + Dwarf_Addr highpc = 0; + Dwarf_Half address_size = 0; + int res = DW_DLV_ERROR; + + if (!dbg->de_debug_loc.dss_data) { + int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error); + if (secload != DW_DLV_OK) { + return secload; + } + } + + /* FIXME: address_size is not necessarily the same in every frame. */ + address_size = dbg->de_pointer_size; + res = _dwarf_read_loc_section(dbg, + &b, &lowpc, &highpc, offset, + address_size,error); + if (res != DW_DLV_OK) { + return res; + } + *hipc_offset = highpc; + *lopc_offset = lowpc; + *entry_len = b.bl_len; + *data = b.bl_data; + *next_entry = b.bl_len + b.bl_section_offset; + return DW_DLV_OK; +} + + diff --git a/libdwarf/dwarf_loc.h b/libdwarf/dwarf_loc.h new file mode 100644 index 0000000..685d199 --- /dev/null +++ b/libdwarf/dwarf_loc.h @@ -0,0 +1,46 @@ +/* + + Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +typedef struct Dwarf_Loc_Chain_s *Dwarf_Loc_Chain; + +struct Dwarf_Loc_Chain_s { + Dwarf_Small lc_atom; + Dwarf_Unsigned lc_number; + Dwarf_Unsigned lc_number2; + Dwarf_Unsigned lc_offset; + Dwarf_Loc_Chain lc_next; +}; diff --git a/libdwarf/dwarf_macro.c b/libdwarf/dwarf_macro.c new file mode 100644 index 0000000..a3d5eb6 --- /dev/null +++ b/libdwarf/dwarf_macro.c @@ -0,0 +1,470 @@ +/* + + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <limits.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif /* HAVE_STDLIB_H */ +#include "dwarf_macro.h" + + +#define LEFTPAREN '(' +#define RIGHTPAREN ')' +#define SPACE ' ' + +/* Given the dwarf macro string, return a pointer to + the value. Returns pointer to 0 byte at end of string + if no value found (meaning the value is the empty string). + + Only understands well-formed dwarf macinfo strings. +*/ +char * +dwarf_find_macro_value_start(char *str) +{ + char *lcp; + int funclike = 0; + + for (lcp = str; *lcp; ++lcp) { + switch (*lcp) { + case LEFTPAREN: + funclike = 1; + break; + case RIGHTPAREN: + /* lcp+1 must be a space, and following char is the value */ + return lcp + 2; + case SPACE: + /* We allow extraneous spaces inside macro parameter ** + list, just in case... This is not really needed. */ + if (!funclike) { + return lcp + 1; + } + break; + } + } + /* Never found value: returns pointer to the 0 byte at end of + string. */ + return lcp; + +} + + +/* + Try to keep fileindex correct in every Macro_Details + record by tracking file starts and ends. + Uses high water mark: space reused, not freed. + Presumption is that this makes sense for most uses. + STARTERMAX is set so that the array need not be expanded for + most files: it is the initial include file depth. +*/ +struct macro_stack_s { + Dwarf_Signed *st_base; + long max; + long next_to_use; + int was_fault; +}; + +static void _dwarf_reset_index_macro_stack(struct macro_stack_s *ms); +static void +free_macro_stack(Dwarf_Debug dbg, struct macro_stack_s *ms) +{ + dwarf_dealloc(dbg,ms->st_base,DW_DLA_STRING); + _dwarf_reset_index_macro_stack(ms); +} + +#define STARTERMAX 10 +static void +_dwarf_reset_index_macro_stack(struct macro_stack_s *ms) +{ + ms->st_base = 0; + ms->max = 0; + ms->next_to_use = 0; + ms->was_fault = 0; +} +static int +_dwarf_macro_stack_push_index(Dwarf_Debug dbg, Dwarf_Signed indx, + struct macro_stack_s *ms) +{ + Dwarf_Signed *newbase; + + if (ms->next_to_use >= ms->max) { + long new_size; + + if (ms->max == 0) { + ms->max = STARTERMAX; + } + new_size = ms->max * 2; + newbase = + _dwarf_get_alloc(dbg, DW_DLA_STRING, + new_size * sizeof(Dwarf_Signed)); + if (newbase == 0) { + /* just leave the old array in place */ + ms->was_fault = 1; + return DW_DLV_ERROR; + } + if(ms->st_base) { + memcpy(newbase, ms->st_base, + ms->next_to_use * sizeof(Dwarf_Signed)); + dwarf_dealloc(dbg, ms->st_base, DW_DLA_STRING); + } + ms->st_base = newbase; + ms->max = new_size; + } + ms->st_base[ms->next_to_use] = indx; + ++ms->next_to_use; + return DW_DLV_OK; +} + +static Dwarf_Signed +_dwarf_macro_stack_pop_index(struct macro_stack_s *ms) +{ + if (ms->was_fault) { + return -1; + } + if (ms->next_to_use > 0) { + ms->next_to_use--; + return (ms->st_base[ms->next_to_use]); + } else { + ms->was_fault = 1; + } + return -1; +} + +/* Starting at macro_offset in .debug_macinfo, + if maximum_count is 0, treat as if it is infinite. + get macro data up thru + maximum_count entries or the end of a compilation + unit's entries (whichever comes first). */ + +int +dwarf_get_macro_details(Dwarf_Debug dbg, + Dwarf_Off macro_offset, + Dwarf_Unsigned maximum_count, + Dwarf_Signed * entry_count, + Dwarf_Macro_Details ** details, + Dwarf_Error * error) +{ + Dwarf_Small *macro_base = 0; + Dwarf_Small *pnext = 0; + Dwarf_Unsigned endloc = 0; + unsigned char uc = 0; + unsigned long depth = 0; + /* By section 6.3.2 Dwarf3 draft 8/9, + the base file should appear as + DW_MACINFO_start_file. See + http://gcc.gnu.org/ml/gcc-bugs/2005-02/msg03442.html + on "[Bug debug/20253] New: [3.4/4.0 regression]: + Macro debug info broken due to lexer change" for how + gcc is broken in some versions. We no longer use + depth as a stopping point, it's not needed as a + stopping point anyway. */ + int res = 0; + /* count space used by strings */ + unsigned long str_space = 0; + int done = 0; + unsigned long space_needed = 0; + unsigned long string_offset = 0; + Dwarf_Small *return_data = 0; + Dwarf_Small *pdata = 0; + unsigned long final_count = 0; + Dwarf_Signed fileindex = -1; + Dwarf_Small *latest_str_loc = 0; + struct macro_stack_s msdata; + + unsigned long count = 0; + unsigned long max_count = (unsigned long) maximum_count; + + _dwarf_reset_index_macro_stack(&msdata); + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + free_macro_stack(dbg,&msdata); + return (DW_DLV_ERROR); + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error); + if (res != DW_DLV_OK) { + free_macro_stack(dbg,&msdata); + return res; + } + if (!dbg->de_debug_abbrev.dss_size) { + free_macro_stack(dbg,&msdata); + return (DW_DLV_NO_ENTRY); + } + + macro_base = dbg->de_debug_macinfo.dss_data; + if (macro_base == NULL) { + free_macro_stack(dbg,&msdata); + return (DW_DLV_NO_ENTRY); + } + if (macro_offset >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + return (DW_DLV_NO_ENTRY); + } + + pnext = macro_base + macro_offset; + if (maximum_count == 0) { + max_count = ULONG_MAX; + } + + + /* how many entries and how much space will they take? */ + + endloc = (pnext - macro_base); + if (endloc >= dbg->de_debug_macinfo.dss_size) { + if (endloc == dbg->de_debug_macinfo.dss_size) { + /* normal: found last entry */ + free_macro_stack(dbg,&msdata); + return DW_DLV_NO_ENTRY; + } + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD); + free_macro_stack(dbg,&msdata); + return (DW_DLV_ERROR); + } + for (count = 0; !done && count < max_count; ++count) { + unsigned long slen; + Dwarf_Word len; + + uc = *pnext; + ++pnext; /* get past the type code */ + switch (uc) { + case DW_MACINFO_define: + case DW_MACINFO_undef: + /* line, string */ + case DW_MACINFO_vendor_ext: + /* number, string */ + (void) _dwarf_decode_u_leb128(pnext, &len); + + pnext += len; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + slen = strlen((char *) pnext) + 1; + pnext += slen; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + str_space += slen; + break; + case DW_MACINFO_start_file: + /* line, file index */ + (void) _dwarf_decode_u_leb128(pnext, &len); + pnext += len; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + (void) _dwarf_decode_u_leb128(pnext, &len); + pnext += len; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + ++depth; + break; + + case DW_MACINFO_end_file: + if (--depth == 0) { + /* done = 1; no, do not stop here, at least one gcc had + the wrong depth settings in the gcc 3.4 timeframe. */ + } + /* no string or number here */ + break; + case 0: + /* end of cu's entries */ + done = 1; + break; + default: + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + /* bogus macinfo! */ + } + + endloc = (pnext - macro_base); + if (endloc == dbg->de_debug_macinfo.dss_size) { + done = 1; + } else if (endloc > dbg->de_debug_macinfo.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD); + free_macro_stack(dbg,&msdata); + return (DW_DLV_ERROR); + } + } + if (count == 0) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INTERNAL_ERR); + return (DW_DLV_ERROR); + } + + /* We have 'count' array entries to allocate and str_space bytes of + string space to provide for. */ + + string_offset = count * sizeof(Dwarf_Macro_Details); + + /* extra 2 not really needed */ + space_needed = string_offset + str_space + 2; + return_data = pdata = + _dwarf_get_alloc(dbg, DW_DLA_STRING, space_needed); + latest_str_loc = pdata + string_offset; + if (pdata == 0) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE); + return (DW_DLV_ERROR); + } + pnext = macro_base + macro_offset; + + done = 0; + + /* A series ends with a type code of 0. */ + + for (final_count = 0; !done && final_count < count; ++final_count) { + unsigned long slen; + Dwarf_Word len; + Dwarf_Unsigned v1; + Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata + + (final_count * sizeof (Dwarf_Macro_Details))); + + endloc = (pnext - macro_base); + if (endloc > dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD); + return (DW_DLV_ERROR); + } + uc = *pnext; + pdmd->dmd_offset = (pnext - macro_base); + pdmd->dmd_type = uc; + pdmd->dmd_fileindex = fileindex; + pdmd->dmd_lineno = 0; + pdmd->dmd_macro = 0; + ++pnext; /* get past the type code */ + switch (uc) { + case DW_MACINFO_define: + case DW_MACINFO_undef: + /* line, string */ + case DW_MACINFO_vendor_ext: + /* number, string */ + v1 = _dwarf_decode_u_leb128(pnext, &len); + pdmd->dmd_lineno = v1; + + pnext += len; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + slen = strlen((char *) pnext) + 1; + strcpy((char *) latest_str_loc, (char *) pnext); + pdmd->dmd_macro = (char *) latest_str_loc; + latest_str_loc += slen; + pnext += slen; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + break; + case DW_MACINFO_start_file: + /* Line, file index */ + v1 = _dwarf_decode_u_leb128(pnext, &len); + pdmd->dmd_lineno = v1; + pnext += len; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + v1 = _dwarf_decode_u_leb128(pnext, &len); + pdmd->dmd_fileindex = v1; + (void) _dwarf_macro_stack_push_index(dbg, fileindex, + &msdata); + /* We ignore the error, we just let fileindex ** be -1 when + we pop this one. */ + fileindex = v1; + pnext += len; + if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + break; + + case DW_MACINFO_end_file: + fileindex = _dwarf_macro_stack_pop_index(&msdata); + break; /* no string or number here */ + case 0: + /* Type code of 0 means the end of cu's entries. */ + done = 1; + break; + default: + /* Bogus macinfo! */ + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT); + return (DW_DLV_ERROR); + } + } + *entry_count = count; + *details = (Dwarf_Macro_Details *) return_data; + free_macro_stack(dbg,&msdata); + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_macro.h b/libdwarf/dwarf_macro.h new file mode 100644 index 0000000..31ea2e6 --- /dev/null +++ b/libdwarf/dwarf_macro.h @@ -0,0 +1,44 @@ +/* + + Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +/* + + + dwarf_macro.h + + $Revision: 1.4 $ $Date: 2004/10/28 22:19:14 $ + +*/ diff --git a/libdwarf/dwarf_opaque.h b/libdwarf/dwarf_opaque.h new file mode 100644 index 0000000..88d1ce3 --- /dev/null +++ b/libdwarf/dwarf_opaque.h @@ -0,0 +1,364 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* The versions applicable by section are: + . DWARF2 DWARF3 DWARF4 + .debug_abbrev - - - + .debug_aranges 2 2 2 + .debug_frame 1 3 4 + .debug_info 2 3 4 + .debug_line 2 3 4 + .debug_loc - - - + .debug_macinfo - - - + .debug_pubtypes x 2 2 + .debug_pubnames 2 2 2 + .debug_ranges x - - + .debug_str - - - + .debug_types x x 4 +*/ + +#include <stddef.h> + +/* The 'debug_info' names below are non-zero (non-NULL) only + if we are processing a debug_info section. And vice versa + for a debug_types section. */ + +struct Dwarf_Die_s { + Dwarf_Byte_Ptr di_debug_ptr; + Dwarf_Abbrev_List di_abbrev_list; + Dwarf_CU_Context di_cu_context; + int di_abbrev_code; + + /* TRUE if part of debug_info. FALSE if part of .debug_types. */ + Dwarf_Bool di_is_info; +}; + +struct Dwarf_Attribute_s { + Dwarf_Half ar_attribute; /* Attribute Value. */ + Dwarf_Half ar_attribute_form; /* Attribute Form. */ + Dwarf_Half ar_attribute_form_direct; + /* Identical to ar_attribute_form except that if + the original form uleb was DW_FORM_indirect, + ar_attribute_form_direct contains DW_FORM_indirect + but ar_attribute_form contains the true form. */ + Dwarf_CU_Context ar_cu_context; + /* The following points to either debug_info or debug_types + depending on if context is cc_is_info or not. */ + Dwarf_Small *ar_debug_ptr; + + Dwarf_Die ar_die;/* Access to the DIE owning the attribute */ + Dwarf_Attribute ar_next; +}; + +/* + This structure provides the context for a compilation unit. + Thus, it contains the Dwarf_Debug, cc_dbg, that this cu + belongs to. It contains the information in the compilation + unit header, cc_length, cc_version_stamp, cc_abbrev_offset, + and cc_address_size, in the .debug_info section for that cu. + In addition, it contains the count, cc_count_cu, of the cu + number of that cu in the list of cu's in the .debug_info. + The count starts at 1, ie cc_count_cu is 1 for the first cu, + 2 for the second and so on. This struct also contains a + pointer, cc_abbrev_table, to a list of pairs of abbrev code + and a pointer to the start of that abbrev + in the .debug_abbrev section. + + Each die will also contain a pointer to such a struct to + record the context for that die. + + Notice that a pointer to the CU DIE itself is + Dwarf_Off off2 = cu_context->cc_debug_info_offset; + cu_die_info_ptr = dbg->de_debug_info.dss_data + + off2 + _dwarf_length_of_cu_header(dbg, off2); + Or similar for de_debug_types. + + **Updated by dwarf_next_cu_header in dwarf_die_deliv.c +*/ +struct Dwarf_CU_Context_s { + Dwarf_Debug cc_dbg; + /* The sum of cc_length, cc_length_size, and cc_extension_size + is the total length of the CU including its header. */ + Dwarf_Word cc_length; + /* cc_length_size is the size in bytes of an offset. + 4 for 32bit dwarf, 8 for 64bit dwarf (whether MIPS/IRIX + 64bit dwarf or standard 64bit dwarf using the extension + mechanism). */ + Dwarf_Small cc_length_size; + /* cc_extension_size is zero unless this is standard + DWARF3 and later 64bit dwarf using the extension mechanism. + If it is the DWARF3 and later 64bit dwarf cc_extension + size is 4. So for 32bit dwarf and MIPS/IRIX 64bit dwarf + cc_extension_size is zero. */ + Dwarf_Small cc_extension_size; + Dwarf_Half cc_version_stamp; + Dwarf_Sword cc_abbrev_offset; + Dwarf_Small cc_address_size; + /* cc_debug_offset is the offset in the section + of the CU header of this CU. Dwarf_Word + should be large enough. May be debug_info or debug_types + but those are distinct. See cc_is_info flag. */ + Dwarf_Word cc_debug_offset; + Dwarf_Sig8 cc_signature; + Dwarf_Unsigned cc_typeoffset; + + Dwarf_Byte_Ptr cc_last_abbrev_ptr; + Dwarf_Hash_Table cc_abbrev_hash_table; + Dwarf_CU_Context cc_next; + /*unsigned char cc_offset_length; */ + Dwarf_Bool cc_is_info; /* TRUE means context is + in debug_info, FALSE means is in debug_types. */ +}; + +/* Consolidates section-specific data in one place. + Section is an Elf specific term, intended as a general + term (for non-Elf objects some code must synthesize the + values somehow). + Makes adding more section-data much simpler. */ +struct Dwarf_Section_s { + Dwarf_Small * dss_data; + Dwarf_Unsigned dss_size; + /* Some Elf sections have a non-zero dss_entrysize which + is the size in bytes of a table entry in the section. + Relocations and symbols are both in tables, so have a + non-zero entrysize. Object formats which do not care + about this should leave this field zero. */ + Dwarf_Unsigned dss_entrysize; + Dwarf_Word dss_index; + /* dss_addr is the 'section address' which is only + non-zero for a GNU eh section. + Purpose: to handle DW_EH_PE_pcrel encoding. Leaving + it zero is fine for non-elf. */ + Dwarf_Addr dss_addr; + Dwarf_Small dss_data_was_malloc; + + /* For non-elf, leaving the following fields zero + will mean they are ignored. */ + /* dss_link should be zero unless a section has a link + to another (sh_link). Used to access relocation data for + a section (and for symtab section, access its strtab). */ + Dwarf_Word dss_link; + /* The following is used when reading .rela sections + (such sections appear in some .o files). */ + Dwarf_Half dss_reloc_index; /* Zero means ignore the reloc fields. */ + Dwarf_Small * dss_reloc_data; + Dwarf_Unsigned dss_reloc_size; + Dwarf_Unsigned dss_reloc_entrysize; + Dwarf_Addr dss_reloc_addr; + /* dss_reloc_symtab is the sh_link of a .rela to its .symtab, leave + it 0 if non-meaningful. */ + Dwarf_Addr dss_reloc_symtab; + /* dss_reloc_link should be zero unless a reloc section has a link + to another (sh_link). Used to access the symtab for relocations + a section. */ + Dwarf_Word dss_reloc_link; + /* Pointer to the elf symtab, used for elf .rela. Leave it 0 + if not relevant. */ + struct Dwarf_Section_s *dss_symtab; +}; + +/* Overview: if next_to_use== first, no error slots are used. + If next_to_use+1 (mod maxcount) == first the slots are all used +*/ +struct Dwarf_Harmless_s { + unsigned dh_maxcount; + unsigned dh_next_to_use; + unsigned dh_first; + unsigned dh_errs_count; + char ** dh_errors; +}; + +/* Data needed seperately for debug_info and debug_types + as we may be reading both interspersed. */ + +struct Dwarf_Debug_InfoTypes_s { + /* Context for the compilation_unit just read by a call to + dwarf_next_cu_header. **Updated by dwarf_next_cu_header in + dwarf_die_deliv.c */ + Dwarf_CU_Context de_cu_context; + /* Points to linked list of CU Contexts for the CU's already read. + These are only CU's read by dwarf_next_cu_header(). */ + Dwarf_CU_Context de_cu_context_list; + /* Points to the last CU Context added to the list by + dwarf_next_cu_header(). */ + Dwarf_CU_Context de_cu_context_list_end; + /* This is the list of CU contexts read for dwarf_offdie(). These + may read ahead of dwarf_next_cu_header(). */ + Dwarf_CU_Context de_offdie_cu_context; + Dwarf_CU_Context de_offdie_cu_context_end; + + /* Offset of last byte of last CU read. */ + Dwarf_Word de_last_offset; + /* de_last_di_info_ptr and de_last_die are used with + dwarf_siblingof, dwarf_child, and dwarf_validate_die_sibling. + dwarf_validate_die_sibling will not give meaningful results + if called inappropriately. */ + Dwarf_Byte_Ptr de_last_di_ptr; + Dwarf_Die de_last_die; +}; +typedef struct Dwarf_Debug_InfoTypes_s *Dwarf_Debug_InfoTypes; + +struct Dwarf_Debug_s { + /* All file access methods and support data + are hidden in this structure. + We get a pointer, callers control the lifetime of the + structure and contents. */ + struct Dwarf_Obj_Access_Interface_s *de_obj_file; + + Dwarf_Handler de_errhand; + Dwarf_Ptr de_errarg; + + struct Dwarf_Debug_InfoTypes_s de_info_reading; + struct Dwarf_Debug_InfoTypes_s de_types_reading; + + /* Number of bytes in the length, and offset field in various + .debug_* sections. It's not very meaningful, and is + only used in one 'approximate' calculation. */ + Dwarf_Small de_length_size; + + /* number of bytes in a pointer of the target in various .debug_ + sections. 4 in 32bit, 8 in MIPS 64, ia64. */ + Dwarf_Small de_pointer_size; + + /* set at creation of a Dwarf_Debug to say if form_string should be + checked for valid length at every call. 0 means do the check. + non-zero means do not do the check. */ + Dwarf_Small de_assume_string_in_bounds; + + /* Dwarf_Alloc_Hdr_s structs used to manage chunks that are + malloc'ed for each allocation type for structs. */ + struct Dwarf_Alloc_Hdr_s de_alloc_hdr[ALLOC_AREA_REAL_TABLE_MAX]; +#ifdef DWARF_SIMPLE_MALLOC + struct simple_malloc_record_s * de_simple_malloc_base; +#endif + + + /* These fields are used to process debug_frame section. **Updated + by dwarf_get_fde_list in dwarf_frame.h */ + /* Points to contiguous block of pointers to Dwarf_Cie_s structs. */ + Dwarf_Cie *de_cie_data; + /* Count of number of Dwarf_Cie_s structs. */ + Dwarf_Signed de_cie_count; + /* Keep eh (GNU) separate!. */ + Dwarf_Cie *de_cie_data_eh; + Dwarf_Signed de_cie_count_eh; + /* Points to contiguous block of pointers to Dwarf_Fde_s structs. */ + Dwarf_Fde *de_fde_data; + /* Count of number of Dwarf_Fde_s structs. */ + Dwarf_Signed de_fde_count; + /* Keep eh (GNU) separate!. */ + Dwarf_Fde *de_fde_data_eh; + Dwarf_Signed de_fde_count_eh; + + struct Dwarf_Section_s de_debug_info; + struct Dwarf_Section_s de_debug_types; + struct Dwarf_Section_s de_debug_abbrev; + struct Dwarf_Section_s de_debug_line; + struct Dwarf_Section_s de_debug_loc; + struct Dwarf_Section_s de_debug_aranges; + struct Dwarf_Section_s de_debug_macinfo; + struct Dwarf_Section_s de_debug_pubnames; + struct Dwarf_Section_s de_debug_str; + struct Dwarf_Section_s de_debug_frame; + + /* gnu: the g++ eh_frame section */ + struct Dwarf_Section_s de_debug_frame_eh_gnu; + + struct Dwarf_Section_s de_debug_pubtypes; /* DWARF3 .debug_pubtypes */ + + struct Dwarf_Section_s de_debug_funcnames; + struct Dwarf_Section_s de_debug_typenames; /* SGI IRIX extension essentially + identical to DWARF3 .debug_pubtypes. */ + struct Dwarf_Section_s de_debug_varnames; + struct Dwarf_Section_s de_debug_weaknames; + struct Dwarf_Section_s de_debug_ranges; + + /* For non-elf, simply leave the following two structs zeroed and + they will be ignored. */ + struct Dwarf_Section_s de_elf_symtab; + struct Dwarf_Section_s de_elf_strtab; + + + void *(*de_copy_word) (void *, const void *, size_t); + unsigned char de_same_endian; + unsigned char de_elf_must_close; /* If non-zero, then + it was dwarf_init (not dwarf_elf_init) + so must elf_end() */ + + /* Default is DW_FRAME_INITIAL_VALUE from header. */ + Dwarf_Half de_frame_rule_initial_value; + + /* Default is DW_FRAME_LAST_REG_NUM. */ + Dwarf_Half de_frame_reg_rules_entry_count; + + Dwarf_Half de_frame_cfa_col_number; + Dwarf_Half de_frame_same_value_number; + Dwarf_Half de_frame_undefined_value_number; + + unsigned char de_big_endian_object; /* Non-zero if big-endian + object opened. */ + + struct Dwarf_Harmless_s de_harmless_errors; +}; + +typedef struct Dwarf_Chain_s *Dwarf_Chain; +struct Dwarf_Chain_s { + void *ch_item; + Dwarf_Chain ch_next; +}; + + +#define CURRENT_VERSION_STAMP 2 /* DWARF2 */ +#define CURRENT_VERSION_STAMP3 3 /* DWARF3 */ +#define CURRENT_VERSION_STAMP4 4 /* DWARF4 */ + + /* Size of cu header version stamp field. */ +#define CU_VERSION_STAMP_SIZE sizeof(Dwarf_Half) + + /* Size of cu header address size field. */ +#define CU_ADDRESS_SIZE_SIZE sizeof(Dwarf_Small) + +void *_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len); + +#define ORIGINAL_DWARF_OFFSET_SIZE 4 +#define DISTINGUISHED_VALUE 0xffffffff +#define DISTINGUISHED_VALUE_OFFSET_SIZE 8 + +/* We don't load the sections until they are needed. This function is + used to load the section. */ +int _dwarf_load_section(Dwarf_Debug, + struct Dwarf_Section_s *, + Dwarf_Error *); diff --git a/libdwarf/dwarf_original_elf_init.c b/libdwarf/dwarf_original_elf_init.c new file mode 100644 index 0000000..1de0af9 --- /dev/null +++ b/libdwarf/dwarf_original_elf_init.c @@ -0,0 +1,194 @@ +/* + + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved. + Portions Copyright 2011 David Anderson. All rights reserved. + + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +#include "config.h" +#include "dwarf_incl.h" +#include "dwarf_elf_access.h" + +#ifdef HAVE_ELF_H +#include <elf.h> +#endif +#ifdef HAVE_LIBELF_H +#include <libelf.h> +#else +#ifdef HAVE_LIBELF_LIBELF_H +#include <libelf/libelf.h> +#endif +#endif + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> + +#define DWARF_DBG_ERROR(dbg,errval,retval) \ + _dwarf_error(dbg, error, errval); return(retval); + +#define FALSE 0 +#define TRUE 1 + +static int +dwarf_elf_init_file_ownership(dwarf_elf_handle elf_file_pointer, + int libdwarf_owns_elf, + Dwarf_Unsigned access, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, + Dwarf_Error * error); + + +/* The basic dwarf initializer function for consumers using + libelf. + Return a libdwarf error code on error, return DW_DLV_OK + if this succeeds. */ +int +dwarf_init(int fd, + Dwarf_Unsigned access, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, Dwarf_Debug * ret_dbg, Dwarf_Error * error) +{ + struct stat fstat_buf; + dwarf_elf_handle elf_file_pointer = 0; + /* ELF_C_READ is a portable value */ + Elf_Cmd what_kind_of_elf_read = ELF_C_READ; + +#if !defined(S_ISREG) +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif + if (fstat(fd, &fstat_buf) != 0) { + DWARF_DBG_ERROR(NULL, DW_DLE_FSTAT_ERROR, DW_DLV_ERROR); + } + if (!S_ISREG(fstat_buf.st_mode)) { + DWARF_DBG_ERROR(NULL, DW_DLE_FSTAT_MODE_ERROR, DW_DLV_ERROR); + } + + if (access != DW_DLC_READ) { + DWARF_DBG_ERROR(NULL, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR); + } + + elf_version(EV_CURRENT); + /* Changed to mmap request per bug 281217. 6/95 */ +#ifdef HAVE_ELF_C_READ_MMAP + /* ELF_C_READ_MMAP is an SGI IRIX specific enum value from IRIX + libelf.h meaning read but use mmap */ + what_kind_of_elf_read = ELF_C_READ_MMAP; +#endif /* !HAVE_ELF_C_READ_MMAP */ + + elf_file_pointer = elf_begin(fd, what_kind_of_elf_read, 0); + if (elf_file_pointer == NULL) { + DWARF_DBG_ERROR(NULL, DW_DLE_ELF_BEGIN_ERROR, DW_DLV_ERROR); + } + return dwarf_elf_init_file_ownership(elf_file_pointer, + TRUE, access, errhand, errarg, ret_dbg, error); +} + +/* An alternate dwarf setup call for consumers using + libelf. + When the caller has opened libelf already, so the + caller must free libelf. */ +int +dwarf_elf_init(dwarf_elf_handle elf_file_pointer, + Dwarf_Unsigned access, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, Dwarf_Error * error) +{ + return dwarf_elf_init_file_ownership(elf_file_pointer, + FALSE, access, errhand, errarg, ret_dbg, error); +} + + +/* Initialize the ELF object access for libdwarf. */ +static int +dwarf_elf_init_file_ownership(dwarf_elf_handle elf_file_pointer, + int libdwarf_owns_elf, + Dwarf_Unsigned access, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, + Dwarf_Error * error) +{ + /* ELF is no longer tied to libdwarf. */ + Dwarf_Obj_Access_Interface *binary_interface = 0; + int res = DW_DLV_OK; + int err = 0; + + if (access != DW_DLC_READ) { + DWARF_DBG_ERROR(NULL, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR); + } + + /* This allocates and fills in *binary_interface. */ + res = dwarf_elf_object_access_init( + elf_file_pointer, + libdwarf_owns_elf, + &binary_interface, + &err); + if(res != DW_DLV_OK){ + DWARF_DBG_ERROR(NULL, err, DW_DLV_ERROR); + } + + /* This mallocs space and returns pointer thru ret_dbg, + saving the binary interface in 'ret-dbg' */ + res = dwarf_object_init(binary_interface, errhand, errarg, + ret_dbg, error); + if(res != DW_DLV_OK){ + dwarf_elf_object_access_finish(binary_interface); + } + return res; +} + + +/* + Frees all memory that was not previously freed + by dwarf_dealloc. + Aside from certain categories. + + This is only applicable when dwarf_init() or dwarf_elf_init() + was used to init 'dbg'. +*/ +int +dwarf_finish(Dwarf_Debug dbg, Dwarf_Error * error) +{ + dwarf_elf_object_access_finish(dbg->de_obj_file); + + return dwarf_object_finish(dbg, error); +} + diff --git a/libdwarf/dwarf_print_lines.c b/libdwarf/dwarf_print_lines.c new file mode 100644 index 0000000..263752b --- /dev/null +++ b/libdwarf/dwarf_print_lines.c @@ -0,0 +1,736 @@ +/* + + Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <time.h> +#include "dwarf_line.h" + +/* FIXME Need to add prologue_end epilogue_begin isa fields. */ +static void +print_line_header(void) +{ + printf + (" s b e p e i d\n" + " t l s r p s i\n" + " m c e o i a s\n" + " section op col t k q l l c\n" + " offset code address file line umn ? ? ? ? ? \n"); +} + +/* FIXME: print new line values: prologue_end epilogue_begin isa */ +static void +print_line_detail(char *prefix, + int opcode, + Dwarf_Unsigned address, + unsigned long file, + unsigned long line, + unsigned long column, + int is_stmt, int basic_block, int end_sequence, + int prologue_end, int epilogue_begin, int isa, + Dwarf_Unsigned discriminator) +{ + printf("%-15s %2d 0x%" DW_PR_XZEROS DW_PR_DUx " " + "%2lu %4lu %2lu %1d %1d %1d", + prefix, + (int) opcode, + (Dwarf_Unsigned) address, + (unsigned long) file, + (unsigned long) line, + (unsigned long) column, + (int) is_stmt, (int) basic_block, (int) end_sequence); + if(discriminator || prologue_end || epilogue_begin || isa) { + printf(" %1d", prologue_end); + printf(" %1d", epilogue_begin); + printf(" %1d", isa); + printf(" 0x%" DW_PR_DUx , discriminator); + } + printf("\n"); +} + + +/* return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR + If err_count_out is non-NULL, this is a special 'check' + call. */ +int +_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error, +int * err_count_out, int only_line_header) +{ + /* This pointer is used to scan the portion of the .debug_line + section for the current cu. */ + Dwarf_Small *line_ptr = 0; + Dwarf_Small *orig_line_ptr = 0; + + /* This points to the last byte of the .debug_line portion for the + current cu. */ + Dwarf_Small *line_ptr_end = 0; + + /* Pointer to a DW_AT_stmt_list attribute in case it exists in the + die. */ + Dwarf_Attribute stmt_list_attr = 0; + + /* Pointer to DW_AT_comp_dir attribute in die. */ + Dwarf_Attribute comp_dir_attr = 0; + + /* Pointer to name of compilation directory. */ + Dwarf_Small *comp_dir = NULL; + + /* Offset into .debug_line specified by a DW_AT_stmt_list + attribute. */ + Dwarf_Unsigned line_offset = 0; + + struct Line_Table_Prefix_s prefix; + + + /* These are the state machine state variables. */ + Dwarf_Addr address = 0; + Dwarf_Word file = 1; + Dwarf_Word line = 1; + Dwarf_Word column = 0; + Dwarf_Bool is_stmt = false; + Dwarf_Bool basic_block = false; + Dwarf_Bool end_sequence = false; + Dwarf_Bool prologue_end = false; + Dwarf_Bool epilogue_begin = false; + Dwarf_Small isa = 0; + Dwarf_Unsigned op_index = 0; + Dwarf_Unsigned discriminator = 0; + + + Dwarf_Sword i=0; + + /* This is the current opcode read from the statement program. */ + Dwarf_Small opcode=0; + + + /* These variables are used to decode leb128 numbers. Leb128_num + holds the decoded number, and leb128_length is its length in + bytes. */ + Dwarf_Word leb128_num=0; + Dwarf_Word leb128_length=0; + Dwarf_Sword advance_line=0; + Dwarf_Half attrform = 0; + /* This is the operand of the latest fixed_advance_pc extended + opcode. */ + Dwarf_Half fixed_advance_pc=0; + + /* In case there are wierd bytes 'after' the line table + prologue this lets us print something. This is a gcc + compiler bug and we expect the bytes count to be 12. */ + Dwarf_Small* bogus_bytes_ptr = 0; + Dwarf_Unsigned bogus_bytes_count = 0; + + + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg=0; + int resattr = DW_DLV_ERROR; + int lres = DW_DLV_ERROR; + int res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + + if (error != NULL) { + *error = NULL; + } + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + + res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_line.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error); + if (resattr != DW_DLV_OK) { + return resattr; + } + + + /* The list of relevant FORMs is small. + DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset + */ + lres = dwarf_whatform(stmt_list_attr,&attrform,error); + if (lres != DW_DLV_OK) { + return lres; + } + if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 && + attrform != DW_FORM_sec_offset ) { + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + lres = dwarf_global_formref(stmt_list_attr, &line_offset, error); + if (lres != DW_DLV_OK) { + return lres; + } + + if (line_offset >= dbg->de_debug_line.dss_size) { + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + orig_line_ptr = dbg->de_debug_line.dss_data; + line_ptr = dbg->de_debug_line.dss_data + line_offset; + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + + /* If die has DW_AT_comp_dir attribute, get the string that names + the compilation directory. */ + resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + if (resattr == DW_DLV_OK) { + int cres = DW_DLV_ERROR; + char *cdir = 0; + + cres = dwarf_formstring(comp_dir_attr, &cdir, error); + if (cres == DW_DLV_ERROR) { + return cres; + } else if (cres == DW_DLV_OK) { + comp_dir = (Dwarf_Small *) cdir; + } + } + if (resattr == DW_DLV_OK) { + dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); + } + + dwarf_init_line_table_prefix(&prefix); + { + Dwarf_Small *line_ptr_out = 0; + int dres = dwarf_read_line_table_prefix(dbg, + line_ptr,dbg->de_debug_line.dss_size - line_offset, + &line_ptr_out, + &prefix, + &bogus_bytes_ptr, + &bogus_bytes_count, + error, + err_count_out); + if (dres == DW_DLV_ERROR) { + dwarf_free_line_table_prefix(&prefix); + return dres; + } + if (dres == DW_DLV_NO_ENTRY) { + dwarf_free_line_table_prefix(&prefix); + return dres; + } + line_ptr_end = prefix.pf_line_ptr_end; + line_ptr = line_ptr_out; + } + if(only_line_header) { + /* Just checking for header errors, nothing more here.*/ + dwarf_free_line_table_prefix(&prefix); + return DW_DLV_OK; + } + + printf("total line info length %ld bytes, " + "line offset 0x%" DW_PR_XZEROS DW_PR_DUx " %" DW_PR_DSd "\n", + (long) prefix.pf_total_length, + (Dwarf_Unsigned) line_offset, (Dwarf_Signed) line_offset); + printf("line table version %d\n",(int) prefix.pf_version); + printf("line table length field length %d prologue length %d\n", + (int)prefix.pf_length_field_length, + (int)prefix.pf_prologue_length); + printf("compilation_directory %s\n", + comp_dir ? ((char *) comp_dir) : ""); + + printf(" min instruction length %d\n", + (int) prefix.pf_minimum_instruction_length); + printf(" default is stmt %d\n", (int) prefix.pf_default_is_stmt); + printf(" line base %d\n", (int) prefix.pf_line_base); + printf(" line_range %d\n", (int) prefix.pf_line_range); + printf(" opcode base %d\n", (int) prefix.pf_opcode_base); + printf(" standard opcode count %d\n", (int) prefix.pf_std_op_count); + + for (i = 1; i < prefix.pf_opcode_base; i++) { + printf(" opcode[%2d] length %d\n", (int) i, + (int) prefix.pf_opcode_length_table[i - 1]); + } + printf(" include directories count %d\n", + (int) prefix.pf_include_directories_count); + for (i = 0; i < prefix.pf_include_directories_count; ++i) { + printf(" include dir[%d] %s\n", + (int) i, prefix.pf_include_directories[i]); + } + printf(" files count %d\n", + (int) prefix.pf_files_count); + + for (i = 0; i < prefix.pf_files_count; ++i) { + struct Line_Table_File_Entry_s *lfile = + prefix.pf_line_table_file_entries + i; + Dwarf_Unsigned tlm2 = lfile->lte_last_modification_time; + Dwarf_Unsigned di = lfile->lte_directory_index; + Dwarf_Unsigned fl = lfile->lte_length_of_file; + + printf(" file[%d] %s (file-number: %d) \n", + (int) i, (char *) lfile->lte_filename, + (int)(i+1)); + printf(" dir index %d\n", (int) di); + { + time_t tt = (time_t) tlm2; + + /* ctime supplies newline */ + printf(" last time 0x%x %s", + (unsigned) tlm2, ctime(&tt)); + } + printf(" file length %ld 0x%lx\n", + (long) fl, (unsigned long) fl); + + } + + + { + Dwarf_Unsigned offset = 0; + if(bogus_bytes_count > 0) { + Dwarf_Unsigned wcount = bogus_bytes_count; + Dwarf_Unsigned boffset = bogus_bytes_ptr - orig_line_ptr; + printf("*** DWARF CHECK: the line table prologue header_length " + " is %" DW_PR_DUu " too high, we pretend it is smaller." + "Section offset: 0x%" DW_PR_XZEROS DW_PR_DUx + " (%" DW_PR_DUu ") ***\n", + wcount, boffset,boffset); + *err_count_out += 1; + } + offset = line_ptr - orig_line_ptr; + printf(" statement prog offset in section: 0x%" + DW_PR_XZEROS DW_PR_DUx " (%" DW_PR_DUu ")\n", + offset, offset); + } + + /* Initialize the part of the state machine dependent on the + prefix. */ + is_stmt = prefix.pf_default_is_stmt; + + print_line_header(); + /* Start of statement program. */ + while (line_ptr < line_ptr_end) { + int type = 0; + + printf(" [0x%06" DW_PR_DSx "] ", + (Dwarf_Signed) (line_ptr - orig_line_ptr)); + opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + /* 'type' is the output */ + WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base, + prefix.pf_opcode_length_table, line_ptr, + prefix.pf_std_op_count); + if (type == LOP_DISCARD) { + int oc = 0; + int opcnt = prefix.pf_opcode_length_table[opcode]; + + printf("*** DWARF CHECK: DISCARD standard opcode %d " + "with %d operands: " + "not understood.", opcode, opcnt); + *err_count_out += 1; + for (oc = 0; oc < opcnt; oc++) { + /* Read and discard operands we don't + understand. + Arbitrary choice of unsigned read. + Signed read would work as well. */ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + printf(" %" DW_PR_DUu + " (0x%" DW_PR_XZEROS DW_PR_DUx ")", + (Dwarf_Unsigned) utmp2, + (Dwarf_Unsigned) utmp2); + } + printf("***\n"); + /* Do nothing, necessary ops done */ + } else if (type == LOP_SPECIAL) { + /* This op code is a special op in the object, no matter + that it might fall into the standard op range in this + compile Thatis, these are special opcodes between + special_opcode_base and MAX_LINE_OP_CODE. (including + special_opcode_base and MAX_LINE_OP_CODE) */ + char special[50]; + Dwarf_Unsigned operation_advance = 0; + unsigned origop = opcode; + + opcode = opcode - prefix.pf_opcode_base; + operation_advance = (opcode / prefix.pf_line_range); + if(prefix.pf_maximum_ops_per_instruction < 2) { + address = address + (prefix.pf_minimum_instruction_length * + operation_advance); + } else { + address = address + (prefix.pf_minimum_instruction_length * + ((op_index + operation_advance)/ + prefix.pf_maximum_ops_per_instruction)); + op_index = (op_index +operation_advance)% + prefix.pf_maximum_ops_per_instruction; + } + line = line + prefix.pf_line_base + + opcode % prefix.pf_line_range; + sprintf(special, "Specialop %3u", origop); + print_line_detail(special, + opcode, address, (int) file, line, column, + is_stmt, basic_block, end_sequence, + prologue_end, epilogue_begin, isa,discriminator); + basic_block = false; + prologue_end = false; + epilogue_begin = false; + discriminator = 0; + } else if (type == LOP_STANDARD) { + switch (opcode) { + + case DW_LNS_copy:{ + print_line_detail("DW_LNS_copy", + opcode, address, file, line, + column, is_stmt, basic_block, + end_sequence, prologue_end, + epilogue_begin, isa,discriminator); + basic_block = false; + prologue_end = false; + epilogue_begin = false; + discriminator = 0; + } + break; + + case DW_LNS_advance_pc:{ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + printf("DW_LNS_advance_pc val %" + DW_PR_DSd " 0x%" + DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Signed) (Dwarf_Word) utmp2, + (Dwarf_Unsigned) (Dwarf_Word) utmp2); + leb128_num = (Dwarf_Word) utmp2; + address = address + + prefix.pf_minimum_instruction_length * leb128_num; + } + break; + case DW_LNS_advance_line:{ + Dwarf_Signed stmp = 0; + + DECODE_LEB128_SWORD(line_ptr, stmp); + advance_line = (Dwarf_Sword) stmp; + printf("DW_LNS_advance_line val %" DW_PR_DSd " 0x%" + DW_PR_XZEROS DW_PR_DSx "\n", + (Dwarf_Signed) advance_line, + (Dwarf_Signed) advance_line); + line = line + advance_line; + } + break; + + case DW_LNS_set_file:{ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + file = (Dwarf_Word) utmp2; + printf("DW_LNS_set_file %ld\n", (long) file); + } + break; + case DW_LNS_set_column:{ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + column = (Dwarf_Word) utmp2; + printf("DW_LNS_set_column val %" DW_PR_DSd " 0x%" + DW_PR_XZEROS DW_PR_DSx "\n", + (Dwarf_Signed) column, (Dwarf_Signed) column); + } + break; + case DW_LNS_negate_stmt:{ + is_stmt = !is_stmt; + printf("DW_LNS_negate_stmt\n"); + } + break; + case DW_LNS_set_basic_block:{ + printf("DW_LNS_set_basic_block\n"); + basic_block = true; + } + break; + + case DW_LNS_const_add_pc:{ + opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base; + if(prefix.pf_maximum_ops_per_instruction < 2) { + Dwarf_Unsigned operation_advance = + (opcode / prefix.pf_line_range); + address = address + + prefix.pf_minimum_instruction_length * + operation_advance; + } else { + Dwarf_Unsigned operation_advance = + (opcode / prefix.pf_line_range); + address = address + prefix.pf_minimum_instruction_length * + ((op_index + operation_advance)/ + prefix.pf_maximum_ops_per_instruction); + op_index = (op_index +operation_advance)% + prefix.pf_maximum_ops_per_instruction; + } + + printf("DW_LNS_const_add_pc new address 0x%" + DW_PR_XZEROS DW_PR_DSx "\n", + (Dwarf_Signed) address); + } + break; + case DW_LNS_fixed_advance_pc:{ + READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half, + line_ptr, sizeof(Dwarf_Half)); + line_ptr += sizeof(Dwarf_Half); + address = address + fixed_advance_pc; + printf("DW_LNS_fixed_advance_pc val %" DW_PR_DSd + " 0x%" DW_PR_XZEROS DW_PR_DSx + " new address 0x%" DW_PR_XZEROS DW_PR_DSx "\n", + (Dwarf_Signed) fixed_advance_pc, + (Dwarf_Signed) fixed_advance_pc, + (Dwarf_Signed) address); + op_index = 0; + } + break; + case DW_LNS_set_prologue_end:{ + prologue_end = true; + printf("DW_LNS_set_prologue_end set true.\n"); + } + break; + /* New in DWARF3 */ + case DW_LNS_set_epilogue_begin:{ + epilogue_begin = true; + printf("DW_LNS_set_epilogue_begin set true.\n"); + } + break; + + /* New in DWARF3 */ + case DW_LNS_set_isa:{ + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + isa = utmp2; + printf("DW_LNS_set_isa new value 0x%" + DW_PR_XZEROS DW_PR_DUx ".\n", + (Dwarf_Unsigned) utmp2); + if (isa != utmp2) { + /* The value of the isa did not fit in our + local so we record it wrong. declare an + error. */ + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, + DW_DLE_LINE_NUM_OPERANDS_BAD); + return (DW_DLV_ERROR); + } + } + break; + } /* end switch */ + } else if (type == LOP_EXTENDED) { + Dwarf_Unsigned utmp3 = 0; + Dwarf_Word instr_length = 0; + Dwarf_Small ext_opcode = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp3); + instr_length = (Dwarf_Word) utmp3; + ext_opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + switch (ext_opcode) { + + case DW_LNE_end_sequence:{ + end_sequence = true; + + print_line_detail("DW_LNE_end_sequence extended", + opcode, address, file, line, + column, is_stmt, basic_block, + end_sequence, prologue_end, + epilogue_begin, isa,discriminator); + + address = 0; + file = 1; + line = 1; + column = 0; + is_stmt = prefix.pf_default_is_stmt; + basic_block = false; + end_sequence = false; + prologue_end = false; + epilogue_begin = false; + isa = 0; + discriminator = 0; + op_index = 0; + } + break; + case DW_LNE_set_address:{ + READ_UNALIGNED(dbg, address, Dwarf_Addr, + line_ptr, + die->di_cu_context->cc_address_size); + + line_ptr += die->di_cu_context->cc_address_size; + printf("DW_LNE_set_address address 0x%" + DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Unsigned) address); + + op_index = 0; + } + break; + case DW_LNE_define_file:{ + Dwarf_Unsigned di = 0; + Dwarf_Unsigned tlm = 0; + Dwarf_Unsigned fl = 0; + + Dwarf_Small *fn = (Dwarf_Small *) line_ptr; + line_ptr = line_ptr + strlen((char *) line_ptr) + 1; + di = _dwarf_decode_u_leb128(line_ptr, + &leb128_length); + line_ptr = line_ptr + leb128_length; + tlm = _dwarf_decode_u_leb128(line_ptr, + &leb128_length); + line_ptr = line_ptr + leb128_length; + fl = _dwarf_decode_u_leb128(line_ptr, + &leb128_length); + line_ptr = line_ptr + leb128_length; + + printf("DW_LNE_define_file %s \n", fn); + printf(" dir index %d\n", (int) di); + { + time_t tt3 = (time_t) tlm; + + /* ctime supplies newline */ + printf(" last time 0x%x %s", + (unsigned) tlm, ctime(&tt3)); + } + printf(" file length %ld 0x%lx\n", + (long) fl, (unsigned long) fl); + + } + break; + case DW_LNE_set_discriminator:{ + /* new in DWARF4 */ + Dwarf_Unsigned utmp2 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + discriminator = (Dwarf_Word) utmp2; + printf("DW_LNE_set_discriminator 0x%" + DW_PR_XZEROS DW_PR_DUx "\n",utmp2); + } + break; + + default:{ + /* This is an extended op code we do not know about, + other than we know now many bytes it is + (and the op code and the bytes of operand). */ + + Dwarf_Unsigned remaining_bytes = instr_length -1; + if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) { + dwarf_free_line_table_prefix(&prefix); + _dwarf_error(dbg, error, + DW_DLE_LINE_EXT_OPCODE_BAD); + return (DW_DLV_ERROR); + } + printf("DW_LNE extended op 0x%x ",ext_opcode); + printf("Bytecount: %" DW_PR_DUu , (Dwarf_Unsigned)instr_length); + if(remaining_bytes > 0) { + printf(" linedata: 0x"); + while (remaining_bytes > 0) { + printf("%02x",(unsigned char)(*(line_ptr))); + line_ptr++; + remaining_bytes--; + } + } + printf("\n"); + } + break; + } /* Dnd switch */ + + } + } + + dwarf_free_line_table_prefix(&prefix); + return (DW_DLV_OK); +} + +/* This is support for dwarfdump: making it possible + for clients wanting line detail info on stdout + to get that detail without including internal libdwarf + header information. + Caller passes in compilation unit DIE. + The _dwarf_ version is obsolete (though supported for + compatibility). + The dwarf_ version is preferred. + The functions are intentionally identical: having + _dwarf_print_lines call dwarf_print_lines might + better emphasize they are intentionally identical, but + that seemed slightly silly given how short the functions are. + Interface adds error_count (output value) February 2009. */ +int +dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error,int *error_count) +{ + int only_line_header = 0; + int res = _dwarf_internal_printlines(die, error, + error_count, + only_line_header); + if (res != DW_DLV_OK) { + return res; + } + return res; +} +int +_dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error) +{ + int only_line_header = 0; + int err_count = 0; + int res = _dwarf_internal_printlines(die, error, + &err_count, + only_line_header); + /* No way to get error count back in this interface */ + if (res != DW_DLV_OK) { + return res; + } + return res; +} + +/* The check is in case we are not printing full line data, + this gets some of the issues noted with .debug_line, + but not all. Call dwarf_print_lines() to get all issues. + Intended for apps like dwarfdump. +*/ +void +dwarf_check_lineheader(Dwarf_Die die, int *err_count_out) +{ + Dwarf_Error err; + int only_line_header = 1; + _dwarf_internal_printlines(die, &err,err_count_out, + only_line_header); + return; +} + diff --git a/libdwarf/dwarf_pubtypes.c b/libdwarf/dwarf_pubtypes.c new file mode 100644 index 0000000..adc1ce3 --- /dev/null +++ b/libdwarf/dwarf_pubtypes.c @@ -0,0 +1,142 @@ +/* + + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +/* Reads DWARF3 .debug_pubtypes section. */ + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_types.h" +#include "dwarf_global.h" + +int +dwarf_get_pubtypes(Dwarf_Debug dbg, + Dwarf_Type ** types, + Dwarf_Signed * ret_type_count, Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_pubtypes,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_pubtypes.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + return _dwarf_internal_get_pubnames_like_data(dbg, + dbg->de_debug_pubtypes.dss_data, + dbg->de_debug_pubtypes.dss_size, + (Dwarf_Global **) types, /* Type punning for sections + with identical format. */ + ret_type_count, error, + DW_DLA_PUBTYPES_CONTEXT, + DW_DLA_GLOBAL, /* We don't have DW_DLA_PUBTYPES, + so use DW_DLA_GLOBAL. */ + DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD, + DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR); +} + +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. +*/ + +void +dwarf_pubtypes_dealloc(Dwarf_Debug dbg, Dwarf_Type * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, + (Dwarf_Global *) dwgl, + count, + DW_DLA_PUBTYPES_CONTEXT, + DW_DLA_GLOBAL, /* We don't have DW_DLA_PUBTYPES, + so use DW_DLA_GLOBAL. */ + DW_DLA_LIST); + return; +} + + + +int +dwarf_pubtypename(Dwarf_Type type_in, char **ret_name, + Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + if (type == NULL) { + _dwarf_error(NULL, error, DW_DLE_TYPE_NULL); + return (DW_DLV_ERROR); + } + *ret_name = (char *) (type->gl_name); + return DW_DLV_OK; +} + + +int +dwarf_pubtype_type_die_offset(Dwarf_Type type_in, + Dwarf_Off * ret_offset, + Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + + return dwarf_global_die_offset(type, ret_offset, error); +} + + +int +dwarf_pubtype_cu_offset(Dwarf_Type type_in, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + + return dwarf_global_cu_offset(type, ret_offset, error); + +} + + +int +dwarf_pubtype_name_offsets(Dwarf_Type type_in, + char **returned_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_die_offset, + Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + + return dwarf_global_name_offsets(type, + returned_name, + die_offset, cu_die_offset, error); +} diff --git a/libdwarf/dwarf_query.c b/libdwarf/dwarf_query.c new file mode 100644 index 0000000..0992a90 --- /dev/null +++ b/libdwarf/dwarf_query.c @@ -0,0 +1,856 @@ +/* + + Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_die_deliv.h" + +/* This is normally reliable. +But not always. +If different compilation +units have different address sizes +this may not give the correct value in all contexts. +If the Elf offset size != address_size +(for example if address_size = 4 but recorded in elf64 object) +this may not give the correct value in all contexts. +*/ +int +dwarf_get_address_size(Dwarf_Debug dbg, + Dwarf_Half * ret_addr_size, Dwarf_Error * error) +{ + Dwarf_Half address_size = 0; + + if (dbg == 0) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + address_size = dbg->de_pointer_size; + *ret_addr_size = address_size; + return DW_DLV_OK; +} + +/* This will be correct in all contexts where the + CU context of a DIE is known. +*/ +int +dwarf_get_die_address_size(Dwarf_Die die, + Dwarf_Half * ret_addr_size, Dwarf_Error * error) +{ + Dwarf_Half address_size = 0; + CHECK_DIE(die, DW_DLV_ERROR); + address_size = die->di_cu_context->cc_address_size; + *ret_addr_size = address_size; + return DW_DLV_OK; +} + +int +dwarf_dieoffset(Dwarf_Die die, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Small *dataptr = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + dataptr = die->di_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + *ret_offset = (die->di_debug_ptr - dataptr); + return DW_DLV_OK; +} + + +/* This function returns the offset of + the die relative to the start of its + compilation-unit rather than .debug_info. + Returns DW_DLV_ERROR on error. */ +int +dwarf_die_CU_offset(Dwarf_Die die, + Dwarf_Off * cu_off, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Small *dataptr = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + cu_context = die->di_cu_context; + dbg = die->di_cu_context->cc_dbg; + dataptr = die->di_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + *cu_off = (die->di_debug_ptr - dataptr - cu_context->cc_debug_offset); + return DW_DLV_OK; +} + +/* A common function to get both offsets (local and global) */ +int +dwarf_die_offsets(Dwarf_Die die, + Dwarf_Off *off, + Dwarf_Off *cu_off, + Dwarf_Error *error) +{ + *off = 0; + *cu_off = 0; + if (DW_DLV_OK == dwarf_dieoffset(die,off,error) && + DW_DLV_OK == dwarf_die_CU_offset(die,cu_off,error)) { + return DW_DLV_OK; + } + return DW_DLV_ERROR; +} + +/* This function returns the global offset + (meaning the section offset) and length of + the CU that this die is a part of. + Used for correctness checking by dwarfdump. */ +int +dwarf_die_CU_offset_range(Dwarf_Die die, + Dwarf_Off * cu_off, + Dwarf_Off * cu_length, + Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + cu_context = die->di_cu_context; + + *cu_off = cu_context->cc_debug_offset; + *cu_length = cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size; + return DW_DLV_OK; +} + + + +int +dwarf_tag(Dwarf_Die die, Dwarf_Half * tag, Dwarf_Error * error) +{ + CHECK_DIE(die, DW_DLV_ERROR); + *tag = (die->di_abbrev_list->ab_tag); + return DW_DLV_OK; +} + + +int +dwarf_attrlist(Dwarf_Die die, + Dwarf_Attribute ** attrbuf, + Dwarf_Signed * attrcnt, Dwarf_Error * error) +{ + Dwarf_Word attr_count = 0; + Dwarf_Word i = 0; + Dwarf_Half attr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Abbrev_List abbrev_list = 0; + Dwarf_Attribute new_attr = 0; + Dwarf_Attribute head_attr = NULL; + Dwarf_Attribute curr_attr = NULL; + Dwarf_Attribute *attr_ptr = 0; + Dwarf_Debug dbg = 0; + Dwarf_Byte_Ptr info_ptr = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + + abbrev_list = _dwarf_get_abbrev_for_code(die->di_cu_context, + die->di_abbrev_list->ab_code); + if (abbrev_list == NULL) { + _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_BAD); + return (DW_DLV_ERROR); + } + abbrev_ptr = abbrev_list->ab_abbrev_ptr; + + info_ptr = die->di_debug_ptr; + SKIP_LEB128_WORD(info_ptr); + + do { + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(abbrev_ptr, utmp2); + attr = (Dwarf_Half) utmp2; + DECODE_LEB128_UWORD(abbrev_ptr, utmp2); + attr_form = (Dwarf_Half) utmp2; + + if (attr != 0) { + new_attr = + (Dwarf_Attribute) _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1); + if (new_attr == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form_direct = attr_form; + new_attr->ar_attribute_form = attr_form; + if (attr_form == DW_FORM_indirect) { + Dwarf_Unsigned utmp6; + + /* DECODE_LEB128_UWORD does info_ptr update */ + DECODE_LEB128_UWORD(info_ptr, utmp6); + attr_form = (Dwarf_Half) utmp6; + new_attr->ar_attribute_form = attr_form; + } + new_attr->ar_cu_context = die->di_cu_context; + new_attr->ar_debug_ptr = info_ptr; + new_attr->ar_die = die; + { + Dwarf_Unsigned sov = _dwarf_get_size_of_val(dbg, + attr_form, + die->di_cu_context->cc_address_size, + info_ptr, + die->di_cu_context->cc_length_size); + info_ptr += sov; + } + + + if (head_attr == NULL) + head_attr = curr_attr = new_attr; + else { + curr_attr->ar_next = new_attr; + curr_attr = new_attr; + } + attr_count++; + } + } while (attr != 0 || attr_form != 0); + + if (attr_count == 0) { + *attrbuf = NULL; + *attrcnt = 0; + return (DW_DLV_NO_ENTRY); + } + + attr_ptr = (Dwarf_Attribute *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, attr_count); + if (attr_ptr == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + curr_attr = head_attr; + for (i = 0; i < attr_count; i++) { + *(attr_ptr + i) = curr_attr; + curr_attr = curr_attr->ar_next; + } + + *attrbuf = attr_ptr; + *attrcnt = attr_count; + return (DW_DLV_OK); +} + + +/* + This function takes a die, and an attr, and returns + a pointer to the start of the value of that attr in + the given die in the .debug_info section. The form + is returned in *attr_form. + + Returns NULL on error, or if attr is not found. + However, *attr_form is 0 on error, and positive + otherwise. +*/ +static Dwarf_Byte_Ptr +_dwarf_get_value_ptr(Dwarf_Die die, + Dwarf_Half attr, Dwarf_Half * attr_form) +{ + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Abbrev_List abbrev_list; + Dwarf_Half curr_attr = 0; + Dwarf_Half curr_attr_form = 0; + Dwarf_Byte_Ptr info_ptr = 0; + + abbrev_list = _dwarf_get_abbrev_for_code(die->di_cu_context, + die->di_abbrev_list->ab_code); + if (abbrev_list == NULL) { + *attr_form = 0; + return (NULL); + } + abbrev_ptr = abbrev_list->ab_abbrev_ptr; + + info_ptr = die->di_debug_ptr; + SKIP_LEB128_WORD(info_ptr); + + do { + Dwarf_Unsigned utmp3; + + DECODE_LEB128_UWORD(abbrev_ptr, utmp3); + curr_attr = (Dwarf_Half) utmp3; + DECODE_LEB128_UWORD(abbrev_ptr, utmp3); + curr_attr_form = (Dwarf_Half) utmp3; + if (curr_attr_form == DW_FORM_indirect) { + Dwarf_Unsigned utmp6; + + /* DECODE_LEB128_UWORD updates info_ptr */ + DECODE_LEB128_UWORD(info_ptr, utmp6); + curr_attr_form = (Dwarf_Half) utmp6; + } + + if (curr_attr == attr) { + *attr_form = curr_attr_form; + return (info_ptr); + } + + info_ptr += _dwarf_get_size_of_val(die->di_cu_context->cc_dbg, + curr_attr_form, + die->di_cu_context->cc_address_size, + info_ptr, + die->di_cu_context->cc_length_size); + } while (curr_attr != 0 || curr_attr_form != 0); + + *attr_form = 1; + return (NULL); +} + + +int +dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error * error) +{ + Dwarf_Half attr_form = 0; + Dwarf_Debug dbg = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Unsigned string_offset = 0; + int res = DW_DLV_ERROR; + + CHECK_DIE(die, DW_DLV_ERROR); + + info_ptr = _dwarf_get_value_ptr(die, DW_AT_name, &attr_form); + if (info_ptr == NULL) { + if (attr_form == 0) { + _dwarf_error(die->di_cu_context->cc_dbg, error, + DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + return DW_DLV_NO_ENTRY; + } + + if (attr_form == DW_FORM_string) { + *ret_name = (char *) (info_ptr); + return DW_DLV_OK; + } + + dbg = die->di_cu_context->cc_dbg; + if (attr_form != DW_FORM_strp) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); + } + + READ_UNALIGNED(dbg, string_offset, Dwarf_Unsigned, + info_ptr, die->di_cu_context->cc_length_size); + + if (string_offset >= dbg->de_debug_str.dss_size) { + _dwarf_error(dbg, error, DW_DLE_STRING_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_str,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_str.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + *ret_name = (char *) (dbg->de_debug_str.dss_data + string_offset); + return DW_DLV_OK; +} + + +int +dwarf_hasattr(Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + Dwarf_Half attr_form = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + + if (_dwarf_get_value_ptr(die, attr, &attr_form) == NULL) { + if (attr_form == 0) { + _dwarf_error(die->di_cu_context->cc_dbg, error, + DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + *return_bool = false; + return DW_DLV_OK; + } + + *return_bool = (true); + return DW_DLV_OK; +} + + +int +dwarf_attr(Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Attribute * ret_attr, Dwarf_Error * error) +{ + Dwarf_Half attr_form = 0; + Dwarf_Attribute attrib = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + + info_ptr = _dwarf_get_value_ptr(die, attr, &attr_form); + if (info_ptr == NULL) { + if (attr_form == 0) { + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + return DW_DLV_NO_ENTRY; + } + + attrib = (Dwarf_Attribute) _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1); + if (attrib == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + attrib->ar_attribute = attr; + attrib->ar_attribute_form = attr_form; + attrib->ar_attribute_form_direct = attr_form; + attrib->ar_cu_context = die->di_cu_context; + attrib->ar_debug_ptr = info_ptr; + attrib->ar_die = die; + *ret_attr = (attrib); + return DW_DLV_OK; +} + + +int +dwarf_lowpc(Dwarf_Die die, + Dwarf_Addr * return_addr, Dwarf_Error * error) +{ + Dwarf_Addr ret_addr = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Debug dbg = 0; + Dwarf_Half address_size = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + + dbg = die->di_cu_context->cc_dbg; + address_size = die->di_cu_context->cc_address_size; + info_ptr = _dwarf_get_value_ptr(die, DW_AT_low_pc, &attr_form); + if ((info_ptr == NULL && attr_form == 0) || + (info_ptr != NULL && attr_form != DW_FORM_addr)) { + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + if (info_ptr == NULL) { + return (DW_DLV_NO_ENTRY); + } + + + READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr, + info_ptr, address_size); + + *return_addr = ret_addr; + return (DW_DLV_OK); +} + + +int +dwarf_highpc(Dwarf_Die die, + Dwarf_Addr * return_addr, Dwarf_Error * error) +{ + Dwarf_Addr ret_addr = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Debug dbg = 0; + Dwarf_Half address_size = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + address_size = die->di_cu_context->cc_address_size; + info_ptr = _dwarf_get_value_ptr(die, DW_AT_high_pc, &attr_form); + if ((info_ptr == NULL && attr_form == 0) || + (info_ptr != NULL && attr_form != DW_FORM_addr)) { + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + if (info_ptr == NULL) { + return (DW_DLV_NO_ENTRY); + } + + READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr, + info_ptr, address_size); + + *return_addr = ret_addr; + return (DW_DLV_OK); +} + + +/* + Takes a die, an attribute attr, and checks if attr + occurs in die. Attr is required to be an attribute + whose form is in the "constant" class. If attr occurs + in die, the value is returned. + Returns DW_DLV_OK, DW_DLV_ERROR, or DW_DLV_NO_ENTRY as + appropriate. Sets the value thru the pointer return_val. + This function is meant to do all the + processing for dwarf_bytesize, dwarf_bitsize, dwarf_bitoffset, + and dwarf_srclang. +*/ +static int +_dwarf_die_attr_unsigned_constant(Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Unsigned * return_val, + Dwarf_Error * error) +{ + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Unsigned ret_value = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + + dbg = die->di_cu_context->cc_dbg; + info_ptr = _dwarf_get_value_ptr(die, attr, &attr_form); + if (info_ptr != NULL) { + switch (attr_form) { + + case DW_FORM_data1: + *return_val = (*(Dwarf_Small *) info_ptr); + return (DW_DLV_OK); + + case DW_FORM_data2: + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_Shalf)); + *return_val = ret_value; + return (DW_DLV_OK); + + case DW_FORM_data4: + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_sfixed)); + *return_val = ret_value; + return (DW_DLV_OK); + + case DW_FORM_data8: + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_Unsigned)); + *return_val = ret_value; + return (DW_DLV_OK); + + case DW_FORM_udata: + *return_val = (_dwarf_decode_u_leb128(info_ptr, NULL)); + return (DW_DLV_OK); + + default: + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + } + if (attr_form == 0) { + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + return DW_DLV_NO_ENTRY; +} + + +int +dwarf_bytesize(Dwarf_Die die, + Dwarf_Unsigned * ret_size, Dwarf_Error * error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_byte_size, + &luns, error); + *ret_size = luns; + return res; +} + + +int +dwarf_bitsize(Dwarf_Die die, + Dwarf_Unsigned * ret_size, Dwarf_Error * error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_bit_size, + &luns, error); + *ret_size = luns; + return res; +} + + +int +dwarf_bitoffset(Dwarf_Die die, + Dwarf_Unsigned * ret_size, Dwarf_Error * error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, + DW_AT_bit_offset, &luns, error); + *ret_size = luns; + return res; +} + + +/* Refer section 3.1, page 21 in Dwarf Definition. */ +int +dwarf_srclang(Dwarf_Die die, + Dwarf_Unsigned * ret_size, Dwarf_Error * error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_language, + &luns, error); + *ret_size = luns; + return res; +} + + +/* Refer section 5.4, page 37 in Dwarf Definition. */ +int +dwarf_arrayorder(Dwarf_Die die, + Dwarf_Unsigned * ret_size, Dwarf_Error * error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_ordering, + &luns, error); + *ret_size = luns; + return res; +} + +/* Return DW_DLV_OK if ok + DW_DLV_ERROR if failure. + + If the die and the attr are not related the result is + meaningless. */ +int +dwarf_attr_offset(Dwarf_Die die, Dwarf_Attribute attr, + Dwarf_Off * offset /* return offset thru this ptr */, + Dwarf_Error * error) +{ + Dwarf_Off attroff = 0; + Dwarf_Small *dataptr = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + dataptr = die->di_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + attroff = (attr->ar_debug_ptr - dataptr); + *offset = attroff; + return DW_DLV_OK; +} + +int +dwarf_die_abbrev_code(Dwarf_Die die) +{ + return die->di_abbrev_code; +} + +/* Returns a flag through ab_has_child. Non-zero if + the DIE has children, zero if it does not. */ +int +dwarf_die_abbrev_children_flag(Dwarf_Die die,Dwarf_Half *ab_has_child) +{ + if (die->di_abbrev_list) { + *ab_has_child = die->di_abbrev_list->ab_has_child; + return DW_DLV_OK; + } + return DW_DLV_ERROR; +} + +/* Helper function for finding form class. */ +static enum Dwarf_Form_Class +dw_get_special_offset(Dwarf_Half attrnum) +{ + switch(attrnum) { + case DW_AT_stmt_list: + return DW_FORM_CLASS_LINEPTR; + case DW_AT_macro_info: + return DW_FORM_CLASS_MACPTR; + case DW_AT_ranges: + return DW_FORM_CLASS_RANGELISTPTR; + case DW_AT_location: + case DW_AT_string_length: + case DW_AT_return_addr: + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: + return DW_FORM_CLASS_LOCLISTPTR; + case DW_AT_sibling: + case DW_AT_byte_size : + case DW_AT_bit_offset : + case DW_AT_bit_size : + case DW_AT_discr : + case DW_AT_import : + case DW_AT_common_reference: + case DW_AT_containing_type: + case DW_AT_default_value: + case DW_AT_lower_bound: + case DW_AT_bit_stride: + case DW_AT_upper_bound: + case DW_AT_abstract_origin: + case DW_AT_base_types: + case DW_AT_count: + case DW_AT_friend: + case DW_AT_namelist_item: + case DW_AT_priority: + case DW_AT_specification: + case DW_AT_type: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_byte_stride: + case DW_AT_extension: + case DW_AT_trampoline: + case DW_AT_small: + case DW_AT_object_pointer: + case DW_AT_signature: + return DW_FORM_CLASS_REFERENCE; + case DW_AT_MIPS_fde: /* SGI/IRIX extension */ + return DW_FORM_CLASS_FRAMEPTR; + } + return DW_FORM_CLASS_UNKNOWN; +} + +/* It takes 4 pieces of data (including the FORM) + to accurately determine the form 'class' as documented + in the DWARF spec. This is per DWARF4, but will work + for DWARF2 or 3 as well. */ +enum Dwarf_Form_Class dwarf_get_form_class( + Dwarf_Half dwversion, + Dwarf_Half attrnum, + Dwarf_Half offset_size, + Dwarf_Half form) +{ + switch(form) { + case DW_FORM_addr: return DW_FORM_CLASS_ADDRESS; + + case DW_FORM_data2: return DW_FORM_CLASS_CONSTANT; + + case DW_FORM_data4: + if(dwversion <= 3 && offset_size == 4) { + enum Dwarf_Form_Class class = dw_get_special_offset(attrnum); + if(class != DW_FORM_CLASS_UNKNOWN) { + return class; + } + } + return DW_FORM_CLASS_CONSTANT; + case DW_FORM_data8: + if(dwversion <= 3 && offset_size == 8) { + enum Dwarf_Form_Class class = dw_get_special_offset(attrnum); + if(class != DW_FORM_CLASS_UNKNOWN) { + return class; + } + } + return DW_FORM_CLASS_CONSTANT; + + case DW_FORM_sec_offset: + { + enum Dwarf_Form_Class class = dw_get_special_offset(attrnum); + if(class != DW_FORM_CLASS_UNKNOWN) { + return class; + } + } + /* We do not know what this is. */ + break; + + case DW_FORM_string: return DW_FORM_CLASS_STRING; + case DW_FORM_strp: return DW_FORM_CLASS_STRING; + + case DW_FORM_block: return DW_FORM_CLASS_BLOCK; + case DW_FORM_block1: return DW_FORM_CLASS_BLOCK; + case DW_FORM_block2: return DW_FORM_CLASS_BLOCK; + case DW_FORM_block4: return DW_FORM_CLASS_BLOCK; + + case DW_FORM_data1: return DW_FORM_CLASS_CONSTANT; + case DW_FORM_sdata: return DW_FORM_CLASS_CONSTANT; + case DW_FORM_udata: return DW_FORM_CLASS_CONSTANT; + + case DW_FORM_ref_addr: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref1: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref2: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref4: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref8: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref_udata: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref_sig8: return DW_FORM_CLASS_REFERENCE; + + case DW_FORM_exprloc: return DW_FORM_CLASS_EXPRLOC; + + case DW_FORM_flag: return DW_FORM_CLASS_FLAG; + case DW_FORM_flag_present: return DW_FORM_CLASS_FLAG; + + + case DW_FORM_indirect: + default: + break; + }; + return DW_FORM_CLASS_UNKNOWN; +}; + +/* Given a DIE, figure out what the CU's DWARF version is + and the size of an offset + and return it through the *version pointer and return + DW_DLV_OK. + + If we cannot find a CU, + return DW_DLV_ERROR on error. + In case of error no Dwarf_Debug was available, + so setting a Dwarf_Error is somewhat futile. + Never returns DW_DLV_NO_ENTRY. +*/ +int +dwarf_get_version_of_die(Dwarf_Die die, + Dwarf_Half *version, + Dwarf_Half *offset_size) +{ + Dwarf_CU_Context cucontext = 0; + if(!die) { + return DW_DLV_ERROR; + } + cucontext = die->di_cu_context; + if(!cucontext) { + return DW_DLV_ERROR; + } + *version = cucontext->cc_version_stamp; + *offset_size = cucontext->cc_length_size; + return DW_DLV_OK; +} + + diff --git a/libdwarf/dwarf_ranges.c b/libdwarf/dwarf_ranges.c new file mode 100644 index 0000000..835a8d5 --- /dev/null +++ b/libdwarf/dwarf_ranges.c @@ -0,0 +1,172 @@ +/* + + Copyright (C) 2008-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include <stdlib.h> +#include "dwarf_incl.h" + +struct ranges_entry { + struct ranges_entry *next; + Dwarf_Ranges cur; +}; + + +#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff) +int dwarf_get_ranges_a(Dwarf_Debug dbg, + Dwarf_Off rangesoffset, + Dwarf_Die die, + Dwarf_Ranges ** rangesbuf, + Dwarf_Signed * listlen, + Dwarf_Unsigned * bytecount, + Dwarf_Error * error) +{ + Dwarf_Small *rangeptr = 0; + Dwarf_Small *beginrangeptr = 0; + Dwarf_Small *section_end = 0; + unsigned entry_count = 0; + struct ranges_entry *base = 0; + struct ranges_entry *last = 0; + struct ranges_entry *curre = 0; + Dwarf_Ranges * ranges_data_out = 0; + unsigned copyindex = 0; + Dwarf_Half address_size = 0; + int res = DW_DLV_ERROR; + + res = _dwarf_load_section(dbg, &dbg->de_debug_ranges,error); + if (res != DW_DLV_OK) { + return res; + } + + if(rangesoffset >= dbg->de_debug_ranges.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD); + return (DW_DLV_ERROR); + + } + address_size = _dwarf_get_address_size(dbg, die); + section_end = dbg->de_debug_ranges.dss_data + + dbg->de_debug_ranges.dss_size; + rangeptr = dbg->de_debug_ranges.dss_data + rangesoffset; + beginrangeptr = rangeptr; + + for(;;) { + struct ranges_entry * re = calloc(sizeof(struct ranges_entry),1); + if(!re) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); + return (DW_DLV_ERROR); + } + if(rangeptr >= section_end) { + return (DW_DLV_NO_ENTRY); + } + if((rangeptr + (2*address_size)) > section_end) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD); + return (DW_DLV_ERROR); + } + entry_count++; + READ_UNALIGNED(dbg,re->cur.dwr_addr1, + Dwarf_Addr, rangeptr, + address_size); + rangeptr += address_size; + READ_UNALIGNED(dbg,re->cur.dwr_addr2 , + Dwarf_Addr, rangeptr, + address_size); + rangeptr += address_size; + if(!base) { + base = re; + last = re; + } else { + last->next = re; + last = re; + } + if(re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) { + re->cur.dwr_type = DW_RANGES_END; + break; + } else if ( re->cur.dwr_addr1 == MAX_ADDR) { + re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION; + } else { + re->cur.dwr_type = DW_RANGES_ENTRY; + } + } + + ranges_data_out = (Dwarf_Ranges *) + _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count); + if(!ranges_data_out) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); + return (DW_DLV_ERROR); + } + curre = base; + *rangesbuf = ranges_data_out; + *listlen = entry_count; + for( copyindex = 0; curre && (copyindex < entry_count); + ++copyindex,++ranges_data_out) { + + struct ranges_entry *r = curre; + *ranges_data_out = curre->cur; + curre = curre->next; + free(r); + } + /* Callers will often not care about the bytes used. */ + if(bytecount) { + *bytecount = rangeptr - beginrangeptr; + } + return DW_DLV_OK; +} +int dwarf_get_ranges(Dwarf_Debug dbg, + Dwarf_Off rangesoffset, + Dwarf_Ranges ** rangesbuf, + Dwarf_Signed * listlen, + Dwarf_Unsigned * bytecount, + Dwarf_Error * error) +{ + Dwarf_Die die = 0; + int res = dwarf_get_ranges_a(dbg,rangesoffset,die, + rangesbuf,listlen,bytecount,error); + return res; +} + +void +dwarf_ranges_dealloc(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf, + Dwarf_Signed rangecount) +{ + dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES); + +} + diff --git a/libdwarf/dwarf_sort_line.c b/libdwarf/dwarf_sort_line.c new file mode 100644 index 0000000..40e337c --- /dev/null +++ b/libdwarf/dwarf_sort_line.c @@ -0,0 +1,676 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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. +*/ + + +/* This file was designed for SGI IRIX compiler use. + The static linker can rearrange the order of functions + in the layout in memory + and provided each has the right form + this will (when called by the SGI IRIX + static linker) rearrange the table so the line table + is arranged in the same order as the memory layout. */ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include <stdlib.h> +#include "dwarf_line.h" +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#define MINIMUM_POSSIBLE_PROLOG_LEN 10 /* 10 is based on */ +/* the definition of the DWARF2/3 line table prolog. The value + here should be >8 (accounting for a 64 bit read) and <= the + length of a legal DWARF2/3 line prolog, which is at least 10 + bytes long (but can be longer). What this constant helps + avoid is reading past the end of a malloc'd buffer in + _dwarf_update_line_sec(). */ + +static int +_dwarf_update_line_sec(Dwarf_Small * line_ptr, + unsigned long remaining_bytes, + int *any_change, + int length_size, + int *err_code, Dwarf_Small ** new_line_ptr); + +/* Used to construct + a linked list of so we can sort and reorder the line info. */ +struct a_line_area { + Dwarf_Addr ala_address; /* from DW_LNE_set_address */ + Dwarf_Unsigned ala_offset; /* byte offset in buffer */ + Dwarf_Unsigned ala_length; /* byte length in buffer */ + long ala_entry_num; /* to guarantee stable sort */ + struct a_line_area *ala_next; +}; + + +/* Written to support the SGI IRIX static linker. + It helps SGI IRIX ld + rearrange lines in .debug_line in a .o created with a text + section per function. The SGI IRIX linker option is: + -OPT:procedure_reorder=ON + where ld-cord (cord(1)ing by ld, + not by cord(1)) may have changed the function order. + + Returns + DW_DLV_OK if nothing went wrong. + DW_DLV_ERROR if could not do anything due to + error. the original buffer is unchanged. + + is_64_bit must be passed in by caller and tells + if this is a 32 or 64bit pointer object section + being processed. + + err_code must be a non-null pointer to integer. + If DW_DLV_ERROR is returned that integer is set + to a dwarf error code so the caller may + print it for diagnostic purposes. + + *any_change is set here + set 0 if no sorting (movement) done. + set 1 if some sorting (movement) done. + on all returns. On error return sets to 0. + + The _dwarf name form is now obsolete, + the dwarf_ name for is preferred. + Both names supported. */ +int +_dwarf_ld_sort_lines(void *orig_buffer, + unsigned long buffer_len, + int is_64_bit, int *any_change, int *err_code) +{ + return dwarf_ld_sort_lines(orig_buffer,buffer_len, + is_64_bit,any_change,err_code); +} +int +dwarf_ld_sort_lines(void *orig_buffer, + unsigned long buffer_len, + int is_64_bit, int *any_change, int *err_code) +{ + + int length_size = 4; + Dwarf_Small *orig_line_ptr; /* our local copy of the user's input + buffer */ + Dwarf_Small *line_ptr; /* starts at orig_line_ptr, gets + incremented thru to end of our copy + of the input buffer */ + Dwarf_Small *new_line_ptr; /* output of _dwarf_update_line_sec(), + used to update line_ptr as we pass + thru compilation units in a .o + .debug_line */ + + unsigned long remaining_bytes = buffer_len; /* total length of + original area left to be processed. Changes as we pass + thru compilation units in a .o .debug_line */ + + int sec_res; + int lany_change = 0; + int did_change = 0; + + if (is_64_bit) + length_size = 8; + + *any_change = 0; + line_ptr = malloc(buffer_len); + if (!line_ptr) { + *err_code = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + orig_line_ptr = line_ptr; + memcpy(line_ptr, orig_buffer, buffer_len); + + + /* We must iterate thru each of a set of prologues and line data. + We process each set in turn. If all pass, we update the + passed-in buffer. */ + sec_res = DW_DLV_OK; + + for (sec_res = _dwarf_update_line_sec(line_ptr, + remaining_bytes, &lany_change, length_size, err_code, &new_line_ptr); + (sec_res == DW_DLV_OK) && (remaining_bytes > 0); + sec_res = _dwarf_update_line_sec(line_ptr, + remaining_bytes, &lany_change, length_size, + err_code, &new_line_ptr)) { + long bytes_used = new_line_ptr - line_ptr; + + line_ptr = new_line_ptr; + remaining_bytes -= bytes_used; + if (lany_change) { + did_change = 1; + } + if (remaining_bytes > 0) { + continue; + } + break; + } + if (sec_res == DW_DLV_ERROR) { + free(orig_line_ptr); + return sec_res; + } + + + /* all passed */ + if (did_change) { + /* So update the passed in buffer orig_buffer is caller's input + area. orig_line_ptr is our modified copy of input area. */ + memcpy(orig_buffer, orig_line_ptr, buffer_len); + *any_change = 1; + } + free(orig_line_ptr); + + return sec_res; +} + + +/* By setting ala_entry_num we guarantee a stable sort, + no duplicates + Sorting in address order. +*/ +static int +cmpr(const void *lin, const void *rin) +{ + const struct a_line_area *l = lin; + const struct a_line_area *r = rin; + + if (l->ala_address < r->ala_address) { + return -1; + } + if (l->ala_address > r->ala_address) { + return 1; + } + if (l->ala_entry_num < r->ala_entry_num) { + return -1; + } + if (l->ala_entry_num > r->ala_entry_num) { + return 1; + } + return 0; /* should never happen. */ +} + +/* The list of line area records is no longer needed. + Free the data allocated. */ +static void +free_area_data(struct a_line_area *arp) +{ + while(arp) { + struct a_line_area *next = arp->ala_next; + free(arp); + arp = next; + } +} + +/* On entry: + line_ptr must point to first + byte of a line group for one (original) .o + + remaining_bytes is the size of the area pointed to + by line_ptr: may be larger than the + current original compilation unit . + + length size is 4 for 32bit pointers, 8 for 64bit pointers + in the data pointed to. + + + On return: + return DW_DLV_OK if all ok. (ignore + *err_code in this case) + + return DW_DLV_ERROR and set *err_code if an error. + + If some line data was moved around, set *any_change to 1. + If error or no movement, set *any_change to 0; + + Set *new_line_ptr to one-byte-past the end of the + current original compilation unit (not necessary + if returning DW_DLV_ERROR, but not harmful). + + This copies the entire array to a malloc area, then + mallocs pieces of it (another malloc) for sorting a CU entries + and copying back. Then at end the whole new thing copied in. + The result is that on error, the input is not touched. + + An alternative would be to just update a piece at a time + and on error stop updating but leave what was done, done. + This alternative would save some temporary malloc space. */ +static int +_dwarf_update_line_sec(Dwarf_Small * line_ptr, + unsigned long remaining_bytes, + int *any_change, + int length_size, + int *err_code, Dwarf_Small ** new_line_ptr) +{ + /* This points to the last byte of the .debug_line portion for the + current cu. */ + Dwarf_Small *line_ptr_end = 0; + + /* This points to the end of the statement program prologue for the + current cu, and serves to check that the prologue was correctly + decoded. */ + + Dwarf_Small *orig_line_ptr = 0; + + /* These are the fields of the statement program header. */ + struct Dwarf_Debug_s dbg_data; + Dwarf_Debug dbg = &dbg_data; + + /* These are the state machine state variables. */ + Dwarf_Addr address = 0; + Dwarf_Word line = 1; + Dwarf_Bool is_stmt = false; + + /* Dwarf_Bool prologue_end; Dwarf_Bool epilogue_begin; */ + Dwarf_Small isa = 0; + + + struct a_line_area *area_base = 0; + struct a_line_area *area_current = 0; + long area_count = 0; + + Dwarf_Addr last_address = 0; + int need_to_sort = 0; + + /* This is the current opcode read from the statement program. */ + Dwarf_Small opcode = 0; + + + /* These variables are used to decode leb128 numbers. Leb128_num + holds the decoded number, and leb128_length is its length in + bytes. */ + Dwarf_Word leb128_num = 0; + Dwarf_Sword advance_line = 0; + + /* This is the operand of the latest fixed_advance_pc extended + opcode. */ + Dwarf_Half fixed_advance_pc = 0; + + /* This is the length of an extended opcode instr. */ + Dwarf_Word instr_length = 0; + Dwarf_Small ext_opcode = 0; + struct Line_Table_Prefix_s prefix; + + + + memset(dbg, 0, sizeof(struct Dwarf_Debug_s)); + dbg->de_copy_word = memcpy; + /* Following is a straightforward decoding of the statement program + prologue information. */ + *any_change = 0; + + + orig_line_ptr = line_ptr; + if (remaining_bytes < MINIMUM_POSSIBLE_PROLOG_LEN) { + /* We are at the end. Remaining should be zero bytes, padding. + This is really just 'end of CU buffer' not an error. The is + no 'entry' left so report there is none. We don't want to + READ_UNALIGNED the total_length below and then belatedly + discover that we read off the end already. */ + return (DW_DLV_NO_ENTRY); + } + + dwarf_init_line_table_prefix(&prefix); + { + Dwarf_Small *line_ptr_out = 0; + Dwarf_Error error; + int dres = dwarf_read_line_table_prefix(dbg, + line_ptr, + remaining_bytes, + &line_ptr_out, + &prefix, + NULL, NULL,&error, + NULL); + + if (dres == DW_DLV_ERROR) { + dwarf_free_line_table_prefix(&prefix); + *err_code = dwarf_errno(error); + dwarf_dealloc(dbg, error, DW_DLA_ERROR); + free_area_data(area_base); + return dres; + } + if (dres == DW_DLV_NO_ENTRY) { + dwarf_free_line_table_prefix(&prefix); + return dres; + } + line_ptr_end = prefix.pf_line_ptr_end; + line_ptr = line_ptr_out; + } + + /* Initialize the state machine. */ + /* file = 1; */ + /* column = 0; */ + is_stmt = prefix.pf_default_is_stmt; + /* basic_block = false; */ + /* end_sequence = false; */ + /* prologue_end = false; */ + /* epilogue_begin = false; */ + isa = 0; + + + /* Start of statement program. */ + while (line_ptr < line_ptr_end) { + int type; + Dwarf_Small *stmt_prog_entry_start = line_ptr; + + opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + /* 'type' is the output */ + WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base, + prefix.pf_opcode_length_table, line_ptr, + prefix.pf_std_op_count); + + if (type == LOP_DISCARD) { + int oc; + int opcnt = prefix.pf_opcode_length_table[opcode]; + + for (oc = 0; oc < opcnt; oc++) { + /* Read and discard operands we don't + understand. + arbitrary choice of unsigned read. + signed read would work as well. */ + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + } + + } else if (type == LOP_SPECIAL) { + opcode = opcode - prefix.pf_opcode_base; + address = address + prefix.pf_minimum_instruction_length * + (opcode / prefix.pf_line_range); + line = + line + prefix.pf_line_base + + opcode % prefix.pf_line_range; + + /* basic_block = false; */ + } else if (type == LOP_STANDARD) { + switch (opcode) { + case DW_LNS_copy:{ + /* basic_block = false; */ + break; + } + + case DW_LNS_advance_pc:{ + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + leb128_num = (Dwarf_Word) utmp2; + address = address + + prefix.pf_minimum_instruction_length * leb128_num; + break; + } + + case DW_LNS_advance_line:{ + Dwarf_Signed stmp; + + DECODE_LEB128_SWORD(line_ptr, stmp); + advance_line = (Dwarf_Sword) stmp; + line = line + advance_line; + break; + } + + case DW_LNS_set_file:{ + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + /* file = (Dwarf_Word)utmp2; */ + break; + } + + case DW_LNS_set_column:{ + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + /* column = (Dwarf_Word)utmp2; */ + break; + } + + case DW_LNS_negate_stmt:{ + is_stmt = !is_stmt; + break; + } + + case DW_LNS_set_basic_block:{ + /* basic_block = true; */ + break; + } + + case DW_LNS_const_add_pc:{ + opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base; + address = address + + prefix.pf_minimum_instruction_length * + (opcode / prefix. pf_line_range); + break; + } + + case DW_LNS_fixed_advance_pc:{ + + READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half, + line_ptr, sizeof(Dwarf_Half)); + line_ptr += sizeof(Dwarf_Half); + address = address + fixed_advance_pc; + break; + } + /* New in DWARF3 */ + case DW_LNS_set_prologue_end:{ + /* prologue_end = true; */ + break; + + + } + /* New in DWARF3 */ + case DW_LNS_set_epilogue_begin:{ + /* epilogue_begin = true; */ + break; + } + + /* New in DWARF3 */ + case DW_LNS_set_isa:{ + Dwarf_Unsigned utmp2; + + DECODE_LEB128_UWORD(line_ptr, utmp2); + isa = utmp2; + if (isa != utmp2) { + /* The value of the isa did not fit in our + local so we record it wrong. declare an + error. */ + dwarf_free_line_table_prefix(&prefix); + *err_code = DW_DLE_LINE_NUM_OPERANDS_BAD; + free_area_data(area_base); + return (DW_DLV_ERROR); + } + break; + } + } + } else if (type == LOP_EXTENDED) { + Dwarf_Unsigned utmp3 = 0; + + DECODE_LEB128_UWORD(line_ptr, utmp3); + instr_length = (Dwarf_Word) utmp3; + ext_opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + switch (ext_opcode) { + + case DW_LNE_end_sequence:{ + /* end_sequence = true; */ + + address = 0; + /* file = 1; */ + line = 1; + /* column = 0; */ + is_stmt = prefix.pf_default_is_stmt; + /* basic_block = false; */ + /* end_sequence = false; */ + /* prologue_end = false; */ + /* epilogue_begin = false; */ + } + break; + case DW_LNE_set_address:{ + struct a_line_area *area = 0; + + READ_UNALIGNED(dbg, address, Dwarf_Addr, + line_ptr, length_size); + /* Here we need to remember the offset into the + buffer and check to see if address went + down. */ + if (address < last_address) { + need_to_sort = 1; + } + last_address = address; + + area = malloc(sizeof(struct a_line_area)); + area->ala_address = address; + area->ala_offset = stmt_prog_entry_start - + orig_line_ptr; + area->ala_entry_num = area_count; + area->ala_next = 0; + area->ala_length = 0; + if (area_current) { + area_current->ala_next = area; + area_current->ala_length = + area->ala_offset - + area_current->ala_offset; + } + ++area_count; + area_current = area; + if (area_base == 0) { + area_base = area; + } + + line_ptr += length_size; + } + break; + + case DW_LNE_define_file:{ + break; + } + + default:{ + Dwarf_Unsigned remaining_bytes = instr_length -1; + line_ptr += remaining_bytes; + break; + } + } + + } + } + + + *new_line_ptr = line_ptr; + if (!need_to_sort) { + dwarf_free_line_table_prefix(&prefix); + free_area_data(area_base); + return (DW_DLV_OK); + } + + /* So now we have something to sort. First, finish off the last + area record: */ + area_current->ala_length = (line_ptr - orig_line_ptr) + -area_current->ala_offset; + + /* Build and sort a simple array of sections. Forcing a stable sort + by comparing on sequence number. We will use the sorted list to + move sections of this part of the line table. Each 'section' + starting with a DW_LNE_set_address opcode, on the assumption + that such only get out of order where there was an ld-cord + function rearrangement and that it is meaningful to restart the + line info there. */ + { + struct a_line_area *ala_array; + struct a_line_area *local; + long start_len; + Dwarf_Small *new_area; + long i; + + ala_array = malloc(area_count * sizeof(struct a_line_area)); + if (!ala_array) { + dwarf_free_line_table_prefix(&prefix); + *err_code = DW_DLE_ALLOC_FAIL; + free_area_data(area_base); + return DW_DLV_ERROR; + } + + for (local = area_base, i = 0; local; + local = local->ala_next, ++i) { + + ala_array[i] = *local; + } + free_area_data(area_base); + /* Zero the stale pointers so we don't use them accidentally. */ + area_base = 0; + area_current = 0; + + qsort(ala_array, area_count, sizeof(struct a_line_area), cmpr); + + /* Now we must rearrange the pieces of the line table. */ + + start_len = + (prefix.pf_line_prologue_start + + prefix.pf_prologue_length) - orig_line_ptr; + new_area = malloc(remaining_bytes); + if (!new_area) { + free(ala_array); + *err_code = DW_DLE_ALLOC_FAIL; + dwarf_free_line_table_prefix(&prefix); + return DW_DLV_ERROR; + } + memcpy(new_area, orig_line_ptr, start_len); + line_ptr = new_area + start_len; + for (i = 0; i < area_count; ++i) { + memcpy(line_ptr, orig_line_ptr + + ala_array[i].ala_offset, ala_array[i].ala_length); + line_ptr += ala_array[i].ala_length; + } + + memcpy(orig_line_ptr, new_area, remaining_bytes); + + free(new_area); + free(ala_array); + ala_array = 0; + new_area = 0; + } + + *any_change = 1; + dwarf_free_line_table_prefix(&prefix); + return (DW_DLV_OK); +} diff --git a/libdwarf/dwarf_string.c b/libdwarf/dwarf_string.c new file mode 100644 index 0000000..c73bc0a --- /dev/null +++ b/libdwarf/dwarf_string.c @@ -0,0 +1,83 @@ +/* + + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" + +int +dwarf_get_str(Dwarf_Debug dbg, + Dwarf_Off offset, + char **string, + Dwarf_Signed * returned_str_len, Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + + if (offset == dbg->de_debug_str.dss_size) { + /* Normal (if we've iterated thru the set of strings using + dwarf_get_str and are at the end). */ + return DW_DLV_NO_ENTRY; + } + if (offset > dbg->de_debug_str.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + if (string == NULL) { + _dwarf_error(dbg, error, DW_DLE_STRING_PTR_NULL); + return (DW_DLV_ERROR); + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_str,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_str.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + *string = (char *) dbg->de_debug_str.dss_data + offset; + + *returned_str_len = (strlen(*string)); + return DW_DLV_OK; +} diff --git a/libdwarf/dwarf_stubs.c b/libdwarf/dwarf_stubs.c new file mode 100644 index 0000000..939f3e1 --- /dev/null +++ b/libdwarf/dwarf_stubs.c @@ -0,0 +1,51 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> + + + +/*ARGSUSED*/ int +dwarf_nextglob(Dwarf_Debug dbg, + Dwarf_Global glob, + Dwarf_Global * returned_nextglob, Dwarf_Error * error) +{ + return (DW_DLV_NO_ENTRY); +} diff --git a/libdwarf/dwarf_types.c b/libdwarf/dwarf_types.c new file mode 100644 index 0000000..55967e8 --- /dev/null +++ b/libdwarf/dwarf_types.c @@ -0,0 +1,132 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_types.h" +#include "dwarf_global.h" + +int +dwarf_get_types(Dwarf_Debug dbg, + Dwarf_Type ** types, + Dwarf_Signed * ret_type_count, Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_typenames,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_typenames.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + return _dwarf_internal_get_pubnames_like_data(dbg, + dbg->de_debug_typenames.dss_data, + dbg->de_debug_typenames.dss_size, + (Dwarf_Global **) types, /* type punning, Dwarf_Type is + never a completed type */ + ret_type_count, + error, + DW_DLA_TYPENAME_CONTEXT, + DW_DLA_TYPENAME, + DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD, + DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR); +} + +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. */ + +void +dwarf_types_dealloc(Dwarf_Debug dbg, Dwarf_Type * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl, + count, + DW_DLA_TYPENAME_CONTEXT, + DW_DLA_TYPENAME, DW_DLA_LIST); + return; +} + + +int +dwarf_typename(Dwarf_Type type_in, char **ret_name, Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + + if (type == NULL) { + _dwarf_error(NULL, error, DW_DLE_TYPE_NULL); + return (DW_DLV_ERROR); + } + + *ret_name = (char *) (type->gl_name); + return DW_DLV_OK; +} + + +int +dwarf_type_die_offset(Dwarf_Type type_in, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + + return dwarf_global_die_offset(type, ret_offset, error); +} + + +int +dwarf_type_cu_offset(Dwarf_Type type_in, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + + return dwarf_global_cu_offset(type, ret_offset, error); +} + + +int +dwarf_type_name_offsets(Dwarf_Type type_in, + char **returned_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_die_offset, Dwarf_Error * error) +{ + Dwarf_Global type = (Dwarf_Global) type_in; + return dwarf_global_name_offsets(type, + returned_name, + die_offset, cu_die_offset, error); +} diff --git a/libdwarf/dwarf_types.h b/libdwarf/dwarf_types.h new file mode 100644 index 0000000..ebd31c6 --- /dev/null +++ b/libdwarf/dwarf_types.h @@ -0,0 +1,41 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +typedef struct Dwarf_Type_Context_s *Dwarf_Type_Context; + +/* type never completed see dwarf_global.h */ diff --git a/libdwarf/dwarf_util.c b/libdwarf/dwarf_util.c new file mode 100644 index 0000000..5af6232 --- /dev/null +++ b/libdwarf/dwarf_util.c @@ -0,0 +1,584 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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 "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_die_deliv.h" + + + +/* Given a form, and a pointer to the bytes encoding + a value of that form, val_ptr, this function returns + the length, in bytes, of a value of that form. + When using this function, check for a return of 0 + a recursive DW_FORM_INDIRECT value. */ +Dwarf_Unsigned +_dwarf_get_size_of_val(Dwarf_Debug dbg, + Dwarf_Unsigned form, + Dwarf_Half address_size, + Dwarf_Small * val_ptr, int v_length_size) +{ + Dwarf_Unsigned length = 0; + Dwarf_Word leb128_length = 0; + Dwarf_Unsigned form_indirect = 0; + Dwarf_Unsigned ret_value = 0; + + switch (form) { + + default: /* Handles form = 0. */ + return (form); + + case DW_FORM_addr: + if(address_size) { + return address_size; + } + /* This should never happen, address_size should be set. */ + return (dbg->de_pointer_size); + case DW_FORM_ref_sig8: + return 8; /* sizeof Dwarf_Sig8 */ + + /* DWARF2 was wrong on the size of the attribute for + DW_FORM_ref_addr. We assume compilers are using the + corrected DWARF3 text (for 32bit pointer target objects pointer and + offsets are the same size anyway). */ + case DW_FORM_ref_addr: + return (v_length_size); + + case DW_FORM_block1: + return (*(Dwarf_Small *) val_ptr + 1); + + case DW_FORM_block2: + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + val_ptr, sizeof(Dwarf_Half)); + return (ret_value + sizeof(Dwarf_Half)); + + case DW_FORM_block4: + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + val_ptr, sizeof(Dwarf_ufixed)); + return (ret_value + sizeof(Dwarf_ufixed)); + + + case DW_FORM_data1: + return (1); + + case DW_FORM_data2: + return (2); + + case DW_FORM_data4: + return (4); + + case DW_FORM_data8: + return (8); + + case DW_FORM_string: + return (strlen((char *) val_ptr) + 1); + + case DW_FORM_block: + case DW_FORM_exprloc: + length = _dwarf_decode_u_leb128(val_ptr, &leb128_length); + return (length + leb128_length); + + case DW_FORM_flag_present: + return (0); + case DW_FORM_flag: + return (1); + + case DW_FORM_sec_offset: + /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */ + return (v_length_size); + + case DW_FORM_ref_udata: + /* Discard the decoded value, we just want the length + of the value. */ + _dwarf_decode_u_leb128(val_ptr, &leb128_length); + return (leb128_length); + + case DW_FORM_indirect: + { + Dwarf_Word indir_len = 0; + + form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len); + if (form_indirect == DW_FORM_indirect) { + return (0); /* We are in big trouble: The true form + of DW_FORM_indirect is + DW_FORM_indirect? Nonsense. Should + never happen. */ + } + return (indir_len + _dwarf_get_size_of_val(dbg, + form_indirect, + address_size, + val_ptr + indir_len, + v_length_size)); + } + + case DW_FORM_ref1: + return (1); + + case DW_FORM_ref2: + return (2); + + case DW_FORM_ref4: + return (4); + + case DW_FORM_ref8: + return (8); + + case DW_FORM_sdata: + /* Discard the decoded value, we just want the length + of the value. */ + _dwarf_decode_s_leb128(val_ptr, &leb128_length); + return (leb128_length); + + case DW_FORM_strp: + return (v_length_size); + + case DW_FORM_udata: + /* Discard the decoded value, we just want the length + of the value. */ + _dwarf_decode_u_leb128(val_ptr, &leb128_length); + return (leb128_length); + } +} + +/* We allow an arbitrary number of HT_MULTIPLE entries + before resizing. It seems up to 20 or 30 + would work nearly as well. + We could have a different resize multiple than 'resize now' + test multiple, but for now we don't do that. */ +#define HT_MULTIPLE 8 + +/* Copy the old entries, updating each to be in + a new list. Don't delete anything. Leave the + htin with stale data. */ +static void +copy_abbrev_table_to_new_table(Dwarf_Hash_Table htin, + Dwarf_Hash_Table htout) +{ + Dwarf_Hash_Table_Entry entry_in = htin->tb_entries; + unsigned entry_in_count = htin->tb_table_entry_count; + Dwarf_Hash_Table_Entry entry_out = htout->tb_entries; + unsigned entry_out_count = htout->tb_table_entry_count; + unsigned k = 0; + for ( ; k < entry_in_count; ++k,++entry_in) { + Dwarf_Abbrev_List listent = entry_in->at_head; + Dwarf_Abbrev_List nextlistent = 0; + + for ( ; listent ; listent = nextlistent) { + unsigned newtmp = listent->ab_code; + unsigned newhash = newtmp%entry_out_count; + Dwarf_Hash_Table_Entry e; + nextlistent = listent->ab_next; + e = entry_out+newhash; + /* Move_entry_to_new_hash. This reverses the + order of the entries, effectively, but + that does not seem significant. */ + listent->ab_next = e->at_head; + e->at_head = listent; + + htout->tb_total_abbrev_count++; + } + } +} + +/* This function returns a pointer to a Dwarf_Abbrev_List_s + struct for the abbrev with the given code. It puts the + struct on the appropriate hash table. It also adds all + the abbrev between the last abbrev added and this one to + the hash table. In other words, the .debug_abbrev section + is scanned sequentially from the top for an abbrev with + the given code. All intervening abbrevs are also put + into the hash table. + + This function hashes the given code, and checks the chain + at that hash table entry to see if a Dwarf_Abbrev_List_s + with the given code exists. If yes, it returns a pointer + to that struct. Otherwise, it scans the .debug_abbrev + section from the last byte scanned for that CU till either + an abbrev with the given code is found, or an abbrev code + of 0 is read. It puts Dwarf_Abbrev_List_s entries for all + abbrev's read till that point into the hash table. The + hash table contains both a head pointer and a tail pointer + for each entry. + + While the lists can move and entries can be moved between + lists on reallocation, any given Dwarf_Abbrev_list entry + never moves once allocated, so the pointer is safe to return. + + Returns NULL on error. */ +Dwarf_Abbrev_List +_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Unsigned code) +{ + Dwarf_Debug dbg = cu_context->cc_dbg; + Dwarf_Hash_Table hash_table_base = cu_context->cc_abbrev_hash_table; + Dwarf_Hash_Table_Entry entry_base = 0; + Dwarf_Hash_Table_Entry entry_cur = 0; + Dwarf_Word hash_num = 0; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Unsigned abbrev_tag = 0; + Dwarf_Unsigned attr_name = 0; + Dwarf_Unsigned attr_form = 0; + + Dwarf_Abbrev_List hash_abbrev_entry = 0; + + Dwarf_Abbrev_List inner_list_entry = 0; + Dwarf_Hash_Table_Entry inner_hash_entry = 0; + + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Byte_Ptr end_abbrev_ptr = 0; + unsigned hashable_val = 0; + + if ( !hash_table_base->tb_entries ) { + hash_table_base->tb_table_entry_count = HT_MULTIPLE; + hash_table_base->tb_total_abbrev_count= 0; + hash_table_base->tb_entries = _dwarf_get_alloc(dbg, + DW_DLA_HASH_TABLE_ENTRY, + hash_table_base->tb_table_entry_count); + if(! hash_table_base->tb_entries) { + return NULL; + } + + } else if (hash_table_base->tb_total_abbrev_count > + ( hash_table_base->tb_table_entry_count * HT_MULTIPLE) ) { + struct Dwarf_Hash_Table_s newht; + /* Effectively multiplies by >= HT_MULTIPLE */ + newht.tb_table_entry_count = hash_table_base->tb_total_abbrev_count; + newht.tb_total_abbrev_count = 0; + newht.tb_entries = _dwarf_get_alloc(dbg, + DW_DLA_HASH_TABLE_ENTRY, + newht.tb_table_entry_count); + + if(! newht.tb_entries) { + return NULL; + } + /* Copy the existing entries to the new table, + rehashing each. */ + copy_abbrev_table_to_new_table(hash_table_base, &newht); + /* Dealloc only the entries hash table array, not the lists + of things pointed to by a hash table entry array. */ + dwarf_dealloc(dbg, hash_table_base->tb_entries,DW_DLA_HASH_TABLE_ENTRY); + hash_table_base->tb_entries = 0; + /* Now overwrite the existing table descriptor with + the new, newly valid, contents. */ + *hash_table_base = newht; + } /* Else is ok as is, add entry */ + + + hashable_val = code; + hash_num = hashable_val % + hash_table_base->tb_table_entry_count; + entry_base = hash_table_base->tb_entries; + entry_cur = entry_base + hash_num; + + /* Determine if the 'code' is the list of synonyms already. */ + for (hash_abbrev_entry = entry_cur->at_head; + hash_abbrev_entry != NULL && hash_abbrev_entry->ab_code != code; + hash_abbrev_entry = hash_abbrev_entry->ab_next); + if (hash_abbrev_entry != NULL) { + /* This returns a pointer to an abbrev list entry, not + the list itself. */ + return (hash_abbrev_entry); + } + + abbrev_ptr = cu_context->cc_last_abbrev_ptr != NULL ? + cu_context->cc_last_abbrev_ptr : + dbg->de_debug_abbrev.dss_data + cu_context->cc_abbrev_offset; + end_abbrev_ptr = dbg->de_debug_abbrev.dss_data + + dbg->de_debug_abbrev.dss_size; + + /* End of abbrev's as we are past the end entirely. + THis can happen */ + if (abbrev_ptr > end_abbrev_ptr) { + return (NULL); + } + /* End of abbrev's for this cu, since abbrev code is 0. */ + if (*abbrev_ptr == 0) { + return (NULL); + } + + do { + unsigned new_hashable_val = 0; + DECODE_LEB128_UWORD(abbrev_ptr, abbrev_code); + DECODE_LEB128_UWORD(abbrev_ptr, abbrev_tag); + + inner_list_entry = (Dwarf_Abbrev_List) + _dwarf_get_alloc(cu_context->cc_dbg, DW_DLA_ABBREV_LIST, 1); + if (inner_list_entry == NULL) { + return (NULL); + } + + new_hashable_val = abbrev_code; + hash_num = new_hashable_val % + hash_table_base->tb_table_entry_count; + inner_hash_entry = entry_base + hash_num; + /* Move_entry_to_new_hash */ + inner_list_entry->ab_next = inner_hash_entry->at_head; + inner_hash_entry->at_head = inner_list_entry; + + hash_table_base->tb_total_abbrev_count++; + + inner_list_entry->ab_code = abbrev_code; + inner_list_entry->ab_tag = abbrev_tag; + inner_list_entry->ab_has_child = *(abbrev_ptr++); + inner_list_entry->ab_abbrev_ptr = abbrev_ptr; + + /* Cycle thru the abbrev content, ignoring the content except + to find the end of the content. */ + do { + DECODE_LEB128_UWORD(abbrev_ptr, attr_name); + DECODE_LEB128_UWORD(abbrev_ptr, attr_form); + } while (attr_name != 0 && attr_form != 0); + + /* We may have fallen off the end of content, that is not + a botch in the section, as there is no rule that the last + abbrev need have abbrev_code of 0. */ + } while ( (abbrev_ptr < end_abbrev_ptr ) && + *abbrev_ptr != 0 && abbrev_code != code); + + cu_context->cc_last_abbrev_ptr = abbrev_ptr; + return (abbrev_code == code ? inner_list_entry : NULL); +} + + +/* return 1 if string ends before 'endptr' else +** return 0 meaning string is not properly terminated. +** Presumption is the 'endptr' pts to end of some dwarf section data. +*/ +int +_dwarf_string_valid(void *startptr, void *endptr) +{ + + char *start = startptr; + char *end = endptr; + + while (start < end) { + if (*start == 0) { + return 1; /* OK! */ + } + ++start; + ++end; + } + return 0; /* FAIL! bad string! */ +} + +/* + A byte-swapping version of memcpy + for cross-endian use. + Only 2,4,8 should be lengths passed in. +*/ +void * +_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len) +{ + void *orig_s1 = s1; + unsigned char *targ = (unsigned char *) s1; + unsigned char *src = (unsigned char *) s2; + + if (len == 4) { + targ[3] = src[0]; + targ[2] = src[1]; + targ[1] = src[2]; + targ[0] = src[3]; + } else if (len == 8) { + targ[7] = src[0]; + targ[6] = src[1]; + targ[5] = src[2]; + targ[4] = src[3]; + targ[3] = src[4]; + targ[2] = src[5]; + targ[1] = src[6]; + targ[0] = src[7]; + } else if (len == 2) { + targ[1] = src[0]; + targ[0] = src[1]; + } +/* should NOT get below here: is not the intended use */ + else if (len == 1) { + targ[0] = src[0]; + } else { + memcpy(s1, s2, len); + } + + return orig_s1; +} + + +/* This calculation used to be sprinkled all over. + Now brought to one place. + + We try to accurately compute the size of a cu header + given a known cu header location ( an offset in .debug_info + or debug_types). */ +/* ARGSUSED */ +Dwarf_Unsigned +_dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset, + Dwarf_Bool is_info) +{ + int local_length_size = 0; + int local_extension_size = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned final_size = 0; + Dwarf_Small *cuptr = + is_info? dbg->de_debug_info.dss_data + offset: + dbg->de_debug_types.dss_data+ offset; + + READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, + cuptr, local_length_size, local_extension_size); + + final_size = local_extension_size + /* initial extension, if present */ + local_length_size + /* Size of cu length field. */ + sizeof(Dwarf_Half) + /* Size of version stamp field. */ + local_length_size + /* Size of abbrev offset field. */ + sizeof(Dwarf_Small); /* Size of address size field. */ + + if(!is_info) { + final_size += + /* type signature size */ + sizeof (Dwarf_Sig8) + + /* type offset size */ + local_length_size; + } + return final_size; +} + +/* Pretend we know nothing about the CU + and just roughly compute the result. */ +Dwarf_Unsigned +_dwarf_length_of_cu_header_simple(Dwarf_Debug dbg, + Dwarf_Bool dinfo) +{ + Dwarf_Unsigned finalsize = 0; + finalsize = dbg->de_length_size + /* Size of cu length field. */ + sizeof(Dwarf_Half) + /* Size of version stamp field. */ + dbg->de_length_size + /* Size of abbrev offset field. */ + sizeof(Dwarf_Small); /* Size of address size field. */ + if(!dinfo) { + finalsize += + /* type signature size */ + sizeof (Dwarf_Sig8) + + /* type offset size */ + dbg->de_length_size; + } + return finalsize; +} + +/* Now that we delay loading .debug_info, we need to do the + load in more places. So putting the load + code in one place now instead of replicating it in multiple + places. */ +int +_dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + if (dbg->de_debug_info.dss_data) { + return DW_DLV_OK; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_info, error); + return res; +} +int +_dwarf_load_debug_types(Dwarf_Debug dbg, Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + if (dbg->de_debug_types.dss_data) { + return DW_DLV_OK; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_types, error); + return res; +} +void +_dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,Dwarf_Hash_Table hash_table) +{ + /* A Hash Table is an array with tb_table_entry_count struct + Dwarf_Hash_Table_s entries in the array. */ + int hashnum = 0; + for (; hashnum < hash_table->tb_table_entry_count; ++hashnum) { + struct Dwarf_Abbrev_List_s *abbrev = 0; + struct Dwarf_Abbrev_List_s *nextabbrev = 0; + struct Dwarf_Hash_Table_Entry_s *tb = &hash_table->tb_entries[hashnum]; + + abbrev = tb->at_head; + for (; abbrev; abbrev = nextabbrev) { + nextabbrev = abbrev->ab_next; + dwarf_dealloc(dbg, abbrev, DW_DLA_ABBREV_LIST); + } + } + /* Frees all the entries at once: an array. */ + dwarf_dealloc(dbg,hash_table->tb_entries,DW_DLA_HASH_TABLE_ENTRY); +} + +/* + If no die provided the size value returned might be wrong. + If different compilation units have different address sizes + this may not give the correct value in all contexts if the die + pointer is NULL. + If the Elf offset size != address_size + (for example if address_size = 4 but recorded in elf64 object) + this may not give the correct value in all contexts if the die + pointer is NULL. + If the die pointer is non-NULL (in which case it must point to + a valid DIE) this will return the correct size. +*/ +int +_dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die) +{ + Dwarf_CU_Context context = 0; + Dwarf_Half addrsize = 0; + if(!die) { + return dbg->de_pointer_size; + } + context = die->di_cu_context; + addrsize = context->cc_address_size; + return addrsize; +} + + + diff --git a/libdwarf/dwarf_util.h b/libdwarf/dwarf_util.h new file mode 100644 index 0000000..fb66916 --- /dev/null +++ b/libdwarf/dwarf_util.h @@ -0,0 +1,324 @@ +#ifndef DWARF_UTIL_H +#define DWARF_UTIL_H +/* + + Copyright (C) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010 SN Systems Ltd. All Rights Reserved + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* 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. +*/ + + + + +/* + Decodes unsigned leb128 encoded numbers. + Make sure ptr is a pointer to a 1-byte type. + In 2003 and earlier this was a hand-inlined + version of _dwarf_decode_u_leb128() which did + not work correctly if Dwarf_Word was 64 bits. +*/ +#define DECODE_LEB128_UWORD(ptr, value) \ + do { \ + Dwarf_Word uleblen; \ + value = _dwarf_decode_u_leb128(ptr,&uleblen); \ + ptr += uleblen; \ + } while (0) + +/* + Decodes signed leb128 encoded numbers. + Make sure ptr is a pointer to a 1-byte type. + In 2003 and earlier this was a hand-inlined + version of _dwarf_decode_s_leb128() which did + not work correctly if Dwarf_Word was 64 bits. + +*/ +#define DECODE_LEB128_SWORD(ptr, value) \ + do { \ + Dwarf_Word sleblen; \ + value = _dwarf_decode_s_leb128(ptr,&sleblen); \ + ptr += sleblen; \ + } while(0) + + +/* + Skips leb128_encoded numbers that are guaranteed + to be no more than 4 bytes long. Same for both + signed and unsigned numbers. +*/ +#define SKIP_LEB128_WORD(ptr) \ + do{ if ((*(ptr++) & 0x80) != 0) { \ + if ((*(ptr++) & 0x80) != 0) { \ + if ((*(ptr++) & 0x80) != 0) { \ + if ((*(ptr++) & 0x80) != 0) { \ + } \ + } \ + } \ + } } while (0) + + +#define CHECK_DIE(die, error_ret_value) \ +do { \ + if (die == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_DIE_NULL); \ + return(error_ret_value); \ + } \ + if (die->di_cu_context == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_DIE_NO_CU_CONTEXT); \ + return(error_ret_value); \ + } \ + if (die->di_cu_context->cc_dbg == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); \ + return(error_ret_value); \ + } \ +} while (0) + + +/* + Reads 'source' for 'length' bytes from unaligned addr. + + Avoids any constant-in-conditional warnings and + avoids a test in the generated code (for non-const cases, + which are in the majority.) + Uses a temp to avoid the test. + The decl here should avoid any problem of size in the temp. + This code is ENDIAN DEPENDENT + The memcpy args are the endian issue. +*/ +typedef Dwarf_Unsigned BIGGEST_UINT; + +#ifdef WORDS_BIGENDIAN +#define READ_UNALIGNED(dbg,dest,desttype, source, length) \ + do { \ + BIGGEST_UINT _ltmp = 0; \ + dbg->de_copy_word( (((char *)(&_ltmp)) + sizeof(_ltmp) - length), \ + source, length) ; \ + dest = (desttype)_ltmp; \ + } while (0) + + +/* + This macro sign-extends a variable depending on the length. + It fills the bytes between the size of the destination and + the length with appropriate padding. + This code is ENDIAN DEPENDENT but dependent only + on host endianness, not object file endianness. + The memcpy args are the issue. +*/ +#define SIGN_EXTEND(dest, length) \ + do {if (*(Dwarf_Sbyte *)((char *)&dest + sizeof(dest) - length) < 0) {\ + memcpy((char *)&dest, "\xff\xff\xff\xff\xff\xff\xff\xff", \ + sizeof(dest) - length); \ + } \ + } while (0) +#else /* LITTLE ENDIAN */ + +#define READ_UNALIGNED(dbg,dest,desttype, source, length) \ + do { \ + BIGGEST_UINT _ltmp = 0; \ + dbg->de_copy_word( (char *)(&_ltmp) , \ + source, length) ; \ + dest = (desttype)_ltmp; \ + } while (0) + + +/* + This macro sign-extends a variable depending on the length. + It fills the bytes between the size of the destination and + the length with appropriate padding. + This code is ENDIAN DEPENDENT but dependent only + on host endianness, not object file endianness. + The memcpy args are the issue. +*/ +#define SIGN_EXTEND(dest, length) \ + do {if (*(Dwarf_Sbyte *)((char *)&dest + (length-1)) < 0) {\ + memcpy((char *)&dest+length, \ + "\xff\xff\xff\xff\xff\xff\xff\xff", \ + sizeof(dest) - length); \ + } \ + } while (0) + +#endif /* ! LITTLE_ENDIAN */ + + + +/* + READ_AREA LENGTH reads the length (the older way + of pure 32 or 64 bit + or the dwarf v3 64bit-extension way) + + It reads the bits from where rw_src_data_p points to + and updates the rw_src_data_p to point past what was just read. + + It updates w_length_size (to the size of an offset, either 4 or 8) + and w_exten_size (set 0 unless this frame has the DWARF3,4 64bit + extension, in which case w_exten_size is set to 4). + + r_dbg is just the current dbg pointer. + w_target is the output length field. + r_targtype is the output type. Always Dwarf_Unsigned so far. + +*/ +/* This one handles the v3 64bit extension + and 32bit (and SGI/MIPS fixed 64 bit via the + dwarf_init-set r_dbg->de_length_size).. + It does not recognize any but the one distingushed value + (the only one with defined meaning). + It assumes that no CU will have a length + 0xffffffxx (32bit length) + or + 0xffffffxx xxxxxxxx (64bit length) + which makes possible auto-detection of the extension. + + This depends on knowing that only a non-zero length + is legitimate (AFAICT), and for IRIX non-standard -64 + dwarf that the first 32 bits of the 64bit offset will be + zero (because the compiler could not handle a truly large + value as of Jan 2003 and because no app has that much debug + info anyway, at least not in the IRIX case). + + At present not testing for '64bit elf' here as that + does not seem necessary (none of the 64bit length seems + appropriate unless it's ident[EI_CLASS] == ELFCLASS64). +*/ +# define READ_AREA_LENGTH(r_dbg,w_target,r_targtype, \ + rw_src_data_p,w_length_size,w_exten_size) \ +do { \ + READ_UNALIGNED(r_dbg,w_target,r_targtype, \ + rw_src_data_p, ORIGINAL_DWARF_OFFSET_SIZE); \ + if(w_target == DISTINGUISHED_VALUE) { \ + /* dwarf3 64bit extension */ \ + w_length_size = DISTINGUISHED_VALUE_OFFSET_SIZE; \ + rw_src_data_p += ORIGINAL_DWARF_OFFSET_SIZE; \ + w_exten_size = ORIGINAL_DWARF_OFFSET_SIZE; \ + READ_UNALIGNED(r_dbg,w_target,r_targtype, \ + rw_src_data_p, DISTINGUISHED_VALUE_OFFSET_SIZE); \ + rw_src_data_p += DISTINGUISHED_VALUE_OFFSET_SIZE; \ + } else { \ + if(w_target == 0 && r_dbg->de_big_endian_object) { \ + /* Might be IRIX: We have to distinguish between */ \ + /* 32-bit DWARF format and IRIX 64-bit DWARF format. */ \ + if (r_dbg->de_length_size == 8) { \ + /* IRIX 64 bit, big endian. This test */ \ + /* is not a truly precise test, a precise test */ \ + /* would check if the target was IRIX. */ \ + READ_UNALIGNED(r_dbg,w_target,r_targtype, \ + rw_src_data_p, DISTINGUISHED_VALUE_OFFSET_SIZE); \ + w_length_size = DISTINGUISHED_VALUE_OFFSET_SIZE; \ + rw_src_data_p += DISTINGUISHED_VALUE_OFFSET_SIZE; \ + w_exten_size = 0; \ + } else { \ + /* 32 bit, big endian */ \ + w_length_size = ORIGINAL_DWARF_OFFSET_SIZE; \ + rw_src_data_p += w_length_size; \ + w_exten_size = 0; \ + } \ + } else { \ + /* Standard 32 bit dwarf2/dwarf3 */ \ + w_exten_size = 0; \ + w_length_size = ORIGINAL_DWARF_OFFSET_SIZE; \ + rw_src_data_p += w_length_size; \ + } \ + } } while(0) + +Dwarf_Unsigned +_dwarf_decode_u_leb128(Dwarf_Small * leb128, + Dwarf_Word * leb128_length); + +Dwarf_Signed +_dwarf_decode_s_leb128(Dwarf_Small * leb128, + Dwarf_Word * leb128_length); + +Dwarf_Unsigned +_dwarf_get_size_of_val(Dwarf_Debug dbg, + Dwarf_Unsigned form, + Dwarf_Half address_size, + Dwarf_Small * val_ptr, + int v_length_size); + +struct Dwarf_Hash_Table_Entry_s; +/* This single struct is the base for the hash table. + The intent is that once the total_abbrev_count across + all the entries is greater than 10*current_table_entry_count + one should build a new Dwarf_Hash_Table_Base_s, rehash + all the existing entries, and delete the old table and entries. + (10 is a heuristic, nothing magic about it, but once the + count gets to 30 or 40 times current_table_entry_count + things really slow down a lot. One (500MB) application had + 127000 abbreviations in one compilation unit) + The incoming 'code' is an abbrev number and those simply + increase linearly so the hashing is perfect always. +*/ +struct Dwarf_Hash_Table_s { + unsigned long tb_table_entry_count; + unsigned long tb_total_abbrev_count; + /* Each table entry is a list of abbreviations. */ + struct Dwarf_Hash_Table_Entry_s *tb_entries; +}; + +/* + This struct is used to build a hash table for the + abbreviation codes for a compile-unit. +*/ +struct Dwarf_Hash_Table_Entry_s { + Dwarf_Abbrev_List at_head; +}; + + + +Dwarf_Abbrev_List +_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, + Dwarf_Unsigned code); + + +/* return 1 if string ends before 'endptr' else +** return 0 meaning string is not properly terminated. +** Presumption is the 'endptr' pts to end of some dwarf section data. +*/ +int _dwarf_string_valid(void *startptr, void *endptr); + +Dwarf_Unsigned _dwarf_length_of_cu_header(Dwarf_Debug, + Dwarf_Unsigned offset,Dwarf_Bool dinfo); +Dwarf_Unsigned _dwarf_length_of_cu_header_simple(Dwarf_Debug,Dwarf_Bool dinfo); + +int _dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error *error); +int _dwarf_load_debug_types(Dwarf_Debug dbg, Dwarf_Error *error); +void _dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg, + struct Dwarf_Hash_Table_s* hash_table); +int _dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die); + +#endif /* DWARF_UTIL_H */ diff --git a/libdwarf/dwarf_vars.c b/libdwarf/dwarf_vars.c new file mode 100644 index 0000000..4df0f5d --- /dev/null +++ b/libdwarf/dwarf_vars.c @@ -0,0 +1,136 @@ +/* + + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_vars.h" +#include "dwarf_global.h" + +int +dwarf_get_vars(Dwarf_Debug dbg, + Dwarf_Var ** vars, + Dwarf_Signed * ret_var_count, Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_varnames,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_abbrev.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + return _dwarf_internal_get_pubnames_like_data(dbg, + dbg->de_debug_varnames.dss_data, + dbg->de_debug_varnames.dss_size, + (Dwarf_Global **) vars, /* Type punning for sections + with identical format. */ + ret_var_count, + error, + DW_DLA_VAR_CONTEXT, + DW_DLA_VAR, + DW_DLE_DEBUG_VARNAMES_LENGTH_BAD, + DW_DLE_DEBUG_VARNAMES_VERSION_ERROR); +} + +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. +*/ + +void +dwarf_vars_dealloc(Dwarf_Debug dbg, Dwarf_Var * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl, + count, + DW_DLA_VAR_CONTEXT, + DW_DLA_VAR, DW_DLA_LIST); + return; +} + + +int +dwarf_varname(Dwarf_Var var_in, char **ret_varname, Dwarf_Error * error) +{ + Dwarf_Global var = (Dwarf_Global) var_in; + + if (var == NULL) { + _dwarf_error(NULL, error, DW_DLE_VAR_NULL); + return (DW_DLV_ERROR); + } + + *ret_varname = (char *) (var->gl_name); + return DW_DLV_OK; +} + + +int +dwarf_var_die_offset(Dwarf_Var var_in, + Dwarf_Off * returned_offset, Dwarf_Error * error) +{ + Dwarf_Global var = (Dwarf_Global) var_in; + + return dwarf_global_die_offset(var, returned_offset, error); + +} + + +int +dwarf_var_cu_offset(Dwarf_Var var_in, + Dwarf_Off * returned_offset, Dwarf_Error * error) +{ + Dwarf_Global var = (Dwarf_Global) var_in; + + return dwarf_global_cu_offset(var, returned_offset, error); +} + + +int +dwarf_var_name_offsets(Dwarf_Var var_in, + char **returned_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_offset, Dwarf_Error * error) +{ + Dwarf_Global var = (Dwarf_Global) var_in; + + return + dwarf_global_name_offsets(var, + returned_name, die_offset, cu_offset, + error); +} diff --git a/libdwarf/dwarf_vars.h b/libdwarf/dwarf_vars.h new file mode 100644 index 0000000..bd5f967 --- /dev/null +++ b/libdwarf/dwarf_vars.h @@ -0,0 +1,41 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +typedef struct Dwarf_Var_Context_s *Dwarf_Var_Context; + +/* struct never completed: see dwarf_global.h */ diff --git a/libdwarf/dwarf_weaks.c b/libdwarf/dwarf_weaks.c new file mode 100644 index 0000000..1d0c70d --- /dev/null +++ b/libdwarf/dwarf_weaks.c @@ -0,0 +1,134 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include <stdio.h> +#include "dwarf_weaks.h" +#include "dwarf_global.h" + +int +dwarf_get_weaks(Dwarf_Debug dbg, + Dwarf_Weak ** weaks, + Dwarf_Signed * ret_weak_count, Dwarf_Error * error) +{ + int res = _dwarf_load_section(dbg, &dbg->de_debug_weaknames,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_weaknames.dss_size) { + return (DW_DLV_NO_ENTRY); + } + + + return _dwarf_internal_get_pubnames_like_data(dbg, + dbg->de_debug_weaknames.dss_data, + dbg->de_debug_weaknames.dss_size, + (Dwarf_Global **) weaks, /* Type punning for sections + with identical format. */ + ret_weak_count, + error, + DW_DLA_WEAK_CONTEXT, + DW_DLA_WEAK, + DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD, + DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR); +} + +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. +*/ + +void +dwarf_weaks_dealloc(Dwarf_Debug dbg, Dwarf_Weak * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl, + count, + DW_DLA_WEAK_CONTEXT, + DW_DLA_WEAK, DW_DLA_LIST); + return; +} + + + +int +dwarf_weakname(Dwarf_Weak weak_in, char **ret_name, Dwarf_Error * error) +{ + Dwarf_Global weak = (Dwarf_Global) weak_in; + + if (weak == NULL) { + _dwarf_error(NULL, error, DW_DLE_WEAK_NULL); + return (DW_DLV_ERROR); + } + *ret_name = (char *) (weak->gl_name); + return DW_DLV_OK; +} + + +int +dwarf_weak_die_offset(Dwarf_Weak weak_in, + Dwarf_Off * weak_off, Dwarf_Error * error) +{ + Dwarf_Global weak = (Dwarf_Global) weak_in; + + return dwarf_global_die_offset(weak, weak_off, error); +} + + +int +dwarf_weak_cu_offset(Dwarf_Weak weak_in, + Dwarf_Off * weak_off, Dwarf_Error * error) +{ + Dwarf_Global weak = (Dwarf_Global) weak_in; + + return dwarf_global_cu_offset(weak, weak_off, error); +} + + +int +dwarf_weak_name_offsets(Dwarf_Weak weak_in, + char **weak_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_offset, Dwarf_Error * error) +{ + Dwarf_Global weak = (Dwarf_Global) weak_in; + + return dwarf_global_name_offsets(weak, + weak_name, die_offset, cu_offset, error); +} diff --git a/libdwarf/dwarf_weaks.h b/libdwarf/dwarf_weaks.h new file mode 100644 index 0000000..d38f5f1 --- /dev/null +++ b/libdwarf/dwarf_weaks.h @@ -0,0 +1,41 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +typedef struct Dwarf_Weak_Context_s *Dwarf_Weak_Context; + +/* struct never completed: see dwarf_global.h */ diff --git a/libdwarf/gennames.c b/libdwarf/gennames.c new file mode 100644 index 0000000..6cfe0a3 --- /dev/null +++ b/libdwarf/gennames.c @@ -0,0 +1,541 @@ +/* + Copyright 2009-2010 SN Systems Ltd. All rights reserved. + Portions Copyright 2009-2011 David Anderson. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +/* 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 <stdio.h> +#include <stdlib.h> /* For exit() declaration etc. */ +#include <errno.h> /* For errno declaration. */ +#include <ctype.h> +#include <string.h> +#include <unistd.h> /* For getopt */ +#include "dwarf.h" +#include "common.h" + +/* gennames.c + Prints routines to return constant name for the associated value + (such as the TAG name string for a particular tag). + + The input is dwarf.h + For each set of names with a common prefix, we create a routine + to return the name given the value. + Also print header file that gives prototypes of routines. + To handle cases where there are multiple names for a single + value (DW_AT_* has some due to ambiguities in the DWARF2 spec) + we take the first of a given value as the definitive name. + TAGs, Attributes, etc are given distinct checks. + + There are multiple output files as some people find one + form more pleasant than the other. + + The doprinting argument is so that when used by tag_tree.c, + and tag_attr.c that we don't get irritating messages on stderr + when those dwarfdump built-time applications are run. + + Some compilers generate better code for switch statements than + others, so the -s and -t options let the user decide which + is better for their compiler (when building dwarfdump): + a simple switch or code doing binary search. + This choice affects the runtime speed of dwarfdump. */ + +typedef int boolean; +#define TRUE 1 +#define FALSE 0 +#define FAILED 1 + +static void OpenAllFiles(); +static void WriteFileTrailers(); +static void CloseAllFiles(); +static void GenerateInitialFileLines(); +static void GenerateOneSet(); +#ifdef TRACE_ARRAY +static void PrintArray(void); +#endif /* TRACE_ARRAY */ +static boolean is_skippable_line(char *pLine); +static void ParseDefinitionsAndWriteOutput(); + +/* We don't need really long lines: the input file is simple. */ +#define MAX_LINE_SIZE 1000 +/* We don't need a variable array size, it just has to be big enough. */ +#define ARRAY_SIZE 256 + +/* To store entries from dwarf.h */ +typedef struct { + char name[64]; /* short name */ + unsigned value; /* value */ +} array_data; + +/* A group_array is a grouping from dwarf.h. + All the TAGs are one group, all the + FORMs are another group, and so on. */ +static array_data group_array[ARRAY_SIZE]; +static unsigned array_count = 0; + +typedef int (*compfn)(const void *,const void *); +static int Compare(array_data *,array_data *); + +static char *prefix_root = "DW_"; +static unsigned prefix_root_len = 3; + +/* f_dwarf_in is the input dwarf.h. The others are output files. */ +static FILE *f_dwarf_in; +static FILE *f_names_h; +static FILE *f_names_c; +static FILE *f_names_enum_h; +static FILE *f_names_new_h; + +/* Size unchecked, but large enough. */ +static char prefix[200] = ""; + +static const char *usage[] = { + "Usage: gennames <options>", + " -i input-table-path", + " -o output-table-path", + " -s use 'switch' in generation", + " -t use 'tables' in generation", + "", +}; + +char *program_name = 0; +static char *input_name = 0; +static char *output_name = 0; +static boolean use_switch = TRUE; +static boolean use_tables = FALSE; + + +/* process arguments */ +static void +process_args(int argc, char *argv[]) +{ + int c = 0; + boolean usage_error = FALSE; + + program_name = argv[0]; + + while ((c = getopt(argc, argv, "i:o:st")) != EOF) { + switch (c) { + case 'i': + input_name = optarg; + break; + case 'o': + output_name = optarg; + break; + case 's': + use_switch = TRUE; + use_tables = FALSE; + break; + case 't': + use_switch = FALSE; + use_tables = TRUE; + break; + default: + usage_error = TRUE; + break; + } + } + + if (usage_error || 1 == optind || optind != argc) { + print_usage_message(usage); + exit(FAILED); + } +} + +int +main(int argc,char **argv) +{ + print_version(argv[0]); + process_args(argc,argv); + print_args(argc,argv); + OpenAllFiles(); + GenerateInitialFileLines(); + ParseDefinitionsAndWriteOutput(); + WriteFileTrailers(); + CloseAllFiles(); + return 0; +} + +/* Print the array used to hold the tags, attributes values */ +#ifdef TRACE_ARRAY +static void +PrintArray(void) +{ + int index; + for (index = 0; index < array_count; ++index) { + printf("%d: Name %s_%s, Value 0x%04x\n", + index,prefix, + array[index].name, + array[index].value); + } +} +#endif /* TRACE_ARRAY */ + +static int +Compare(array_data *elem1,array_data *elem2) +{ + if (elem1->value < elem2->value) { + return -1; + } + if (elem1->value > elem2->value) { + return 1; + } + return 0; +} + +static FILE * +open_path(const char *base, const char *file, const char *direction) +{ + FILE *f = 0; + /* POSIX PATH_MAX would suffice, normally stdio BUFSIZ is larger + than PATH_MAX */ + char path_name[BUFSIZ]; + snprintf(path_name,sizeof(path_name),"%s/%s",base,file); + f = fopen(path_name,direction); + if (!f) { + printf("Error openning '%s'\n",path_name); + exit(1); + } + return f; +} + +/* Open files and write the basic headers */ +static void +OpenAllFiles() +{ + char *dwarf_h = "dwarf.h"; + char *names_h = "dwarf_names.h"; + char *names_c = "dwarf_names.c"; + char *names_enum_h = "dwarf_names_enum.h"; + char *names_new_h = "dwarf_names_new.h"; + + f_dwarf_in = open_path(input_name,dwarf_h,"r"); + f_names_enum_h = open_path(output_name,names_enum_h,"w"); + f_names_new_h = open_path(output_name,names_new_h,"w"); + f_names_h = open_path(output_name,names_h,"w"); + f_names_c = open_path(output_name,names_c,"w"); +} + +static void +GenerateInitialFileLines() +{ + /* Generate entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"/* Automatically generated, do not edit. */\n"); + fprintf(f_names_enum_h,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_enum_h,"\n/* BEGIN FILE */\n\n"); + fprintf(f_names_enum_h,"#ifndef __DWARF_NAMES_ENUM_H__\n"); + fprintf(f_names_enum_h,"#define __DWARF_NAMES_ENUM_H__\n"); + + /* Generate entries for 'dwarf_names_new.h' */ + fprintf(f_names_new_h,"/* Automatically generated, do not edit. */\n"); + fprintf(f_names_new_h,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_new_h,"\n/* BEGIN FILE */\n\n"); + fprintf(f_names_new_h,"/* define DWARF_PRINT_PREFIX before this \n"); + fprintf(f_names_new_h," point if you wish to. */\n"); + fprintf(f_names_new_h,"#ifndef DWARF_PRINT_PREFIX \n"); + fprintf(f_names_new_h,"#define DWARF_PRINT_PREFIX dwarf_\n"); + fprintf(f_names_new_h,"#endif\n"); + fprintf(f_names_new_h,"#define dw_glue(x,y) x##y\n"); + fprintf(f_names_new_h,"#define dw_glue2(x,y) dw_glue(x,y)\n"); + fprintf(f_names_new_h,"#define DWPREFIX(x) dw_glue2(DWARF_PRINT_PREFIX,x)\n"); + + /* Generate entries for 'dwarf_names.h' */ + fprintf(f_names_h,"/* Generated routines, do not edit. */\n"); + fprintf(f_names_h,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_h,"\n/* BEGIN FILE */\n\n"); + + /* Generate entries for 'dwarf_names.c' */ + fprintf(f_names_c,"/* Generated routines, do not edit. */\n"); + fprintf(f_names_c,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_c,"\n/* BEGIN FILE */\n\n"); + fprintf(f_names_c,"#include \"dwarf.h\"\n\n"); + fprintf(f_names_c,"#include \"libdwarf.h\"\n\n"); + + if (use_tables) { + fprintf(f_names_c,"typedef struct Names_Data {\n"); + fprintf(f_names_c," const char *l_name; \n"); + fprintf(f_names_c," unsigned value; \n"); + fprintf(f_names_c,"} Names_Data;\n\n"); + + /* Generate code to find an entry */ + fprintf(f_names_c,"/* Use standard binary search to get entry */\n"); + fprintf(f_names_c,"static int\nfind_entry(Names_Data *table," + "const int last,unsigned value, const char **s_out)\n"); + fprintf(f_names_c,"{\n"); + fprintf(f_names_c," int low = 0;\n"); + fprintf(f_names_c," int high = last;\n"); + fprintf(f_names_c," int mid;\n"); + fprintf(f_names_c,"\n"); + fprintf(f_names_c," while (low < high) {\n"); + fprintf(f_names_c," mid = low + ((high - low) / 2);\n"); + fprintf(f_names_c," if (table[mid].value < value) {\n"); + fprintf(f_names_c," low = mid + 1;\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c," else {\n"); + fprintf(f_names_c," high = mid;\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c,"\n"); + fprintf(f_names_c," if (low < last && table[low].value == value) {\n"); + fprintf(f_names_c," /* Found: low is the entry */\n"); + fprintf(f_names_c," *s_out = table[low].l_name;\n"); + fprintf(f_names_c," return DW_DLV_OK;\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n"); + fprintf(f_names_c,"}\n"); + fprintf(f_names_c,"\n"); + } +} + +/* Close files and write basic trailers */ +static void +WriteFileTrailers() +{ + /* Generate entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"#endif /* __DWARF_NAMES_ENUM_H__ */\n"); + fprintf(f_names_enum_h,"\n/* END FILE */\n"); + + /* Generate entries for 'dwarf_names_new.h' */ + fprintf(f_names_new_h,"\n/* END FILE */\n"); + + /* Generate entries for 'dwarf_names.h' */ + fprintf(f_names_h,"\n/* END FILE */\n"); + + /* Generate entries for 'dwarf_names.c' */ + fprintf(f_names_c,"\n/* END FILE */\n"); +} + +static void +CloseAllFiles() +{ + fclose(f_dwarf_in); + fclose(f_names_enum_h); + fclose(f_names_new_h); + fclose(f_names_h); + fclose(f_names_c); +} + +/* Write the table and code for a common set of names */ +static void +GenerateOneSet() +{ + unsigned index; + unsigned prev_value = 0; + size_t len; + char *prefix_id = prefix + prefix_root_len; + +#ifdef TRACE_ARRAY + printf("List before sorting:\n"); + PrintArray(); +#endif /* TRACE_ARRAY */ + + /* Sort the array, because the values in 'libdwarf.h' are not in + ascending order; if we use '-t' we must be sure the values are + sorted, for the binary search to work properly */ + qsort((void *)&group_array,array_count,sizeof(array_data),(compfn)Compare); + +#ifdef TRACE_ARRAY + printf("\nList after sorting:\n"); + PrintArray(); +#endif /* TRACE_ARRAY */ + + /* Generate entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"\nenum Dwarf_%s_e {\n",prefix_id); + + /* Generate entries for 'dwarf_names_new.h' */ + fprintf(f_names_new_h,"int DWPREFIX(get_%s_name) (unsigned int, const char **);\n",prefix_id); + + /* Generate entries for 'dwarf_names.h' and libdwarf.h */ + fprintf(f_names_h,"extern int dwarf_get_%s_name(unsigned int /*val_in*/, const char ** /*s_out */);\n",prefix_id); + + /* Generate code for 'dwarf_names.c' */ + fprintf(f_names_c,"/* ARGSUSED */\n"); + fprintf(f_names_c,"int\n"); + fprintf(f_names_c,"dwarf_get_%s_name (unsigned int val,const char ** s_out)\n",prefix_id); + fprintf(f_names_c,"{\n"); + if (use_tables) { + fprintf(f_names_c," static Names_Data Dwarf_%s_n[] = {\n",prefix_id); + } else { + fprintf(f_names_c," switch (val) {\n"); + } + + for (index = 0; index < array_count; ++index) { + /* Check if value already dumped */ + if (index > 0 && group_array[index].value == prev_value) { + continue; + } + prev_value = group_array[index].value; + + len = 39 - strlen(prefix); + fprintf(f_names_enum_h," %s_%-*s = 0x%04x", + prefix,(int)len,group_array[index].name,group_array[index].value); + fprintf(f_names_enum_h,(index + 1 < array_count) ? ",\n" : "\n"); + + /* Generate entries for 'dwarf_names.c' */ + if (use_tables) { + /* The 20 just makes nice formatting in the output. */ + len = 20 - strlen(group_array[index].name); + fprintf(f_names_c," {/* %3d */ \"%s_%s\", ", + index,prefix,group_array[index].name); + fprintf(f_names_c," %s_%s}", prefix,group_array[index].name); + fprintf(f_names_c,(index + 1 < array_count) ? ",\n" : "\n"); + } else { + fprintf(f_names_c," case %s_%s:\n", + prefix,group_array[index].name); + fprintf(f_names_c," *s_out = \"%s_%s\";\n", + prefix,group_array[index].name); + fprintf(f_names_c," return DW_DLV_OK;\n"); + } + } + + /* Closing entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"};\n"); + + if (use_tables) { + /* Closing entries for 'dwarf_names.c' */ + fprintf(f_names_c," };\n\n"); + + /* Closing code for 'dwarf_names.c' */ + fprintf(f_names_c," const int last_entry = %d;\n",array_count); + fprintf(f_names_c," /* find the entry */\n"); + fprintf(f_names_c," int r = find_entry(Dwarf_%s_n,last_entry,val,s_out);\n",prefix_id); + fprintf(f_names_c," return r; \n"); + fprintf(f_names_c,"}\n"); + } else { + fprintf(f_names_c," }\n"); + fprintf(f_names_c," return DW_DLV_NO_ENTRY; \n"); + fprintf(f_names_c,"}\n"); + } + + /* Mark the group_array as empty */ + array_count = 0; +} + +/* Detect empty lines (and other lines we do not want to read) */ +static boolean +is_skippable_line(char *pLine) +{ + boolean empty = TRUE; + + for (; *pLine && empty; ++pLine) { + empty = isspace(*pLine); + } + return empty; +} + +static void safe_strncpy(char *out, unsigned out_len, +char *in,unsigned in_len) +{ + if(in_len >= out_len) { + fprintf(stderr,"Impossible input line from dwarf.h. Giving up. \n"); + fprintf(stderr,"Length %u is too large, limited to %u.\n", + in_len,out_len); + exit(1); + } + strncpy(out,in,in_len); +} + + +/* Parse the 'dwarf.h' file and generate the tables */ +static void +ParseDefinitionsAndWriteOutput() +{ + char new_prefix[64]; + char *second_underscore = NULL; + char type[1000]; + char name[1000]; + char value[1000]; + char extra[1000]; + char line_in[MAX_LINE_SIZE]; + int pending = FALSE; + int prefix_len = 0; + + /* Process each line from 'dwarf.h' */ + while (!feof(f_dwarf_in)) { + errno = 0; + char *fgbad = fgets(line_in,sizeof(line_in),f_dwarf_in); + if(!fgbad) { + if(feof(f_dwarf_in)) { + break; + } + /* Is error. errno must be set. */ + fprintf(stderr,"Error reading dwarf.h!. Errno %d\n",errno); + exit(1); + } + if (is_skippable_line(line_in)) { + continue; + } + sscanf(line_in,"%s %s %s %s",type,name,value,extra); + if (strcmp(type,"#define") || + strncmp(name,prefix_root,prefix_root_len)) { + continue; + } + + second_underscore = strchr(name + prefix_root_len,'_'); + prefix_len = (int)(second_underscore - name); + safe_strncpy(new_prefix,sizeof(new_prefix),name,prefix_len); + new_prefix[prefix_len] = 0; + + /* Check for new prefix set */ + if (strcmp(prefix,new_prefix)) { + if (pending) { + /* Generate current prefix set */ + GenerateOneSet(); + } + pending = TRUE; + strcpy(prefix,new_prefix); + } + + /* Be sure we have a valid entry */ + if (array_count >= ARRAY_SIZE) { + printf("Too many entries for current group_array size"); + exit(1); + } + + /* Move past the second underscore */ + ++second_underscore; + + /* Record current entry */ + strcpy(group_array[array_count].name,second_underscore); + group_array[array_count].value = strtoul(value,NULL,16); + ++array_count; + } + if (pending) { + /* Generate final prefix set */ + GenerateOneSet(); + } +} diff --git a/libdwarf/index.v2.mm b/libdwarf/index.v2.mm new file mode 100644 index 0000000..c5fd9ac --- /dev/null +++ b/libdwarf/index.v2.mm @@ -0,0 +1,266 @@ +.ds fB IN-% +.PF "''\s10\\\\*(fB\s0''" +.PH +.ce +\s12INDEX\s0 + +.\" %W% %P% %E% %I% %U% +.\" Copyright 1993 UNIX System Laboratories, Inc. +.\" XX macro marks new index entry. +.de XX +. br +. ti 0 +. ne 2 +. vs 12 +\s10\f1\\$1\0 \s8\fR\\$2\f1 +.. +.\" header between letters of the alphabet +.de YY +. sp 2 +. ne 4 +\fR\s16\\$2\s0\f1 +. sp 0.5 +.. +.\" markup surrounding book acronym +.\" markup surrounding chapter number +.vs 12 +.ps 8 +.CH "Index" IN +.2C +.in +2 +.\" SCCS path name: /lfs/doc/DMG/Projects/Indexing/sccs/bin/s.index.head +.\" SCCS version SID: 1.8 +.\" Date this version: 92/08/10 +.\" Time this version: 13:06:03 +.YY a A +.XX "\&abbreviations table" "\*(C{\*(}C4, 66\-67" +.XX "\&ABI" "\*(C{\*(}C10, 60" +.XX "\&accelerated access" "\*(C{\*(}C49" +.XX "\&access declarations" "\*(C{\*(}C41" +.XX "\&accessibility" "\*(C{\*(}C18, 41, 74" +.XX "\&activations" "\*(C{\*(}C5, 59" +.XX "\&address space" "" +.XX "\&\0 contiguous" "\*(C{\*(}C23, 26" +.XX "\&\0 flat" "\*(C{\*(}C19" +.XX "\&\0 multiple" "\*(C{\*(}C13" +.XX "\&\0 segmented" "\*(C{\*(}C5, 19, 26, 33, 50, 66" +.XX "\&addresses" "" +.XX "\&\0 class" "\*(C{\*(}C19, 26, 38, 75" +.XX "\&\0 offset portion" "\*(C{\*(}C19, 50, 66, 77" +.XX "\&\0 size of" "\*(C{\*(}C50, 66, 77" +.XX "\&anonymous types" "\*(C{\*(}C30" +.XX "\&anonymous unions" "\*(C{\*(}C33, 41" +.XX "\&arrays" "\*(C{\*(}C5, 39" +.XX "\&\0 dimensions" "\*(C{\*(}C39" +.XX "\&\0 ordering" "\*(C{\*(}C39, 77" +.XX "\&\0 stride" "\*(C{\*(}C39" +.XX "\&artificial entries" "\*(C{\*(}C19" +.XX "\&attributes" "\*(C{\*(}C3, 7, 67" +.XX "\&\0 addresses" "\*(C{\*(}C8, 67" +.XX "\&\0 blocks" "\*(C{\*(}C8, 67" +.XX "\&\0 constants" "\*(C{\*(}C8, 68" +.XX "\&\0 flags" "\*(C{\*(}C8, 69" +.XX "\&\0 forms" "\*(C{\*(}C4, 7, 67" +.XX "\&\0 names" "\*(C{\*(}C4, 7, 67" +.XX "\&\0 ordering" "\*(C{\*(}C9, 27" +.XX "\&\0 references" "\*(C{\*(}C8, 69" +.XX "\&\0 strings" "\*(C{\*(}C9, 70" +.XX "\&\0 values" "\*(C{\*(}C4, 7, 66" +.YY b B +.XX "\&base types" "\*(C{\*(}C18, 24, 37, 65, 74" +.XX "\&bit fields" "\*(C{\*(}C42" +.YY c C +.XX "\&C " "\*(C{\*(}C3, 26, 33, 39\-40, 45, 47, 57" +.XX "\&C++ " "\*(C{\*(}C3, 5, 18\-19, 21, 28, 32\-33, 40\-41, 43, 47, 49, 57" +.XX "\&call frame information" "\*(C{\*(}C5, 59, 65, 78" +.XX "\&\0 Common Information Entry" "\*(C{\*(}C61" +.XX "\&\0 Frame Description Entry" "\*(C{\*(}C62" +.XX "\&\0 instructions" "\*(C{\*(}C62, 78" +.XX "\&\0 register rules" "\*(C{\*(}C61" +.XX "\&\0 structure" "\*(C{\*(}C60" +.XX "\&\0 usage" "\*(C{\*(}C64" +.XX "\&calling conventions" "\*(C{\*(}C26, 65, 76" +.XX "\&catch blocks" "\*(C{\*(}C32" +.XX "\&classes" "\*(C{\*(}C33, 40" +.XX "\&\0 derived" "\*(C{\*(}C40" +.XX "\&\0 friends" "\*(C{\*(}C41" +.XX "\&\0 incomplete" "\*(C{\*(}C40" +.XX "\&\0 virtual base" "\*(C{\*(}C41" +.XX "\&common blocks" "\*(C{\*(}C27, 35" +.XX "\&compatibility" "\*(C{\*(}C3, 65" +.XX "\&compilation units" "\*(C{\*(}C23, 28, 44, 66" +.XX "\&\0 header" "\*(C{\*(}C66" +.XX "\&constants" "\*(C{\*(}C33\-34" +.YY d D +.XX "\&\f(CW.debug\fP " "\*(C{\*(}C4" +.XX "\&\f(CW.debug_abbrev\fP " "\*(C{\*(}C66\-67, 79" +.XX "\&\f(CW.debug_aranges\fP " "\*(C{\*(}C49, 77, 79" +.XX "\&\f(CW.debug_frame\fP " "\*(C{\*(}C61, 79" +.XX "\&\f(CW.debug_info\fP " "\*(C{\*(}C3\-4, 7, 49\-50, 66, 79" +.XX "\&\f(CW.debug_line\fP " "\*(C{\*(}C4, 50, 79" +.XX "\&\f(CW.debug_loc\fP " "\*(C{\*(}C17, 79" +.XX "\&\f(CW.debug_macinfo\fP " "\*(C{\*(}C57, 79" +.XX "\&\f(CW.debug_pubnames\fP " "\*(C{\*(}C49, 77, 79" +.XX "\&\f(CW.debug_str\fP " "\*(C{\*(}C70, 79" +.XX "\&debugging information entries" "\*(C{\*(}C3, 7, 9, 66" +.XX "\&\0 child entries" "\*(C{\*(}C4, 9, 67" +.XX "\&\0 null entries" "\*(C{\*(}C9, 66\-67" +.XX "\&\0 siblings" "\*(C{\*(}C4, 9, 67" +.XX "\&declarations" "" +.XX "\&\0 accessibility" "\*(C{\*(}C18, 74" +.XX "\&\0 coordinates" "\*(C{\*(}C20, 28, 30, 44" +.XX "\&\0 defining" "\*(C{\*(}C20, 33, 40, 43" +.XX "\&\0 external" "\*(C{\*(}C25, 33" +.XX "\&\0 imported" "\*(C{\*(}C35" +.XX "\&\0 non-defining" "\*(C{\*(}C4, 20, 26, 33, 38, 40" +.XX "\&\0 scope" "\*(C{\*(}C34, 37" +.XX "\&\0 types of" "\*(C{\*(}C4, 18" +.XX "\&\0 visibility" "\*(C{\*(}C18, 75" +.XX "\&discriminants" "\*(C{\*(}C44, 77" +.XX "\&discriminated unions" "\*(C{\*(}C40, 44, 77" +.YY e E +.XX "\&entry points" "\*(C{\*(}C25" +.XX "\&\0 declarations owned by" "\*(C{\*(}C27" +.XX "\&\0 locations" "\*(C{\*(}C26" +.XX "\&\0 return types" "\*(C{\*(}C26" +.XX "\&enumerations" "\*(C{\*(}C5, 39, 45" +.XX "\&error values" "\*(C{\*(}C65" +.XX "\&exceptions" "\*(C{\*(}C5, 28, 32" +.YY f F +.XX "\&file types" "\*(C{\*(}C48" +.XX "\&flat address space" "\*(C{\*(}C19" +.XX "\&Fortran" "\*(C{\*(}C3, 27, 35, 46\-47" +.XX "\&FORTRAN77" "\*(C{\*(}C3" +.XX "\&Fortran90" "\*(C{\*(}C3, 34\-35" +.XX "\&friends" "\*(C{\*(}C41" +.YY i I +.XX "\&identifiers" "" +.XX "\&\0 case" "\*(C{\*(}C24, 76" +.XX "\&\0 names" "\*(C{\*(}C21, 49" +.XX "\&imports" "\*(C{\*(}C35" +.XX "\&inheritance" "\*(C{\*(}C40" +.YY l L +.XX "\&labels" "\*(C{\*(}C31" +.XX "\&languages" "\*(C{\*(}C3, 23, 75" +.XX "\&LEB128" "\*(C{\*(}C8, 51, 68, 70" +.XX "\&lexical blocks" "\*(C{\*(}C31" +.XX "\&line number information" "\*(C{\*(}C4, 20, 23, 50, 77" +.XX "\&\0 definitions" "\*(C{\*(}C51, 77" +.XX "\&\0 extended opcodes" "\*(C{\*(}C52, 56, 78" +.XX "\&\0 general rules" "\*(C{\*(}C59" +.XX "\&\0 prologue" "\*(C{\*(}C52" +.XX "\&\0 special opcodes" "\*(C{\*(}C52, 54" +.XX "\&\0 standard opcodes" "\*(C{\*(}C52, 55, 78" +.XX "\&\0 state machine registers" "\*(C{\*(}C51" +.XX "\&locations" "" +.XX "\&\0 arithmetic operations" "\*(C{\*(}C13" +.XX "\&\0 control flow operations" "\*(C{\*(}C14" +.XX "\&\0 descriptions" "\*(C{\*(}C4, 10, 19, 41, 72" +.XX "\&\0 examples" "\*(C{\*(}C15\-16" +.XX "\&\0 expressions" "\*(C{\*(}C10, 41, 65, 72" +.XX "\&\0 lists" "\*(C{\*(}C4, 10, 17, 74" +.XX "\&\0 literal encodings" "\*(C{\*(}C11" +.XX "\&\0 logical operations" "\*(C{\*(}C13" +.XX "\&\0 register based addressing" "\*(C{\*(}C12" +.XX "\&\0 register name operators" "\*(C{\*(}C10" +.XX "\&\0 special operations" "\*(C{\*(}C15" +.XX "\&\0 stack" "\*(C{\*(}C11\-12, 15" +.XX "\&lookup" "" +.XX "\&\0 by address" "\*(C{\*(}C49, 77" +.XX "\&\0 by name" "\*(C{\*(}C49, 77" +.YY m M +.XX "\¯o information" "\*(C{\*(}C4, 24, 57, 78" +.XX "\&\0 base source entries" "\*(C{\*(}C58" +.XX "\&\0 command line options" "\*(C{\*(}C58" +.XX "\&\0 define and undefine entries" "\*(C{\*(}C57" +.XX "\&\0 end file entries" "\*(C{\*(}C58" +.XX "\&\0 start file entries" "\*(C{\*(}C58" +.XX "\&\0 vendor extensions" "\*(C{\*(}C58" +.XX "\&main programs" "\*(C{\*(}C26" +.XX "\&members" "\*(C{\*(}C30" +.XX "\&\0 bit fields" "\*(C{\*(}C42" +.XX "\&\0 data" "\*(C{\*(}C40\-41" +.XX "\&\0 functions" "\*(C{\*(}C25, 40, 43" +.XX "\&\0 locations" "\*(C{\*(}C11, 43" +.XX "\&\0 pointers to" "\*(C{\*(}C47" +.XX "\&\0 static data" "\*(C{\*(}C33, 40, 49" +.XX "\&Modula2" "\*(C{\*(}C3, 18, 25, 32" +.XX "\&modules" "\*(C{\*(}C25" +.XX "\&\0 definition" "\*(C{\*(}C25" +.XX "\&\0 priority" "\*(C{\*(}C25" +.YY n N +.XX "\&namelists" "\*(C{\*(}C35" +.YY o O +.XX "\&optimized code" "\*(C{\*(}C10, 18, 33" +.YY p P +.XX "\¶meters" "" +.XX "\&\0 default value" "\*(C{\*(}C34" +.XX "\&\0 formal" "\*(C{\*(}C27, 32\-33, 45" +.XX "\&\0 optional" "\*(C{\*(}C34" +.XX "\&\0 unspecified" "\*(C{\*(}C27, 32, 46" +.XX "\&\0 variable" "\*(C{\*(}C34" +.XX "\&Pascal" "\*(C{\*(}C3, 32, 40, 46, 48" +.XX "\&pointers to members" "\*(C{\*(}C47" +.XX "\&pre-processor" "\*(C{\*(}C4, 57" +.YY r R +.XX "\&records" "\*(C{\*(}C40" +.YY s S +.XX "\&scope" "\*(C{\*(}C34, 37" +.XX "\&segmented address space" "\*(C{\*(}C5, 19, 26, 33, 50, 66" +.XX "\&set types" "\*(C{\*(}C46" +.XX "\&source" "" +.XX "\&\0 columns" "\*(C{\*(}C20, 51" +.XX "\&\0 files" "\*(C{\*(}C20, 23, 51, 53, 56, 58, 78" +.XX "\&\0 lines" "\*(C{\*(}C20, 51, 57" +.XX "\&string table" "\*(C{\*(}C70" +.XX "\&string types" "\*(C{\*(}C46" +.XX "\&structures" "\*(C{\*(}C33, 40" +.XX "\&\0 derived" "\*(C{\*(}C40" +.XX "\&\0 incomplete" "\*(C{\*(}C40" +.XX "\&subranges" "\*(C{\*(}C39, 46" +.XX "\&subroutines" "\*(C{\*(}C19, 25" +.XX "\&\0 declarations owned by" "\*(C{\*(}C27" +.XX "\&\0 frame base" "\*(C{\*(}C12, 27" +.XX "\&\0 inline" "\*(C{\*(}C28, 76" +.XX "\&\0 inlined" "\*(C{\*(}C29" +.XX "\&\0 locations" "\*(C{\*(}C26" +.XX "\&\0 members" "\*(C{\*(}C25, 43" +.XX "\&\0 nested" "\*(C{\*(}C27" +.XX "\&\0 out-of-line" "\*(C{\*(}C30" +.XX "\&\0 prototypes" "\*(C{\*(}C26, 45" +.XX "\&\0 return addresses" "\*(C{\*(}C27" +.XX "\&\0 return types" "\*(C{\*(}C26, 45" +.XX "\&\0 types" "\*(C{\*(}C19, 45" +.YY t T +.XX "\&tags" "\*(C{\*(}C4, 7, 65, 67" +.XX "\&templates" "\*(C{\*(}C5, 28, 43" +.XX "\&try blocks" "\*(C{\*(}C32" +.XX "\&type modifiers" "\*(C{\*(}C18, 38" +.XX "\&typedefs" "\*(C{\*(}C38" +.XX "\&types" "" +.XX "\&\0 base" "\*(C{\*(}C18, 24, 37, 65, 74" +.XX "\&\0 constant" "\*(C{\*(}C18, 38" +.XX "\&\0 modifiers" "\*(C{\*(}C18, 38" +.XX "\&\0 packed" "\*(C{\*(}C18, 38" +.XX "\&\0 pointer" "\*(C{\*(}C18\-19, 38" +.XX "\&\0 reference" "\*(C{\*(}C18\-19, 38" +.XX "\&\0 user-defined" "\*(C{\*(}C18" +.XX "\&\0 volatile" "\*(C{\*(}C18, 38" +.YY u U +.XX "\&unions" "\*(C{\*(}C33, 40, 42" +.XX "\&\0 anonymous" "\*(C{\*(}C33, 41" +.XX "\&\0 incomplete" "\*(C{\*(}C40" +.XX "\&user-defined types" "\*(C{\*(}C18" +.YY v V +.XX "\&variable length data" "\*(C{\*(}C4, 8, 68, 70" +.XX "\&variables" "\*(C{\*(}C33" +.XX "\&variants" "\*(C{\*(}C40, 44, 77" +.XX "\&vendor extensions" "\*(C{\*(}C4, 58, 60, 65" +.XX "\&Version 1" "\*(C{\*(}C3\-4, 10, 66" +.XX "\&Version 2" "\*(C{\*(}C3, 10, 66, 78" +.XX "\&virtual functions" "\*(C{\*(}C3, 19, 43" +.XX "\&virtuality" "\*(C{\*(}C19, 41, 43, 75" +.XX "\&visibility" "\*(C{\*(}C18, 75" +.YY w W +.XX "\&with statements" "\*(C{\*(}C32" +.1C diff --git a/libdwarf/index.v2.pdf b/libdwarf/index.v2.pdf Binary files differnew file mode 100644 index 0000000..5d45154 --- /dev/null +++ b/libdwarf/index.v2.pdf diff --git a/libdwarf/install.sh b/libdwarf/install.sh new file mode 100755 index 0000000..0ff4b6a --- /dev/null +++ b/libdwarf/install.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/libdwarf/libdwarf.h b/libdwarf/libdwarf.h new file mode 100644 index 0000000..128bd1e --- /dev/null +++ b/libdwarf/libdwarf.h @@ -0,0 +1,2964 @@ +/* + + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2011 David Anderson. All rights reserved. + Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved. + Portions Copyright 2010 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +#ifndef _LIBDWARF_H +#define _LIBDWARF_H +#ifdef __cplusplus +extern "C" { +#endif +/* + libdwarf.h + $Revision: #9 $ $Date: 2008/01/17 $ + + For libdwarf producers and consumers + + The interface is defined as having 8-byte signed and unsigned + values so it can handle 64-or-32bit target on 64-or-32bit host. + Addr is the native size: it represents pointers on + the host machine (not the target!). + + This contains declarations for types and all producer + and consumer functions. + + Function declarations are written on a single line each here + so one can use grep to each declaration in its entirety. + The declarations are a little harder to read this way, but... + +*/ + +struct Elf; +typedef struct Elf* dwarf_elf_handle; + +/* To enable printing with printf regardless of the + actual underlying data type, we define the DW_PR_xxx macros. + To ensure uses of DW_PR_DUx or DW_PR_DSx look the way you want + ensure the right DW_PR_XZEROS define is uncommented. +*/ +/*#define DW_PR_XZEROS "" */ +#define DW_PR_XZEROS "08" +#if (_MIPS_SZLONG == 64) +/* Special case for MIPS, so -64 (LP64) build gets simple -long-. + Non-MIPS LP64 or ILP64 environments should probably ensure + _MIPS_SZLONG set to 64 everywhere this header is #included. +*/ +typedef int Dwarf_Bool; /* boolean type */ +typedef unsigned long Dwarf_Off; /* 4 or 8 byte file offset */ +typedef unsigned long Dwarf_Unsigned; /* 4 or 8 byte unsigned value */ +typedef unsigned short Dwarf_Half; /* 2 byte unsigned value */ +typedef unsigned char Dwarf_Small; /* 1 byte unsigned value */ +typedef signed long Dwarf_Signed; /* 4 or 8 byte signed value */ +typedef unsigned long Dwarf_Addr; /* target memory address */ +#define DW_PR_DUx "lx" +#define DW_PR_DSx "lx" +#define DW_PR_DUu "lu" +#define DW_PR_DSd "ld" + +#else /* 32-bit */ +/* This is for ILP32, allowing i/o of 64bit dwarf info. + Also should be fine for LP64 and ILP64 cases. +*/ +typedef int Dwarf_Bool; /* boolean type */ +typedef unsigned long long Dwarf_Off; /* 8 byte file offset */ +typedef unsigned long long Dwarf_Unsigned; /* 8 byte unsigned value*/ +typedef unsigned short Dwarf_Half; /* 2 byte unsigned value */ +typedef unsigned char Dwarf_Small; /* 1 byte unsigned value */ +typedef signed long long Dwarf_Signed; /* 8 byte signed value */ +typedef unsigned long long Dwarf_Addr; /* target memory address */ +#define DW_PR_DUx "llx" +#define DW_PR_DSx "llx" +#define DW_PR_DUu "llu" +#define DW_PR_DSd "lld" +#endif +#ifdef HAVE_NONSTANDARD_PRINTF_64_FORMAT +/* Windows does not use std C formatting, so allow it. */ +#undef DW_PR_DUx +#undef DW_PR_DSx +#undef DW_PR_DUu +#undef DW_PR_DSd +#define DW_PR_DUx "I64x" +#define DW_PR_DSx "I64x" +#define DW_PR_DUu "I64u" +#define DW_PR_DSd "I64d" +#endif /* HAVE_NONSTANDARD_FORMAT */ + +typedef void* Dwarf_Ptr; /* host machine pointer */ + +/* Used for DW_FORM_ref_sig8. It is not a string, it + is 8 bytes of a signature one would use to find + a type unit. See dwarf_formsig8() +*/ +typedef struct { + char signature[8]; +} Dwarf_Sig8; + +/* Contains info on an uninterpreted block of data +*/ +typedef struct { + Dwarf_Unsigned bl_len; /* length of block */ + Dwarf_Ptr bl_data; /* uninterpreted data */ + Dwarf_Small bl_from_loclist; /*non-0 if loclist, else debug_info*/ + Dwarf_Unsigned bl_section_offset; /* Section (not CU) offset + which 'data' comes from. */ +} Dwarf_Block; + + +/* location record +*/ +typedef struct { + Dwarf_Small lr_atom; /* location operation */ + Dwarf_Unsigned lr_number; /* operand */ + Dwarf_Unsigned lr_number2; /* for OP_BREGx */ + Dwarf_Unsigned lr_offset; /* offset in locexpr for OP_BRA etc */ +} Dwarf_Loc; + + +/* location description +*/ +typedef struct { + Dwarf_Addr ld_lopc; /* beginning of active range */ + Dwarf_Addr ld_hipc; /* end of active range */ + Dwarf_Half ld_cents; /* count of location records */ + Dwarf_Loc* ld_s; /* pointer to list of same */ + Dwarf_Small ld_from_loclist; + /* non-0 if loclist, else debug_info*/ + + Dwarf_Unsigned ld_section_offset; /* Section (not CU) offset + where loc-expr begins*/ +} Dwarf_Locdesc; + +/* First appears in DWARF3. + The dwr_addr1/addr2 data is either an offset (DW_RANGES_ENTRY) + or an address (dwr_addr2 in DW_RANGES_ADDRESS_SELECTION) or + both are zero (DW_RANGES_END). +*/ +enum Dwarf_Ranges_Entry_Type { DW_RANGES_ENTRY, + DW_RANGES_ADDRESS_SELECTION, + DW_RANGES_END +}; +typedef struct { + Dwarf_Addr dwr_addr1; + Dwarf_Addr dwr_addr2; + enum Dwarf_Ranges_Entry_Type dwr_type; +} Dwarf_Ranges; + +/* Frame description instructions expanded. +*/ +typedef struct { + Dwarf_Small fp_base_op; + Dwarf_Small fp_extended_op; + Dwarf_Half fp_register; + + /* Value may be signed, depends on op. + Any applicable data_alignment_factor has + not been applied, this is the raw offset. */ + Dwarf_Unsigned fp_offset; + Dwarf_Off fp_instr_offset; +} Dwarf_Frame_Op; /* DWARF2 */ + +typedef struct { + Dwarf_Small fp_base_op; + Dwarf_Small fp_extended_op; + Dwarf_Half fp_register; + + /* Value may be signed, depends on op. + Any applicable data_alignment_factor has + not been applied, this is the raw offset. */ + Dwarf_Unsigned fp_offset_or_block_len; + Dwarf_Small *fp_expr_block; + + Dwarf_Off fp_instr_offset; +} Dwarf_Frame_Op3; /* DWARF3 and DWARF2 compatible */ + +/* ***IMPORTANT NOTE, TARGET DEPENDENCY **** + DW_REG_TABLE_SIZE must be at least as large as + the number of registers + (DW_FRAME_LAST_REG_NUM) as defined in dwarf.h + Preferably identical to DW_FRAME_LAST_REG_NUM. + Ensure [0-DW_REG_TABLE_SIZE] does not overlap + DW_FRAME_UNDEFINED_VAL or DW_FRAME_SAME_VAL. + Also ensure DW_FRAME_REG_INITIAL_VALUE is set to what + is appropriate to your cpu. + For various CPUs DW_FRAME_UNDEFINED_VAL is correct + as the value for DW_FRAME_REG_INITIAL_VALUE. + + For consumer apps, this can be set dynamically: see + dwarf_set_frame_rule_table_size(); */ +#ifndef DW_REG_TABLE_SIZE +#define DW_REG_TABLE_SIZE 66 +#endif + +/* For MIPS, DW_FRAME_SAME_VAL is the correct default value + for a frame register value. For other CPUS another value + may be better, such as DW_FRAME_UNDEFINED_VAL. + See dwarf_set_frame_rule_table_size +*/ +#ifndef DW_FRAME_REG_INITIAL_VALUE +#define DW_FRAME_REG_INITIAL_VALUE DW_FRAME_SAME_VAL +#endif + +/* Taken as meaning 'undefined value', this is not + a column or register number. + Only present at libdwarf runtime in the consumer + interfaces. Never on disk. + DW_FRAME_* Values present on disk are in dwarf.h + Ensure this is > DW_REG_TABLE_SIZE (the reg table + size is changeable at runtime with the *reg3() interfaces, + and this value must be greater than the reg table size). +*/ +#define DW_FRAME_UNDEFINED_VAL 1034 + +/* Taken as meaning 'same value' as caller had, not a column + or register number. + Only present at libdwarf runtime in the consumer + interfaces. Never on disk. + DW_FRAME_* Values present on disk are in dwarf.h + Ensure this is > DW_REG_TABLE_SIZE (the reg table + size is changeable at runtime with the *reg3() interfaces, + and this value must be greater than the reg table size). +*/ +#define DW_FRAME_SAME_VAL 1035 + +/* For DWARF3 consumer interfaces, make the CFA a column with no + real table number. This is what should have been done + for the DWARF2 interfaces. This actually works for + both DWARF2 and DWARF3, but see the libdwarf documentation + on Dwarf_Regtable3 and dwarf_get_fde_info_for_reg3() + and dwarf_get_fde_info_for_all_regs3() + Do NOT use this with the older dwarf_get_fde_info_for_reg() + or dwarf_get_fde_info_for_all_regs() consumer interfaces. + Must be higher than any register count for *any* ABI + (ensures maximum applicability with minimum effort). + Ensure this is > DW_REG_TABLE_SIZE (the reg table + size is changeable at runtime with the *reg3() interfaces, + and this value must be greater than the reg table size). + Only present at libdwarf runtime in the consumer + interfaces. Never on disk. +*/ +#define DW_FRAME_CFA_COL3 1436 + +/* The following are all needed to evaluate DWARF3 register rules. +*/ +#define DW_EXPR_OFFSET 0 /* DWARF2 only sees this. */ +#define DW_EXPR_VAL_OFFSET 1 +#define DW_EXPR_EXPRESSION 2 +#define DW_EXPR_VAL_EXPRESSION 3 + +typedef struct Dwarf_Regtable_Entry_s { + /* For each index i (naming a hardware register with dwarf number + i) the following is true and defines the value of that register: + + If dw_regnum is Register DW_FRAME_UNDEFINED_VAL + it is not DWARF register number but + a place holder indicating the register has no defined value. + If dw_regnum is Register DW_FRAME_SAME_VAL + it is not DWARF register number but + a place holder indicating the register has the same + value in the previous frame. + + DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL are + only present at libdwarf runtime. Never on disk. + DW_FRAME_* Values present on disk are in dwarf.h + + Otherwise: the register number is a DWARF register number + (see ABI documents for how this translates to hardware/ + software register numbers in the machine hardware) + and the following applies: + + if dw_value_type == DW_EXPR_OFFSET (the only case for dwarf2): + If dw_offset_relevant is non-zero, then + the value is stored at at the address CFA+N where + N is a signed offset. + Rule: Offset(N) + If dw_offset_relevant is zero, then the value of the register + is the value of (DWARF) register number dw_regnum. + Rule: register(F) + Other values of dw_value_type are an error. + */ + Dwarf_Small dw_offset_relevant; + + /* For DWARF2, always 0 */ + Dwarf_Small dw_value_type; + + Dwarf_Half dw_regnum; + + /* The data type here should the larger of Dwarf_Addr + and Dwarf_Unsigned and Dwarf_Signed. */ + Dwarf_Addr dw_offset; +} Dwarf_Regtable_Entry; + +typedef struct Dwarf_Regtable_s { + struct Dwarf_Regtable_Entry_s rules[DW_REG_TABLE_SIZE]; +} Dwarf_Regtable; + +/* opaque type. Functional interface shown later. */ +struct Dwarf_Reg_value3_s; +typedef struct Dwarf_Reg_value3_s Dwarf_Reg_Value3; + +typedef struct Dwarf_Regtable_Entry3_s { +/* For each index i (naming a hardware register with dwarf number + i) the following is true and defines the value of that register: + + If dw_regnum is Register DW_FRAME_UNDEFINED_VAL + it is not DWARF register number but + a place holder indicating the register has no defined value. + If dw_regnum is Register DW_FRAME_SAME_VAL + it is not DWARF register number but + a place holder indicating the register has the same + value in the previous frame. + + DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL and + DW_FRAME_CFA_COL3 are only present at libdwarf runtime. + Never on disk. + DW_FRAME_* Values present on disk are in dwarf.h + Because DW_FRAME_SAME_VAL and DW_FRAME_UNDEFINED_VAL + and DW_FRAME_CFA_COL3 are definable at runtime + consider the names symbolic in this comment, not absolute. + + Otherwise: the register number is a DWARF register number + (see ABI documents for how this translates to hardware/ + software register numbers in the machine hardware) + and the following applies: + + In a cfa-defining entry (rt3_cfa_rule) the regnum is the + CFA 'register number'. Which is some 'normal' register, + not DW_FRAME_CFA_COL3, nor DW_FRAME_SAME_VAL, nor + DW_FRAME_UNDEFINED_VAL. + + If dw_value_type == DW_EXPR_OFFSET (the only possible case for + dwarf2): + If dw_offset_relevant is non-zero, then + the value is stored at at the address + CFA+N where N is a signed offset. + dw_regnum is the cfa register rule which means + one ignores dw_regnum and uses the CFA appropriately. + So dw_offset_or_block_len is a signed value, really, + and must be printed/evaluated as such. + Rule: Offset(N) + If dw_offset_relevant is zero, then the value of the register + is the value of (DWARF) register number dw_regnum. + Rule: register(R) + If dw_value_type == DW_EXPR_VAL_OFFSET + the value of this register is CFA +N where N is a signed offset. + dw_regnum is the cfa register rule which means + one ignores dw_regnum and uses the CFA appropriately. + Rule: val_offset(N) + If dw_value_type == DW_EXPR_EXPRESSION + The value of the register is the value at the address + computed by evaluating the DWARF expression E. + Rule: expression(E) + The expression E byte stream is pointed to by dw_block_ptr. + The expression length in bytes is given by + dw_offset_or_block_len. + If dw_value_type == DW_EXPR_VAL_EXPRESSION + The value of the register is the value + computed by evaluating the DWARF expression E. + Rule: val_expression(E) + The expression E byte stream is pointed to by dw_block_ptr. + The expression length in bytes is given by + dw_offset_or_block_len. + Other values of dw_value_type are an error. +*/ + Dwarf_Small dw_offset_relevant; + Dwarf_Small dw_value_type; + Dwarf_Half dw_regnum; + Dwarf_Unsigned dw_offset_or_block_len; + Dwarf_Ptr dw_block_ptr; + +}Dwarf_Regtable_Entry3; + +/* For the DWARF3 version, moved the DW_FRAME_CFA_COL + out of the array and into its own struct. + Having it part of the array is not very easy to work + with from a portability point of view: changing + the number for every architecture is a pain (if one fails + to set it correctly a register rule gets clobbered when + setting CFA). With MIPS it just happened to be easy to use + DW_FRAME_CFA_COL (it was wrong conceptually but it was easy...). + + rt3_rules and rt3_reg_table_size must be filled in before + calling libdwarf. Filled in with a pointer to an array + (pointer and array set up by the calling application) + of rt3_reg_table_size Dwarf_Regtable_Entry3_s structs. + libdwarf does not allocate or deallocate space for the + rules, you must do so. libdwarf will initialize the + contents rules array, you do not need to do so (though + if you choose to initialize the array somehow that is ok: + libdwarf will overwrite your initializations with its own). + +*/ +typedef struct Dwarf_Regtable3_s { + struct Dwarf_Regtable_Entry3_s rt3_cfa_rule; + + Dwarf_Half rt3_reg_table_size; + struct Dwarf_Regtable_Entry3_s * rt3_rules; +} Dwarf_Regtable3; + + +/* Use for DW_EPXR_STANDARD., DW_EXPR_VAL_OFFSET. + Returns DW_DLV_OK if the value is available. + If DW_DLV_OK returns the regnum and offset thru the pointers + (which the consumer must use appropriately). +*/ +int dwarf_frame_get_reg_register(struct Dwarf_Regtable_Entry3_s *reg_in, + Dwarf_Small *offset_relevant, + Dwarf_Half *regnum_out, + Dwarf_Signed *offset_out); + +/* Use for DW_EXPR_EXPRESSION, DW_EXPR_VAL_EXPRESSION. + Returns DW_DLV_OK if the value is available. + The caller must pass in the address of a valid + Dwarf_Block (the caller need not initialize it). +*/ +int dwarf_frame_get_reg_expression(struct Dwarf_Regtable_Entry3_s *reg_in, + Dwarf_Block *block_out); + + +/* For DW_DLC_SYMBOLIC_RELOCATIONS output to caller + v2, adding drd_length: some relocations are 4 and + some 8 bytes (pointers are 8, section offsets 4) in + some dwarf environments. (MIPS relocations are all one + size in any given ABI.) Changing drd_type to an unsigned char + to keep struct size down. +*/ +enum Dwarf_Rel_Type { + dwarf_drt_none, /* Should not get to caller */ + dwarf_drt_data_reloc, /* Simple normal relocation. */ + dwarf_drt_segment_rel, /* Special reloc, exceptions. */ + /* dwarf_drt_first_of_length_pair and drt_second + are for for the .word end - begin case. */ + dwarf_drt_first_of_length_pair, + dwarf_drt_second_of_length_pair +}; + +typedef struct Dwarf_P_Marker_s * Dwarf_P_Marker; +struct Dwarf_P_Marker_s { + Dwarf_Unsigned ma_marker; + Dwarf_Unsigned ma_offset; +}; + +typedef struct Dwarf_Relocation_Data_s * Dwarf_Relocation_Data; +struct Dwarf_Relocation_Data_s { + unsigned char drd_type; /* Cast to/from Dwarf_Rel_Type + to keep size small in struct. */ + unsigned char drd_length; /* Length in bytes of data being + relocated. 4 for 32bit data, + 8 for 64bit data. */ + Dwarf_Unsigned drd_offset; /* Where the data to reloc is. */ + Dwarf_Unsigned drd_symbol_index; +}; + +typedef struct Dwarf_P_String_Attr_s * Dwarf_P_String_Attr; +struct Dwarf_P_String_Attr_s { + Dwarf_Unsigned sa_offset; /* Offset of string attribute data */ + Dwarf_Unsigned sa_nbytes; +}; + + +/* Opaque types for Consumer Library. */ +typedef struct Dwarf_Debug_s* Dwarf_Debug; +typedef struct Dwarf_Die_s* Dwarf_Die; +typedef struct Dwarf_Line_s* Dwarf_Line; +typedef struct Dwarf_Global_s* Dwarf_Global; +typedef struct Dwarf_Func_s* Dwarf_Func; +typedef struct Dwarf_Type_s* Dwarf_Type; +typedef struct Dwarf_Var_s* Dwarf_Var; +typedef struct Dwarf_Weak_s* Dwarf_Weak; +typedef struct Dwarf_Error_s* Dwarf_Error; +typedef struct Dwarf_Attribute_s* Dwarf_Attribute; +typedef struct Dwarf_Abbrev_s* Dwarf_Abbrev; +typedef struct Dwarf_Fde_s* Dwarf_Fde; +typedef struct Dwarf_Cie_s* Dwarf_Cie; +typedef struct Dwarf_Arange_s* Dwarf_Arange; + +/* Opaque types for Producer Library. */ +typedef struct Dwarf_P_Debug_s* Dwarf_P_Debug; +typedef struct Dwarf_P_Die_s* Dwarf_P_Die; +typedef struct Dwarf_P_Attribute_s* Dwarf_P_Attribute; +typedef struct Dwarf_P_Fde_s* Dwarf_P_Fde; +typedef struct Dwarf_P_Expr_s* Dwarf_P_Expr; +typedef Dwarf_Unsigned Dwarf_Tag; + + +/* error handler function +*/ +typedef void (*Dwarf_Handler)(Dwarf_Error /*error*/, Dwarf_Ptr /*errarg*/); + + +/* Begin libdwarf Object File Interface declarations. + +As of February 2008 there are multiple dwarf_reader object access +initialization methods available: +The traditional dwarf_elf_init() and dwarf_init() and dwarf_finish() + which assume libelf and POSIX file access. +An object-file and library agnostic dwarf_object_init() and dwarf_object_finish() + which allow the coder to provide object access routines + abstracting away the elf interface. So there is no dependence in the + reader code on the object format and no dependence on libelf. + See the code in dwarf_elf_access.c and dwarf_original_elf_init.c + to see an example of initializing the structures mentioned below. + +Projects using dwarf_elf_init() or dwarf_init() can ignore +the Dwarf_Obj_Access* structures entirely as all these details +are completed for you. + +*/ + +typedef struct Dwarf_Obj_Access_Interface_s Dwarf_Obj_Access_Interface; +typedef struct Dwarf_Obj_Access_Methods_s Dwarf_Obj_Access_Methods; +typedef struct Dwarf_Obj_Access_Section_s Dwarf_Obj_Access_Section; + + +/* Used in the get_section interface function + in Dwarf_Obj_Access_Section_s. Since libdwarf + depends on standard DWARF section names an object + format that has no such names (but has some + method of setting up 'sections equivalents') + must arrange to return standard DWARF section + names in the 'name' field. libdwarf does + not free the strings in 'name'. */ +struct Dwarf_Obj_Access_Section_s { + /* addr is the virtual address of the first byte of + the section data. Usually zero when the address + makes no sense for a given section. */ + Dwarf_Addr addr; + + /* Size in bytes of the section. */ + Dwarf_Unsigned size; + + /* Having an accurate section name makes debugging of libdwarf easier. + and is essential to find the .debug_ sections. */ + const char* name; + /* Set link to zero if it is meaningless. If non-zero + it should be a link to a rela section or from symtab + to strtab. In Elf it is sh_link. */ + Dwarf_Unsigned link; + /* Elf sections that are tables have a non-zero entrysize so + the count of entries can be calculated even without + the right structure definition. If your object format + does not have this data leave this zero. */ + Dwarf_Unsigned entrysize; +}; + +/* Returned by the get_endianness function in + Dwarf_Obj_Access_Methods_s. */ +typedef enum { + DW_OBJECT_MSB, + DW_OBJECT_LSB +} Dwarf_Endianness; + +/* The functions we need to access object data from libdwarf are declared here. + + In these function pointer declarations + 'void *obj' is intended to be a pointer (the object field in + Dwarf_Obj_Access_Interface_s) + that hides the library-specific and object-specific data that makes + it possible to handle multiple object formats and multiple libraries. + It's not required that one handles multiple such in a single libdwarf + archive/shared-library (but not ruled out either). + See dwarf_elf_object_access_internals_t and dwarf_elf_access.c + for an example. + +*/ +struct Dwarf_Obj_Access_Methods_s { + /* + get_section_info + + Get address, size, and name info about a section. + + Parameters + section_index - Zero-based index. + return_section - Pointer to a structure in which section info + will be placed. Caller must provide a valid pointer to a + structure area. The structure's contents will be overwritten + by the call to get_section_info. + error - A pointer to an integer in which an error code may be stored. + + Return + DW_DLV_OK - Everything ok. + DW_DLV_ERROR - Error occurred. Use 'error' to determine the + libdwarf defined error. + DW_DLV_NO_ENTRY - No such section. */ + int (*get_section_info)(void* obj, Dwarf_Half section_index, + Dwarf_Obj_Access_Section* return_section, int* error); + /* + get_byte_order + + Get whether the object file represented by this interface is big-endian + (DW_OBJECT_MSB) or little endian (DW_OBJECT_LSB). + + Parameters + obj - Equivalent to 'this' in OO languages. + + Return + Endianness of object. Cannot fail. */ + Dwarf_Endianness (*get_byte_order)(void* obj); + /* + get_length_size + + Get the size of a length field in the underlying object file. + libdwarf currently supports * 4 and 8 byte sizes, but may + support larger in the future. + Perhaps the return type should be an enumeration? + + Parameters + obj - Equivalent to 'this' in OO languages. + + Return + Size of length. Cannot fail. */ + Dwarf_Small (*get_length_size)(void* obj); + /* + get_pointer_size + + Get the size of a pointer field in the underlying object file. + libdwarf currently supports 4 and 8 byte sizes. + Perhaps the return type should be an enumeration? + + Return + Size of pointer. Cannot fail. */ + Dwarf_Small (*get_pointer_size)(void* obj); + /* + get_section_count + + Get the number of sections in the object file. + + Parameters + + Return + Number of sections */ + Dwarf_Unsigned (*get_section_count)(void* obj); + /* + load_section + + Get a pointer to an array of bytes that represent the section. + + Parameters + section_index - Zero-based index. + return_data - The address of a pointer to which the section data block + will be assigned. + error - Pointer to an integer for returning libdwarf-defined + error numbers. + + Return + DW_DLV_OK - No error. + DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined + error number. + DW_DLV_NO_ENTRY - No such section. */ + int (*load_section)(void* obj, Dwarf_Half section_index, + Dwarf_Small** return_data, int* error); + + /** + relocate_a_section + If relocations are not supported leave this pointer NULL. + + Get a pointer to an array of bytes that represent the section. + + Parameters + section_index - Zero-based index of the section to be relocated. + error - Pointer to an integer for returning libdwarf-defined + error numbers. + + Return + DW_DLV_OK - No error. + DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined + error number. + DW_DLV_NO_ENTRY - No such section. */ + int (*relocate_a_section)(void* obj, Dwarf_Half section_index, + Dwarf_Debug dbg, + int* error); + +}; + + + +/* These structures are allocated and deallocated by your code + when you are using the libdwarf Object File Interface + [dwarf_object_init() and dwarf_object_finish()] directly. + dwarf_object_finish() does not free + struct Dwarf_Obj_Access_Interface_s or its content. + (libdwarf does record a pointer to this struct: you must + ensure that pointer remains valid for as long as + a libdwarf instance is open (meaning + after dwarf_init() and before dwarf_finish()). + + If you are reading Elf objects and libelf use dwarf_init() + or dwarf_elf_init() which take care of these details. +*/ +struct Dwarf_Obj_Access_Interface_s { + /* object is a void* as it hides the data the object access routines + need (which varies by library in use and object format). + */ + void* object; + const Dwarf_Obj_Access_Methods * methods; +}; + +/* End libdwarf Object File Interface */ + +/* + Dwarf_dealloc() alloc_type arguments. + Argument points to: +*/ +#define DW_DLA_STRING 0x01 /* char* */ +#define DW_DLA_LOC 0x02 /* Dwarf_Loc */ +#define DW_DLA_LOCDESC 0x03 /* Dwarf_Locdesc */ +#define DW_DLA_ELLIST 0x04 /* Dwarf_Ellist (not used)*/ +#define DW_DLA_BOUNDS 0x05 /* Dwarf_Bounds (not used) */ +#define DW_DLA_BLOCK 0x06 /* Dwarf_Block */ +#define DW_DLA_DEBUG 0x07 /* Dwarf_Debug */ +#define DW_DLA_DIE 0x08 /* Dwarf_Die */ +#define DW_DLA_LINE 0x09 /* Dwarf_Line */ +#define DW_DLA_ATTR 0x0a /* Dwarf_Attribute */ +#define DW_DLA_TYPE 0x0b /* Dwarf_Type (not used) */ +#define DW_DLA_SUBSCR 0x0c /* Dwarf_Subscr (not used) */ +#define DW_DLA_GLOBAL 0x0d /* Dwarf_Global */ +#define DW_DLA_ERROR 0x0e /* Dwarf_Error */ +#define DW_DLA_LIST 0x0f /* a list */ +#define DW_DLA_LINEBUF 0x10 /* Dwarf_Line* (not used) */ +#define DW_DLA_ARANGE 0x11 /* Dwarf_Arange */ +#define DW_DLA_ABBREV 0x12 /* Dwarf_Abbrev */ +#define DW_DLA_FRAME_OP 0x13 /* Dwarf_Frame_Op */ +#define DW_DLA_CIE 0x14 /* Dwarf_Cie */ +#define DW_DLA_FDE 0x15 /* Dwarf_Fde */ +#define DW_DLA_LOC_BLOCK 0x16 /* Dwarf_Loc Block (not used) */ +#define DW_DLA_FRAME_BLOCK 0x17 /* Dwarf_Frame Block (not used) */ +#define DW_DLA_FUNC 0x18 /* Dwarf_Func */ +#define DW_DLA_TYPENAME 0x19 /* Dwarf_Type */ +#define DW_DLA_VAR 0x1a /* Dwarf_Var */ +#define DW_DLA_WEAK 0x1b /* Dwarf_Weak */ +#define DW_DLA_ADDR 0x1c /* Dwarf_Addr sized entries */ +#define DW_DLA_RANGES 0x1d /* Dwarf_Ranges */ + +/* The augmenter string for CIE */ +#define DW_CIE_AUGMENTER_STRING_V0 "z" + +/* dwarf_init() access arguments +*/ +#define DW_DLC_READ 0 /* read only access */ +#define DW_DLC_WRITE 1 /* write only access */ +#define DW_DLC_RDWR 2 /* read/write access NOT SUPPORTED*/ + +/* dwarf_producer_init*() access flag modifiers + If HAVE_DWARF2_99_EXTENSION is defined at libdwarf build time + and DW_DLC_OFFSET_SIZE_64 is passed in producer_init() + flags then the DWARF3 64 bit offset extension is used + to generate 64 bit offsets. +*/ +#define DW_DLC_SIZE_64 0x40000000 /* 64-bit address-size target */ +#define DW_DLC_SIZE_32 0x20000000 /* 32-bit address-size target */ +#define DW_DLC_OFFSET_SIZE_64 0x10000000 /* 64-bit offset-size DWARF */ + +/* dwarf_producer_init*() access flag modifiers +*/ +#define DW_DLC_ISA_MIPS 0x00000000 /* MIPS target */ +#define DW_DLC_ISA_IA64 0x01000000 /* IA64 target */ +#define DW_DLC_STREAM_RELOCATIONS 0x02000000 /* Old style binary relocs */ + + /* Usable with assembly output because it is up to the producer to + deal with locations in whatever manner the producer code wishes. + Possibly emitting text an assembler will recognize. */ +#define DW_DLC_SYMBOLIC_RELOCATIONS 0x04000000 + +#define DW_DLC_TARGET_BIGENDIAN 0x08000000 /* Big endian target */ +#define DW_DLC_TARGET_LITTLEENDIAN 0x00100000 /* Little endian target */ + +#if 0 + /* + The libdwarf producer interfaces jumble these two semantics together in + confusing ways. We *should* have flags like these... + But changing the code means a lot of diffs. So for now, + we leave things as they are + */ + #define DW_DLC_SUN_OFFSET32 0x00010000 /* use 32-bit sec offsets */ + #define DW_DLC_SUN_OFFSET64 0x00020000 /* use 64-bit sec offsets */ + #define DW_DLC_SUN_POINTER32 0x00040000 /* use 4 for address_size */ + #define DW_DLC_SUN_POINTER64 0x00080000 /* use 8 for address_size */ +#endif + +/* dwarf_pcline() slide arguments +*/ +#define DW_DLS_BACKWARD -1 /* slide backward to find line */ +#define DW_DLS_NOSLIDE 0 /* match exactly without sliding */ +#define DW_DLS_FORWARD 1 /* slide forward to find line */ + +/* libdwarf error numbers +*/ +#define DW_DLE_NE 0 /* no error */ +#define DW_DLE_VMM 1 /* dwarf format/library version mismatch */ +#define DW_DLE_MAP 2 /* memory map failure */ +#define DW_DLE_LEE 3 /* libelf error */ +#define DW_DLE_NDS 4 /* no debug section */ +#define DW_DLE_NLS 5 /* no line section */ +#define DW_DLE_ID 6 /* invalid descriptor for query */ +#define DW_DLE_IOF 7 /* I/O failure */ +#define DW_DLE_MAF 8 /* memory allocation failure */ +#define DW_DLE_IA 9 /* invalid argument */ +#define DW_DLE_MDE 10 /* mangled debugging entry */ +#define DW_DLE_MLE 11 /* mangled line number entry */ +#define DW_DLE_FNO 12 /* file not open */ +#define DW_DLE_FNR 13 /* file not a regular file */ +#define DW_DLE_FWA 14 /* file open with wrong access */ +#define DW_DLE_NOB 15 /* not an object file */ +#define DW_DLE_MOF 16 /* mangled object file header */ +#define DW_DLE_EOLL 17 /* end of location list entries */ +#define DW_DLE_NOLL 18 /* no location list section */ +#define DW_DLE_BADOFF 19 /* Invalid offset */ +#define DW_DLE_EOS 20 /* end of section */ +#define DW_DLE_ATRUNC 21 /* abbreviations section appears truncated*/ +#define DW_DLE_BADBITC 22 /* Address size passed to dwarf bad*/ + /* It is not an allowed size (64 or 32) */ + /* Error codes defined by the current Libdwarf Implementation. */ +#define DW_DLE_DBG_ALLOC 23 +#define DW_DLE_FSTAT_ERROR 24 +#define DW_DLE_FSTAT_MODE_ERROR 25 +#define DW_DLE_INIT_ACCESS_WRONG 26 +#define DW_DLE_ELF_BEGIN_ERROR 27 +#define DW_DLE_ELF_GETEHDR_ERROR 28 +#define DW_DLE_ELF_GETSHDR_ERROR 29 +#define DW_DLE_ELF_STRPTR_ERROR 30 +#define DW_DLE_DEBUG_INFO_DUPLICATE 31 +#define DW_DLE_DEBUG_INFO_NULL 32 +#define DW_DLE_DEBUG_ABBREV_DUPLICATE 33 +#define DW_DLE_DEBUG_ABBREV_NULL 34 +#define DW_DLE_DEBUG_ARANGES_DUPLICATE 35 +#define DW_DLE_DEBUG_ARANGES_NULL 36 +#define DW_DLE_DEBUG_LINE_DUPLICATE 37 +#define DW_DLE_DEBUG_LINE_NULL 38 +#define DW_DLE_DEBUG_LOC_DUPLICATE 39 +#define DW_DLE_DEBUG_LOC_NULL 40 +#define DW_DLE_DEBUG_MACINFO_DUPLICATE 41 +#define DW_DLE_DEBUG_MACINFO_NULL 42 +#define DW_DLE_DEBUG_PUBNAMES_DUPLICATE 43 +#define DW_DLE_DEBUG_PUBNAMES_NULL 44 +#define DW_DLE_DEBUG_STR_DUPLICATE 45 +#define DW_DLE_DEBUG_STR_NULL 46 +#define DW_DLE_CU_LENGTH_ERROR 47 +#define DW_DLE_VERSION_STAMP_ERROR 48 +#define DW_DLE_ABBREV_OFFSET_ERROR 49 +#define DW_DLE_ADDRESS_SIZE_ERROR 50 +#define DW_DLE_DEBUG_INFO_PTR_NULL 51 +#define DW_DLE_DIE_NULL 52 +#define DW_DLE_STRING_OFFSET_BAD 53 +#define DW_DLE_DEBUG_LINE_LENGTH_BAD 54 +#define DW_DLE_LINE_PROLOG_LENGTH_BAD 55 +#define DW_DLE_LINE_NUM_OPERANDS_BAD 56 +#define DW_DLE_LINE_SET_ADDR_ERROR 57 /* No longer used. */ +#define DW_DLE_LINE_EXT_OPCODE_BAD 58 +#define DW_DLE_DWARF_LINE_NULL 59 +#define DW_DLE_INCL_DIR_NUM_BAD 60 +#define DW_DLE_LINE_FILE_NUM_BAD 61 +#define DW_DLE_ALLOC_FAIL 62 +#define DW_DLE_NO_CALLBACK_FUNC 63 +#define DW_DLE_SECT_ALLOC 64 +#define DW_DLE_FILE_ENTRY_ALLOC 65 +#define DW_DLE_LINE_ALLOC 66 +#define DW_DLE_FPGM_ALLOC 67 +#define DW_DLE_INCDIR_ALLOC 68 +#define DW_DLE_STRING_ALLOC 69 +#define DW_DLE_CHUNK_ALLOC 70 +#define DW_DLE_BYTEOFF_ERR 71 +#define DW_DLE_CIE_ALLOC 72 +#define DW_DLE_FDE_ALLOC 73 +#define DW_DLE_REGNO_OVFL 74 +#define DW_DLE_CIE_OFFS_ALLOC 75 +#define DW_DLE_WRONG_ADDRESS 76 +#define DW_DLE_EXTRA_NEIGHBORS 77 +#define DW_DLE_WRONG_TAG 78 +#define DW_DLE_DIE_ALLOC 79 +#define DW_DLE_PARENT_EXISTS 80 +#define DW_DLE_DBG_NULL 81 +#define DW_DLE_DEBUGLINE_ERROR 82 +#define DW_DLE_DEBUGFRAME_ERROR 83 +#define DW_DLE_DEBUGINFO_ERROR 84 +#define DW_DLE_ATTR_ALLOC 85 +#define DW_DLE_ABBREV_ALLOC 86 +#define DW_DLE_OFFSET_UFLW 87 +#define DW_DLE_ELF_SECT_ERR 88 +#define DW_DLE_DEBUG_FRAME_LENGTH_BAD 89 +#define DW_DLE_FRAME_VERSION_BAD 90 +#define DW_DLE_CIE_RET_ADDR_REG_ERROR 91 +#define DW_DLE_FDE_NULL 92 +#define DW_DLE_FDE_DBG_NULL 93 +#define DW_DLE_CIE_NULL 94 +#define DW_DLE_CIE_DBG_NULL 95 +#define DW_DLE_FRAME_TABLE_COL_BAD 96 +#define DW_DLE_PC_NOT_IN_FDE_RANGE 97 +#define DW_DLE_CIE_INSTR_EXEC_ERROR 98 +#define DW_DLE_FRAME_INSTR_EXEC_ERROR 99 +#define DW_DLE_FDE_PTR_NULL 100 +#define DW_DLE_RET_OP_LIST_NULL 101 +#define DW_DLE_LINE_CONTEXT_NULL 102 +#define DW_DLE_DBG_NO_CU_CONTEXT 103 +#define DW_DLE_DIE_NO_CU_CONTEXT 104 +#define DW_DLE_FIRST_DIE_NOT_CU 105 +#define DW_DLE_NEXT_DIE_PTR_NULL 106 +#define DW_DLE_DEBUG_FRAME_DUPLICATE 107 +#define DW_DLE_DEBUG_FRAME_NULL 108 +#define DW_DLE_ABBREV_DECODE_ERROR 109 +#define DW_DLE_DWARF_ABBREV_NULL 110 +#define DW_DLE_ATTR_NULL 111 +#define DW_DLE_DIE_BAD 112 +#define DW_DLE_DIE_ABBREV_BAD 113 +#define DW_DLE_ATTR_FORM_BAD 114 +#define DW_DLE_ATTR_NO_CU_CONTEXT 115 +#define DW_DLE_ATTR_FORM_SIZE_BAD 116 +#define DW_DLE_ATTR_DBG_NULL 117 +#define DW_DLE_BAD_REF_FORM 118 +#define DW_DLE_ATTR_FORM_OFFSET_BAD 119 +#define DW_DLE_LINE_OFFSET_BAD 120 +#define DW_DLE_DEBUG_STR_OFFSET_BAD 121 +#define DW_DLE_STRING_PTR_NULL 122 +#define DW_DLE_PUBNAMES_VERSION_ERROR 123 +#define DW_DLE_PUBNAMES_LENGTH_BAD 124 +#define DW_DLE_GLOBAL_NULL 125 +#define DW_DLE_GLOBAL_CONTEXT_NULL 126 +#define DW_DLE_DIR_INDEX_BAD 127 +#define DW_DLE_LOC_EXPR_BAD 128 +#define DW_DLE_DIE_LOC_EXPR_BAD 129 +#define DW_DLE_ADDR_ALLOC 130 +#define DW_DLE_OFFSET_BAD 131 +#define DW_DLE_MAKE_CU_CONTEXT_FAIL 132 +#define DW_DLE_REL_ALLOC 133 +#define DW_DLE_ARANGE_OFFSET_BAD 134 +#define DW_DLE_SEGMENT_SIZE_BAD 135 +#define DW_DLE_ARANGE_LENGTH_BAD 136 +#define DW_DLE_ARANGE_DECODE_ERROR 137 +#define DW_DLE_ARANGES_NULL 138 +#define DW_DLE_ARANGE_NULL 139 +#define DW_DLE_NO_FILE_NAME 140 +#define DW_DLE_NO_COMP_DIR 141 +#define DW_DLE_CU_ADDRESS_SIZE_BAD 142 +#define DW_DLE_INPUT_ATTR_BAD 143 +#define DW_DLE_EXPR_NULL 144 +#define DW_DLE_BAD_EXPR_OPCODE 145 +#define DW_DLE_EXPR_LENGTH_BAD 146 +#define DW_DLE_MULTIPLE_RELOC_IN_EXPR 147 +#define DW_DLE_ELF_GETIDENT_ERROR 148 +#define DW_DLE_NO_AT_MIPS_FDE 149 +#define DW_DLE_NO_CIE_FOR_FDE 150 +#define DW_DLE_DIE_ABBREV_LIST_NULL 151 +#define DW_DLE_DEBUG_FUNCNAMES_DUPLICATE 152 +#define DW_DLE_DEBUG_FUNCNAMES_NULL 153 +#define DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR 154 +#define DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD 155 +#define DW_DLE_FUNC_NULL 156 +#define DW_DLE_FUNC_CONTEXT_NULL 157 +#define DW_DLE_DEBUG_TYPENAMES_DUPLICATE 158 +#define DW_DLE_DEBUG_TYPENAMES_NULL 159 +#define DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR 160 +#define DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD 161 +#define DW_DLE_TYPE_NULL 162 +#define DW_DLE_TYPE_CONTEXT_NULL 163 +#define DW_DLE_DEBUG_VARNAMES_DUPLICATE 164 +#define DW_DLE_DEBUG_VARNAMES_NULL 165 +#define DW_DLE_DEBUG_VARNAMES_VERSION_ERROR 166 +#define DW_DLE_DEBUG_VARNAMES_LENGTH_BAD 167 +#define DW_DLE_VAR_NULL 168 +#define DW_DLE_VAR_CONTEXT_NULL 169 +#define DW_DLE_DEBUG_WEAKNAMES_DUPLICATE 170 +#define DW_DLE_DEBUG_WEAKNAMES_NULL 171 +#define DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR 172 +#define DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD 173 +#define DW_DLE_WEAK_NULL 174 +#define DW_DLE_WEAK_CONTEXT_NULL 175 +#define DW_DLE_LOCDESC_COUNT_WRONG 176 +#define DW_DLE_MACINFO_STRING_NULL 177 +#define DW_DLE_MACINFO_STRING_EMPTY 178 +#define DW_DLE_MACINFO_INTERNAL_ERROR_SPACE 179 +#define DW_DLE_MACINFO_MALLOC_FAIL 180 +#define DW_DLE_DEBUGMACINFO_ERROR 181 +#define DW_DLE_DEBUG_MACRO_LENGTH_BAD 182 +#define DW_DLE_DEBUG_MACRO_MAX_BAD 183 +#define DW_DLE_DEBUG_MACRO_INTERNAL_ERR 184 +#define DW_DLE_DEBUG_MACRO_MALLOC_SPACE 185 +#define DW_DLE_DEBUG_MACRO_INCONSISTENT 186 +#define DW_DLE_DF_NO_CIE_AUGMENTATION 187 +#define DW_DLE_DF_REG_NUM_TOO_HIGH 188 +#define DW_DLE_DF_MAKE_INSTR_NO_INIT 189 +#define DW_DLE_DF_NEW_LOC_LESS_OLD_LOC 190 +#define DW_DLE_DF_POP_EMPTY_STACK 191 +#define DW_DLE_DF_ALLOC_FAIL 192 +#define DW_DLE_DF_FRAME_DECODING_ERROR 193 +#define DW_DLE_DEBUG_LOC_SECTION_SHORT 194 +#define DW_DLE_FRAME_AUGMENTATION_UNKNOWN 195 +#define DW_DLE_PUBTYPE_CONTEXT 196 /* Unused. */ +#define DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD 197 +#define DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR 198 +#define DW_DLE_DEBUG_PUBTYPES_DUPLICATE 199 +#define DW_DLE_FRAME_CIE_DECODE_ERROR 200 +#define DW_DLE_FRAME_REGISTER_UNREPRESENTABLE 201 +#define DW_DLE_FRAME_REGISTER_COUNT_MISMATCH 202 +#define DW_DLE_LINK_LOOP 203 +#define DW_DLE_STRP_OFFSET_BAD 204 +#define DW_DLE_DEBUG_RANGES_DUPLICATE 205 +#define DW_DLE_DEBUG_RANGES_OFFSET_BAD 206 +#define DW_DLE_DEBUG_RANGES_MISSING_END 207 +#define DW_DLE_DEBUG_RANGES_OUT_OF_MEM 208 +#define DW_DLE_DEBUG_SYMTAB_ERR 209 +#define DW_DLE_DEBUG_STRTAB_ERR 210 +#define DW_DLE_RELOC_MISMATCH_INDEX 211 +#define DW_DLE_RELOC_MISMATCH_RELOC_INDEX 212 +#define DW_DLE_RELOC_MISMATCH_STRTAB_INDEX 213 +#define DW_DLE_RELOC_SECTION_MISMATCH 214 +#define DW_DLE_RELOC_SECTION_MISSING_INDEX 215 +#define DW_DLE_RELOC_SECTION_LENGTH_ODD 216 +#define DW_DLE_RELOC_SECTION_PTR_NULL 217 +#define DW_DLE_RELOC_SECTION_MALLOC_FAIL 218 +#define DW_DLE_NO_ELF64_SUPPORT 219 +#define DW_DLE_MISSING_ELF64_SUPPORT 220 +#define DW_DLE_ORPHAN_FDE 221 +#define DW_DLE_DUPLICATE_INST_BLOCK 222 +#define DW_DLE_BAD_REF_SIG8_FORM 223 +#define DW_DLE_ATTR_EXPRLOC_FORM_BAD 224 +#define DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD 225 +#define DW_DLE_NOT_REF_FORM 226 +#define DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE 227 +#define DW_DLE_REF_SIG8_NOT_HANDLED 228 +#define DW_DLE_DEBUG_FRAME_POSSIBLE_ADDRESS_BOTCH 229 +#define DW_DLE_LOC_BAD_TERMINATION 230 +#define DW_DLE_SYMTAB_SECTION_LENGTH_ODD 231 +#define DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD 232 +#define DW_DLE_RELOC_SECTION_RELOC_TARGET_SIZE_UNKNOWN 233 +#define DW_DLE_SYMTAB_SECTION_ENTRYSIZE_ZERO 234 +#define DW_DLE_LINE_NUMBER_HEADER_ERROR 235 +#define DW_DLE_DEBUG_TYPES_NULL 236 +#define DW_DLE_DEBUG_TYPES_DUPLICATE 237 +#define DW_DLE_DEBUG_TYPES_ONLY_DWARF4 238 +#define DW_DLE_DEBUG_TYPEOFFSET_BAD 239 +#define DW_DLE_GNU_OPCODE_ERROR 240 + + + /* DW_DLE_LAST MUST EQUAL LAST ERROR NUMBER */ +#define DW_DLE_LAST 239 +#define DW_DLE_LO_USER 0x10000 + + /* Taken as meaning 'undefined value', this is not + a column or register number. + Only present at libdwarf runtime. Never on disk. + DW_FRAME_* Values present on disk are in dwarf.h + */ +#define DW_FRAME_UNDEFINED_VAL 1034 + + /* Taken as meaning 'same value' as caller had, not a column + or register number + Only present at libdwarf runtime. Never on disk. + DW_FRAME_* Values present on disk are in dwarf.h + */ +#define DW_FRAME_SAME_VAL 1035 + + + +/* error return values +*/ +#define DW_DLV_BADADDR (~(Dwarf_Addr)0) + /* for functions returning target address */ + +#define DW_DLV_NOCOUNT ((Dwarf_Signed)-1) + /* for functions returning count */ + +#define DW_DLV_BADOFFSET (~(Dwarf_Off)0) + /* for functions returning offset */ + +/* standard return values for functions */ +#define DW_DLV_NO_ENTRY -1 +#define DW_DLV_OK 0 +#define DW_DLV_ERROR 1 + +/* Special values for offset_into_exception_table field of dwarf fde's. */ +/* The following value indicates that there is no Exception table offset + associated with a dwarf frame. */ +#define DW_DLX_NO_EH_OFFSET (-1LL) +/* The following value indicates that the producer was unable to analyse the + source file to generate Exception tables for this function. */ +#define DW_DLX_EH_OFFSET_UNAVAILABLE (-2LL) + + +/*===========================================================================*/ +/* Dwarf consumer interface initialization and termination operations */ + +/* Initialization based on Unix open fd (using libelf internally). */ +int dwarf_init(int /*fd*/, + Dwarf_Unsigned /*access*/, + Dwarf_Handler /*errhand*/, + Dwarf_Ptr /*errarg*/, + Dwarf_Debug* /*dbg*/, + Dwarf_Error* /*error*/); + +/* Initialization based on libelf/sgi-fastlibelf open pointer. */ +int dwarf_elf_init(dwarf_elf_handle /*elf*/, + Dwarf_Unsigned /*access*/, + Dwarf_Handler /*errhand*/, + Dwarf_Ptr /*errarg*/, + Dwarf_Debug* /*dbg*/, + Dwarf_Error* /*error*/); + +/* Undocumented function for memory allocator. */ +void dwarf_print_memory_stats(Dwarf_Debug /*dbg*/); + +int dwarf_get_elf(Dwarf_Debug /*dbg*/, + dwarf_elf_handle* /*return_elfptr*/, + Dwarf_Error* /*error*/); + +int dwarf_finish(Dwarf_Debug /*dbg*/, Dwarf_Error* /*error*/); + + +int dwarf_object_init(Dwarf_Obj_Access_Interface* /* obj */, + Dwarf_Handler /* errhand */, + Dwarf_Ptr /* errarg */, + Dwarf_Debug* /* dbg */, + Dwarf_Error* /* error */); + +int dwarf_object_finish(Dwarf_Debug /* dbg */, + Dwarf_Error* /* error */); + +/* Die traversal operations. + dwarf_next_cu_header_b() traverses debug_info CU headers. + */ +int dwarf_next_cu_header_b(Dwarf_Debug /*dbg*/, + Dwarf_Unsigned* /*cu_header_length*/, + Dwarf_Half* /*version_stamp*/, + Dwarf_Off* /*abbrev_offset*/, + Dwarf_Half* /*address_size*/, + Dwarf_Half* /*length_size*/, + Dwarf_Half* /*extension_size*/, + Dwarf_Unsigned* /*next_cu_header_offset*/, + Dwarf_Error* /*error*/); + +/* dwarf_next_cu_header_types() traverses debug_types CU headers. + New in October, 2011 + */ +int dwarf_next_cu_header_c(Dwarf_Debug /*dbg*/, + Dwarf_Bool /*is_info*/, + Dwarf_Unsigned* /*cu_header_length*/, + Dwarf_Half* /*version_stamp*/, + Dwarf_Off* /*abbrev_offset*/, + Dwarf_Half* /*address_size*/, + Dwarf_Half* /*length_size*/, + Dwarf_Half* /*extension_size*/, + Dwarf_Sig8* /*type signature*/, + Dwarf_Unsigned* /*typeoffset*/, + Dwarf_Unsigned* /*next_cu_header_offset*/, + Dwarf_Error* /*error*/); +/* The following is obsolete, though supported. November 2009. */ +int dwarf_next_cu_header(Dwarf_Debug /*dbg*/, + Dwarf_Unsigned* /*cu_header_length*/, + Dwarf_Half* /*version_stamp*/, + Dwarf_Off* /*abbrev_offset*/, + Dwarf_Half* /*address_size*/, + Dwarf_Unsigned* /*next_cu_header_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_siblingof(Dwarf_Debug /*dbg*/, + Dwarf_Die /*die*/, + Dwarf_Die* /*return_siblingdie*/, + Dwarf_Error* /*error*/); +/* dwarf_siblingof_b new October 2011. */ +int dwarf_siblingof_b(Dwarf_Debug /*dbg*/, + Dwarf_Die /*die*/, + Dwarf_Bool /*is_info*/, + Dwarf_Die* /*return_siblingdie*/, + Dwarf_Error* /*error*/); + +int dwarf_child(Dwarf_Die /*die*/, + Dwarf_Die* /*return_childdie*/, + Dwarf_Error* /*error*/); + +/* Finding die given global (not CU-relative) offset. + Applies only to debug_info. */ +int dwarf_offdie(Dwarf_Debug /*dbg*/, + Dwarf_Off /*offset*/, + Dwarf_Die* /*return_die*/, + Dwarf_Error* /*error*/); + +/* dwarf_offdie_b() new October 2011 */ +/* Finding die given global (not CU-relative) offset. + Applies to debug_info (is_info true) or debug_types (is_info false). */ +int dwarf_offdie_b(Dwarf_Debug /*dbg*/, + Dwarf_Off /*offset*/, + Dwarf_Bool /*is_info*/, + Dwarf_Die* /*return_die*/, + Dwarf_Error* /*error*/); + +/* Returns the is_info flag through the pointer if the function returns + DW_DLV_OK. Needed so client software knows if a DIE is in debug_info + or debug_types. + New October 2011. */ +Dwarf_Bool dwarf_get_die_infotypes_flag(Dwarf_Die /*die*/); + +/* Higher level functions (Unimplemented) */ +int dwarf_pcfile(Dwarf_Debug /*dbg*/, + Dwarf_Addr /*pc*/, + Dwarf_Die* /*return_die*/, + Dwarf_Error* /*error*/); + +/* Unimplemented */ +int dwarf_pcsubr(Dwarf_Debug /*dbg*/, + Dwarf_Addr /*pc*/, + Dwarf_Die* /*return_die*/, + Dwarf_Error* /*error*/); + +/* Unimplemented */ +int dwarf_pcscope(Dwarf_Debug /*dbg*/, + Dwarf_Addr /*pc*/, + Dwarf_Die* /*return_die*/, + Dwarf_Error* /*error*/); + +/* operations on DIEs */ +int dwarf_tag(Dwarf_Die /*die*/, + Dwarf_Half* /*return_tag*/, + Dwarf_Error* /*error*/); + +/* utility? */ +/* dwarf_dieoffset returns the global debug_info + section offset, not the CU relative offset. */ +int dwarf_dieoffset(Dwarf_Die /*die*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +/* dwarf_CU_dieoffset_given_die returns + the global debug_info section offset of the CU die + that is the CU containing the given_die + (the passed in DIE can be any DIE). + This information makes it possible for a consumer to + find and print CU context information for any die. + See also dwarf_get_cu_die_offset_given_cu_header_offset(). */ +int dwarf_CU_dieoffset_given_die(Dwarf_Die /*given_die*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +/* dwarf_die_CU_offset returns the CU relative offset + not the global debug_info section offset, given + any DIE in the CU. See also dwarf_CU_dieoffset_given_die(). + */ +int dwarf_die_CU_offset(Dwarf_Die /*die*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_die_CU_offset_range(Dwarf_Die /*die*/, + Dwarf_Off* /*return_CU_header_offset*/, + Dwarf_Off* /*return_CU_length_bytes*/, + Dwarf_Error* /*error*/); + +int dwarf_attr (Dwarf_Die /*die*/, + Dwarf_Half /*attr*/, + Dwarf_Attribute * /*returned_attr*/, + Dwarf_Error* /*error*/); + +int dwarf_diename(Dwarf_Die /*die*/, + char ** /*diename*/, + Dwarf_Error* /*error*/); + +/* Returns the abbrev code of the die. Cannot fail. */ +int dwarf_die_abbrev_code(Dwarf_Die /*die */); + +/* Returns a flag through ab_has_child. Non-zero if + the DIE has children, zero if it does not. */ +int dwarf_die_abbrev_children_flag(Dwarf_Die /*die*/, + Dwarf_Half * /*ab_has_child*/); + +/* Validate the sibling DIE. This only makes sense to call + if the sibling's DIEs have been travsersed and + dwarf_child() called on each, + so that the last DIE dwarf_child saw was the last. + Essentially ensuring that (after such traversal) that we + are in the same place a sibling attribute would identify. + In case we return DW_DLV_ERROR, the global offset of the last + DIE traversed by dwarf_child is returned through *offset */ +int dwarf_validate_die_sibling(Dwarf_Die /*sibling*/,Dwarf_Off* /*offset*/); + +/* convenience functions, alternative to using dwarf_attrlist() */ +int dwarf_hasattr(Dwarf_Die /*die*/, + Dwarf_Half /*attr*/, + Dwarf_Bool * /*returned_bool*/, + Dwarf_Error* /*error*/); + +/* dwarf_loclist_n preferred over dwarf_loclist */ +int dwarf_loclist_n(Dwarf_Attribute /*attr*/, + Dwarf_Locdesc*** /*llbuf*/, + Dwarf_Signed * /*locCount*/, + Dwarf_Error* /*error*/); + +int dwarf_loclist(Dwarf_Attribute /*attr*/, /* inflexible! */ + Dwarf_Locdesc** /*llbuf*/, + Dwarf_Signed * /*locCount*/, + Dwarf_Error* /*error*/); + +/* Extracts a dwarf expression from an expression byte stream. + Useful to get expressions from DW_CFA_def_cfa_expression + DW_CFA_expression DW_CFA_val_expression expression bytes. + 27 April 2009: dwarf_loclist_from_expr() interface with + no addr_size is obsolete but supported, + use dwarf_loclist_from_expr_a() instead. +*/ +int dwarf_loclist_from_expr(Dwarf_Debug dbg, + Dwarf_Ptr expression_in, + Dwarf_Unsigned expression_length, + Dwarf_Locdesc ** llbuf, + Dwarf_Signed * listlen, Dwarf_Error * error); + +/* dwarf_loclist_from_expr_a() new 27 Apr 2009: added addr_size argument. */ +int dwarf_loclist_from_expr_a(Dwarf_Debug dbg, + Dwarf_Ptr expression_in, + Dwarf_Unsigned expression_length, + Dwarf_Half addr_size, + Dwarf_Locdesc ** llbuf, + Dwarf_Signed * listlen, Dwarf_Error * error); + +/* Unimplemented */ +int dwarf_stringlen(Dwarf_Die /*die*/, + Dwarf_Locdesc ** /*returned_locdesc*/, + Dwarf_Error* /*error*/); + +/* Unimplemented */ +int dwarf_subscrcnt(Dwarf_Die /*die*/, + Dwarf_Signed * /*returned_count*/, + Dwarf_Error* /*error*/); + +/* Unimplemented */ +int dwarf_nthsubscr(Dwarf_Die /*die*/, + Dwarf_Unsigned /*ssndx*/, + Dwarf_Die * /*returned_die*/, + Dwarf_Error* /*error*/); + +int dwarf_lowpc(Dwarf_Die /*die*/, + Dwarf_Addr * /*returned_addr*/, + Dwarf_Error* /*error*/); + +int dwarf_highpc(Dwarf_Die /*die*/, + Dwarf_Addr * /*returned_addr*/, + Dwarf_Error* /*error*/); + +int dwarf_bytesize(Dwarf_Die /*die*/, + Dwarf_Unsigned * /*returned_size*/, + Dwarf_Error* /*error*/); + +/* Unimplemented */ +int dwarf_isbitfield(Dwarf_Die /*die*/, + Dwarf_Bool * /*returned_bool*/, + Dwarf_Error* /*error*/); + +int dwarf_bitsize(Dwarf_Die /*die*/, + Dwarf_Unsigned * /*returned_size*/, + Dwarf_Error* /*error*/); + +int dwarf_bitoffset(Dwarf_Die /*die*/, + Dwarf_Unsigned * /*returned_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_srclang(Dwarf_Die /*die*/, + Dwarf_Unsigned * /*returned_lang*/, + Dwarf_Error* /*error*/); + +int dwarf_arrayorder(Dwarf_Die /*die*/, + Dwarf_Unsigned * /*returned_order*/, + Dwarf_Error* /*error*/); + +/* end of convenience function list */ + +/* this is the main interface to attributes of a DIE */ +int dwarf_attrlist(Dwarf_Die /*die*/, + Dwarf_Attribute** /*attrbuf*/, + Dwarf_Signed * /*attrcount*/, + Dwarf_Error* /*error*/); + +/* query operations for attributes */ +int dwarf_hasform(Dwarf_Attribute /*attr*/, + Dwarf_Half /*form*/, + Dwarf_Bool * /*returned_bool*/, + Dwarf_Error* /*error*/); + +int dwarf_whatform(Dwarf_Attribute /*attr*/, + Dwarf_Half * /*returned_form*/, + Dwarf_Error* /*error*/); + +int dwarf_whatform_direct(Dwarf_Attribute /*attr*/, + Dwarf_Half * /*returned_form*/, + Dwarf_Error* /*error*/); + +int dwarf_whatattr(Dwarf_Attribute /*attr*/, + Dwarf_Half * /*returned_attr_num*/, + Dwarf_Error* /*error*/); + +/* + The following are concerned with the Primary Interface: getting + the actual data values. One function per 'kind' of FORM. +*/ +/* dwarf_formref returns, thru return_offset, a CU-relative offset + and does not allow DW_FORM_ref_addr*/ +int dwarf_formref(Dwarf_Attribute /*attr*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); +/* dwarf_global_formref returns, thru return_offset, + a debug_info-relative offset and does allow all reference forms*/ +int dwarf_global_formref(Dwarf_Attribute /*attr*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +/* dwarf_formsig8 returns in the caller-provided 8 byte area + the 8 bytes of a DW_FORM_ref_sig8. Not a string. */ +int dwarf_formsig8(Dwarf_Attribute /*attr*/, + Dwarf_Sig8 * /*returned sig bytes*/, + Dwarf_Error* /*error*/); + +int dwarf_formaddr(Dwarf_Attribute /*attr*/, + Dwarf_Addr * /*returned_addr*/, + Dwarf_Error* /*error*/); + +int dwarf_formflag(Dwarf_Attribute /*attr*/, + Dwarf_Bool * /*returned_bool*/, + Dwarf_Error* /*error*/); + +int dwarf_formudata(Dwarf_Attribute /*attr*/, + Dwarf_Unsigned * /*returned_val*/, + Dwarf_Error* /*error*/); + +int dwarf_formsdata(Dwarf_Attribute /*attr*/, + Dwarf_Signed * /*returned_val*/, + Dwarf_Error* /*error*/); + +int dwarf_formblock(Dwarf_Attribute /*attr*/, + Dwarf_Block ** /*returned_block*/, + Dwarf_Error* /*error*/); + +int dwarf_formstring(Dwarf_Attribute /*attr*/, + char ** /*returned_string*/, + Dwarf_Error* /*error*/); + +int dwarf_formexprloc(Dwarf_Attribute /*attr*/, + Dwarf_Unsigned * /*return_exprlen*/, + Dwarf_Ptr * /*block_ptr*/, + Dwarf_Error * /*error*/); + + +/* end attribute query operations. */ + +/* line number operations */ +/* dwarf_srclines is the normal interface */ +int dwarf_srclines(Dwarf_Die /*die*/, + Dwarf_Line** /*linebuf*/, + Dwarf_Signed * /*linecount*/, + Dwarf_Error* /*error*/); + +/* dwarf_srclines_dealloc, created July 2005, is the new + method for deallocating what dwarf_srclines returns. + More complete free than using dwarf_dealloc directly. */ +void dwarf_srclines_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Line* /*linebuf*/, + Dwarf_Signed /*count */); + + +int dwarf_srcfiles(Dwarf_Die /*die*/, + char*** /*srcfiles*/, + Dwarf_Signed * /*filecount*/, + Dwarf_Error* /*error*/); + +/* Unimplemented. */ +int dwarf_dieline(Dwarf_Die /*die*/, + Dwarf_Line * /*returned_line*/, + Dwarf_Error * /*error*/); + +int dwarf_linebeginstatement(Dwarf_Line /*line*/, + Dwarf_Bool * /*returned_bool*/, + Dwarf_Error* /*error*/); + +int dwarf_lineendsequence(Dwarf_Line /*line*/, + Dwarf_Bool * /*returned_bool*/, + Dwarf_Error* /*error*/); + +int dwarf_lineno(Dwarf_Line /*line*/, + Dwarf_Unsigned * /*returned_lineno*/, + Dwarf_Error* /*error*/); + +int dwarf_line_srcfileno(Dwarf_Line /*line*/, + Dwarf_Unsigned * /*ret_fileno*/, + Dwarf_Error * /*error*/); + +/* Is the line address from DW_LNS_set_address? */ +int dwarf_line_is_addr_set(Dwarf_Line /*line*/, + Dwarf_Bool * /*is_addr_set*/, + Dwarf_Error * /*error*/); + +int dwarf_lineaddr(Dwarf_Line /*line*/, + Dwarf_Addr * /*returned_addr*/, + Dwarf_Error* /*error*/); + +/* dwarf_lineoff() is OBSOLETE as of December 2011. Do not use. */ +int dwarf_lineoff(Dwarf_Line /*line*/, + Dwarf_Signed * /*returned_lineoffset*/, + Dwarf_Error* /*error*/); +/* dwarf_lineoff_b() correctly returns an unsigned column number + through the pointer returned_offset. + dwarf_lineoff_b() is new in December 2011. */ +int dwarf_lineoff_b(Dwarf_Line /*line*/, + Dwarf_Unsigned * /*returned_lineoffset*/, + Dwarf_Error* /*error*/); + +int dwarf_linesrc(Dwarf_Line /*line*/, + char ** /*returned_name*/, + Dwarf_Error* /*error*/); + +int dwarf_lineblock(Dwarf_Line /*line*/, + Dwarf_Bool * /*returned_bool*/, + Dwarf_Error* /*error*/); + +/* We gather these into one call as it's likely one + will want all or none of them. */ +int dwarf_prologue_end_etc(Dwarf_Line /* line */, + Dwarf_Bool * /*prologue_end*/, + Dwarf_Bool * /*eplogue_begin*/, + Dwarf_Unsigned * /* isa */, + Dwarf_Unsigned * /* discriminator */, + Dwarf_Error * /*error*/); + +/* Tertiary interface to line info */ +/* Unimplemented */ +int dwarf_pclines(Dwarf_Debug /*dbg*/, + Dwarf_Addr /*pc*/, + Dwarf_Line** /*linebuf*/, + Dwarf_Signed * /*linecount*/, + Dwarf_Signed /*slide*/, + Dwarf_Error* /*error*/); +/* end line number operations */ + +/* global name space operations (.debug_pubnames access) */ +int dwarf_get_globals(Dwarf_Debug /*dbg*/, + Dwarf_Global** /*globals*/, + Dwarf_Signed * /*number_of_globals*/, + Dwarf_Error* /*error*/); +void dwarf_globals_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Global* /*globals*/, + Dwarf_Signed /*number_of_globals*/); + +int dwarf_globname(Dwarf_Global /*glob*/, + char ** /*returned_name*/, + Dwarf_Error* /*error*/); + +int dwarf_global_die_offset(Dwarf_Global /*global*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error * /*error*/); + +/* This returns the CU die global offset if one knows the + CU header global offset. + See also dwarf_CU_dieoffset_given_die(). */ +int dwarf_get_cu_die_offset_given_cu_header_offset( + Dwarf_Debug /*dbg*/, + Dwarf_Off /*in_cu_header_offset*/, + Dwarf_Off * /*out_cu_die_offset*/, + Dwarf_Error * /*err*/); + +/* The _b form is new October 2011. */ +int dwarf_get_cu_die_offset_given_cu_header_offset_b( + Dwarf_Debug /*dbg*/, + Dwarf_Off /*in_cu_header_offset*/, + Dwarf_Bool /*is_info. True means look in debug_Info, + false use debug_types.*/, + Dwarf_Off * /*out_cu_die_offset*/, + Dwarf_Error * /*err*/); + +#ifdef __sgi /* pragma is sgi MIPS only */ +#pragma optional dwarf_get_cu_die_offset_given_cu_header_offset +#endif + +int dwarf_global_cu_offset(Dwarf_Global /*global*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_global_name_offsets(Dwarf_Global /*global*/, + char ** /*returned_name*/, + Dwarf_Off* /*die_offset*/, + Dwarf_Off* /*cu_offset*/, + Dwarf_Error* /*error*/); + +/* Static function name operations. */ +int dwarf_get_funcs(Dwarf_Debug /*dbg*/, + Dwarf_Func** /*funcs*/, + Dwarf_Signed * /*number_of_funcs*/, + Dwarf_Error* /*error*/); +void dwarf_funcs_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Func* /*funcs*/, + Dwarf_Signed /*number_of_funcs*/); + +int dwarf_funcname(Dwarf_Func /*func*/, + char ** /*returned_name*/, + Dwarf_Error* /*error*/); + +int dwarf_func_die_offset(Dwarf_Func /*func*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_func_cu_offset(Dwarf_Func /*func*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_func_name_offsets(Dwarf_Func /*func*/, + char ** /*returned_name*/, + Dwarf_Off* /*die_offset*/, + Dwarf_Off* /*cu_offset*/, + Dwarf_Error* /*error*/); + +/* User-defined type name operations, SGI IRIX .debug_typenames section. + Same content as DWARF3 .debug_pubtypes, but defined years before + .debug_pubtypes was defined. SGI IRIX only. */ +int dwarf_get_types(Dwarf_Debug /*dbg*/, + Dwarf_Type** /*types*/, + Dwarf_Signed * /*number_of_types*/, + Dwarf_Error* /*error*/); +void dwarf_types_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Type* /*types*/, + Dwarf_Signed /*number_of_types*/); + + +int dwarf_typename(Dwarf_Type /*type*/, + char ** /*returned_name*/, + Dwarf_Error* /*error*/); + +int dwarf_type_die_offset(Dwarf_Type /*type*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_type_cu_offset(Dwarf_Type /*type*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_type_name_offsets(Dwarf_Type /*type*/, + char ** /*returned_name*/, + Dwarf_Off* /*die_offset*/, + Dwarf_Off* /*cu_offset*/, + Dwarf_Error* /*error*/); + +/* User-defined type name operations, DWARF3 .debug_pubtypes section. +*/ +int dwarf_get_pubtypes(Dwarf_Debug /*dbg*/, + Dwarf_Type** /*types*/, + Dwarf_Signed * /*number_of_types*/, + Dwarf_Error* /*error*/); +void dwarf_pubtypes_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Type* /*pubtypes*/, + Dwarf_Signed /*number_of_pubtypes*/); + + +int dwarf_pubtypename(Dwarf_Type /*type*/, + char ** /*returned_name*/, + Dwarf_Error* /*error*/); + +int dwarf_pubtype_die_offset(Dwarf_Type /*type*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_pubtype_cu_offset(Dwarf_Type /*type*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_pubtype_name_offsets(Dwarf_Type /*type*/, + char ** /*returned_name*/, + Dwarf_Off* /*die_offset*/, + Dwarf_Off* /*cu_offset*/, + Dwarf_Error* /*error*/); + +/* File-scope static variable name operations. */ +int dwarf_get_vars(Dwarf_Debug /*dbg*/, + Dwarf_Var** /*vars*/, + Dwarf_Signed * /*number_of_vars*/, + Dwarf_Error* /*error*/); +void dwarf_vars_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Var* /*vars*/, + Dwarf_Signed /*number_of_vars*/); + + +int dwarf_varname(Dwarf_Var /*var*/, + char ** /*returned_name*/, + Dwarf_Error* /*error*/); + +int dwarf_var_die_offset(Dwarf_Var /*var*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_var_cu_offset(Dwarf_Var /*var*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_var_name_offsets(Dwarf_Var /*var*/, + char ** /*returned_name*/, + Dwarf_Off* /*die_offset*/, + Dwarf_Off* /*cu_offset*/, + Dwarf_Error* /*error*/); + +/* weak name operations. */ +int dwarf_get_weaks(Dwarf_Debug /*dbg*/, + Dwarf_Weak** /*weaks*/, + Dwarf_Signed * /*number_of_weaks*/, + Dwarf_Error* /*error*/); +void dwarf_weaks_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Weak* /*weaks*/, + Dwarf_Signed /*number_of_weaks*/); + + +int dwarf_weakname(Dwarf_Weak /*weak*/, + char ** /*returned_name*/, + Dwarf_Error* /*error*/); + +int dwarf_weak_die_offset(Dwarf_Weak /*weak*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_weak_cu_offset(Dwarf_Weak /*weak*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_weak_name_offsets(Dwarf_Weak /*weak*/, + char ** /*returned_name*/, + Dwarf_Off* /*die_offset*/, + Dwarf_Off* /*cu_offset*/, + Dwarf_Error* /*error*/); + +/* location list section operation. (.debug_loc access) */ +int dwarf_get_loclist_entry(Dwarf_Debug /*dbg*/, + Dwarf_Unsigned /*offset*/, + Dwarf_Addr* /*hipc*/, + Dwarf_Addr* /*lopc*/, + Dwarf_Ptr* /*data*/, + Dwarf_Unsigned* /*entry_len*/, + Dwarf_Unsigned* /*next_entry*/, + Dwarf_Error* /*error*/); + +/* abbreviation section operations */ +int dwarf_get_abbrev(Dwarf_Debug /*dbg*/, + Dwarf_Unsigned /*offset*/, + Dwarf_Abbrev * /*returned_abbrev*/, + Dwarf_Unsigned* /*length*/, + Dwarf_Unsigned* /*attr_count*/, + Dwarf_Error* /*error*/); + +int dwarf_get_abbrev_tag(Dwarf_Abbrev /*abbrev*/, + Dwarf_Half* /*return_tag_number*/, + Dwarf_Error* /*error*/); +int dwarf_get_abbrev_code(Dwarf_Abbrev /*abbrev*/, + Dwarf_Unsigned* /*return_code_number*/, + Dwarf_Error* /*error*/); +/* See comments in dwarf_abbrev.c. Not an entirely safe function. */ +int dwarf_get_abbrev_count(Dwarf_Debug /*dbg*/); + +int dwarf_get_abbrev_children_flag(Dwarf_Abbrev /*abbrev*/, + Dwarf_Signed* /*return_flag*/, + Dwarf_Error* /*error*/); + +int dwarf_get_abbrev_entry(Dwarf_Abbrev /*abbrev*/, + Dwarf_Signed /*index*/, + Dwarf_Half * /*returned_attr_num*/, + Dwarf_Signed* /*form*/, + Dwarf_Off* /*offset*/, + Dwarf_Error* /*error*/); + +/* consumer string section operation */ +int dwarf_get_str(Dwarf_Debug /*dbg*/, + Dwarf_Off /*offset*/, + char** /*string*/, + Dwarf_Signed * /*strlen_of_string*/, + Dwarf_Error* /*error*/); + +/* Consumer op on gnu .eh_frame info */ +int dwarf_get_fde_list_eh( + Dwarf_Debug /*dbg*/, + Dwarf_Cie** /*cie_data*/, + Dwarf_Signed* /*cie_element_count*/, + Dwarf_Fde** /*fde_data*/, + Dwarf_Signed* /*fde_element_count*/, + Dwarf_Error* /*error*/); + + +/* consumer operations on frame info: .debug_frame */ +int dwarf_get_fde_list(Dwarf_Debug /*dbg*/, + Dwarf_Cie** /*cie_data*/, + Dwarf_Signed* /*cie_element_count*/, + Dwarf_Fde** /*fde_data*/, + Dwarf_Signed* /*fde_element_count*/, + Dwarf_Error* /*error*/); + +/* Release storage gotten by dwarf_get_fde_list_eh() or + dwarf_get_fde_list() */ +void dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg, + Dwarf_Cie *cie_data, + Dwarf_Signed cie_element_count, + Dwarf_Fde *fde_data, + Dwarf_Signed fde_element_count); + + + +int dwarf_get_fde_range(Dwarf_Fde /*fde*/, + Dwarf_Addr* /*low_pc*/, + Dwarf_Unsigned* /*func_length*/, + Dwarf_Ptr* /*fde_bytes*/, + Dwarf_Unsigned* /*fde_byte_length*/, + Dwarf_Off* /*cie_offset*/, + Dwarf_Signed* /*cie_index*/, + Dwarf_Off* /*fde_offset*/, + Dwarf_Error* /*error*/); + +/* Useful for IRIX only: see dwarf_get_cie_augmentation_data() + dwarf_get_fde_augmentation_data() for GNU .eh_frame. */ +int dwarf_get_fde_exception_info(Dwarf_Fde /*fde*/, + Dwarf_Signed* /* offset_into_exception_tables */, + Dwarf_Error* /*error*/); + + +int dwarf_get_cie_of_fde(Dwarf_Fde /*fde*/, + Dwarf_Cie * /*cie_returned*/, + Dwarf_Error* /*error*/); + +int dwarf_get_cie_info(Dwarf_Cie /*cie*/, + Dwarf_Unsigned * /*bytes_in_cie*/, + Dwarf_Small* /*version*/, + char ** /*augmenter*/, + Dwarf_Unsigned* /*code_alignment_factor*/, + Dwarf_Signed* /*data_alignment_factor*/, + Dwarf_Half* /*return_address_register_rule*/, + Dwarf_Ptr* /*initial_instructions*/, + Dwarf_Unsigned* /*initial_instructions_length*/, + Dwarf_Error* /*error*/); + +/* dwarf_get_cie_index new September 2009. */ +int dwarf_get_cie_index( + Dwarf_Cie /*cie*/, + Dwarf_Signed* /*index*/, + Dwarf_Error* /*error*/ ); + + +int dwarf_get_fde_instr_bytes(Dwarf_Fde /*fde*/, + Dwarf_Ptr * /*outinstrs*/, Dwarf_Unsigned * /*outlen*/, + Dwarf_Error * /*error*/); + +int dwarf_get_fde_info_for_all_regs(Dwarf_Fde /*fde*/, + Dwarf_Addr /*pc_requested*/, + Dwarf_Regtable* /*reg_table*/, + Dwarf_Addr* /*row_pc*/, + Dwarf_Error* /*error*/); + +int dwarf_get_fde_info_for_all_regs3(Dwarf_Fde /*fde*/, + Dwarf_Addr /*pc_requested*/, + Dwarf_Regtable3* /*reg_table*/, + Dwarf_Addr* /*row_pc*/, + Dwarf_Error* /*error*/); + +/* In this older interface DW_FRAME_CFA_COL is a meaningful + column (which does not work well with DWARF3 or + non-MIPS architectures). */ +int dwarf_get_fde_info_for_reg(Dwarf_Fde /*fde*/, + Dwarf_Half /*table_column*/, + Dwarf_Addr /*pc_requested*/, + Dwarf_Signed* /*offset_relevant*/, + Dwarf_Signed* /*register*/, + Dwarf_Signed* /*offset*/, + Dwarf_Addr* /*row_pc*/, + Dwarf_Error* /*error*/); + +/* See discussion of dw_value_type, libdwarf.h. + Use of DW_FRAME_CFA_COL is not meaningful in this interface. + See dwarf_get_fde_info_for_cfa_reg3(). +*/ +/* dwarf_get_fde_info_for_reg3 is useful on a single column, but + it is inefficient to iterate across all table_columns using this + function. Instead call dwarf_get_fde_info_for_all_regs3() and index + into the table it fills in. */ +int dwarf_get_fde_info_for_reg3(Dwarf_Fde /*fde*/, + Dwarf_Half /*table_column*/, + Dwarf_Addr /*pc_requested*/, + Dwarf_Small * /*value_type*/, + Dwarf_Signed * /*offset_relevant*/, + Dwarf_Signed* /*register*/, + Dwarf_Signed* /*offset_or_block_len*/, + Dwarf_Ptr * /*block_ptr */, + Dwarf_Addr* /*row_pc_out*/, + Dwarf_Error* /*error*/); + +/* Use this to get the cfa. */ +int dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde /*fde*/, + Dwarf_Addr /*pc_requested*/, + Dwarf_Small * /*value_type*/, + Dwarf_Signed * /*offset_relevant*/, + Dwarf_Signed* /*register*/, + Dwarf_Signed* /*offset_or_block_len*/, + Dwarf_Ptr * /*block_ptr */, + Dwarf_Addr* /*row_pc_out*/, + Dwarf_Error* /*error*/); + +int dwarf_get_fde_for_die(Dwarf_Debug /*dbg*/, + Dwarf_Die /*subr_die */, + Dwarf_Fde * /*returned_fde*/, + Dwarf_Error* /*error*/); + +int dwarf_get_fde_n(Dwarf_Fde* /*fde_data*/, + Dwarf_Unsigned /*fde_index*/, + Dwarf_Fde * /*returned_fde*/, + Dwarf_Error* /*error*/); + +int dwarf_get_fde_at_pc(Dwarf_Fde* /*fde_data*/, + Dwarf_Addr /*pc_of_interest*/, + Dwarf_Fde * /*returned_fde*/, + Dwarf_Addr* /*lopc*/, + Dwarf_Addr* /*hipc*/, + Dwarf_Error* /*error*/); + +/* GNU .eh_frame augmentation information, raw form, see + Linux Standard Base Core Specification version 3.0 . */ +int dwarf_get_cie_augmentation_data(Dwarf_Cie /* cie*/, + Dwarf_Small ** /* augdata */, + Dwarf_Unsigned * /* augdata_len */, + Dwarf_Error* /*error*/); +/* GNU .eh_frame augmentation information, raw form, see + Linux Standard Base Core Specification version 3.0 . */ +int dwarf_get_fde_augmentation_data(Dwarf_Fde /* fde*/, + Dwarf_Small ** /* augdata */, + Dwarf_Unsigned * /* augdata_len */, + Dwarf_Error* /*error*/); + +int dwarf_expand_frame_instructions(Dwarf_Cie /*cie*/, + Dwarf_Ptr /*instruction*/, + Dwarf_Unsigned /*i_length*/, + Dwarf_Frame_Op** /*returned_op_list*/, + Dwarf_Signed* /*op_count*/, + Dwarf_Error* /*error*/); + +/* Operations on .debug_aranges. */ +int dwarf_get_aranges(Dwarf_Debug /*dbg*/, + Dwarf_Arange** /*aranges*/, + Dwarf_Signed * /*arange_count*/, + Dwarf_Error* /*error*/); + + + +int dwarf_get_arange( + Dwarf_Arange* /*aranges*/, + Dwarf_Unsigned /*arange_count*/, + Dwarf_Addr /*address*/, + Dwarf_Arange * /*returned_arange*/, + Dwarf_Error* /*error*/); + +int dwarf_get_cu_die_offset( + Dwarf_Arange /*arange*/, + Dwarf_Off* /*return_offset*/, + Dwarf_Error* /*error*/); + +int dwarf_get_arange_cu_header_offset( + Dwarf_Arange /*arange*/, + Dwarf_Off* /*return_cu_header_offset*/, + Dwarf_Error* /*error*/); +#ifdef __sgi /* pragma is sgi MIPS only */ +#pragma optional dwarf_get_arange_cu_header_offset +#endif + +/* DWARF2,3 interface. No longer really adequate (it was never + right for segmented address spaces, please switch + to using dwarf_get_arange_info_b instead. + There is no effective difference between these + functions if the address space + of the target is not segmented. */ +int dwarf_get_arange_info( + Dwarf_Arange /*arange*/, + Dwarf_Addr* /*start*/, + Dwarf_Unsigned* /*length*/, + Dwarf_Off* /*cu_die_offset*/, + Dwarf_Error* /*error*/ ); + +/* New for DWARF4, entries may have segment information. + *segment is only meaningful if *segment_entry_size is non-zero. */ +int dwarf_get_arange_info_b( + Dwarf_Arange /*arange*/, + Dwarf_Unsigned* /*segment*/, + Dwarf_Unsigned* /*segment_entry_size*/, + Dwarf_Addr * /*start*/, + Dwarf_Unsigned* /*length*/, + Dwarf_Off * /*cu_die_offset*/, + Dwarf_Error * /*error*/ ); + + +/* consumer .debug_macinfo information interface. +*/ +struct Dwarf_Macro_Details_s { + Dwarf_Off dmd_offset; /* offset, in the section, + of this macro info */ + Dwarf_Small dmd_type; /* the type, DW_MACINFO_define etc*/ + Dwarf_Signed dmd_lineno; /* the source line number where + applicable and vend_def number if + vendor_extension op */ + + Dwarf_Signed dmd_fileindex;/* the source file index: + applies to define undef start_file */ + char * dmd_macro; /* macro name (with value for defineop) + string from vendor ext */ +}; + +/* dwarf_print_lines is for use by dwarfdump: it prints + line info to stdout. + The _dwarf name is obsolete. Use dwarf_ instead. + Added extra argnument 2/2009 for better checking. +*/ +int _dwarf_print_lines(Dwarf_Die /*cu_die*/,Dwarf_Error * /*error*/); +int dwarf_print_lines(Dwarf_Die /*cu_die*/,Dwarf_Error * /*error*/, + int * /*error_count_out */); + +/* dwarf_check_lineheader lets dwarfdump get detailed messages + about some compiler errors we detect. + We return the count of detected errors through the + pointer. +*/ +void dwarf_check_lineheader(Dwarf_Die /*cu_die*/,int *errcount_out); + +/* dwarf_ld_sort_lines helps SGI IRIX ld + rearrange lines in .debug_line in a .o created with a text + section per function. + -OPT:procedure_reorder=ON + where ld-cord (cord(1)ing by ld, + not by cord(1)) may have changed the function order. + The _dwarf name is obsolete. Use dwarf_ instead. +*/ +int _dwarf_ld_sort_lines( + void * /*orig_buffer*/, + unsigned long /* buffer_len*/, + int /*is_64_bit*/, + int * /*any_change*/, + int * /*err_code*/); +int dwarf_ld_sort_lines( + void * /*orig_buffer*/, + unsigned long /*buffer_len*/, + int /*is_64_bit*/, + int * /*any_change*/, + int * /*err_code*/); + +/* Used by dwarfdump -v to print fde offsets from debugging + info. + The _dwarf name is obsolete. Use dwarf_ instead. +*/ +int _dwarf_fde_section_offset(Dwarf_Debug dbg, + Dwarf_Fde /*in_fde*/, + Dwarf_Off * /*fde_off*/, + Dwarf_Off * /*cie_off*/, + Dwarf_Error * /*err*/); +int dwarf_fde_section_offset(Dwarf_Debug dbg, + Dwarf_Fde /*in_fde*/, + Dwarf_Off * /*fde_off*/, + Dwarf_Off * /*cie_off*/, + Dwarf_Error * /*err*/); + +/* Used by dwarfdump -v to print cie offsets from debugging + info. + The _dwarf name is obsolete. Use dwarf_ instead. +*/ +int dwarf_cie_section_offset(Dwarf_Debug /*dbg*/, + Dwarf_Cie /*in_cie*/, + Dwarf_Off * /*cie_off */, + Dwarf_Error * /*err*/); +int _dwarf_cie_section_offset(Dwarf_Debug /*dbg*/, + Dwarf_Cie /*in_cie*/, + Dwarf_Off * /*cie_off*/, + Dwarf_Error * /*err*/); + +typedef struct Dwarf_Macro_Details_s Dwarf_Macro_Details; + +int dwarf_get_macro(Dwarf_Debug /*dbg*/, + char * /*requested_macro_name*/, + Dwarf_Addr /*pc_of_request*/, + char ** /*returned_macro_value*/, + Dwarf_Error * /*error*/); + +int dwarf_get_all_defined_macros(Dwarf_Debug /*dbg*/, + Dwarf_Addr /*pc_of_request*/, + Dwarf_Signed * /*returned_count*/, + char *** /*returned_pointers_to_macros*/, + Dwarf_Error * /*error*/); + +char *dwarf_find_macro_value_start(char * /*macro_string*/); + +int dwarf_get_macro_details(Dwarf_Debug /*dbg*/, + Dwarf_Off /*macro_offset*/, + Dwarf_Unsigned /*maximum_count*/, + Dwarf_Signed * /*entry_count*/, + Dwarf_Macro_Details ** /*details*/, + Dwarf_Error * /*err*/); + + +int dwarf_get_address_size(Dwarf_Debug /*dbg*/, + Dwarf_Half * /*addr_size*/, + Dwarf_Error * /*error*/); +int dwarf_get_die_address_size(Dwarf_Die /*die*/, + Dwarf_Half * /*addr_size*/, + Dwarf_Error * /*error*/); + +/* The dwarf specification separates FORMs into +different classes. To do the seperation properly +requires 4 pieces of data as of DWARF4 (thus the +function arguments listed here). +The DWARF4 specification class definition suffices to +describe all DWARF versions. +See section 7.5.4, Attribute Encodings. +A return of DW_FORM_CLASS_UNKNOWN means we could not properly figure +out what form-class it is. + + DW_FORM_CLASS_FRAMEPTR is MIPS/IRIX only, and refers + to the DW_AT_MIPS_fde attribute (a reference to the + .debug_frame section). +*/ +enum Dwarf_Form_Class { + DW_FORM_CLASS_UNKNOWN, DW_FORM_CLASS_ADDRESS, + DW_FORM_CLASS_BLOCK, DW_FORM_CLASS_CONSTANT, + DW_FORM_CLASS_EXPRLOC, DW_FORM_CLASS_FLAG, + DW_FORM_CLASS_LINEPTR, DW_FORM_CLASS_LOCLISTPTR, + DW_FORM_CLASS_MACPTR, DW_FORM_CLASS_RANGELISTPTR, + DW_FORM_CLASS_REFERENCE, DW_FORM_CLASS_STRING, + DW_FORM_CLASS_FRAMEPTR +}; + +enum Dwarf_Form_Class dwarf_get_form_class( + Dwarf_Half /* dwversion */, + Dwarf_Half /* attrnum */, + Dwarf_Half /*offset_size */, + Dwarf_Half /*form*/); + +/* Utility operations */ +Dwarf_Unsigned dwarf_errno(Dwarf_Error /*error*/); + +char* dwarf_errmsg(Dwarf_Error /*error*/); + +/* stringcheck zero is default and means do all + string length validity checks. + Call with parameter value 1 to turn off many such checks (and + increase performance). + Call with zero for safest running. + Actual value saved and returned is only 8 bits! Upper bits + ignored by libdwarf (and zero on return). + Returns previous value. */ +int dwarf_set_stringcheck(int /*stringcheck*/); + +/* 'apply' defaults to 1 and means do all + 'rela' relocations on reading in a dwarf object section with + such relocations. + Call with parameter value 0 to turn off application of + such relocations. + Since the static linker leaves 'bogus' data in object sections + with a 'rela' relocation section such data cannot be read + sensibly without processing the relocations. Such relocations + do not exist in executables and shared objects (.so), the + relocations only exist in plain .o relocatable object files. + Actual value saved and returned is only 8 bits! Upper bits + ignored by libdwarf (and zero on return). + Returns previous value. */ +int dwarf_set_reloc_application(int /*apply*/); + + +/* Unimplemented */ +Dwarf_Handler dwarf_seterrhand(Dwarf_Debug /*dbg*/, Dwarf_Handler /*errhand*/); + +/* Unimplemented */ +Dwarf_Ptr dwarf_seterrarg(Dwarf_Debug /*dbg*/, Dwarf_Ptr /*errarg*/); + +void dwarf_dealloc(Dwarf_Debug /*dbg*/, void* /*space*/, + Dwarf_Unsigned /*type*/); + + +/* DWARF Producer Interface */ + +/* New form June, 2011. Adds user_data argument. */ +typedef int (*Dwarf_Callback_Func_c)( + char* /*name*/, + int /*size*/, + Dwarf_Unsigned /*type*/, + Dwarf_Unsigned /*flags*/, + Dwarf_Unsigned /*link*/, + Dwarf_Unsigned /*info*/, + Dwarf_Unsigned* /*sect_name_index*/, + void * /*user_data*/, + int* /*error*/); + +/* New form June, 2011. Adds user_data */ +Dwarf_P_Debug dwarf_producer_init_c( + Dwarf_Unsigned /*flags*/, + Dwarf_Callback_Func_c /*func*/, + Dwarf_Handler /*errhand*/, + Dwarf_Ptr /*errarg*/, + void * /*user_data*/, + Dwarf_Error * /*error*/); + +typedef int (*Dwarf_Callback_Func_b)( + char* /*name*/, + int /*size*/, + Dwarf_Unsigned /*type*/, + Dwarf_Unsigned /*flags*/, + Dwarf_Unsigned /*link*/, + Dwarf_Unsigned /*info*/, + Dwarf_Unsigned* /*sect_name_index*/, + int* /*error*/); + +/* Intermediate form. Made obsolescent by dwarf_producer_init_c, + but supported. */ +Dwarf_P_Debug dwarf_producer_init_b( + Dwarf_Unsigned /*flags*/, + Dwarf_Callback_Func_b /*func*/, + Dwarf_Handler /*errhand*/, + Dwarf_Ptr /*errarg*/, + Dwarf_Error * /*error*/); + +/* Original, oldest form. From 1991. */ +typedef int (*Dwarf_Callback_Func)( + char* /*name*/, + int /*size*/, + Dwarf_Unsigned /*type*/, + Dwarf_Unsigned /*flags*/, + Dwarf_Unsigned /*link*/, + Dwarf_Unsigned /*info*/, + int* /*sect name index*/, + int* /*error*/); + +/* Original, oldest form. From 1991. */ +Dwarf_P_Debug dwarf_producer_init( + Dwarf_Unsigned /*creation_flags*/, + Dwarf_Callback_Func /*func*/, + Dwarf_Handler /*errhand*/, + Dwarf_Ptr /*errarg*/, + Dwarf_Error* /*error*/); + +Dwarf_Signed dwarf_transform_to_disk_form(Dwarf_P_Debug /*dbg*/, + Dwarf_Error* /*error*/); + +Dwarf_Ptr dwarf_get_section_bytes(Dwarf_P_Debug /*dbg*/, + Dwarf_Signed /*dwarf_section*/, + Dwarf_Signed* /*elf_section_index*/, + Dwarf_Unsigned* /*length*/, + Dwarf_Error* /*error*/); + +int dwarf_get_relocation_info_count( + Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned * /*count_of_relocation_sections*/, + int * /*drd_buffer_version*/, + Dwarf_Error* /*error*/); + +int dwarf_get_relocation_info( + Dwarf_P_Debug /*dbg*/, + Dwarf_Signed * /*elf_section_index*/, + Dwarf_Signed * /*elf_section_index_link*/, + Dwarf_Unsigned * /*relocation_buffer_count*/, + Dwarf_Relocation_Data * /*reldata_buffer*/, + Dwarf_Error* /*error*/); + +/* v1: no drd_length field, enum explicit */ +/* v2: has the drd_length field, enum value in uchar member */ +#define DWARF_DRD_BUFFER_VERSION 2 + +/* Markers are not written to DWARF2/3/4, they are user + defined and may be used for any purpose. +*/ +Dwarf_Signed dwarf_get_die_markers( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Marker * /*marker_list*/, + Dwarf_Unsigned * /*marker_count*/, + Dwarf_Error * /*error*/); + +int dwarf_get_string_attributes_count(Dwarf_P_Debug, + Dwarf_Unsigned *, + int *, + Dwarf_Error *); + +int dwarf_get_string_attributes_info(Dwarf_P_Debug, + Dwarf_Signed *, + Dwarf_Unsigned *, + Dwarf_P_String_Attr *, + Dwarf_Error *); + +void dwarf_reset_section_bytes(Dwarf_P_Debug /*dbg*/); + +Dwarf_Unsigned dwarf_producer_finish(Dwarf_P_Debug /*dbg*/, + Dwarf_Error* /*error*/); + +/* Producer attribute addition functions. */ +Dwarf_P_Attribute dwarf_add_AT_targ_address(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Unsigned /*pc_value*/, + Dwarf_Signed /*sym_index*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_block(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Small* /*block_data*/, + Dwarf_Unsigned /*block_len*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_targ_address_b(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Unsigned /*pc_value*/, + Dwarf_Unsigned /*sym_index*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_ref_address(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Unsigned /*pc_value*/, + Dwarf_Unsigned /*sym_index*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_unsigned_const(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Unsigned /*value*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_signed_const(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Signed /*value*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_reference(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_P_Die /*otherdie*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_dataref( + Dwarf_P_Debug /* dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Unsigned /*pcvalue*/, + Dwarf_Unsigned /*sym_index*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_const_value_string(Dwarf_P_Die /*ownerdie*/, + char* /*string_value*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_location_expr(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_P_Expr /*loc_expr*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_string(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + char* /*string*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_flag(Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*ownerdie*/, + Dwarf_Half /*attr*/, + Dwarf_Small /*flag*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_producer(Dwarf_P_Die /*ownerdie*/, + char* /*producer_string*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_const_value_signedint(Dwarf_P_Die /*ownerdie*/, + Dwarf_Signed /*signed_value*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_const_value_unsignedint( + Dwarf_P_Die /*ownerdie*/, + Dwarf_Unsigned /*unsigned_value*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_comp_dir(Dwarf_P_Die /*ownerdie*/, + char* /*current_working_directory*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die /*die*/, + char* /*name*/, + Dwarf_Error* /*error*/); + +/* Producer line creation functions (.debug_line) */ +Dwarf_Unsigned dwarf_add_directory_decl(Dwarf_P_Debug /*dbg*/, + char* /*name*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_file_decl(Dwarf_P_Debug /*dbg*/, + char* /*name*/, + Dwarf_Unsigned /*dir_index*/, + Dwarf_Unsigned /*time_last_modified*/, + Dwarf_Unsigned /*length*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_line_entry_b(Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned /*file_index*/, + Dwarf_Addr /*code_address*/, + Dwarf_Unsigned /*lineno*/, + Dwarf_Signed /*column_number*/, + Dwarf_Bool /*is_source_stmt_begin*/, + Dwarf_Bool /*is_basic_block_begin*/, + Dwarf_Bool /*is_epilogue_begin*/, + Dwarf_Bool /*is_prologue_end*/, + Dwarf_Unsigned /*isa*/, + Dwarf_Unsigned /*discriminator*/, + Dwarf_Error* /*error*/); +Dwarf_Unsigned dwarf_add_line_entry(Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned /*file_index*/, + Dwarf_Addr /*code_address*/, + Dwarf_Unsigned /*lineno*/, + Dwarf_Signed /*column_number*/, + Dwarf_Bool /*is_source_stmt_begin*/, + Dwarf_Bool /*is_basic_block_begin*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_lne_set_address(Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned /*offset*/, + Dwarf_Unsigned /*symbol_index*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_lne_end_sequence(Dwarf_P_Debug /*dbg*/, + Dwarf_Addr /*end_address*/, + Dwarf_Error* /*error*/); + +/* Producer .debug_frame functions */ +Dwarf_Unsigned dwarf_add_frame_cie(Dwarf_P_Debug /*dbg*/, + char* /*augmenter*/, + Dwarf_Small /*code_alignment_factor*/, + Dwarf_Small /*data_alignment_factor*/, + Dwarf_Small /*return_address_reg*/, + Dwarf_Ptr /*initialization_bytes*/, + Dwarf_Unsigned /*init_byte_len*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_frame_fde( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Fde /*fde*/, + Dwarf_P_Die /*corresponding subprogram die*/, + Dwarf_Unsigned /*cie_to_use*/, + Dwarf_Unsigned /*virt_addr_of_described_code*/, + Dwarf_Unsigned /*length_of_code*/, + Dwarf_Unsigned /*symbol_index*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_frame_fde_b( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Fde /*fde*/, + Dwarf_P_Die /*die*/, + Dwarf_Unsigned /*cie*/, + Dwarf_Addr /*virt_addr*/, + Dwarf_Unsigned /*code_len*/, + Dwarf_Unsigned /*sym_idx*/, + Dwarf_Unsigned /*sym_idx_of_end*/, + Dwarf_Addr /*offset_from_end_sym*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_frame_info_b( + Dwarf_P_Debug dbg /*dbg*/, + Dwarf_P_Fde /*fde*/, + Dwarf_P_Die /*die*/, + Dwarf_Unsigned /*cie*/, + Dwarf_Addr /*virt_addr*/, + Dwarf_Unsigned /*code_len*/, + Dwarf_Unsigned /*symidx*/, + Dwarf_Unsigned /*end_symbol */, + Dwarf_Addr /*offset_from_end_symbol */, + Dwarf_Signed /*offset_into_exception_tables*/, + Dwarf_Unsigned /*exception_table_symbol*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_frame_info( + Dwarf_P_Debug dbg /*dbg*/, + Dwarf_P_Fde /*fde*/, + Dwarf_P_Die /*die*/, + Dwarf_Unsigned /*cie*/, + Dwarf_Addr /*virt_addr*/, + Dwarf_Unsigned /*code_len*/, + Dwarf_Unsigned /*symidx*/, + Dwarf_Signed /*offset_into_exception_tables*/, + Dwarf_Unsigned /*exception_table_symbol*/, + Dwarf_Error* /*error*/); + +Dwarf_P_Fde dwarf_add_fde_inst( + Dwarf_P_Fde /*fde*/, + Dwarf_Small /*op*/, + Dwarf_Unsigned /*val1*/, + Dwarf_Unsigned /*val2*/, + Dwarf_Error* /*error*/); + +/* New September 17, 2009 */ +int dwarf_insert_fde_inst_bytes( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Fde /*fde*/, + Dwarf_Unsigned /*len*/, + Dwarf_Ptr /*ibytes*/, + Dwarf_Error* /*error*/); + + +Dwarf_P_Fde dwarf_new_fde(Dwarf_P_Debug /*dbg*/, Dwarf_Error* /*error*/); + +Dwarf_P_Fde dwarf_fde_cfa_offset( + Dwarf_P_Fde /*fde*/, + Dwarf_Unsigned /*register_number*/, + Dwarf_Signed /*offset*/, + Dwarf_Error* /*error*/); + +/* die creation & addition routines */ +Dwarf_P_Die dwarf_new_die( + Dwarf_P_Debug /*dbg*/, + Dwarf_Tag /*tag*/, + Dwarf_P_Die /*parent*/, + Dwarf_P_Die /*child*/, + Dwarf_P_Die /*left */, + Dwarf_P_Die /*right*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_die_to_debug( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + Dwarf_Error* /*error*/); + +/* Markers are not written to DWARF2/3/4, they are user + defined and may be used for any purpose. +*/ +Dwarf_Unsigned dwarf_add_die_marker( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + Dwarf_Unsigned /*marker*/, + Dwarf_Error * /*error*/); + +Dwarf_Unsigned dwarf_get_die_marker( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + Dwarf_Unsigned * /*marker*/, + Dwarf_Error * /*error*/); + +Dwarf_P_Die dwarf_die_link( + Dwarf_P_Die /*die*/, + Dwarf_P_Die /*parent*/, + Dwarf_P_Die /*child*/, + Dwarf_P_Die /*left*/, + Dwarf_P_Die /*right*/, + Dwarf_Error* /*error*/); + +void dwarf_dealloc_compressed_block( + Dwarf_P_Debug, + void * +); + +/* Call this passing in return value from dwarf_uncompress_integer_block() + to free the space the decompression allocated. */ +void dwarf_dealloc_uncompressed_block( + Dwarf_Debug, + void * +); + +void * dwarf_compress_integer_block( + Dwarf_P_Debug, /* dbg */ + Dwarf_Bool, /* signed==true (or unsigned) */ + Dwarf_Small, /* size of integer units: 8, 16, 32, 64 */ + void*, /* data */ + Dwarf_Unsigned, /* number of elements */ + Dwarf_Unsigned*, /* number of bytes in output block */ + Dwarf_Error* /* error */ +); + +/* Decode an array of signed leb integers (so of course the + array is not composed of fixed length values, but is instead + a sequence of sleb values). + Returns a DW_DLV_BADADDR on error. + Otherwise returns a pointer to an array of 32bit integers. + The signed argument must be non-zero (the decode + assumes sleb integers in the input data) at this time. + Size of integer units must be 32 (32 bits each) at this time. + Number of bytes in block is a byte count (not array count). + Returns number of units in output block (ie, number of elements + of the array that the return value points to) thru the argument. */ +void * dwarf_uncompress_integer_block( + Dwarf_Debug, /* dbg */ + Dwarf_Bool, /* signed==true (or unsigned) */ + Dwarf_Small, /* size of integer units: 8, 16, 32, 64 */ + void*, /* input data */ + Dwarf_Unsigned, /* number of bytes in input */ + Dwarf_Unsigned*, /* number of units in output block */ + Dwarf_Error* /* error */ +); + +/* Operations to create location expressions. */ +Dwarf_P_Expr dwarf_new_expr(Dwarf_P_Debug /*dbg*/, Dwarf_Error* /*error*/); + +void dwarf_expr_reset( + Dwarf_P_Expr /*expr*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_expr_gen( + Dwarf_P_Expr /*expr*/, + Dwarf_Small /*opcode*/, + Dwarf_Unsigned /*val1*/, + Dwarf_Unsigned /*val2*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_expr_addr( + Dwarf_P_Expr /*expr*/, + Dwarf_Unsigned /*addr*/, + Dwarf_Signed /*sym_index*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_expr_addr_b( + Dwarf_P_Expr /*expr*/, + Dwarf_Unsigned /*addr*/, + Dwarf_Unsigned /*sym_index*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_expr_current_offset( + Dwarf_P_Expr /*expr*/, + Dwarf_Error* /*error*/); + +Dwarf_Addr dwarf_expr_into_block( + Dwarf_P_Expr /*expr*/, + Dwarf_Unsigned* /*length*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_arange(Dwarf_P_Debug /*dbg*/, + Dwarf_Addr /*begin_address*/, + Dwarf_Unsigned /*length*/, + Dwarf_Signed /*symbol_index*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_arange_b( + Dwarf_P_Debug /*dbg*/, + Dwarf_Addr /*begin_address*/, + Dwarf_Unsigned /*length*/, + Dwarf_Unsigned /*symbol_index*/, + Dwarf_Unsigned /*end_symbol_index*/, + Dwarf_Addr /*offset_from_end_symbol*/, + Dwarf_Error * /*error*/); + +Dwarf_Unsigned dwarf_add_pubname( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + char* /*pubname_name*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_funcname( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + char* /*func_name*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_typename( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + char* /*type_name*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_varname( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + char* /*var_name*/, + Dwarf_Error* /*error*/); + +Dwarf_Unsigned dwarf_add_weakname( + Dwarf_P_Debug /*dbg*/, + Dwarf_P_Die /*die*/, + char* /*weak_name*/, + Dwarf_Error* /*error*/); + +/* .debug_macinfo producer functions + Functions must be called in right order: the section is output + In the order these are presented. +*/ +int dwarf_def_macro(Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned /*line*/, + char * /*macname, with (arglist), no space before (*/, + char * /*macvalue*/, + Dwarf_Error* /*error*/); + +int dwarf_undef_macro(Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned /*line*/, + char * /*macname, no arglist, of course*/, + Dwarf_Error* /*error*/); + +int dwarf_start_macro_file(Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned /*fileindex*/, + Dwarf_Unsigned /*linenumber*/, + Dwarf_Error* /*error*/); + +int dwarf_end_macro_file(Dwarf_P_Debug /*dbg*/, + Dwarf_Error* /*error*/); + +int dwarf_vendor_ext(Dwarf_P_Debug /*dbg*/, + Dwarf_Unsigned /*constant*/, + char * /*string*/, + Dwarf_Error* /*error*/); + +/* end macinfo producer functions */ + +int dwarf_attr_offset(Dwarf_Die /*die*/, + Dwarf_Attribute /*attr of above die*/, + Dwarf_Off * /*returns offset thru this ptr */, + Dwarf_Error * /*error*/); + +/* This is a hack so clients can verify offsets. + Added April 2005 so that debugger can detect broken offsets + (which happened in an IRIX executable larger than 2GB + with MIPSpro 7.3.1.3 toolchain.). +*/ +int +dwarf_get_section_max_offsets(Dwarf_Debug /*dbg*/, + Dwarf_Unsigned * /*debug_info_size*/, + Dwarf_Unsigned * /*debug_abbrev_size*/, + Dwarf_Unsigned * /*debug_line_size*/, + Dwarf_Unsigned * /*debug_loc_size*/, + Dwarf_Unsigned * /*debug_aranges_size*/, + Dwarf_Unsigned * /*debug_macinfo_size*/, + Dwarf_Unsigned * /*debug_pubnames_size*/, + Dwarf_Unsigned * /*debug_str_size*/, + Dwarf_Unsigned * /*debug_frame_size*/, + Dwarf_Unsigned * /*debug_ranges_size*/, + Dwarf_Unsigned * /*debug_pubtypes_size*/); + +/* New October 2011., adds .debug_types section to the sizes + returned. */ +int +dwarf_get_section_max_offsets_b(Dwarf_Debug /*dbg*/, + + Dwarf_Unsigned * /*debug_info_size*/, + Dwarf_Unsigned * /*debug_abbrev_size*/, + Dwarf_Unsigned * /*debug_line_size*/, + Dwarf_Unsigned * /*debug_loc_size*/, + Dwarf_Unsigned * /*debug_aranges_size*/, + Dwarf_Unsigned * /*debug_macinfo_size*/, + Dwarf_Unsigned * /*debug_pubnames_size*/, + Dwarf_Unsigned * /*debug_str_size*/, + Dwarf_Unsigned * /*debug_frame_size*/, + Dwarf_Unsigned * /*debug_ranges_size*/, + Dwarf_Unsigned * /*debug_pubtypes_size*/, + Dwarf_Unsigned * /*debug_types_size*/); + +/* The 'set' calls here return the original (before any change + by these set routines) of the respective fields. */ +/* Multiple releases spelled 'initial' as 'inital' . + The 'inital' spelling should not be used. */ +Dwarf_Half dwarf_set_frame_rule_inital_value(Dwarf_Debug /*dbg*/, + Dwarf_Half /*value*/); +/* Additional interface with correct 'initial' spelling. */ +/* It is likely you will want to call the following 6 functions + before accessing any frame information. All are useful + to tailor handling of pseudo-registers needed to turn + frame operation references into simpler forms and to + reflect ABI specific data. Of course altering libdwarf.h + and dwarf.h allow the same capabilities, but such header changes + do not let one change these values at runtime. */ +Dwarf_Half dwarf_set_frame_rule_initial_value(Dwarf_Debug /*dbg*/, + Dwarf_Half /*value*/); +Dwarf_Half dwarf_set_frame_rule_table_size(Dwarf_Debug /*dbg*/, + Dwarf_Half /*value*/); +Dwarf_Half dwarf_set_frame_cfa_value(Dwarf_Debug /*dbg*/, + Dwarf_Half /*value*/); +Dwarf_Half dwarf_set_frame_same_value(Dwarf_Debug /*dbg*/, + Dwarf_Half /*value*/); +Dwarf_Half dwarf_set_frame_undefined_value(Dwarf_Debug /*dbg*/, + Dwarf_Half /*value*/); +/* dwarf_set_default_address_size only sets 'value' if value is + greater than zero. */ +Dwarf_Small dwarf_set_default_address_size(Dwarf_Debug /*dbg*/, + Dwarf_Small /* value */); + +/* As of April 27, 2009, this version with no diepointer is + obsolete though supported. Use dwarf_get_ranges_a() instead. */ +int dwarf_get_ranges(Dwarf_Debug /*dbg*/, + Dwarf_Off /*rangesoffset*/, + Dwarf_Ranges ** /*rangesbuf*/, + Dwarf_Signed * /*listlen*/, + Dwarf_Unsigned * /*bytecount*/, + Dwarf_Error * /*error*/); + +/* This adds the address_size argument. New April 27, 2009 */ +int dwarf_get_ranges_a(Dwarf_Debug /*dbg*/, + Dwarf_Off /*rangesoffset*/, + Dwarf_Die /* diepointer */, + Dwarf_Ranges ** /*rangesbuf*/, + Dwarf_Signed * /*listlen*/, + Dwarf_Unsigned * /*bytecount*/, + Dwarf_Error * /*error*/); + +void dwarf_ranges_dealloc(Dwarf_Debug /*dbg*/, + Dwarf_Ranges * /*rangesbuf*/, + Dwarf_Signed /*rangecount*/); + +/* The harmless error list is a circular buffer of + errors we note but which do not stop us from processing + the object. Created so dwarfdump or other tools + can report such inconsequential errors without causing + anything to stop early. */ +#define DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE 4 +#define DW_HARMLESS_ERROR_MSG_STRING_SIZE 200 +/* User code supplies size of array of pointers errmsg_ptrs_array + in count and the array of pointers (the pointers themselves + need not be initialized). + The pointers returned in the array of pointers + are invalidated by ANY call to libdwarf. + Use them before making another libdwarf call! + The array of string pointers passed in always has + a final null pointer, so if there are N pointers the + and M actual strings, then MIN(M,N-1) pointers are + set to point to error strings. The array of pointers + to strings always terminates with a NULL pointer. + If 'count' is passed in zero then errmsg_ptrs_array + is not touched. + + The function returns DW_DLV_NO_ENTRY if no harmless errors + were noted so far. Returns DW_DLV_OK if there are errors. + Never returns DW_DLV_ERROR. + + Each call empties the error list (discarding all current entries). + If newerr_count is non-NULL the count of harmless errors + since the last call is returned through the pointer + (some may have been discarded or not returned, it is a circular + list...). + If DW_DLV_NO_ENTRY is returned none of the arguments + here are touched or used. + */ +int dwarf_get_harmless_error_list(Dwarf_Debug /*dbg*/, + unsigned /*count*/, + const char ** /*errmsg_ptrs_array*/, + unsigned * /*newerr_count*/); + +/* Insertion is only for testing the harmless error code, it is not + necessarily useful otherwise. */ +void dwarf_insert_harmless_error(Dwarf_Debug /*dbg*/, + char * /*newerror*/); + +/* The size of the circular list of strings may be set + and reset as needed. If it is shortened excess + messages are simply dropped. It returns the previous + size. If zero passed in the size is unchanged + and it simply returns the current size */ +unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug /*dbg*/, + unsigned /*maxcount*/); +/* The harmless error strings (if any) are freed when the dbg + is dwarf_finish()ed. */ + +/* When the val_in is known these dwarf_get_TAG_name (etc) + functions return the string corresponding to the val_in passed in + through the pointer s_out and the value returned is DW_DLV_OK. + The strings are in static storage + and must not be freed. + If DW_DLV_NO_ENTRY is returned the val_in is not known and + *s_out is not set. DW_DLV_ERROR is never returned.*/ + +/* The following copied from a generated dwarf_names.h */ + +/* BEGIN FILE */ + +extern int dwarf_get_TAG_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_children_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_FORM_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_AT_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_OP_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_ATE_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_DS_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_END_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_ATCF_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_ACCESS_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_VIS_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_VIRTUALITY_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_LANG_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_ID_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_CC_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_INL_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_ORD_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_DSC_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_LNS_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_LNE_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_ISA_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_MACINFO_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_CFA_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_EH_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_FRAME_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_CHILDREN_name(unsigned int /*val_in*/, const char ** /*s_out */); +extern int dwarf_get_ADDR_name(unsigned int /*val_in*/, const char ** /*s_out */); + +/* END FILE */ + +/* Convert local offset into global offset */ +int dwarf_convert_to_global_offset(Dwarf_Attribute /*attr*/, + Dwarf_Off /*offset*/, + Dwarf_Off* /*ret_offset*/, + Dwarf_Error* /*error*/); + +/* Get both offsets (local and global) */ +int dwarf_die_offsets(Dwarf_Die /*die*/, + Dwarf_Off* /*global_offset*/, + Dwarf_Off* /*local_offset*/, + Dwarf_Error* /*error*/); + +/* Giving a section name, get its size and address */ +int dwarf_get_section_info_by_name(Dwarf_Debug /*dbg*/, + const char * /*section_name*/, + Dwarf_Addr* /*section_addr*/, + Dwarf_Unsigned* /*section_size*/, + Dwarf_Error* /*error*/); + +/* Giving a section index, get its size and address */ +int dwarf_get_section_info_by_index(Dwarf_Debug /*dbg*/, + int /*section_index*/, + const char ** /*section_name*/, + Dwarf_Addr* /*section_addr*/, + Dwarf_Unsigned* /*section_size*/, + Dwarf_Error* /*error*/); + +/* Get section count, of object file sections. */ +int dwarf_get_section_count(Dwarf_Debug /*dbg*/); + +/* Get the version and offset size of a CU context. + This is useful as a precursor to + calling dwarf_get_form_class() at times. */ +int dwarf_get_version_of_die(Dwarf_Die /*die*/, + Dwarf_Half * /*version*/, + Dwarf_Half * /*offset_size*/); + +/* Record some application command line options in libdwarf. + This is not arc/argv processing, just precooked setting + of a flag in libdwarf based on something the application + wants. check_verbose_mode of TRUE means do more checking + and sometimes print errors (from libdwarf). + Not restricted to a single Dwarf_Debug, it applies + to the libdwarf the executable is using. +*/ +typedef struct { + Dwarf_Bool check_verbose_mode; +} Dwarf_Cmdline_Options; +extern Dwarf_Cmdline_Options dwarf_cmdline_options; + +/* Set libdwarf to reflect some application command line options. */ +void dwarf_record_cmdline_options(Dwarf_Cmdline_Options /*options*/); + +#ifdef __cplusplus +} +#endif +#endif /* _LIBDWARF_H */ + + diff --git a/libdwarf/libdwarf2.1.mm b/libdwarf/libdwarf2.1.mm new file mode 100644 index 0000000..d94f946 --- /dev/null +++ b/libdwarf/libdwarf2.1.mm @@ -0,0 +1,6626 @@ +n\." +\." the following line may be removed if the ff ligature works on your machine +.lg 0 +\." set up heading formats +.ds HF 3 3 3 3 3 2 2 +.ds HP +2 +2 +1 +0 +0 +.nr Hs 5 +.nr Hb 5 +\." ============================================== +\." Put current date in the following at each rev +.ds vE rev 2.02, December 13, 2011 +\." ============================================== +\." ============================================== +.ds | | +.ds ~ ~ +.ds ' ' +.if t .ds Cw \&\f(CW +.if n .ds Cw \fB +.de Cf \" Place every other arg in Cw font, beginning with first +.if \\n(.$=1 \&\*(Cw\\$1\fP +.if \\n(.$=2 \&\*(Cw\\$1\fP\\$2 +.if \\n(.$=3 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP +.if \\n(.$=4 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4 +.if \\n(.$=5 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP +.if \\n(.$=6 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6 +.if \\n(.$=7 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP +.if \\n(.$=8 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8 +.if \\n(.$=9 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8\ +*(Cw +.. +.nr Cl 4 +.SA 1 +.TL +A Consumer Library Interface to DWARF +.AF "" +.AU "David Anderson" +.PF "'\*(vE'- \\\\nP -''" +.AS 1 +This document describes an interface to a library of functions +.FS +UNIX is a registered trademark of UNIX System Laboratories, Inc. +in the United States and other countries. +.FE +to access DWARF debugging information entries and DWARF line number +information (and other DWARF2/3 information). +It does not make recommendations as to how the functions +described in this document should be implemented nor does it +suggest possible optimizations. +.P +The document is oriented to reading DWARF version 2 +and version 3. +There are certain sections which are SGI-specific (those +are clearly identified in the document). +.P +\*(vE + +.AE +.MT 4 + +.H 1 "INTRODUCTION" +This document describes an interface to \fIlibdwarf\fP, a +library of functions to provide access to DWARF debugging information +records, DWARF line number information, DWARF address range and global +names information, weak names information, DWARF frame description +information, DWARF static function names, DWARF static variables, and +DWARF type information. +.P +The document has long mentioned the +"Unix International Programming Languages Special Interest Group" +(PLSIG), under whose auspices the +DWARF committee was formed around 1991. +"Unix International" +was disbanded in the 1990s and no longer exists. +.P +The DWARF committee published DWARF2 July 27, 1993. +.P +In the mid 1990s this document and the library it describes +(which the committee never endorsed, having decided +not to endorse or approve any particular library interface) +was made available on the internet by Silicon Graphics, Inc. +.P +In 2005 the DWARF committee began an affiliation with FreeStandards.org. +In 2007 FreeStandards.org merged with The Linux Foundation. +The DWARF committee dropped its affiliation with FreeStandards.org +in 2007 and established the dwarfstd.org website. +See "http://www.dwarfstd.org" for current +information on standardization activities +and a copy of the standard. +.H 2 "Copyright" +Copyright 1993-2006 Silicon Graphics, Inc. + +Copyright 2007-2011 David Anderson. + +Permission is hereby granted to +copy or republish or use any or all of this document without +restriction except that when publishing more than a small amount +of the document +please acknowledge Silicon Graphics, Inc and David Anderson. + +This document 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. + +.H 2 "Purpose and Scope" +The purpose of this document is to document a library of functions +to access DWARF debugging information. There is no effort made in +this document to address the creation of these records as those +issues are addressed separately +(see "A Producer Library Interface to DWARF"). + +.P +Additionally, the focus of this document is the functional interface, +and as such, implementation as well as optimization issues are +intentionally ignored. + + +.H 2 "Document History" +.P +A document was written about 1991 which had similar +layout and interfaces. +Written by people from Hal Corporation, +That document described a library for reading DWARF1. +The authors distributed paper copies to the committee +with the clearly expressed intent to propose the document as +a supported interface definition. +The committee decided not to pursue a library definition. +.P +SGI wrote the document you are now reading in 1993 +with a similar layout and content and organization, but +it was complete document rewrite with the intent to read DWARF2 +(the DWARF version then in existence). +The intent was (and is) to also cover +future revisions of DWARF. +All the function interfaces were changed +in 1994 to uniformly +return a simple integer success-code (see DW_DLV_OK etc), +generally following +the recommendations in the chapter titled "Candy Machine Interfaces" +of "Writing Solid Code", a book by +Steve Maguire (published by Microsoft Press). +.H 2 "Definitions" +DWARF debugging information entries (DIEs) are the segments of information +placed in the \f(CW.debug_*\fP sections by compilers, assemblers, and +linkage editors that, in conjunction with line number entries, are +necessary for symbolic source-level debugging. +Refer to the latest +"\fIDWARF Debugging Information Format\fP" from www.dwarfstd.org for a more +complete description of these entries. + +.P +This document adopts all the terms and definitions in "\fIDWARF Debugging +Information Format\fP" versions 2,3, and 4. +It originally focused on the implementation at +Silicon Graphics, Inc., but now +attempts to be more generally useful. + +.H 2 "Overview" +The remaining sections of this document describe the proposed interface +to \f(CWlibdwarf\fP, first by describing the purpose of additional types +defined by the interface, followed by descriptions of the available +operations. This document assumes you are thoroughly familiar with the +information contained in the \fIDWARF Debugging Information Format\fP +document. +.P +We separate the functions into several categories to emphasize that not +all consumers want to use all the functions. We call the categories +Debugger, Internal-level, High-level, and Miscellaneous not because one is more +important than another but as a way of making the rather large set of +function calls easier to understand. +.P +Unless otherwise specified, all functions and structures should be +taken as being designed for Debugger consumers. +.P +The Debugger Interface of this library is intended to be used by debuggers. +The interface is low-level (close to dwarf) but suppresses irrelevant detail. +A debugger will want to absorb all of some sections at startup and will +want to see little or nothing of some sections except at need. And even +then will probably want to absorb only the information in a single compilation +unit at a time. A debugger does not care about +implementation details of the library. +.P +The Internal-level Interface is for a DWARF prettyprinter and checker. +A +thorough prettyprinter will want to know all kinds of internal things +(like actual FORM numbers and actual offsets) so it can check for +appropriate structure in the DWARF data and print (on request) all +that internal information for human users and libdwarf authors and +compiler-writers. +Calls in this interface provide data a debugger +does not care about. +.P +The High-level Interface is for higher level access +(it is not really a high level interface!). +Programs such as +disassemblers will want to be able to display relevant information +about functions and line numbers without having to invest too much +effort in looking at DWARF. +.P +The miscellaneous interface is just what is left over: the error handler +functions. +.P +The following is a brief mention of the changes in this libdwarf from +the libdwarf draft for DWARF Version 1 and recent changes. +.H 2 "Items Changed" +.P +Added new functions (some for libdwarf client code) +and internal logic support for the +DWARF4 .debug_types section. +The new functions are +dwarf_next_cu_header_c(), +dwarf_siblingof_b(), dwarf_offdie_b(), +dwarf_get_cu_die_offset_given_cu_header_offset_b(), +dwarf_get_die_infotypes_flag(), +dwarf_get_section_max_offsets_b(). +.P +New functions and logic support additional detailed error reporting +so that more compiler bugs can be reported sensibly +by consumer code (as opposed +to having libdwarf just assume +things are ok and blindly continuing on +with erroneous data). +November 20, 2010 +.P +It seems impossible to default to both DW_FRAME_CFA_COL +and DW_FRAME_CFA_COL3 in a single build of libdwarf, +so the default is now unambiguously DW_FRAME_CFA_COL3 +unless the configure option --enable-oldframecol +is specified at configure time. +The function dwarf_set_frame_cfa_value() +may be used to override the default : using that function gives +consumer applications full control (its use is highly +recommended). +(January 17,2010) +.P +Added dwarf_set_reloc_application() and the default +automatic application of Elf 'rela' relocations +to DWARF sections (such rela sections appear in .o files, not +in executables or shared objects, in general). +The dwarf_set_reloc_application() routine lets a consumer +turn off the automatic application of 'rela' relocations +if desired (it is not clear why anyone would really want to do that, +but possibly a consumer could write its own relocation application). +An example application that traverses a set of DIEs +was added to the new dwarfexample directory (not +in this libdwarf directory, but in parallel to it). +(July 10, 2009) +.P +Added dwarf_get_TAG_name() (and the FORM AT and so on) +interface functions so applications can get the string +of the TAG, Attribute, etc as needed. (June 2009) +.P +Added dwarf_get_ranges_a() and dwarf_loclist_from_expr_a() +functions which add arguments allowing a correct address_size +when the address_size varies by compilation unit (a varying +address_size is quite rare as of May 2009). +(May 2009) +.P +Added dwarf_set_frame_same_value(), and +dwarf_set_frame_undefined_value() to complete +the set of frame-information functions needed to allow +an application get all frame information +returned correctly (meaning that it +can be correctly interpreted) for all ABIs. +Documented dwarf_set_frame_cfa_value(). +Corrected spelling to dwarf_set_frame_rule_initial_value(). +(April 2009). +.P +Added support for various DWARF3 features, but primarily +a new frame-information interface tailorable at run-time +to more than a single ABI. +See dwarf_set_frame_rule_initial_value(), dwarf_set_frame_rule_table_size(), +dwarf_set_frame_cfa_value(). +See also dwarf_get_fde_info_for_reg3() and +dwarf_get_fde_info_for_cfa_reg3(). (April 2006) +.P +Added support for DWARF3 .debug_pubtypes section. +Corrected various leaks (revising dealloc() calls, adding +new functions) and corrected dwarf_formstring() documentation. +.P +Added dwarf_srclines_dealloc() as the previous deallocation +method documented for data returned by +dwarf_srclines() was incapable of freeing +all the allocated storage (14 July 2005). +.P +dwarf_nextglob(), dwarf_globname(), and dwarf_globdie() were all changed +to operate on the items in the .debug_pubnames section. +.P +All functions were modified to return solely an error code. +Data is returned through pointer arguments. +This makes writing safe and correct library-using-code far easier. +For justification for this approach, see +the chapter titled "Candy Machine Interfaces" +in the book "Writing Solid Code" by +Steve Maguire. + +.H 2 "Items Removed" +.P +Dwarf_Type +was removed since types are no longer special. +.P +dwarf_typeof() +was removed since types are no longer special. +.P +Dwarf_Ellist +was removed since element lists no longer are a special format. +.P +Dwarf_Bounds +was removed since bounds have been generalized. +.P +dwarf_nextdie() +was replaced by dwarf_next_cu_header() to reflect the +real way DWARF is organized. +The dwarf_nextdie() was only useful for getting to compilation +unit beginnings, so it does not seem harmful to remove it in favor +of a more direct function. +.P +dwarf_childcnt() is removed on grounds +that no good use was apparent. +.P +dwarf_prevline() and dwarf_nextline() were removed on grounds this +is better left to a debugger to do. +Similarly, dwarf_dieline() was removed. +.P +dwarf_is1stline() was removed as it was not meaningful for the +revised DWARF line operations. +.P +Any libdwarf implementation might well decide to support all the +removed functionality and to retain the DWARF Version 1 meanings +of that functionality. +This would be difficult because the +original libdwarf draft +specification used traditional C library interfaces which +confuse the values returned by successful calls with +exceptional conditions like failures and 'no more data' indications. + +.H 2 "Revision History" +.VL 15 +.LI "October 2011" +DWARF4 support for reading .debug_types added. +.LI "March 93" +Work on DWARF2 SGI draft begins +.LI "June 94" +The function returns are changed to return an error/success code +only. +.LI "April 2006: +Support for DWARF3 consumer operations is close to completion. +.LI "November 2010: +Added various new functions and improved error checking. +.LE + +.H 1 "Types Definitions" + +.H 2 "General Description" +The \fIlibdwarf.h\fP header file contains typedefs and preprocessor +definitions of types and symbolic names used to reference objects +of \fIlibdwarf\fP. The types defined by typedefs contained in +\fIlibdwarf.h\fP all use the convention of adding \f(CWDwarf_\fP +as a prefix and can be placed in three categories: + +.BL +.LI +Scalar types : The scalar types defined in \fIlibdwarf.h\fP are +defined primarily for notational convenience and identification. +Depending on the individual definition, they are interpreted as a +value, a pointer, or as a flag. +.LI +Aggregate types : Some values can not be represented by a single +scalar type; they must be represented by a collection of, or as a +union of, scalar and/or aggregate types. +.LI +Opaque types : The complete definition of these types is intentionally +omitted; their use is as handles for query operations, which will yield +either an instance of another opaque type to be used in another query, or +an instance of a scalar or aggregate type, which is the actual result. +.P + +.H 2 "Scalar Types" +The following are the defined by \fIlibdwarf.h\fP: + +.DS +\f(CW +typedef int Dwarf_Bool; +typedef unsigned long long Dwarf_Off; +typedef unsigned long long Dwarf_Unsigned; +typedef unsigned short Dwarf_Half; +typedef unsigned char Dwarf_Small; +typedef signed long long Dwarf_Signed; +typedef unsigned long long Dwarf_Addr; +typedef void *Dwarf_Ptr; +typedef void (*Dwarf_Handler)(Dwarf_Error *error, Dwarf_Ptr errarg); +.DE + +.nr aX \n(Fg+1 +Dwarf_Ptr is an address for use by the host program calling the library, +not for representing pc-values/addresses within the target object file. +Dwarf_Addr is for pc-values within the target object file. The sample +scalar type assignments above are for a \fIlibdwarf.h\fP that can read +and write +32-bit or 64-bit binaries on a 32-bit or 64-bit host machine. +The types must be defined appropriately +for each implementation of libdwarf. +A description of these scalar types in the SGI/MIPS +environment is given in Figure \n(aX. + +.DS +.TS +center box, tab(:); +lfB lfB lfB lfB +l c c l. +NAME:SIZE:ALIGNMENT:PURPOSE +_ +Dwarf_Bool:4:4:Boolean states +Dwarf_Off:8:8:Unsigned file offset +Dwarf_Unsigned:8:8:Unsigned large integer +Dwarf_Half:2:2:Unsigned medium integer +Dwarf_Small:1:1:Unsigned small integer +Dwarf_Signed:8:8:Signed large integer +Dwarf_Addr:8:8:Program address +:::(target program) +Dwarf_Ptr:4|8:4|8:Dwarf section pointer +:::(host program) +Dwarf_Handler:4|8:4|8:Pointer to +:::error handler function +.TE +.FG "Scalar Types" +.DE + +.H 2 "Aggregate Types" +The following aggregate types are defined by +\fIlibdwarf.h\fP: +\f(CWDwarf_Loc\fP, +\f(CWDwarf_Locdesc\fP, +\f(CWDwarf_Block\fP, +\f(CWDwarf_Frame_Op\fP. +\f(CWDwarf_Regtable\fP. +\f(CWDwarf_Regtable3\fP. +While most of \f(CWlibdwarf\fP acts on or returns simple values or +opaque pointer types, this small set of structures seems useful. + +.H 3 "Location Record" +The \f(CWDwarf_Loc\fP type identifies a single atom of a location description +or a location expression. + +.DS +\f(CWtypedef struct { + Dwarf_Small lr_atom; + Dwarf_Unsigned lr_number; + Dwarf_Unsigned lr_number2; + Dwarf_Unsigned lr_offset; +} Dwarf_Loc;\fP +.DE + +The \f(CWlr_atom\fP identifies the atom corresponding to the \f(CWDW_OP_*\fP +definition in \fIdwarf.h\fP and it represents the operation to be performed +in order to locate the item in question. + +.P +The \f(CWlr_number\fP field is the operand to be used in the calculation +specified by the \f(CWlr_atom\fP field; not all atoms use this field. +Some atom operations imply signed numbers so it is necessary to cast +this to a \f(CWDwarf_Signed\fP type for those operations. + +.P +The \f(CWlr_number2\fP field is the second operand specified by the +\f(CWlr_atom\fP field; only \f(CWDW_OP_BREGX\fP has this field. Some +atom operations imply signed numbers so it may be necessary to cast +this to a \f(CWDwarf_Signed\fP type for those operations. +.P +For a \f(CWDW_OP_implicit_value\fP operator the \f(CWlr_number2\fP +field is a pointer to the bytes of the value. The field pointed to +is \f(CWlr_number\fP bytes long. There is no explicit terminator. +Do not attempt to \f(CWfree\fP the bytes which \f(CWlr_number2\fP +points at and do not alter those bytes. The pointer value +remains valid till the open Dwarf_Debug is closed. +This is a rather ugly use of a host integer to hold a pointer. +You will normally have to do a 'cast' operation to use the value. +.P +The \f(CWlr_offset\fP field is the byte offset (within the block the +location record came from) of the atom specified by the \f(CWlr_atom\fP +field. This is set on all atoms. This is useful for operations +\f(CWDW_OP_SKIP\fP and \f(CWDW_OP_BRA\fP. + +.H 3 "Location Description" +The \f(CWDwarf_Locdesc\fP type represents an ordered list of +\f(CWDwarf_Loc\fP records used in the calculation to locate +an item. Note that in many cases, the location can only be +calculated at runtime of the associated program. + +.DS +\f(CWtypedef struct { + Dwarf_Addr ld_lopc; + Dwarf_Addr ld_hipc; + Dwarf_Unsigned ld_cents; + Dwarf_Loc* ld_s; +} Dwarf_Locdesc;\fP +.DE + +The \f(CWld_lopc\fP and \f(CWld_hipc\fP fields provide an address range for +which this location descriptor is valid. Both of these fields are set to +\fIzero\fP if the location descriptor is valid throughout the scope of the +item it is associated with. These addresses are virtual memory addresses, +not offsets-from-something. The virtual memory addresses do not account +for dso movement (none of the pc values from libdwarf do that, it is up to +the consumer to do that). + +.P +The \f(CWld_cents\fP field contains a count of the number of \f(CWDwarf_Loc\fP +entries pointed to by the \f(CWld_s\fP field. + +.P +The \f(CWld_s\fP field points to an array of \f(CWDwarf_Loc\fP records. + +.H 3 "Data Block" +.SP +The \f(CWDwarf_Block\fP type is used to contain the value of an attribute +whose form is either \f(CWDW_FORM_block1\fP, \f(CWDW_FORM_block2\fP, +\f(CWDW_FORM_block4\fP, \f(CWDW_FORM_block8\fP, or \f(CWDW_FORM_block\fP. +Its intended use is to deliver the value for an attribute of any of these +forms. + +.DS +\f(CWtypedef struct { + Dwarf_Unsigned bl_len; + Dwarf_Ptr bl_data; +} Dwarf_Block;\fP +.DE + +.P +The \f(CWbl_len\fP field contains the length in bytes of the data pointed +to by the \f(CWbl_data\fP field. + +.P +The \f(CWbl_data\fP field contains a pointer to the uninterpreted data. +Since we use a \f(CWDwarf_Ptr\fP here one must copy the pointer to some +other type (typically an \f(CWunsigned char *\fP) so one can add increments +to index through the data. The data pointed to by \f(CWbl_data\fP is not +necessarily at any useful alignment. + +.H 3 "Frame Operation Codes: DWARF 2" +This interface is adequate for DWARF2 but not for DWARF3. +A separate interface usable for DWARF3 and for DWARF2 is described below. +This interface is deprecated. Use the interface for DWARF3 and DWARF2. +See also the section "Low Level Frame Operations" below. +.P +The DWARF2 \f(CWDwarf_Frame_Op\fP type is used to contain the data of a single +instruction of an instruction-sequence of low-level information from the +section containing frame information. This is ordinarily used by +Internal-level Consumers trying to print everything in detail. + +.DS +\f(CWtypedef struct { + Dwarf_Small fp_base_op; + Dwarf_Small fp_extended_op; + Dwarf_Half fp_register; + Dwarf_Signed fp_offset; + Dwarf_Offset fp_instr_offset; +} Dwarf_Frame_Op; +.DE + +\f(CWfp_base_op\fP is the 2-bit basic op code. \f(CWfp_extended_op\fP is +the 6-bit extended opcode (if \f(CWfp_base_op\fP indicated there was an +extended op code) and is zero otherwise. +.P +\f(CWfp_register\fP +is any (or the first) register value as defined +in the \f(CWCall Frame Instruction Encodings\fP figure +in the \f(CWdwarf\fP document. +If not used with the Op it is 0. +.P +\f(CWfp_offset\fP +is the address, delta, offset, or second register as defined +in the \f(CWCall Frame Instruction Encodings\fP figure +in the \f(CWdwarf\fP document. +If this is an \f(CWaddress\fP then the value should be cast to +\f(CW(Dwarf_Addr)\fP before being used. +In any implementation this field *must* be as large as the +larger of Dwarf_Signed and Dwarf_Addr for this to work properly. +If not used with the op it is 0. +.P +\f(CWfp_instr_offset\fP is the byte_offset (within the instruction +stream of the frame instructions) of this operation. It starts at 0 +for a given frame descriptor. + +.H 3 "Frame Regtable: DWARF 2" +This interface is adequate for DWARF2 +and MIPS but not for DWARF3. +A separate and preferred interface usable for DWARF3 and for DWARF2 +is described below. +See also the section "Low Level Frame Operations" below. +.P +The \f(CWDwarf_Regtable\fP type is used to contain the +register-restore information for all registers at a given +PC value. +Normally used by debuggers. +If you wish to default to this interface and to the use +of DW_FRAME_CFA_COL, specify --enable_oldframecol +at libdwarf configure time. +Or add a call dwarf_set_frame_cfa_value(dbg,DW_FRAME_CFA_COL) +after your dwarf_init() call, this call replaces the +default libdwarf-compile-time value with DW_FRAME_CFA_COL. +.DS +/* DW_REG_TABLE_SIZE must reflect the number of registers + *(DW_FRAME_LAST_REG_NUM) as defined in dwarf.h + */ +#define DW_REG_TABLE_SIZE <fill in size here, 66 for MIPS/IRIX> +\f(CWtypedef struct { + struct { + Dwarf_Small dw_offset_relevant; + Dwarf_Half dw_regnum; + Dwarf_Addr dw_offset; + } rules[DW_REG_TABLE_SIZE]; +} Dwarf_Regtable;\fP +.DE +.P +The array is indexed by register number. +The field values for each index are described next. +For clarity we describe the field values for index rules[M] +(M being any legal array element index). +.P +\f(CWdw_offset_relevant\fP is non-zero to indicate the \f(CWdw_offset\fP +field is meaningful. If zero then the \f(CWdw_offset\fP is zero +and should be ignored. +.P +\f(CWdw_regnum \fPis the register number applicable. +If \f(CWdw_offset_relevant\fP is zero, then this is the register +number of the register containing the value for register M. +If \f(CWdw_offset_relevant\fP is non-zero, then this is +the register number of the register to use as a base (M may be +DW_FRAME_CFA_COL, for example) and the \f(CWdw_offset\fP +value applies. The value of register M is therefore +the value of register \f(CWdw_regnum\fP. +.P +\f(CWdw_offset\fP should be ignored if \f(CWdw_offset_relevant\fP is zero. +If \f(CWdw_offset_relevant\fP is non-zero, then +the consumer code should add the value to +the value of the register \f(CWdw_regnum\fP to produce the +value. + +.H 3 "Frame Operation Codes: DWARF 3 (and DWARF2)" +This interface is adequate for DWARF3 and for DWARF2 (and DWARF4). +It is new in libdwarf in April 2006. +See also the section "Low Level Frame Operations" below. +.P +The DWARF2 \f(CWDwarf_Frame_Op3\fP type is used to contain the data of a single +instruction of an instruction-sequence of low-level information from the +section containing frame information. This is ordinarily used by +Internal-level Consumers trying to print everything in detail. + +.DS +\f(CWtypedef struct { + Dwarf_Small fp_base_op; + Dwarf_Small fp_extended_op; + Dwarf_Half fp_register; + + /* Value may be signed, depends on op. + Any applicable data_alignment_factor has + not been applied, this is the raw offset. */ + Dwarf_Unsigned fp_offset_or_block_len; + Dwarf_Small *fp_expr_block; + + Dwarf_Off fp_instr_offset; +} Dwarf_Frame_Op3;\fP +.DE + +\f(CWfp_base_op\fP is the 2-bit basic op code. \f(CWfp_extended_op\fP is +the 6-bit extended opcode (if \f(CWfp_base_op\fP indicated there was an +extended op code) and is zero otherwise. +.P +\f(CWfp_register\fP +is any (or the first) register value as defined +in the \f(CWCall Frame Instruction Encodings\fP figure +in the \f(CWdwarf\fP document. +If not used with the Op it is 0. +.P +\f(CWfp_offset_or_block_len\fP +is the address, delta, offset, or second register as defined +in the \f(CWCall Frame Instruction Encodings\fP figure +in the \f(CWdwarf\fP document. Or (depending on the op, it +may be the length of the dwarf-expression block pointed to +by \f(CWfp_expr_block\fP. +If this is an \f(CWaddress\fP then the value should be cast to +\f(CW(Dwarf_Addr)\fP before being used. +In any implementation this field *must* be as large as the +larger of Dwarf_Signed and Dwarf_Addr for this to work properly. +If not used with the op it is 0. +.P +\f(CWfp_expr_block\fP (if applicable to the op) +points to a dwarf-expression block which is \f(CWfp_offset_or_block_len\fP +bytes long. +.P +\f(CWfp_instr_offset\fP is the byte_offset (within the instruction +stream of the frame instructions) of this operation. It starts at 0 +for a given frame descriptor. + +.H 3 "Frame Regtable: DWARF 3" +This interface is adequate for DWARF3 and for DWARF2. +It is new in libdwarf as of April 2006. +The default configure of libdwarf +inserts DW_FRAME_CFA_COL3 as the default CFA column. +Or add a call dwarf_set_frame_cfa_value(dbg,DW_FRAME_CFA_COL3) +after your dwarf_init() call, this call replaces the +default libdwarf-compile-time value with DW_FRAME_CFA_COL3. +.P +The \f(CWDwarf_Regtable3\fP type is used to contain the +register-restore information for all registers at a given +PC value. +Normally used by debuggers. +.DS +\f(CWtypedef struct Dwarf_Regtable_Entry3_s { + Dwarf_Small dw_offset_relevant; + Dwarf_Small dw_value_type; + Dwarf_Half dw_regnum; + Dwarf_Unsigned dw_offset_or_block_len; + Dwarf_Ptr dw_block_ptr; +}Dwarf_Regtable_Entry3; + +typedef struct Dwarf_Regtable3_s { + struct Dwarf_Regtable_Entry3_s rt3_cfa_rule; + + Dwarf_Half rt3_reg_table_size; + struct Dwarf_Regtable_Entry3_s * rt3_rules; +} Dwarf_Regtable3;\fP + +.DE +.P +The array is indexed by register number. +The field values for each index are described next. +For clarity we describe the field values for index rules[M] +(M being any legal array element index). +(DW_FRAME_CFA_COL3 DW_FRAME_SAME_VAL, DW_FRAME_UNDEFINED_VAL +are not legal array indexes, nor is any index < 0 or >= +rt3_reg_table_size); +The caller of routines using this +struct must create data space for rt3_reg_table_size entries +of struct Dwarf_Regtable_Entry3_s and arrange that +rt3_rules points to that space and that rt3_reg_table_size +is set correctly. The caller need not (but may) +initialize the contents of the rt3_cfa_rule or the rt3_rules array. +The following applies to each rt3_rules rule M: +.P +.in +4 +\f(CWdw_regnum\fP is the register number applicable. +If \f(CWdw_regnum\fP is DW_FRAME_UNDEFINED_VAL, then the +register I has undefined value. +If \f(CWdw_regnum\fP is DW_FRAME_SAME_VAL, then the +register I has the same value as in the previous frame. +.P +If \f(CWdw_regnum\fP is neither of these two, then the following apply: +.P +.P +\f(CWdw_value_type\fP determines the meaning of the other fields. +It is one of DW_EXPR_OFFSET (0), +DW_EXPR_VAL_OFFSET(1), DW_EXPR_EXPRESSION(2) or +DW_EXPR_VAL_EXPRESSION(3). + +.P +If \f(CWdw_value_type\fP is DW_EXPR_OFFSET (0) then +this is as in DWARF2 and the offset(N) rule or the register(R) +rule +of the DWARF3 and DWARF2 document applies. +The value is either: +.in +4 +If \f(CWdw_offset_relevant\fP is non-zero, then \f(CWdw_regnum\fP +is effectively ignored but must be identical to +DW_FRAME_CFA_COL3 (and the \f(CWdw_offset\fP value applies. +The value of register M is therefore +the value of CFA plus the value +of \f(CWdw_offset\fP. The result of the calculation +is the address in memory where the value of register M resides. +This is the offset(N) rule of the DWARF2 and DWARF3 documents. +.P +\f(CWdw_offset_relevant\fP is zero it indicates the \f(CWdw_offset\fP +field is not meaningful. +The value of register M is +the value currently in register \f(CWdw_regnum\fP (the +value DW_FRAME_CFA_COL3 must not appear, only real registers). +This is the register(R) rule of the DWARF3 spec. +.in -4 + +.P +If \f(CWdw_value_type\fP is DW_EXPR_OFFSET (1) then +this is the the val_offset(N) rule of the DWARF3 spec applies. +The calculation is identical to that of DW_EXPR_OFFSET (0) +but the value is interpreted as the value of register M +(rather than the address where register M's value is stored). +.P +If \f(CWdw_value_type\fP is DW_EXPR_EXPRESSION (2) then +this is the the expression(E) rule of the DWARF3 document. +.P +.in +4 +\f(CWdw_offset_or_block_len\fP is the length in bytes of +the in-memory block pointed at by \f(CWdw_block_ptr\fP. +\f(CWdw_block_ptr\fP is a DWARF expression. +Evaluate that expression and the result is the address +where the previous value of register M is found. +.in -4 +.P +If \f(CWdw_value_type\fP is DW_EXPR_VAL_EXPRESSION (3) then +this is the the val_expression(E) rule of the DWARF3 spec. +.P +.in +4 +\f(CWdw_offset_or_block_len\fP is the length in bytes of +the in-memory block pointed at by \f(CWdw_block_ptr\fP. +\f(CWdw_block_ptr\fP is a DWARF expression. +Evaluate that expression and the result is the +previous value of register M. +.in -4 +.P +The rule \f(CWrt3_cfa_rule\fP is the current value of +the CFA. It is interpreted exactly like +any register M rule (as described just above) except that +\f(CWdw_regnum\fP cannot be CW_FRAME_CFA_REG3 or +DW_FRAME_UNDEFINED_VAL or DW_FRAME_SAME_VAL but must +be a real register number. +.in -4 + + + +.H 3 "Macro Details Record" +The \f(CWDwarf_Macro_Details\fP type gives information about +a single entry in the .debug.macinfo section. +.DS +\f(CWstruct Dwarf_Macro_Details_s { + Dwarf_Off dmd_offset; + Dwarf_Small dmd_type; + Dwarf_Signed dmd_lineno; + Dwarf_Signed dmd_fileindex; + char * dmd_macro; +}; +typedef struct Dwarf_Macro_Details_s Dwarf_Macro_Details; +.DE +.P +\f(CWdmd_offset\fP is the byte offset, within the .debug_macinfo +section, of this macro information. +.P +\f(CWdmd_type\fP is the type code of this macro info entry +(or 0, the type code indicating that this is the end of +macro information entries for a compilation unit. +See \f(CWDW_MACINFO_define\fP, etc in the DWARF document. +.P +\f(CWdmd_lineno\fP is the line number where this entry was found, +or 0 if there is no applicable line number. +.P +\f(CWdmd_fileindex\fP is the file index of the file involved. +This is only guaranteed meaningful on a \f(CWDW_MACINFO_start_file\fP +\f(CWdmd_type\fP. Set to -1 if unknown (see the functional +interface for more details). +.P +\f(CWdmd_macro\fP is the applicable string. +For a \f(CWDW_MACINFO_define\fP +this is the macro name and value. +For a +\f(CWDW_MACINFO_undef\fP, or +this is the macro name. +For a +\f(CWDW_MACINFO_vendor_ext\fP +this is the vendor-defined string value. +For other \f(CWdmd_type\fPs this is 0. + +.H 2 "Opaque Types" +The opaque types declared in \fIlibdwarf.h\fP are used as descriptors +for queries against DWARF information stored in various debugging +sections. Each time an instance of an opaque type is returned as a +result of a \fIlibdwarf\fP operation (\f(CWDwarf_Debug\fP excepted), +it should be freed, using \f(CWdwarf_dealloc()\fP when it is no longer +of use (read the following documentation for details, as in at least +one case there is a special routine provided for deallocation +and \f(CWdwarf_dealloc()\fP is not directly called: +see \f(CWdwarf_srclines()\fP). +Some functions return a number of instances of an opaque type +in a block, by means of a pointer to the block and a count of the number +of opaque descriptors in the block: +see the function description for deallocation rules for such functions. +The list of opaque types defined +in \fIlibdwarf.h\fP that are pertinent to the Consumer Library, and their +intended use is described below. + +.DS +\f(CWtypedef struct Dwarf_Debug_s* Dwarf_Debug;\fP +.DE +An instance of the \f(CWDwarf_Debug\fP type is created as a result of a +successful call to \f(CWdwarf_init()\fP, or \f(CWdwarf_elf_init()\fP, +and is used as a descriptor for subsequent access to most \f(CWlibdwarf\fP +functions on that object. The storage pointed to by this descriptor +should be not be freed, using the \f(CWdwarf_dealloc()\fP function. +Instead free it with \f(CWdwarf_finish()\fP. +.P + +.DS +\f(CWtypedef struct Dwarf_Die_s* Dwarf_Die;\fP +.DE +An instance of a \f(CWDwarf_Die\fP type is returned from a successful +call to the \f(CWdwarf_siblingof()\fP, \f(CWdwarf_child\fP, or +\f(CWdwarf_offdie_b()\fP function, and is used as a descriptor for queries +about information related to that DIE. The storage pointed to by this +descriptor should be freed, using \f(CWdwarf_dealloc()\fP with the allocation +type \f(CWDW_DLA_DIE\fP when no longer needed. + +.DS +\f(CWtypedef struct Dwarf_Line_s* Dwarf_Line;\fP +.DE +Instances of \f(CWDwarf_Line\fP type are returned from a successful call +to the \f(CWdwarf_srclines()\fP function, and are used as descriptors for +queries about source lines. The storage pointed to by these descriptors +should be individually freed, using \f(CWdwarf_dealloc()\fP with the +allocation type \f(CWDW_DLA_LINE\fP when no longer needed. + +.DS +\f(CWtypedef struct Dwarf_Global_s* Dwarf_Global;\fP +.DE +Instances of \f(CWDwarf_Global\fP type are returned from a successful +call to the \f(CWdwarf_get_globals()\fP function, and are used as +descriptors for queries about global names (pubnames). + +.DS +\f(CWtypedef struct Dwarf_Weak_s* Dwarf_Weak;\fP +.DE +Instances of \f(CWDwarf_Weak\fP type are returned from a successful call +to the +SGI-specific \f(CWdwarf_get_weaks()\fP +function, and are used as descriptors for +queries about weak names. The storage pointed to by these descriptors +should be individually freed, using \f(CWdwarf_dealloc()\fP with the +allocation type +\f(CWDW_DLA_WEAK_CONTEXT\fP +(or +\f(CWDW_DLA_WEAK\fP, an older name, supported for compatibility) +when no longer needed. + +.DS +\f(CWtypedef struct Dwarf_Func_s* Dwarf_Func;\fP +.DE +Instances of \f(CWDwarf_Func\fP type are returned from a successful +call to the +SGI-specific \f(CWdwarf_get_funcs()\fP +function, and are used as +descriptors for queries about static function names. + +.DS +\f(CWtypedef struct Dwarf_Type_s* Dwarf_Type;\fP +.DE +Instances of \f(CWDwarf_Type\fP type are returned from a successful call +to the +SGI-specific \f(CWdwarf_get_types()\fP +function, and are used as descriptors for +queries about user defined types. + +.DS +\f(CWtypedef struct Dwarf_Var_s* Dwarf_Var;\fP +.DE +Instances of \f(CWDwarf_Var\fP type are returned from a successful call +to the SGI-specific \f(CWdwarf_get_vars()\fP +function, and are used as descriptors for +queries about static variables. + +.DS +\f(CWtypedef struct Dwarf_Error_s* Dwarf_Error;\fP +.DE +This descriptor points to a structure that provides detailed information +about errors detected by \f(CWlibdwarf\fP. Users typically provide a +location for \f(CWlibdwarf\fP to store this descriptor for the user to +obtain more information about the error. The storage pointed to by this +descriptor should be freed, using \f(CWdwarf_dealloc()\fP with the +allocation type \f(CWDW_DLA_ERROR\fP when no longer needed. + +.DS +\f(CWtypedef struct Dwarf_Attribute_s* Dwarf_Attribute;\fP +.DE +Instances of \f(CWDwarf_Attribute\fP type are returned from a successful +call to the \f(CWdwarf_attrlist()\fP, or \f(CWdwarf_attr()\fP functions, +and are used as descriptors for queries about attribute values. The storage +pointed to by this descriptor should be individually freed, using +\f(CWdwarf_dealloc()\fP with the allocation type \f(CWDW_DLA_ATTR\fP when +no longer needed. + +.DS +\f(CWtypedef struct Dwarf_Abbrev_s* Dwarf_Abbrev;\fP +.DE +An instance of a \f(CWDwarf_Abbrev\fP type is returned from a successful +call to \f(CWdwarf_get_abbrev()\fP, and is used as a descriptor for queries +about abbreviations in the .debug_abbrev section. The storage pointed to +by this descriptor should be freed, using \f(CWdwarf_dealloc()\fP with the +allocation type \f(CWDW_DLA_ABBREV\fP when no longer needed. + +.DS +\f(CWtypedef struct Dwarf_Fde_s* Dwarf_Fde;\fP +.DE +Instances of \f(CWDwarf_Fde\fP type are returned from a successful call +to the \f(CWdwarf_get_fde_list()\fP, \f(CWdwarf_get_fde_for_die()\fP, or +\f(CWdwarf_get_fde_at_pc()\fP functions, and are used as descriptors for +queries about frames descriptors. + +.DS +\f(CWtypedef struct Dwarf_Cie_s* Dwarf_Cie;\fP +.DE +Instances of \f(CWDwarf_Cie\fP type are returned from a successful call +to the \f(CWdwarf_get_fde_list()\fP function, and are used as descriptors +for queries about information that is common to several frames. + +.DS +\f(CWtypedef struct Dwarf_Arange_s* Dwarf_Arange;\fP +.DE +Instances of \f(CWDwarf_Arange\fP type are returned from successful calls +to the \f(CWdwarf_get_aranges()\fP, or \f(CWdwarf_get_arange()\fP functions, +and are used as descriptors for queries about address ranges. The storage +pointed to by this descriptor should be individually freed, using +\f(CWdwarf_dealloc()\fP with the allocation type \f(CWDW_DLA_ARANGE\fP when +no longer needed. + +.H 1 "Error Handling" +The method for detection and disposition of error conditions that arise +during access of debugging information via \fIlibdwarf\fP is consistent +across all \fIlibdwarf\fP functions that are capable of producing an +error. This section describes the method used by \fIlibdwarf\fP in +notifying client programs of error conditions. + +.P +Most functions within \fIlibdwarf\fP accept as an argument a pointer to +a \f(CWDwarf_Error\fP descriptor where a \f(CWDwarf_Error\fP descriptor +is stored if an error is detected by the function. Routines in the client +program that provide this argument can query the \f(CWDwarf_Error\fP +descriptor to determine the nature of the error and perform appropriate +processing. + +.P +A client program can also specify a function to be invoked upon detection +of an error at the time the library is initialized (see \f(CWdwarf_init()\fP). +When a \fIlibdwarf\fP routine detects an error, this function is called +with two arguments: a code indicating the nature of the error and a pointer +provided by the client at initialization (again see \f(CWdwarf_init()\fP). +This pointer argument can be used to relay information between the error +handler and other routines of the client program. A client program can +specify or change both the error handling function and the pointer argument +after initialization using \f(CWdwarf_seterrhand()\fP and +\f(CWdwarf_seterrarg()\fP. + +.P +In the case where \fIlibdwarf\fP functions are not provided a pointer +to a \f(CWDwarf_Error\fP descriptor, and no error handling function was +provided at initialization, \fIlibdwarf\fP functions terminate execution +by calling \f(CWabort(3C)\fP. + +.P +The following lists the processing steps taken upon detection of an +error: +.AL 1 +.LI +Check the \f(CWerror\fP argument; if not a \fINULL\fP pointer, allocate +and initialize a \f(CWDwarf_Error\fP descriptor with information describing +the error, place this descriptor in the area pointed to by \f(CWerror\fP, +and return a value indicating an error condition. +.LI +If an \f(CWerrhand\fP argument was provided to \f(CWdwarf_init()\fP +at initialization, call \f(CWerrhand()\fP passing it the error descriptor +and the value of the \f(CWerrarg\fP argument provided to \f(CWdwarf_init()\fP. +If the error handling function returns, return a value indicating an +error condition. +.LI +Terminate program execution by calling \f(CWabort(3C)\fP. +.LE +.SP + +In all cases, it is clear from the value returned from a function +that an error occurred in executing the function, since +DW_DLV_ERROR is returned. +.P +As can be seen from the above steps, the client program can provide +an error handler at initialization, and still provide an \f(CWerror\fP +argument to \fIlibdwarf\fP functions when it is not desired to have +the error handler invoked. + +.P +If a \f(CWlibdwarf\fP function is called with invalid arguments, the +behavior is undefined. In particular, supplying a \f(CWNULL\fP pointer +to a \f(CWlibdwarf\fP function (except where explicitly permitted), +or pointers to invalid addresses or uninitialized data causes undefined +behavior; the return value in such cases is undefined, and the function +may fail to invoke the caller supplied error handler or to return a +meaningful error number. Implementations also may abort execution for +such cases. + +.P +Some errors are so inconsequential that it does not warrant +rejecting an object or returning an error. +An example would be a frame length not being a multiple of +an address-size (right now this is the only such inconsequential +error). To make it possible for a client to report such errors +the function \f(CWdwarf_get_harmless_error_list\fP +returns strings with error text in them. This function +may be ignored if client code does not want to bother with +such error reporting. See \f(CWDW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE\fP +in the libdwarf source code. + +.P +.H 2 "Returned values in the functional interface" +Values returned by \f(CWlibdwarf\fP functions to indicate +success and errors +.nr aX \n(Fg+1 +are enumerated in Figure \n(aX. +The \f(CWDW_DLV_NO_ENTRY\fP +case is useful for functions +need to indicate that while there was no data to return +there was no error either. +For example, \f(CWdwarf_siblingof()\fP +may return \f(CWDW_DLV_NO_ENTRY\fP to indicate that that there was +no sibling to return. +.DS +.TS +center box, tab(:); +lfB cfB lfB +l c l. +SYMBOLIC NAME:VALUE:MEANING +_ +DW_DLV_ERROR:1:Error +DW_DLV_OK:0:Successful call +DW_DLV_NO_ENTRY:-1:No applicable value +.TE +.FG "Error Indications" +.DE +.P +Each function in the interface that returns a value returns one +of the integers in the above figure. +.P +If \f(CWDW_DLV_ERROR\fP is returned and a pointer to a \f(CWDwarf_Error\fP +pointer is passed to the function, then a Dwarf_Error handle is returned +through the pointer. No other pointer value in the interface returns a value. +After the \f(CWDwarf_Error\fP is no longer of interest, +a \f(CWdwarf_dealloc(dbg,dw_err,DW_DLA_ERROR)\fP on the error +pointer is appropriate to free any space used by the error information. +.P +If \f(CWDW_DLV_NO_ENTRY\fP is returned no pointer value in the +interface returns a value. +.P +If \f(CWDW_DLV_OK\fP is returned, the \f(CWDwarf_Error\fP pointer, if +supplied, is not touched, but any other values to be returned +through pointers are returned. +In this case calls (depending on the exact function +returning the error) to \f(CWdwarf_dealloc()\fP may be appropriate +once the particular pointer returned is no longer of interest. +.P +Pointers passed to allow values to be returned through them are +uniformly the last pointers +in each argument list. +.P +All the interface functions are defined from the point of view of +the writer-of-the-library (as is traditional for UN*X library +documentation), not from the point of view of the user of the library. +The caller might code: +.P +.DS +\f(CWDwarf_Line line; +Dwarf_Signed ret_loff; +Dwarf_Error err; +int retval = dwarf_lineoff(line,&ret_loff,&err);\fP +.DE +for the function defined as +.P +.DS +\f(CWint dwarf_lineoff(Dwarf_Line line,Dwarf_Signed *return_lineoff, + Dwarf_Error* err);\fP +.DE +and this document refers to the function as +returning the value through *err or *return_lineoff or +uses the phrase "returns in +the location pointed to by err". +Sometimes other similar phrases are used. + +.H 1 "Memory Management" +Several of the functions that comprise \fIlibdwarf\fP return pointers +(opaque descriptors) to structures that have been dynamically allocated +by the library. To aid in the management of dynamic memory, the function +\f(CWdwarf_dealloc()\fP is provided to free storage allocated as a result +of a call to a \fIlibdwarf\fP function. This section describes the strategy +that should be taken by a client program in managing dynamic storage. + +.H 2 "Read-only Properties" +All pointers (opaque descriptors) returned by or as a result of a +\fIlibdwarf Consumer Library\fP +call should be assumed to point to read-only memory. +The results are undefined for \fIlibdwarf\fP clients that attempt +to write to a region pointed to by a value returned by a +\fIlibdwarf Consumer Library\fP +call. + +.H 2 "Storage Deallocation" +See the section "Returned values in the functional interface", +above, for the general rules where +calls to \f(CWdwarf_dealloc()\fP +is appropriate. +.P +In some cases the pointers returned by a \fIlibdwarf\fP call are pointers +to data which is not freeable. +The library knows from the allocation type +provided to it whether the space is freeable or not and will not free +inappropriately when \f(CWdwarf_dealloc()\fP is called. +So it is vital +that \f(CWdwarf_dealloc()\fP be called with the proper allocation type. +.P +For most storage allocated by \fIlibdwarf\fP, the client can free the +storage for reuse by calling \f(CWdwarf_dealloc()\fP, providing it with +the \f(CWDwarf_Debug\fP descriptor specifying the object for which the +storage was allocated, a pointer to the area to be free-ed, and an +identifier that specifies what the pointer points to (the allocation +type). For example, to free a \f(CWDwarf_Die die\fP belonging the the +object represented by \f(CWDwarf_Debug dbg\fP, allocated by a call to +\f(CWdwarf_siblingof()\fP, the call to \f(CWdwarf_dealloc()\fP would be: +.DS + \f(CWdwarf_dealloc(dbg, die, DW_DLA_DIE);\fP +.DE + +To free storage allocated in the form of a list of pointers (opaque +descriptors), each member of the list should be deallocated, followed +by deallocation of the actual list itself. The following code fragment +uses an invocation of \f(CWdwarf_attrlist()\fP as an example to illustrate +a technique that can be used to free storage from any \fIlibdwarf\fP +routine that returns a list: +.DS +\f(CWDwarf_Unsigned atcnt; +Dwarf_Attribute *atlist; +int errv; + +errv = dwarf_attrlist(somedie, &atlist,&atcnt, &error); +if (errv == DW_DLV_OK) { + + for (i = 0; i < atcnt; ++i) { + /* use atlist[i] */ + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); +}\fP +.DE + +The \f(CWDwarf_Debug\fP returned from \f(CWdwarf_init()\fP +or \f(CWdwarf_elf_init()\fP +cannot be freed using \f(CWdwarf_dealloc()\fP. +The function \f(CWdwarf_finish()\fP will deallocate all dynamic storage +associated with an instance of a \f(CWDwarf_Debug\fP type. In particular, +it will deallocate all dynamically allocated space associated with the +\f(CWDwarf_Debug\fP descriptor, and finally make the descriptor invalid. + +An \f(CWDwarf_Error\fP returned from \f(CWdwarf_init()\fP +or \f(CWdwarf_elf_init()\fP +in case of a failure cannot be freed +using \f(CWdwarf_dealloc()\fP. +The only way to free the \f(CWDwarf_Error\fP from either of those +calls is to use \f2free(3)\fP directly. +Every \f(CWDwarf_Error\fP must be freed +by \f(CWdwarf_dealloc()\fP except those +returned by \f(CWdwarf_init()\fP +or \f(CWdwarf_elf_init()\fP. + +.P +The codes that identify the storage pointed to in calls to +.nr aX \n(Fg+1 +\f(CWdwarf_dealloc()\fP are described in figure \n(aX. +.DS +.TS +center box, tab(:); +lfB lfB +l l. +IDENTIFIER:USED TO FREE +_ +DW_DLA_STRING : char* +DW_DLA_LOC : Dwarf_Loc +DW_DLA_LOCDESC : Dwarf_Locdesc +DW_DLA_ELLIST : Dwarf_Ellist (not used) +DW_DLA_BOUNDS : Dwarf_Bounds (not used) +DW_DLA_BLOCK : Dwarf_Block +DW_DLA_DEBUG : Dwarf_Debug (do not use) +DW_DLA_DIE : Dwarf_Die +DW_DLA_LINE : Dwarf_Line +DW_DLA_ATTR : Dwarf_Attribute +DW_DLA_TYPE : Dwarf_Type (not used) +DW_DLA_SUBSCR : Dwarf_Subscr (not used) +DW_DLA_GLOBAL_CONTEXT : Dwarf_Global +DW_DLA_ERROR : Dwarf_Error +DW_DLA_LIST : a list of opaque descriptors +DW_DLA_LINEBUF : Dwarf_Line* (not used) +DW_DLA_ARANGE : Dwarf_Arange +DW_DLA_ABBREV : Dwarf_Abbrev +DW_DLA_FRAME_OP : Dwarf_Frame_Op +DW_DLA_CIE : Dwarf_Cie +DW_DLA_FDE : Dwarf_Fde +DW_DLA_LOC_BLOCK : Dwarf_Loc Block +DW_DLA_FRAME_BLOCK : Dwarf_Frame Block (not used) +DW_DLA_FUNC_CONTEXT : Dwarf_Func +DW_DLA_TYPENAME_CONTEXT : Dwarf_Type +DW_DLA_VAR_CONTEXT : Dwarf_Var +DW_DLA_WEAK_CONTEXT : Dwarf_Weak +DW_DLA_PUBTYPES_CONTEXT : Dwarf_Pubtype +.TE +.FG "Allocation/Deallocation Identifiers" +.DE + +.P +.H 1 "Functional Interface" +This section describes the functions available in the \fIlibdwarf\fP +library. Each function description includes its definition, followed +by one or more paragraph describing the function's operation. + +.P +The following sections describe these functions. + +.H 2 "Initialization Operations" +These functions are concerned with preparing an object file for subsequent +access by the functions in \fIlibdwarf\fP and with releasing allocated +resources when access is complete. + +.H 3 "dwarf_init()" + +.DS +\f(CWint dwarf_init( + int fd, + Dwarf_Unsigned access, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * dbg, + Dwarf_Error *error)\fP +.DE +When it returns \f(CWDW_DLV_OK\fP, +the function \f(CWdwarf_init()\fP returns through +\f(CWdbg\fP a \f(CWDwarf_Debug\fP descriptor +that represents a handle for accessing debugging records associated with +the open file descriptor \f(CWfd\fP. +\f(CWDW_DLV_NO_ENTRY\fP is returned if the object +does not contain DWARF debugging information. +\f(CWDW_DLV_ERROR\fP is returned if +an error occurred. +The +\f(CWaccess\fP argument indicates what access is allowed for the section. +The \f(CWDW_DLC_READ\fP parameter is valid +for read access (only read access is defined or discussed in this +document). +The \f(CWerrhand\fP +argument is a pointer to a function that will be invoked whenever an error +is detected as a result of a \fIlibdwarf\fP operation. The \f(CWerrarg\fP +argument is passed as an argument to the \f(CWerrhand\fP function. +The file +descriptor associated with the \f(CWfd\fP argument must refer to an ordinary +file (i.e. not a pipe, socket, device, /proc entry, etc.), be opened with +the at least as much permission as specified by the \f(CWaccess\fP argument, +and cannot be closed or used as an argument to any system calls by the +client until after \f(CWdwarf_finish()\fP is called. +The seek position of +the file associated with \f(CWfd\fP is undefined upon return of +\f(CWdwarf_init()\fP. + +With SGI IRIX, by default it is allowed that the app +\f(CWclose()\fP \f(CWfd\fP immediately after calling \f(CWdwarf_init()\fP, +but that is not a portable approach (that it +works is an accidental +side effect of the fact that SGI IRIX uses \f(CWELF_C_READ_MMAP\fP +in its hidden internal call to \f(CWelf_begin()\fP). +The portable approach is to consider that \f(CWfd\fP +must be left open till after the corresponding dwarf_finish() call +has returned. + +Since \f(CWdwarf_init()\fP uses the same error handling processing as other +\fIlibdwarf\fP functions (see \fIError Handling\fP above), client programs +will generally supply an \f(CWerror\fP parameter to bypass the default actions +during initialization unless the default actions are appropriate. + +.H 3 "dwarf_elf_init()" +.DS +\f(CWint dwarf_elf_init( + Elf * elf_file_pointer, + Dwarf_Unsigned access, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * dbg, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_elf_init()\fP is identical to \f(CWdwarf_init()\fP +except that an open \f(CWElf *\fP pointer is passed instead of a file +descriptor. +In systems supporting \f(CWELF\fP object files this may be +more space or time-efficient than using \f(CWdwarf_init()\fP. +The client is allowed to use the \f(CWElf *\fP pointer +for its own purposes without restriction during the time the +\f(CWDwarf_Debug\fP +is open, except that the client should not \f(CWelf_end()\fP the +pointer till after \f(CWdwarf_finish\fP is called. + +.H 3 "dwarf_get_elf()" +.DS +\f(CWint dwarf_get_elf( + Dwarf_Debug dbg, + Elf ** elf, + Dwarf_Error *error)\fP +.DE +When it returns \f(CWDW_DLV_OK\fP, +the function \f(CWdwarf_get_elf()\fP returns through the +pointer \f(CWelf\fP the \f(CWElf *\fP handle +used to access the object represented by the \f(CWDwarf_Debug\fP +descriptor \f(CWdbg\fP. It returns \f(CWDW_DLV_ERROR\fP on error. + +Because \f(CWint dwarf_init()\fP opens an Elf descriptor +on its fd and \f(CWdwarf_finish()\fP does not close that +descriptor, an app should use \f(CWdwarf_get_elf\fP +and should call \f(CWelf_end\fP with the pointer returned +through the \f(CWElf**\fP handle created by \f(CWint dwarf_init()\fP. + +This function is not meaningful for a system that does not use the +Elf format for objects. + +.H 3 "dwarf_finish()" +.DS +\f(CWint dwarf_finish( + Dwarf_Debug dbg, + Dwarf_Error *error)\fP +.DE +The function +\f(CWdwarf_finish()\fP releases all \fILibdwarf\fP internal resources +associated with the descriptor \f(CWdbg\fP, and invalidates \f(CWdbg\fP. +It returns \f(CWDW_DLV_ERROR\fP if there is an error during the +finishing operation. It returns \f(CWDW_DLV_OK\fP +for a successful operation. + +Because \f(CWint dwarf_init()\fP opens an Elf descriptor +on its fd and \f(CWdwarf_finish()\fP does not close that +descriptor, an app should use \f(CWdwarf_get_elf\fP +and should call \f(CWelf_end\fP with the pointer returned +through the \f(CWElf**\fP handle created by \f(CWint dwarf_init()\fP. + +.H 3 "dwarf_set_stringcheck()" +.DS +\f(CWint dwarf_set_stringcheck( + int stringcheck)\fP +.DE +The function +\f(CWint dwarf_set_stringcheck()\fP sets a global flag +and returns the previous value of the global flag. + +If the stringcheck global flag is zero (the default) +libdwarf does not do string length validity checks. +If the stringcheck global flag is non-zero +libdwarf does do string length validity checks (the checks +do slow libdwarf down). + +The global flag is really just 8 bits long, upperbits are not noticed +or recorded. + +.H 3 "dwarf_set_reloc_application()" +.DS +\f(CWint dwarf_set_reloc_application( + int apply)\fP +.DE +The function +\f(CWint dwarf_set_reloc_application()\fP sets a global flag +and returns the previous value of the global flag. + +If the reloc_application global flag is non-zero (the default) +then the applicable .rela section (if one exists) will be +processed and applied to any DWARF section when it is read in. +If the reloc_application global flag is zero no such +relocation-application is attempted. + +Not all +machine types (elf header e_machine) +or all relocations are supported, but then very few +relocation types apply to DWARF debug sections. + +The global flag is really just 8 bits long, upperbits are not noticed +or recorded. + +It seems unlikely anyone will need to call this function. + +.H 3 "dwarf_record_cmdline_options()" +.DS +\f(CWint dwarf_record_cmdline_options( + Dwarf_Cmdline_Options options)\fP +.DE +The function +\f(CWint dwarf_record_cmdline_options()\fP +copies a Dwarf_Cmdline_Options structure from +consumer code to libdwarf. + +The structure is defined in \f(CWlibdwarf.h\fP. + +The initial version of this structure has a single field +\f(CWcheck_verbose_mode\fP which, if non-zero, tells +libdwarf to print some detailed messages to stdout in case +certain errors are detected. + +The default for this value is FALSE (0) so the extra messages +are off by default. + +.H 2 "Section size operations" +.P +These operations are informative but not normally needed. +.H 3 "dwarf_get_section_max_offsets_b()" +.DS +\f(CWint dwarf_get_section_max_offsets_b(Dwarf_debug dbg, + Dwarf_Unsigned * /*debug_info_size*/, + Dwarf_Unsigned * /*debug_abbrev_size*/, + Dwarf_Unsigned * /*debug_line_size*/, + Dwarf_Unsigned * /*debug_loc_size*/, + Dwarf_Unsigned * /*debug_aranges_size*/, + Dwarf_Unsigned * /*debug_macinfo_size*/, + Dwarf_Unsigned * /*debug_pubnames_size*/, + Dwarf_Unsigned * /*debug_str_size*/, + Dwarf_Unsigned * /*debug_frame_size*/, + Dwarf_Unsigned * /*debug_ranges_size*/, + Dwarf_Unsigned * /*debug_pubtypes_size*/, + Dwarf_Unsigned * /*debug_types_size*/); +.DE +.P +The function +\f(CWdwarf_get_section_max_offsets_b()\fP an open +Dwarf_Dbg and reports on the section sizes by pushing +section size values back through the pointers. + +Created in October 2011. + +.H 3 "dwarf_get_section_max_offsets()" +.DS +\f(CWint dwarf_get_section_max_offsets(Dwarf_debug dbg, + Dwarf_Unsigned * /*debug_info_size*/, + Dwarf_Unsigned * /*debug_abbrev_size*/, + Dwarf_Unsigned * /*debug_line_size*/, + Dwarf_Unsigned * /*debug_loc_size*/, + Dwarf_Unsigned * /*debug_aranges_size*/, + Dwarf_Unsigned * /*debug_macinfo_size*/, + Dwarf_Unsigned * /*debug_pubnames_size*/, + Dwarf_Unsigned * /*debug_str_size*/, + Dwarf_Unsigned * /*debug_frame_size*/, + Dwarf_Unsigned * /*debug_ranges_size*/, + Dwarf_Unsigned * /*debug_pubtypes_size*/); +.DE +.P +The function is the same as \f(CWdwarf_get_section_max_offsets_b()\fP +except it is missing the \f(CWdebug_types_size()\fP argument. +Though obsolete it is still supported. + + + +.H 2 "Debugging Information Entry Delivery Operations" +These functions are concerned with accessing debugging information +entries. + +.H 3 "dwarf_next_cu_header_c()" +.DS +\f(CWint dwarf_next_cu_header_c( + Dwarf_debug dbg, + Dwarf_Bool is_info, + Dwarf_Unsigned *cu_header_length, + Dwarf_Half *version_stamp, + Dwarf_Unsigned *abbrev_offset, + Dwarf_Half *address_size, + Dwarf_Half *offset_size, + Dwarf_Half *extension_size, + Dwarf_Sig8 *signature, + Dwarf_Unsigned *typeoffset + Dwarf_Unsigned *next_cu_header, + Dwarf_Error *error); +.DE +The function +\f(CWdwarf_next_cu_header_c()\fP operates on +the either the .debug_info section +(if \f(CWis_info\fP is non-zero) or .debug_types +section +(if \f(CWis_info\fP is zero). +It returns \f(CWDW_DLV_ERROR\fP +if it fails, and +\f(CWDW_DLV_OK\fP if it succeeds. +.P +If it succeeds, \f(CW*next_cu_header\fP is set to +the offset in the .debug_info section of the next +compilation-unit header if it succeeds. On reading the last +compilation-unit header in the .debug_info section it contains +the size of the .debug_info or debug_types section. +The next call to +\f(CWdwarf_next_cu_header_b()\fP returns \f(CWDW_DLV_NO_ENTRY\fP +without reading a +compilation-unit or setting \f(CW*next_cu_header\fP. +Subsequent calls to \f(CWdwarf_next_cu_header()\fP +repeat the cycle by reading the first compilation-unit and so on. +.P +The other +values returned through pointers are the values in the compilation-unit +header. If any of \f(CWcu_header_length\fP, \f(CWversion_stamp\fP, +\f(CWabbrev_offset\fP, \f(CWaddress_size\fP, +\f(CWoffset_size\fP, \f(CWextension_size\fP, +\f(CWsignature\fP, or \f(CWtypeoffset\fP, +is \f(CWNULL\fP, the +argument is ignored (meaning it is not an error to provide a +\f(CWNULL\fP pointer for any or all of these arguments). +.P +\f(CWcu_header_length\fP returns the length in bytes of the compilation +unit header. +.P +\f(CWversion_stamp\fP returns the section version, which +would be (for .debug_info) 2 for DWARF2, 3 for DWARF4, or +4 for DWARF4. +.P +\f(CWabbrev_offset\fP returns the .debug_abbrev +section offset of the abbreviations +for this compilation unit. +.P +\f(CWaddress_size\fP returns the size of an address in this +compilation unit. Which is usually 4 or 8. +.P +\f(CWoffset_size\fP returns the size in bytes of +an offset for the compilation unit. The offset size +is 4 for 32bit dwarf +and 8 for 64bit dwarf. +This is the offset size in dwarf data, not +the address size inside the executable code. +The offset size can be 4 even +if embedded in a 64bit elf file (which +is normal for 64bit elf), and can be 8 even in +a 32bit elf file (which probably will never be seen +in practice). +.P +The +\f(CWextension_size\fP pointer is only relevant if +the \f(CWoffset_size\fP pointer returns 8. +The value is not normally useful but is returned +through the pointer for completeness. +The pointer \f(CWextension_size\fP returns 0 +if the CU is MIPS/IRIX non-standard 64bit dwarf +(MIPS/IRIX 64bit dwarf was created years before DWARF3 +defined 64bit dwarf) +and returns 4 if the dwarf uses the standard 64bit +extension (the 4 is the size in bytes of the 0xffffffff +in the initial length field +which indicates the following 8 bytes in the .debug_info section +are the real length). +See the DWARF3 or DWARF4 standard, section 7.4. +.P +The +\f(CWsignature\fP pointer is only relevant if +\f(CWis_info\fP is zero, and if relevant the 8 byte type +signature of the .debug_types CU header is assigned through +the pointer. +.P +The +\f(CWtypeoffset\fP pointer is only relevant if +\f(CWis_info\fP is zero, and if relevant the local offset +within the CU of the the type offset the .debug_types entry +represents is assigned through the pointer. +The +\f(CWtypeoffset\fP matters because a +DW_AT_type referencing the type unit may reference an inner type, +such as a C++ class in a C++ namespace, but the type itself +has the enclosing namespace in the .debug_type type_unit. + +.H 3 "dwarf_next_cu_header_b()" +.DS +\f(CWint dwarf_next_cu_header_b( + Dwarf_debug dbg, + Dwarf_Unsigned *cu_header_length, + Dwarf_Half *version_stamp, + Dwarf_Unsigned *abbrev_offset, + Dwarf_Half *address_size, + Dwarf_Half *offset_size, + Dwarf_Half *extension_size, + Dwarf_Unsigned *next_cu_header, + Dwarf_Error *error); +.DE +.P +This is obsolete as of October 2011 though supported. +.P +The function +\f(CWdwarf_next_cu_header_b()\fP operates on +the .debug_info section. It operates exactly like +\f(CWdwarf_next_cu_header_c()\fP but +is missing the +\f(CWsignature\fP, and \f(CWtypeoffset\fP +fields. +This is kept for compatibility. +All code using this should be changed to use +\f(CWdwarf_next_cu_header_c()\fP + +.H 3 "dwarf_next_cu_header()" +.P +The following is the original form, missing the +\f(CWoffset_size\fP, \f(CWextension_size\fP, +\f(CWsignature\fP, and \f(CWtypeoffset\fP +fields in +\f(CWdwarf_next_cu_header_c()\fP. +This is kept for compatibility. +All code using this should be changed to use +\f(CWdwarf_next_cu_header_c()\fP +.DS +\f(CWint dwarf_next_cu_header( + Dwarf_debug dbg, + Dwarf_Unsigned *cu_header_length, + Dwarf_Half *version_stamp, + Dwarf_Unsigned *abbrev_offset, + Dwarf_Half *address_size, + Dwarf_Unsigned *next_cu_header, + Dwarf_Error *error); +.DE + +.H 3 "dwarf_siblingof_b()" +.DS +\f(CWint dwarf_siblingof_b( + Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Bool is_info, + Dwarf_Die *return_sib, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_siblingof_b()\fP +returns \f(CWDW_DLV_ERROR\fP and sets the \f(CWerror\fP pointer on error. +If there is no sibling it returns \f(CWDW_DLV_NO_ENTRY\fP. +When it succeeds, +\f(CWdwarf_siblingof_b()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_sib\fP to the \f(CWDwarf_Die\fP +descriptor of the sibling of \f(CWdie\fP. + +If \f(CWis_info\fP is non-zero then the \f(CWdie\fP +is assumed to refer to a .debug_info DIE. +If \f(CWis_info\fP is zero then the \f(CWdie\fP +is assumed to refer to a .debug_types DIE. +Note that the first call (the call that gets the compilation-unit +DIE in a compilation unit) passes in a NULL \f(CWdie\fP +so having the caller pass in \f(CWis_info\fP is essential. +And if \f(CWdie\fP is non-NULL it is still essential for the +call to pass in \f(CWis_info\fP set properly to reflect the +section the DIE came from. +The function +\f(CWdwarf_get_die_infotypes_flag()\fP is of interest as +it returns the proper is_info value from any non-NULL \f(CWdie\fP +pointer. + + +If \f(CWdie\fP is \fINULL\fP, the \f(CWDwarf_Die\fP descriptor of the +first die in the compilation-unit is returned. +This die has the +\f(CWDW_TAG_compile_unit\fP, +\f(CWDW_TAG_partial_unit\fP, +or \f(CWDW_TAG_type_unit\fP +tag. + +.in +2 +.DS +\f(CWDwarf_Die return_sib = 0; +Dwarf_Error error = 0; +int res; +Dwarf_Bool is_info = 1; +/* in_die might be NULL or a valid Dwarf_Die */ +res = dwarf_siblingof_b(dbg,in_die,is_info,&return_sib, &error); +if (res == DW_DLV_OK) { + /* Use return_sib here. */ + dwarf_dealloc(dbg, return_sib, DW_DLA_DIE); + /* return_sib is no longer usable for anything, we + ensure we do not use it accidentally with: */ + return_sib = 0; +}\fP +.DE +.in -2 + +.H 3 "dwarf_siblingof()" +.DS +\f(CWint dwarf_siblingof( + Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Die *return_sib, + Dwarf_Error *error)\fP +.DE +.P +\f(CWint dwarf_siblingof()\fP operates exactly the same as +\f(CWint dwarf_siblingof_b()\fP, but +\f(CWint dwarf_siblingof()\fP refers only to .debug_info +DIEs. + + +.H 3 "dwarf_child()" +.DS +\f(CWint dwarf_child( + Dwarf_Die die, + Dwarf_Die *return_kid, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_child()\fP +returns \f(CWDW_DLV_ERROR\fP and sets the \f(CWerror\fP die on error. +If there is no child it returns \f(CWDW_DLV_NO_ENTRY\fP. +When it succeeds, +\f(CWdwarf_child()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_kid\fP +to the \f(CWDwarf_Die\fP descriptor +of the first child of \f(CWdie\fP. +The function +\f(CWdwarf_siblingof()\fP can be used with the return value of +\f(CWdwarf_child()\fP to access the other children of \f(CWdie\fP. + +.in +2 +.DS +\f(CWDwarf_Die return_kid = 0; +Dwarf_Error error = 0; +int res; + +res = dwarf_child(dbg,in_die,&return_kid, &error); +if (res == DW_DLV_OK) { + /* Use return_kid here. */ + dwarf_dealloc(dbg, return_kid, DW_DLA_DIE); + /* return_die is no longer usable for anything, we + ensure we do not use it accidentally with: */ + return_kid = 0; +}\fP +.DE +.in -2 + +.H 3 "dwarf_offdie_b()" +.DS +\f(CWint dwarf_offdie_b( + Dwarf_Debug dbg, + Dwarf_Off offset, + Dwarf_Bool is_info, + Dwarf_Die *return_die, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_offdie_b()\fP +returns \f(CWDW_DLV_ERROR\fP and sets the \f(CWerror\fP die on error. +When it succeeds, +\f(CWdwarf_offdie_b()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_die\fP +to the +the \f(CWDwarf_Die\fP +descriptor of the debugging information entry at \f(CWoffset\fP in +the section containing debugging information entries i.e the .debug_info +section. +A return of \f(CWDW_DLV_NO_ENTRY\fP +means that the \f(CWoffset\fP in the section is of a byte containing +all 0 bits, indicating that there +is no abbreviation code. Meaning this 'die offset' is not +the offset of a real die, but is instead an offset of a null die, +a padding die, or of some random zero byte: this should +not be returned in normal use. +.P +It is the user's +responsibility to make sure that \f(CWoffset\fP is the start of a valid +debugging information entry. The result of passing it an invalid +offset could be chaos. +.P +If \f(CWis_info\fP is non-zero the \f(CWoffset\fP must refer +to a .debug_info section offset. +If \f(CWis_info\fP zero the \f(CWoffset\fP must refer +to a .debug_types section offset. +Error returns or misleading +values may result if the +\f(CWis_info\fP flag +or the \f(CWoffset\fP value +are incorrect. + +.in +2 +.DS +\f(CWDwarf_Error error = 0; +Dwarf_Die return_die = 0; +int res; + +res = dwarf_offdie_b(dbg,die_offset,&return_die, &error); +if (res == DW_DLV_OK) { + /* Use return_die here. */ + dwarf_dealloc(dbg, return_die, DW_DLA_DIE); + /* return_die is no longer usable for anything, we + ensure we do not use it accidentally with: */ + return_die = 0; +}\fP +.DE +.in -2 + +.H 3 "dwarf_offdie()" +.DS +\f(CWint dwarf_offdie( + Dwarf_Debug dbg, + Dwarf_Off offset, + Dwarf_Die *return_die, + Dwarf_Error *error)\fP +.DE +.P +The function \f(CWdwarf_offdie()\fP is obsolete, use +\f(CWdwarf_offdie_b()\fP instead. +The function is still supported in the library, but only +references the .debug_info section. + + +.H 3 "dwarf_validate_die_sibling()" +.DS +\f(CWint validate_die_sibling( + Dwarf_Die sibling, + Dwarf_Off *offset)\fP +.DE +When used correctly in a depth-first walk of a DIE tree this +function validates that any DW_AT_sibling attribute gives +the same offset as the direct tree walk. +That is the only purpose of this function. + +The function \f(CWdwarf_validate_die_sibling()\fP +returns \f(CWDW_DLV_OK\fP if the last die processed +in a depth-first DIE tree walk was the same offset as +generated by a call to \f(CWdwarf_siblingof()\fP. +Meaning that the DW_AT_sibling attribute value, if any, was correct. + +If the conditions are not met then DW_DLV_ERROR is returned +and \f(CW*offset\fP is set to the offset +in the .debug_info section of the last DIE processed. +If the application prints the offset a knowledgeable +user may be able to figure out what the compiler did wrong. + +.H 2 "Debugging Information Entry Query Operations" +These queries return specific information about debugging information +entries or a descriptor that can be used on subsequent queries when +given a \f(CWDwarf_Die\fP descriptor. Note that some operations are +specific to debugging information entries that are represented by a +\f(CWDwarf_Die\fP descriptor of a specific type. +For example, not all +debugging information entries contain an attribute having a name, so +consequently, a call to \f(CWdwarf_diename()\fP using a \f(CWDwarf_Die\fP +descriptor that does not have a name attribute will return +\f(CWDW_DLV_NO_ENTRY\fP. +This is not an error, i.e. calling a function that needs a specific +attribute is not an error for a die that does not contain that specific +attribute. +.P +There are several methods that can be used to obtain the value of an +attribute in a given die: +.AL 1 +.LI +Call \f(CWdwarf_hasattr()\fP to determine if the debugging information +entry has the attribute of interest prior to issuing the query for +information about the attribute. + +.LI +Supply an \f(CWerror\fP argument, and check its value after the call to +a query indicates an unsuccessful return, to determine the nature of the +problem. The \f(CWerror\fP argument will indicate whether an error occurred, +or the specific attribute needed was missing in that die. + +.LI +Arrange to have an error handling function invoked upon detection of an +error (see \f(CWdwarf_init()\fP). + +.LI +Call \f(CWdwarf_attrlist()\fP and iterate through the returned list of +attributes, dealing with each one as appropriate. +.LE +.P + +.H 3 "dwarf_get_die_infotypes_flag()" +.DS +\f(CWDwarf_Bool dwarf_get_die_infotypes_flag(Dwarf_Die die)\fP +.DE +.P +The function \f(CWdwarf_tag()\fP returns the section flag +indicating which section the DIE originates from. +If the returned value is non-zero the DIE +originates from the .debug_info section. +If the returned value is zero the DIE +originates from the .debug_types section. + +.H 3 "dwarf_tag()" +.DS +\f(CWint dwarf_tag( + Dwarf_Die die, + Dwarf_Half *tagval, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_tag()\fP returns the \f(CWtag\fP of \f(CWdie\fP +through the pointer \f(CWtagval\fP if it succeeds. +It returns \f(CWDW_DLV_OK\fP if it succeeds. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 3 "dwarf_dieoffset()" +.DS +\f(CWint dwarf_dieoffset( + Dwarf_Die die, + Dwarf_Off * return_offset, + Dwarf_Error *error)\fP +.DE +When it succeeds, +the function \f(CWdwarf_dieoffset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP +to the position of \f(CWdie\fP +in the section containing debugging information entries +(the \f(CWreturn_offset\fP is a section-relative offset). +In other words, +it sets \f(CWreturn_offset\fP +to the offset of the start of the debugging information entry +described by \f(CWdie\fP in the section containing dies i.e .debug_info. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 3 "dwarf_die_CU_offset()" +.DS +\f(CWint dwarf_die_CU_offset( + Dwarf_Die die, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_die_CU_offset()\fP is similar to +\f(CWdwarf_dieoffset()\fP, except that it puts the offset of the DIE +represented by the \f(CWDwarf_Die\fP \f(CWdie\fP, from the +start of the compilation-unit that it belongs to rather than the start +of .debug_info (the \f(CWreturn_offset\fP is a CU-relative offset). + +.H 3 "dwarf_die_offsets()" +.DS +\f(CWint dwarf_die_offsets( + Dwarf_Die die, + Dwarf_Off *global_off, + Dwarf_Off *cu_off, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_die_offsets()\fP is a combination of +\f(CWdwarf_dieoffset()\fP and \f(CWdwarf_die_cu_offset()\fP +in that it returns both the global .debug_info offset and +the CU-relative offset of the \f(CWdie\fP in a single call. + + +.H 3 "dwarf_ptr_CU_offset()" +.DS +\f(CWint dwarf_ptr_CU_offset( + Dwarf_CU_Context cu_context, + Dwarf_Byte_ptr di_ptr , + Dwarf_Off *cu_off)\fP +.DE +Given a valid CU context pointer and a pointer into that CU +context, +the function \f(CWdwarf_ptr_CU_offset()\fP returns DW_DLV_OK +and sets \f(CW*cu_off\fP to the CU-relative (local) offset +in that CU. + + +.H 3 "dwarf_CU_dieoffset_given_die()" +.DS +\f(CWint dwarf_CU_dieoffset_given_die( + Dwarf_Die given_die, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_CU_dieoffset_given_die()\fP is similar to +\f(CWdwarf_die_CU_offset()\fP, except that it puts the +global offset of the CU DIE owning \f(CWgiven_die\fP +of .debug_info (the \f(CWreturn_offset\fP is a global section offset). +.P +This is useful when processing a DIE tree and encountering +an error or other surprise in a DIE, as the \f(CWreturn_offset\fP +can be passed to \f(CWdwarf_offdie_b()\fP to return a pointer +to the CU die of the CU owning the \f(CWgiven_die\fP passed +to \f(CWdwarf_CU_dieoffset_given_die()\fP. The consumer can +extract information from the CU die and the \f(CWgiven_die\fP +(in the normal way) and print it. + +An example (a snippet) of code using this function +follows. It assumes that \f(CWin_die\fP is a DIE +that, for some reason, you have decided needs CU context +printed (assuming \f(CWprint_die_data\fP +does some reasonable printing). + +.in +2 +.DS +int res; +Dwarf_Off cudieoff = 0; +Dwarf_Die cudie = 0; + +print_die_data(dbg,in_die); +res = dwarf_CU_dieoffset_given_die(in_die,&cudieoff,&error); +if(res != DW_DLV_OK) { + printf("FAIL: dwarf_CU_dieoffset_given_die did not work\n"); + exit(1); +} +res = dwarf_offdie_b(dbg,cudieoff,&cudie,&error); +if(res != DW_DLV_OK) { + printf("FAIL: dwarf_offdie did not work\n"); + exit(1); +} +print_die_data(dbg,cudie); +dwarf_dealloc(dbg,cudie, DW_DLA_DIE); +.DE +.in -2 + + + +.H 3 "dwarf_die_CU_offset_range()" +.DS +\f(CWint dwarf_die_CU_offset_range( + Dwarf_Die die, + Dwarf_Off *cu_global_offset, + Dwarf_Off *cu_length, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_die_CU_offset_range()\fP +returns the offset of the beginning of the CU and the length of the CU. +The offset and length are of the entire CU that this DIE is +a part of. It is used by dwarfdump (for example) to check +the validity of offsets. +Most applications will have no reason to call this function. + + +.H 3 "dwarf_diename()" +.DS +\f(CWint dwarf_diename( + Dwarf_Die die, + char ** return_name, + Dwarf_Error *error)\fP +.DE +When it succeeds, +the function \f(CWdwarf_diename()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_name\fP +to +a pointer to a +null-terminated string of characters that represents the name +attribute of \f(CWdie\fP. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWdie\fP does not have a name attribute. +It returns \f(CWDW_DLV_ERROR\fP if +an error occurred. +The storage pointed to by a successful return of +\f(CWdwarf_diename()\fP should be freed using the allocation type +\f(CWDW_DLA_STRING\fP when no longer of interest (see +\f(CWdwarf_dealloc()\fP). + +.H 3 "dwarf_die_abbrev_code()" +.DS +\f(CWint dwarf_die_abbrev_code( Dwarf_Die die)\fP +.DE +The function returns +the abbreviation code of the DIE. +That is, it returns the abbreviation "index" +into the abbreviation table for the compilation unit +of which the DIE is a part. +It cannot fail. No errors are possible. +The pointer \f(CWdie()\fP must not be NULL. + +.H 3 "dwarf_die_abbrev_children_flag()" +.DS +\f(CWint dwarf_die_abbrev_children_flag( Dwarf_Die die, + Dwarf_Half *has_child)\fP +.DE +The function returns the has-children flag of the \f(CWdie\fP +passed in through the \f(CW*has_child\fP passed in and returns +\f(CWDW_DLV_OK\fP on success. +A non-zero value of \f(CW*has_child\fP means the \f(CWdie\fP +has children. + +On failure it returns \f(CWDW_DLV_ERROR\fP. + +The function was developed to let +consumer code do better error reporting +in some circumstances, it is not generally needed. + + +.H 3 "dwarf_get_version_of_die()" +.DS +\f(CWint dwarf_get_version_of_die(Dwarf_Die die, + Dwarf_Half *version, + Dwarf_Half *offset_size)\fP +.DE +The function returns the CU context version through \f(CW*version\fP +and the CU context offset-size through \f(CW*offset_size\fP and +returns \f(CWDW_DLV_OK\fP on success. + +In case of error, the only errors possible involve +an inappropriate NULL \f(CWdie\fP pointer so no Dwarf_Debug +pointer is available. Therefore setting a Dwarf_Error would not +be very meaningful (there is no Dwarf_Debug to +attach it to). The function returns DW_DLV_ERROR on error. + +The values returned through the pointers are the values +two arguments to dwarf_get_form_class() requires. + +.H 3 "dwarf_attrlist()" +.DS +\f(CWint dwarf_attrlist( + Dwarf_Die die, + Dwarf_Attribute** attrbuf, + Dwarf_Signed *attrcount, + Dwarf_Error *error)\fP +.DE +When it returns \f(CWDW_DLV_OK\fP, +the function \f(CWdwarf_attrlist()\fP sets \f(CWattrbuf\fP to point +to an array of \f(CWDwarf_Attribute\fP descriptors corresponding to +each of the attributes in die, and returns the number of elements in +the array through \f(CWattrcount\fP. +\f(CWDW_DLV_NO_ENTRY\fP is returned if the count is zero (no +\f(CWattrbuf\fP is allocated in this case). +\f(CWDW_DLV_ERROR\fP is returned on error. +On a successful return from \f(CWdwarf_attrlist()\fP, each of the +\f(CWDwarf_Attribute\fP descriptors should be individually freed using +\f(CWdwarf_dealloc()\fP with the allocation type \f(CWDW_DLA_ATTR\fP, +followed by free-ing the list pointed to by \f(CW*attrbuf\fP using +\f(CWdwarf_dealloc()\fP with the allocation type \f(CWDW_DLA_LIST\fP, +when no longer of interest (see \f(CWdwarf_dealloc()\fP). + +Freeing the attrlist: +.in +2 +.DS +\f(CWDwarf_Unsigned atcnt; +Dwarf_Attribute *atlist; +int errv; + +errv = dwarf_attrlist(somedie, &atlist,&atcnt, &error); +if (errv == DW_DLV_OK) { + + for (i = 0; i < atcnt; ++i) { + /* use atlist[i] */ + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); +}\fP +.DE +.in -2 +.P +.H 3 "dwarf_hasattr()" +.DS +\f(CWint dwarf_hasattr( + Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Bool *return_bool, + Dwarf_Error *error)\fP +.DE +When it succeeds, the +function \f(CWdwarf_hasattr()\fP returns \f(CWDW_DLV_OK\fP +and sets \f(CW*return_bool\fP to \fInon-zero\fP if +\f(CWdie\fP has the attribute \f(CWattr\fP and \fIzero\fP otherwise. +If it fails, it returns \f(CWDW_DLV_ERROR\fP. + +.H 3 "dwarf_attr()" +.DS +\f(CWint dwarf_attr( + Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Attribute *return_attr, + Dwarf_Error *error)\fP +.DE +.P +When it returns \f(CWDW_DLV_OK\fP, +the function \f(CWdwarf_attr()\fP +sets +\f(CW*return_attr\fP to the \f(CWDwarf_Attribute\fP +descriptor of \f(CWdie\fP having the attribute \f(CWattr\fP. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWattr\fP is not contained +in \f(CWdie\fP. +It returns \f(CWDW_DLV_ERROR\fP if an error occurred. + + +.H 3 "dwarf_lowpc()" +.DS +\f(CWint dwarf_lowpc( + Dwarf_Die die, + Dwarf_Addr * return_lowpc, + Dwarf_Error * error)\fP +.DE +The function \f(CWdwarf_lowpc()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_lowpc\fP +to the low program counter +value associated with the \f(CWdie\fP descriptor if \f(CWdie\fP +represents a debugging information entry with this attribute. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWdie\fP does not have this +attribute. +It returns \f(CWDW_DLV_ERROR\fP if an error occurred. + +.H 3 "dwarf_highpc()" +.DS +\f(CWint dwarf_highpc( + Dwarf_Die die, + Dwarf_Addr * return_highpc, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_highpc()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_highpc\fP +the high program counter +value associated with the \f(CWdie\fP descriptor if \f(CWdie\fP +represents a debugging information entry with this attribute. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWdie\fP does not have this +attribute. +It returns \f(CWDW_DLV_ERROR\fP if an error occurred. + +.H 3 "dwarf_bytesize()" +.DS +\f(CWDwarf_Signed dwarf_bytesize( + Dwarf_Die die, + Dwarf_Unsigned *return_size, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_bytesize()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_size\fP +to the number of bytes +needed to contain an instance of the aggregate debugging information +entry represented by \f(CWdie\fP. +It returns \f(CWDW_DLV_NO_ENTRY\fP if +\f(CWdie\fP does not contain the byte size attribute \f(CWDW_AT_byte_size\fP. +It returns \f(CWDW_DLV_ERROR\fP if +an error occurred. + +.\"#if 0 +.\".DS +.\"\f(CWDwarf_Bool dwarf_isbitfield( +.\" Dwarf_Die die, +.\" Dwarf_Error *error)\fP +.\".DE +.\"The function \f(CWdwarf_isbitfield()\fP returns \fInon-zero\fP if +.\"\f(CWdie\fP is a descriptor for a debugging information entry that +.\"represents a bit field member. It returns \fIzero\fP if \f(CWdie\fP +.\"is not associated with a bit field member. This function is currently +.\"unimplemented. +.\"#endif + +.H 3 "dwarf_bitsize()" +.DS +\f(CWint dwarf_bitsize( + Dwarf_Die die, + Dwarf_Unsigned *return_size, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_bitsize()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_size\fP +to the number of +bits +occupied by the bit field value that is an attribute of the given +die. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWdie\fP does not +contain the bit size attribute \f(CWDW_AT_bit_size\fP. +It returns \f(CWDW_DLV_ERROR\fP if +an error occurred. + +.H 3 "dwarf_bitoffset()" +.DS +\f(CWint dwarf_bitoffset( + Dwarf_Die die, + Dwarf_Unsigned *return_size, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_bitoffset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_size\fP +to the number of bits +to the left of the most significant bit of the bit field value. +This bit offset is not necessarily the net bit offset within the +structure or class , since \f(CWDW_AT_data_member_location\fP +may give a byte offset to this \f(CWDIE\fP and the bit offset +returned through the pointer +does not include the bits in the byte offset. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWdie\fP does not contain the +bit offset attribute \f(CWDW_AT_bit_offset\fP. +It returns \f(CWDW_DLV_ERROR\fP if +an error occurred. + +.H 3 "dwarf_srclang()" +.DS +\f(CWint dwarf_srclang( + Dwarf_Die die, + Dwarf_Unsigned *return_lang, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_srclang()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_lang\fP +to +a code indicating the +source language of the compilation unit represented by the descriptor +\f(CWdie\fP. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWdie\fP does not +represent a source file debugging information entry (i.e. contain the +attribute \f(CWDW_AT_language\fP). +It returns \f(CWDW_DLV_ERROR\fP if +an error occurred. + +.H 3 "dwarf_arrayorder()" +.DS +\f(CWint dwarf_arrayorder( + Dwarf_Die die, + Dwarf_Unsigned *return_order, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_arrayorder()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_order\fP +a code indicating +the ordering of the array represented by the descriptor \f(CWdie\fP. +It returns \f(CWDW_DLV_NO_ENTRY\fP if \f(CWdie\fP does not contain the +array order attribute \f(CWDW_AT_ordering\fP. +It returns \f(CWDW_DLV_ERROR\fP if +an error occurred. + +.H 2 "Attribute Queries" +Based on the attributes form, these operations are concerned with +returning uninterpreted attribute data. Since it is not always +obvious from the return value of these functions if an error occurred, +one should always supply an \f(CWerror\fP parameter or have arranged +to have an error handling function invoked (see \f(CWdwarf_init()\fP) +to determine the validity of the returned value and the nature of any +errors that may have occurred. + +A \f(CWDwarf_Attribute\fP descriptor describes an attribute of a +specific die. Thus, each \f(CWDwarf_Attribute\fP descriptor is +implicitly associated with a specific die. + +.H 3 "dwarf_hasform()" +.DS +\f(CWint dwarf_hasform( + Dwarf_Attribute attr, + Dwarf_Half form, + Dwarf_Bool *return_hasform, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_hasform()\fP returns +\f(CWDW_DLV_OK\fP and and puts a +\fInon-zero\fP + value in the +\f(CW*return_hasform\fP boolean if the +attribute represented by the \f(CWDwarf_Attribute\fP descriptor +\f(CWattr\fP has the attribute form \f(CWform\fP. +If the attribute does not have that form \fIzero\fP +is put into \f(CW*return_hasform\fP. +\f(CWDW_DLV_ERROR\fP is returned on error. + +.H 3 "dwarf_whatform()" +.DS +\f(CWint dwarf_whatform( + Dwarf_Attribute attr, + Dwarf_Half *return_form, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_whatform()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_form\fP +to the attribute form code of +the attribute represented by the \f(CWDwarf_Attribute\fP descriptor +\f(CWattr\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +An attribute using DW_FORM_indirect effectively has two forms. +This function returns the 'final' form for \f(CWDW_FORM_indirect\fP, +not the \f(CWDW_FORM_indirect\fP itself. This function is +what most applications will want to call. + +.H 3 "dwarf_whatform_direct()" +.DS +\f(CWint dwarf_whatform_direct( + Dwarf_Attribute attr, + Dwarf_Half *return_form, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_whatform_direct()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_form\fP +to the attribute form code of +the attribute represented by the \f(CWDwarf_Attribute\fP descriptor +\f(CWattr\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +An attribute using \f(CWDW_FORM_indirect\fP effectively has two forms. +This returns the form 'directly' in the initial form field. +So when the form field is \f(CWDW_FORM_indirect\fP +this call returns the \f(CWDW_FORM_indirect\fP form, +which is sometimes useful for dump utilities. + +.H 3 "dwarf_whatattr()" +.DS +\f(CWint dwarf_whatattr( + Dwarf_Attribute attr, + Dwarf_Half *return_attr, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_whatattr()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_attr\fP +to the attribute code +represented by the \f(CWDwarf_Attribute\fP descriptor \f(CWattr\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 3 "dwarf_formref()" +.DS +\f(CWint dwarf_formref( + Dwarf_Attribute attr, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_formref()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP +to the CU-relative offset +represented by the descriptor \f(CWattr\fP if the form of the attribute +belongs to the \f(CWREFERENCE\fP class. +\f(CWattr\fP must be a CU-local reference, +not form \f(CWDW_FORM_ref_addr\fP and not \f(CWDW_FORM_sec_offset\fP . +It is an error for the form to +not belong to the \f(CWREFERENCE\fP class. +It returns \f(CWDW_DLV_ERROR\fP on error. + +Beginning November 2010: +All \f(CWDW_DLV_ERROR\fP returns set \f(CW*return_offset\fP. Most +errors set \f(CW*return_offset\fP to zero, but +for error \f(CWDW_DLE_ATTR_FORM_OFFSET_BAD\fP +the function sets \f(CW*return_offset\fP to the invalid +offset (which allows the caller to print a more +detailed error message). + +See also \f(CWdwarf_global_formref\fP below. + + +.H 3 "dwarf_global_formref()" +.DS +\f(CWint dwarf_global_formref( + Dwarf_Attribute attr, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_global_formref()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP +to the section-relative offset +represented by the descriptor \f(CWattr\fP if the form of the attribute +belongs to the \f(CWREFERENCE\fP or other section-references classes. +.P +\f(CWattr\fP can be any legal +\f(CWREFERENCE\fP class form plus \f(CWDW_FORM_ref_addr\fP or +\f(CWDW_FORM_sec_offset\fP. +It is an error for the form to +not belong to one of the reference classes. +It returns \f(CWDW_DLV_ERROR\fP on error. +See also \f(CWdwarf_formref\fP above. +.P +The caller must determine which section the offset returned applies to. +The function \f(CWdwarf_get_form_class()\fP is useful to determine +the applicable section. +.P +The function converts CU relative offsets from forms +such as DW_FORM_ref4 into +global section offsets. + +.H 3 "dwarf_convert_to_global_offset()" +.DS +\f(CWint dwarf_convert_to_global_offset( + Dwarf_Attribute attr, + Dwarf_Off offset, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_convert_to_global_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP +to the section-relative offset +represented by the cu-relative offset \f(CWoffset\fP +if the form of the attribute +belongs to the \f(CWREFERENCE\fP class. +\f(CWattr\fP must be a CU-local reference (DWARF class REFERENCE) +or form \f(CWDW_FORM_ref_addr\fP and the \f(CWattr\fP +must be directly relevant for the calculated \f(CW*return_offset\fP +to mean anything. + +The function returns \f(CWDW_DLV_ERROR\fP on error. + +The function is not strictly necessary but may be a +convenience for attribute printing in case of error. + + +.H 3 "dwarf_formaddr()" +.DS +\f(CWint dwarf_formaddr( + Dwarf_Attribute attr, + Dwarf_Addr * return_addr, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_formaddr()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_addr\fP +to +the address +represented by the descriptor \f(CWattr\fP if the form of the attribute +belongs to the \f(CWADDRESS\fP class. +It is an error for the form to +not belong to this class. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 3 "dwarf_formflag()" +.DS +\f(CWint dwarf_formflag( + Dwarf_Attribute attr, + Dwarf_Bool * return_bool, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_formflag()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_bool\fP +\f(CW1\fP (i.e. true) (if the attribute has a non-zero value) +or \f(CW0\fP (i.e. false) (if the attribute has a zero value). +It returns \f(CWDW_DLV_ERROR\fP on error or if the \f(CWattr\fP +does not have form flag. + +.H 3 "dwarf_formudata()" +.DS +\f(CWint dwarf_formudata( + Dwarf_Attribute attr, + Dwarf_Unsigned * return_uvalue, + Dwarf_Error * error)\fP +.DE +The function +\f(CWdwarf_formudata()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_uvalue\fP +to +the \f(CWDwarf_Unsigned\fP +value of the attribute represented by the descriptor \f(CWattr\fP if the +form of the attribute belongs to the \f(CWCONSTANT\fP class. +It is an +error for the form to not belong to this class. +It returns \f(CWDW_DLV_ERROR\fP on error. + +Never returns \f(CWDW_DLV_NO_ENTRY\fP. + +For DWARF2 and DWARF3, \f(CWDW_FORM_data4\fP and \f(CWDW_FORM_data8\fP +are possibly class \f(CWCONSTANT\fP, +and for DWARF4 and later they +are definitely class \f(CWCONSTANT\fP. + +.H 3 "dwarf_formsdata()" +.DS +\f(CWint dwarf_formsdata( + Dwarf_Attribute attr, + Dwarf_Signed * return_svalue, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_formsdata()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_svalue\fP +to +the \f(CWDwarf_Signed\fP +value of the attribute represented by the descriptor \f(CWattr\fP if the +form of the attribute belongs to the \f(CWCONSTANT\fP class. +It is an +error for the form to not belong to this class. +If the size of the data +attribute referenced is smaller than the size of the \f(CWDwarf_Signed\fP +type, its value is sign extended. +It returns \f(CWDW_DLV_ERROR\fP on error. + +Never returns \f(CWDW_DLV_NO_ENTRY\fP. + +For DWARF2 and DWARF3, \f(CWDW_FORM_data4\fP and \f(CWDW_FORM_data8\fP +are possibly class \f(CWCONSTANT\fP, +and for DWARF4 and later they +are definitely class \f(CWCONSTANT\fP. + +.H 3 "dwarf_formblock()" +.DS +\f(CWint dwarf_formblock( + Dwarf_Attribute attr, + Dwarf_Block ** return_block, + Dwarf_Error * error)\fP +.DE +The function \f(CWdwarf_formblock()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_block\fP +to +a pointer to a +\f(CWDwarf_Block\fP structure containing the value of the attribute +represented by the descriptor \f(CWattr\fP if the form of the +attribute belongs to the \f(CWBLOCK\fP class. +It is an error +for the form to not belong to this class. +The storage pointed +to by a successful return of \f(CWdwarf_formblock()\fP should +be freed using the allocation type \f(CWDW_DLA_BLOCK\fP, when +no longer of interest (see \f(CWdwarf_dealloc()\fP). +It returns +\f(CWDW_DLV_ERROR\fP on error. + + +.H 3 "dwarf_formstring()" + +.DS +\f(CWint dwarf_formstring( + Dwarf_Attribute attr, + char ** return_string, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_formstring()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_string\fP +to +a pointer to a +null-terminated string containing the value of the attribute +represented by the descriptor \f(CWattr\fP if the form of the +attribute belongs to the \f(CWSTRING\fP class. +It is an error +for the form to not belong to this class. +The storage pointed +to by a successful return of \f(CWdwarf_formstring()\fP +should not be freed. The pointer points into +existing DWARF memory and the pointer becomes stale/invalid +after a call to \f(CWdwarf_finish\fP. +\f(CWdwarf_formstring()\fP returns \f(CWDW_DLV_ERROR\fP on error. + +.H 3 "dwarf_formsig8()" +.DS +\f(CWint dwarf_formsig8( + Dwarf_Attribute attr, + Dwarf_Sig8 * return_sig8, + Dwarf_Error * error)\fP +.DE +The function \f(CWdwarf_formsig8()\fP returns +\f(CWDW_DLV_OK\fP and copies the 8 byte signature +to a \f(CWDwarf_Sig8\fP structure provided by the caller +if the form of the +attribute is of form \f(CWDW_FORM_ref_sig8\fP +( a member of the \f(CWREFERENCE\fP class). +It is an error +for the form to be anything but \f(CWDW_FORM_ref_sig8\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +.P +This form is used to refer to a type unit. + +.H 3 "dwarf_formsig8()" +.DS +\f(CWint dwarf_formexprloc( + Dwarf_Attribute attr, + Dwarf_Unsigned * return_exprlen, + Dwarf_Ptr * block_ptr, + Dwarf_Error * error)\fP +.DE +The function \f(CWdwarf_formexprloc()\fP returns +\f(CWDW_DLV_OK\fP and sets the two values thru the pointers +to the length and bytes of the DW_FORM_exprloc entry +if the form of the +attribute is of form \f(CWDW_FORM_experloc\fP. +It is an error +for the form to be anything but \f(CWDW_FORM_exprloc\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +.P +On success the value set through the +\f(CWreturn_exprlen\fP pointer is the length +of the location expression. +On success the value set through the +\f(CWblock_ptr\fP pointer is a pointer to +the bytes of the location expression itself. + +.H 3 "dwarf_get_form_class()" +.DS +\f(CWenum Dwarf_Form_Class dwarf_get_form_class( + Dwarf_Half dwversion, + Dwarf_Half attrnum, + Dwarf_Half offset_size, + Dwarf_Half form)\fP +.DE +.P +The function is just for the convenience +of libdwarf clients that might wish to categorize +the FORM of a particular attribute. +The DWARF specification divides FORMs into classes +in Chapter 7 and this function figures out the correct +class for a form. +.P +The \f(CWdwversion\fP passed in shall be the dwarf version +of the compilation unit involved (2 for DWARF2, 3 for +DWARF3, 4 for DWARF 4). +The \f(CWattrnum\fP passed in shall be the attribute +number of the attribute involved (for example, \f(CWDW_AT_name\fP ). +The \f(CWoffset_size\fP passed in shall be the +length of an offset in the current compilation unit +(4 for 32bit dwarf or 8 for 64bit dwarf). +The \f(CWform\fP passed in shall be the attribute form number. +If \f(CWform\fP \f(CWDW_FORM_indirect\fP +is passed in \f(CWDW_FORM_CLASS_UNKNOWN\fP will be returned +as this form has no defined 'class'. +.P +When it returns \f(CWDW_FORM_CLASS_UNKNOWN\fP the +function is simply saying it could not determine the +correct class given the arguments +presented. Some user-defined +attributes might have this problem. + +The function \f(CWdwarf_get_version_of_die()\fP may be helpful +in filling out arguments for a call to \f(CWdwarf_get_form_class()\fP. + +.H 3 "dwarf_loclist_n()" +.DS +\f(CWint dwarf_loclist_n( + Dwarf_Attribute attr, + Dwarf_Locdesc ***llbuf, + Dwarf_Signed *listlen, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_loclist_n()\fP sets \f(CW*llbuf\fP to point to +an array of \f(CWDwarf_Locdesc\fP pointers corresponding to each of +the location expressions in a location list, and sets +\f(CW*listlen\fP to the number +of elements in the array and +returns \f(CWDW_DLV_OK\fP if the attribute is +appropriate. +.P +This is the preferred function for Dwarf_Locdesc as +it is the interface allowing access to an entire +loclist. (use of \f(CWdwarf_loclist_n()\fP is +suggested as the better interface, though +\f(CWdwarf_loclist()\fP is still +supported.) +.P +If the attribute is a reference to a location list +(DW_FORM_data4 or DW_FORM_data8) +the location list entries are used to fill +in all the fields of the \f(CWDwarf_Locdesc\fP(s) returned. +.P +If the attribute is a location description +(DW_FORM_block2 or DW_FORM_block4) +then some of the \f(CWDwarf_Locdesc\fP values of the single +\f(CWDwarf_Locdesc\fP record are set to 'sensible' +but arbitrary values. Specifically, ld_lopc is set to 0 and +ld_hipc is set to all-bits-on. And \f(CW*listlen\fP is set to 1. +.P +It returns \f(CWDW_DLV_ERROR\fP on error. +.P +\f(CWdwarf_loclist_n()\fP works on \f(CWDW_AT_location\fP, +\f(CWDW_AT_data_member_location\fP, \f(CWDW_AT_vtable_elem_location\fP, +\f(CWDW_AT_string_length\fP, \f(CWDW_AT_use_location\fP, and +\f(CWDW_AT_return_addr\fP attributes. +.P +If the attribute is \f(CWDW_AT_data_member_location\fP the value +may be of class CONSTANT. \f(CWdwarf_loclist_n()\fP is unable +to read class CONSTANT, so you need to first determine the +class using \f(CWdwarf_get_form_class()\fP and if it is +class CONSTANT call +\f(CWdwarf_formsdata()\fP or \f(CWdwarf_formudata()\fP +to get the constant value (you may need to call both as +DWARF4 does not define the signedness of the constant value). +.P +Storage allocated by a successful call of \f(CWdwarf_loclist_n()\fP should +be deallocated when no longer of interest (see \f(CWdwarf_dealloc()\fP). +The block of \f(CWDwarf_Loc\fP structs pointed to by the \f(CWld_s\fP +field of each \f(CWDwarf_Locdesc\fP structure +should be deallocated with the allocation type +\f(CWDW_DLA_LOC_BLOCK\fP. +and the \f(CWllbuf[]\fP space pointed to should be deallocated with +allocation type \f(CWDW_DLA_LOCDESC\fP. +This should be followed by deallocation of the \f(CWllbuf\fP +using the allocation type \f(CWDW_DLA_LIST\fP. +.in +2 +.DS +\f(CWDwarf_Signed lcnt; +Dwarf_Locdesc **llbuf; +int lres; + +lres = dwarf_loclist_n(someattr, &llbuf,&lcnt &error); +if (lres == DW_DLV_OK) { + for (i = 0; i < lcnt; ++i) { + /* use llbuf[i] */ + + dwarf_dealloc(dbg, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(dbg,llbuf[i], DW_DLA_LOCDESC); + } + dwarf_dealloc(dbg, llbuf, DW_DLA_LIST); +}\fP +.DE +.in -2 +.P + +.H 3 "dwarf_loclist()" +.DS +\f(CWint dwarf_loclist( + Dwarf_Attribute attr, + Dwarf_Locdesc **llbuf, + Dwarf_Signed *listlen, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_loclist()\fP sets \f(CW*llbuf\fP to point to +a \f(CWDwarf_Locdesc\fP pointer for the single location expression +it can return. +It sets +\f(CW*listlen\fP to 1. +and returns \f(CWDW_DLV_OK\fP +if the attribute is +appropriate. +.P +It is less flexible than \f(CWdwarf_loclist_n()\fP in that +\f(CWdwarf_loclist()\fP can handle a maximum of one +location expression, not a full location list. +If a location-list is present it returns only +the first location-list entry location description. +Use \f(CWdwarf_loclist_n()\fP instead. +.P +It returns \f(CWDW_DLV_ERROR\fP on error. +\f(CWdwarf_loclist()\fP works on \f(CWDW_AT_location\fP, +\f(CWDW_AT_data_member_location\fP, \f(CWDW_AT_vtable_elem_location\fP, +\f(CWDW_AT_string_length\fP, \f(CWDW_AT_use_location\fP, and +\f(CWDW_AT_return_addr\fP attributes. +.P +Storage allocated by a successful call of \f(CWdwarf_loclist()\fP should +be deallocated when no longer of interest (see \f(CWdwarf_dealloc()\fP). +The block of \f(CWDwarf_Loc\fP structs pointed to by the \f(CWld_s\fP +field of each \f(CWDwarf_Locdesc\fP structure +should be deallocated with the allocation type \f(CWDW_DLA_LOC_BLOCK\fP. +This should be followed by deallocation of the \f(CWllbuf\fP +using the allocation type \f(CWDW_DLA_LOCDESC\fP. +.in +2 +.DS +\f(CWDwarf_Signed lcnt; +Dwarf_Locdesc *llbuf; +int lres; + +lres = dwarf_loclist(someattr, &llbuf,&lcnt,&error); +if (lres == DW_DLV_OK) { + /* lcnt is always 1, (and has always been 1) */ */ + + /* Use llbuf here. */ + + + dwarf_dealloc(dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC); +/* Earlier version. +* for (i = 0; i < lcnt; ++i) { +* /* use llbuf[i] */ +* +* /* Deallocate Dwarf_Loc block of llbuf[i] */ +* dwarf_dealloc(dbg, llbuf[i].ld_s, DW_DLA_LOC_BLOCK); +* } +* dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC); +*/ + +}\fP +.DE +.in -2 +.P + +.H 3 "dwarf_loclist_from_expr()" +.DS +\f(CWint dwarf_loclist_from_expr( + Dwarf_Ptr bytes_in, + Dwarf_Unsigned bytes_len, + Dwarf_Locdesc **llbuf, + Dwarf_Signed *listlen, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_loclist_from_expr()\fP sets \f(CW*llbuf\fP to point to +a \f(CWDwarf_Locdesc\fP pointer for the single location expression +which is pointed to by \f(CW*bytes_in\fP (whose length is +\f(CW*bytes_len\fP). +It sets +\f(CW*listlen\fP to 1. +and returns \f(CWDW_DLV_OK\fP +if decoding is successful. +Some sources of bytes of expressions are dwarf expressions +in frame operations like \f(CWDW_CFA_def_cfa_expression\fP, +\f(CWDW_CFA_expression\fP, and \f(CWDW_CFA_val_expression\fP. +.P +Any address_size data in the location expression is assumed +to be the same size as the default address_size for the object +being read (normally 4 or 8). +.P +It returns \f(CWDW_DLV_ERROR\fP on error. +.P +Storage allocated by a successful call of \f(CWdwarf_loclist_from_expr()\fP should +be deallocated when no longer of interest (see \f(CWdwarf_dealloc()\fP). +The block of \f(CWDwarf_Loc\fP structs pointed to by the \f(CWld_s\fP +field of each \f(CWDwarf_Locdesc\fP structure +should be deallocated with the allocation type \f(CWDW_DLA_LOC_BLOCK\fP. +This should be followed by deallocation of the \f(CWllbuf\fP +using the allocation type \f(CWDW_DLA_LOCDESC\fP. +.in +2 +.DS +\f(CWDwarf_Signed lcnt; +Dwarf_Locdesc *llbuf; +int lres; +/* Example with an empty buffer here. */ +Dwarf_Ptr data = ""; +Dwarf_Unsigned len = 0; + +lres = dwarf_loclist_from_expr(data,len, &llbuf,&lcnt, &error); +if (lres == DW_DLV_OK) { + /* lcnt is always 1 */ + + /* Use llbuf here.*/ + + dwarf_dealloc(dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC); + +}\fP +.DE +.in -2 +.P + +.H 3 "dwarf_loclist_from_expr_a()" +.DS +\f(CWint dwarf_loclist_from_expr_a( + Dwarf_Ptr bytes_in, + Dwarf_Unsigned bytes_len, + Dwarf_Half addr_size, + Dwarf_Locdesc **llbuf, + Dwarf_Signed *listlen, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_loclist_from_expr_a()\fP +is identical to \f(CWdwarf_loclist_from_expr()\fP +in every way except that the caller passes the additional argument +\f(CWaddr_size\fP containing the address size (normally 4 or 8) +applying this location expression. +.P +The \f(CWaddr_size\fP argument (added 27April2009) is needed +to correctly interpret frame information as different compilation +units can have different address sizes. +DWARF4 adds address_size to the CIE header. + +.P +.H 2 "Line Number Operations" +These functions are concerned with accessing line number entries, +mapping debugging information entry objects to their corresponding +source lines, and providing a mechanism for obtaining information +about line number entries. Although, the interface talks of "lines" +what is really meant is "statements". In case there is more than +one statement on the same line, there will be at least one descriptor +per statement, all with the same line number. If column number is +also being represented they will have the column numbers of the start +of the statements also represented. +.P +There can also be more than one Dwarf_Line per statement. +For example, if a file is preprocessed by a language translator, +this could result in translator output showing 2 or more sets of line +numbers per translated line of output. + +.H 3 "Get A Set of Lines" +The function returns information about every source line for a +particular compilation-unit. +The compilation-unit is specified +by the corresponding die. +.H 4 "dwarf_srclines()" +.DS +\f(CWint dwarf_srclines( + Dwarf_Die die, + Dwarf_Line **linebuf, + Dwarf_Signed *linecount, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_srclines()\fP places all line number descriptors +for a single compilation unit into a single block, sets \f(CW*linebuf\fP +to point to that block, +sets \f(CW*linecount\fP to the number of descriptors in this block +and returns \f(CWDW_DLV_OK\fP. +The compilation-unit is indicated by the given \f(CWdie\fP which must be +a compilation-unit die. +It returns \f(CWDW_DLV_ERROR\fP on error. +On +successful return, line number information +should be freed using \f(CWdwarf_srclines_dealloc()\fP +when no longer of interest. +.P +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Line *linebuf; +int sres; + +sres = dwarf_srclines(somedie, &linebuf,&cnt, &error); +if (sres == DW_DLV_OK) { + for (i = 0; i < cnt; ++i) { + /* use linebuf[i] */ + } + dwarf_srclines_dealloc(dbg, linebuf, cnt); +}\fP +.DE + +.in -2 +.P +The following dealloc code (the only documented method before July 2005) +still works, but does not completely free all data allocated. +The \f(CWdwarf_srclines_dealloc()\fP routine was created +to fix the problem of incomplete deallocation. +.P +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Line *linebuf; +int sres; + +sres = dwarf_srclines(somedie, &linebuf,&cnt, &error); +if (sres == DW_DLV_OK) { + for (i = 0; i < cnt; ++i) { + /* use linebuf[i] */ + dwarf_dealloc(dbg, linebuf[i], DW_DLA_LINE); + } + dwarf_dealloc(dbg, linebuf, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.H 3 "Get the set of Source File Names" + +The function returns the names of the source files that have contributed +to the compilation-unit represented by the given DIE. Only the source +files named in the statement program prologue are returned. + + +.DS +\f(CWint dwarf_srcfiles( + Dwarf_Die die, + char ***srcfiles, + Dwarf_Signed *srccount, + Dwarf_Error *error)\fP +.DE +When it succeeds +\f(CWdwarf_srcfiles()\fP returns +\f(CWDW_DLV_OK\fP +and +puts +the number of source +files named in the statement program prologue indicated by the given +\f(CWdie\fP +into \f(CW*srccount\fP. +Source files defined in the statement program are ignored. +The given \f(CWdie\fP should have the tag +\f(CWDW_TAG_compile_unit\fP, +\f(CWDW_TAG_partial_unit\fP, +or \f(CWDW_TAG_type_unit\fP +. +The location pointed to by \f(CWsrcfiles\fP is set to point to a list +of pointers to null-terminated strings that name the source +files. +On a successful return from this function, each of the +strings returned should be individually freed using \f(CWdwarf_dealloc()\fP +with the allocation type \f(CWDW_DLA_STRING\fP when no longer of +interest. +This should be followed by free-ing the list using +\f(CWdwarf_dealloc()\fP with the allocation type \f(CWDW_DLA_LIST\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP +if there is no +corresponding statement program (i.e., if there is no line information). +.in +2 +.DS +\f(CWDwarf_Signed cnt; +char **srcfiles; +int res; + +res = dwarf_srcfiles(somedie, &srcfiles,&cnt &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use srcfiles[i] */ + dwarf_dealloc(dbg, srcfiles[i], DW_DLA_STRING); + } + dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST); +}\fP +.DE +.in -2 +.H 3 "Get information about a Single Table Line" +The following functions can be used on the \f(CWDwarf_Line\fP descriptors +returned by \f(CWdwarf_srclines()\fP to obtain information about the +source lines. + +.H 4 "dwarf_linebeginstatement()" +.DS +\f(CWint dwarf_linebeginstatement( + Dwarf_Line line, + Dwarf_Bool *return_bool, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_linebeginstatement()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_bool\fP +to +\fInon-zero\fP +(if \f(CWline\fP represents a line number entry that is marked as +beginning a statement). +or +\fIzero\fP ((if \f(CWline\fP represents a line number entry +that is not marked as beginning a statement). +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.P +.H 4 "dwarf_lineendsequence()" +.DS +\f(CWint dwarf_lineendsequence( + Dwarf_Line line, + Dwarf_Bool *return_bool, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_lineendsequence()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_bool\fP +\fInon-zero\fP +(in which case +\f(CWline\fP represents a line number entry that is marked as +ending a text sequence) +or +\fIzero\fP (in which case +\f(CWline\fP represents a line number entry +that is not marked as ending a text sequence). +A line number entry that is marked as +ending a text sequence is an entry with an address +one beyond the highest address used by the current +sequence of line table entries (that is, the table entry is +a DW_LNE_end_sequence entry (see the DWARF specification)). +.P +The function \f(CWdwarf_lineendsequence()\fP +returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.P +.H 4 "dwarf_lineno()" +.DS +\f(CWint dwarf_lineno( + Dwarf_Line line, + Dwarf_Unsigned * returned_lineno, + Dwarf_Error * error)\fP +.DE +The function \f(CWdwarf_lineno()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_lineno\fP to +the source statement line +number corresponding to the descriptor \f(CWline\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.P +.H 4 "dwarf_line_srcfileno()" +.DS +\f(CWint dwarf_line_srcfileno( + Dwarf_Line line, + Dwarf_Unsigned * returned_fileno, + Dwarf_Error * error)\fP +.DE +The function \f(CWdwarf_line_srcfileno()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_fileno\fP to +the source statement line +number corresponding to the descriptor \f(CWfile number\fP. +When the number returned through \f(CW*returned_fileno\fP is zero it means +the file name is unknown (see the DWARF2/3 line table specification). +When the number returned through \f(CW*returned_fileno\fP is non-zero +it is a file number: +subtract 1 from this file number +to get an +index into the array of strings returned by \f(CWdwarf_srcfiles()\fP +(verify the resulting index is in range for the array of strings +before indexing into the array of strings). +The file number may exceed the size of +the array of strings returned by \f(CWdwarf_srcfiles()\fP +because \f(CWdwarf_srcfiles()\fP does not return files names defined with +the \f(CWDW_DLE_define_file\fP operator. +The function \f(CWdwarf_line_srcfileno()\fP returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.P +.H 4 "dwarf_lineaddr()" +.DS +\f(CWint dwarf_lineaddr( + Dwarf_Line line, + Dwarf_Addr *return_lineaddr, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_lineaddr()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_lineaddr\fP to +the address associated +with the descriptor \f(CWline\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.P +.H 4 "dwarf_lineoff()" +.DS +\f(CWint dwarf_lineoff( + Dwarf_Line line, + Dwarf_Signed * return_lineoff, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_lineoff()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_lineoff\fP to +the column number at which +the statement represented by \f(CWline\fP begins. +.P +It sets \f(CWreturn_lineoff\fP to zero +if the column number of the statement is not represented +(meaning the producer library call was given zero +as the column number). Zero is the correct value meaning "left edge" +as defined in the DWARF2/3/4 specication (section 6.2.2). +.P +Before December 2011 zero was not returned through +the \f(CWreturn_lineoff\fP pointer, -1 was returned through the pointer. +The reason for this oddity is unclear, lost in history. +But there is no good reason for -1. +.P +The type of \f(CWreturn_lineoff\fP is a pointer-to-signed, but there +is no good reason for the value to be signed, the DWARF specification +does not deal with negative column numbers. However, changing the +declaration would cause compilation errors for little benefit, so +the pointer-to-signed is left unchanged. +.P +On error it returns \f(CWDW_DLV_ERROR\fP. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_linesrc()" +.DS +\f(CWint dwarf_linesrc( + Dwarf_Line line, + char ** return_linesrc, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_linesrc()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_linesrc\fP to +a pointer to a +null-terminated string of characters that represents the name of the +source-file where \f(CWline\fP occurs. +It returns \f(CWDW_DLV_ERROR\fP on +error. +.P +If the applicable file name in the line table Statement Program Prolog +does not start with a '/' character +the string in \f(CWDW_AT_comp_dir\fP (if applicable and present) +or the applicable +directory name from the line Statement Program Prolog +is prepended to the +file name in the line table Statement Program Prolog +to make a full path. +.P +The storage pointed to by a successful return of +\f(CWdwarf_linesrc()\fP should be freed using \f(CWdwarf_dealloc()\fP with +the allocation type \f(CWDW_DLA_STRING\fP when no longer of interest. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_lineblock()" +.DS +\f(CWint dwarf_lineblock( + Dwarf_Line line, + Dwarf_Bool *return_bool, + Dwarf_Error *error)\fP +.DE +The function +\f(CWdwarf_lineblock()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_linesrc\fP to +non-zero (i.e. true)(if the line is marked as +beginning a basic block) +or zero (i.e. false) (if the line is marked as not +beginning a basic block). +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_is_addr_set()" +.DS +\f(CWint dwarf_line_is_addr_set( + Dwarf_Line line, + Dwarf_Bool *return_bool, + Dwarf_Error *error)\fP +.DE +The function +\f(CWdwarf_line_is_addr_set()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_bool\fP to +non-zero (i.e. true)(if the line is marked as +being a DW_LNE_set_address operation) +or zero (i.e. false) (if the line is marked as not +being a DW_LNE_set_address operation). +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +This is intended to allow consumers to do a more useful job +printing and analyzing DWARF data, it is not strictly +necessary. + +.H 4 "dwarf_prologue_end_etc()" +.DS +\f(CWint dwarf_prologue_end_etc(Dwarf_Line line, + Dwarf_Bool * prologue_end, + Dwarf_Bool * epilogue_begin, + Dwarf_Unsigned * isa, + Dwarf_Unsigned * discriminator, + Dwarf_Error * error)\fP +.DE +The function +\f(CWdwarf_prologue_end_etc()\fP returns +\f(CWDW_DLV_OK\fP and sets the returned fields to +values currently set. +While it is pretty safe to assume that the +\f(CWisa\fP +and +\f(CWdiscriminator\fP +values returned are very small integers, there is +no restriction in the standard. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +This function is new in December 2011. + + +.H 2 "Global Name Space Operations" +These operations operate on the .debug_pubnames section of the debugging +information. + + +.H 2 "Global Name Space Operations" +These operations operate on the .debug_pubnames section of the debugging +information. + +.H 3 "Debugger Interface Operations" + +.H 4 "dwarf_get_globals()" +.DS +\f(CWint dwarf_get_globals( + Dwarf_Debug dbg, + Dwarf_Global **globals, + Dwarf_Signed * return_count, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_globals()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_count\fP to +the count of pubnames +represented in the section containing pubnames i.e. .debug_pubnames. +It also stores at \f(CW*globals\fP, a pointer +to a list of \f(CWDwarf_Global\fP descriptors, one for each of the +pubnames in the .debug_pubnames section. +The returned results are for the entire section. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if the .debug_pubnames +section does not exist. + +.P +On a successful return from +\f(CWdwarf_get_globals()\fP, the \f(CWDwarf_Global\fP +descriptors should be +freed using \f(CWdwarf_globals_dealloc()\fP. +\f(CWdwarf_globals_dealloc()\fP is new as of July 15, 2005 +and is the preferred approach to freeing this memory.. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Global *globs; +int res; + +res = dwarf_get_globals(dbg, &globs,&cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use globs[i] */ + } + dwarf_globals_dealloc(dbg, globs, cnt); +}\fP +.DE +.in -2 + + +.P +The following code is deprecated as of July 15, 2005 as it does not +free all relevant memory. +This approach still works as well as it ever did. +On a successful return from +\f(CWdwarf_get_globals()\fP, the \f(CWDwarf_Global\fP +descriptors should be individually +freed using \f(CWdwarf_dealloc()\fP with the allocation type +\f(CWDW_DLA_GLOBAL_CONTEXT\fP, +(or +\f(CWDW_DLA_GLOBAL\fP, an older name, supported for compatibility) +followed by the deallocation of the list itself +with the allocation type \f(CWDW_DLA_LIST\fP when the descriptors are +no longer of interest. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Global *globs; +int res; + +res = dwarf_get_globals(dbg, &globs,&cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use globs[i] */ + dwarf_dealloc(dbg, globs[i], DW_DLA_GLOBAL_CONTEXT); + } + dwarf_dealloc(dbg, globs, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.H 4 "dwarf_globname()" +.DS +\f(CWint dwarf_globname( + Dwarf_Global global, + char ** return_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_globname()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_name\fP to +a pointer to a +null-terminated string that names the pubname represented by the +\f(CWDwarf_Global\fP descriptor, \f(CWglobal\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +On a successful return from this function, the string should +be freed using \f(CWdwarf_dealloc()\fP, with the allocation type +\f(CWDW_DLA_STRING\fP when no longer of interest. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_global_die_offset()" +.DS +\f(CWint dwarf_global_die_offset( + Dwarf_Global global, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_global_die_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the DIE representing +the pubname that is described by the \f(CWDwarf_Global\fP descriptor, +\f(CWglob\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_global_cu_offset()" +.DS +\f(CWint dwarf_global_cu_offset( + Dwarf_Global global, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_global_cu_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the compilation-unit +header of the compilation-unit that contains the pubname described +by the \f(CWDwarf_Global\fP descriptor, \f(CWglobal\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_get_cu_die_offset_given_cu_header_offset()" +.DS +\f(CWint dwarf_get_cu_die_offset_given_cu_header_offset_b( + Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, + Dwarf_Bool is_info, + Dwarf_Off * out_cu_die_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_cu_die_offset_given_cu_header_offset()\fP +returns +\f(CWDW_DLV_OK\fP and sets \f(CW*out_cu_die_offset\fP to +the offset of the compilation-unit DIE given the +offset \f(CWin_cu_header_offset\fP of a compilation-unit header. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +.P +If \f(CWis_info\fP is non-zero the \f(CWin_cu_header_offset\fP must refer +to a .debug_info section offset. +If \f(CWis_info\fP zero the \f(CWin_cu_header_offset\fP must refer +to a .debug_types section offset. +Chaos may result if the \f(CWis_info\fP flag is incorrect. + +This effectively turns a compilation-unit-header offset +into a compilation-unit DIE offset (by adding the +size of the applicable CU header). +This function is also sometimes useful with the +\f(CWdwarf_weak_cu_offset()\fP, +\f(CWdwarf_func_cu_offset()\fP, +\f(CWdwarf_type_cu_offset()\fP, +and +\f(CWint dwarf_var_cu_offset()\fP +functions, though for those functions the data is +only in .debug_info by definition. + +.H 4 "dwarf_get_cu_die_offset_given_cu_header_offset()" +.DS +\f(CWint dwarf_get_cu_die_offset_given_cu_header_offset( + Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, + Dwarf_Off * out_cu_die_offset, + Dwarf_Error *error)\fP +.DE +This function is superseded by +\f(CWdwarf_get_cu_die_offset_given_cu_header_offset_b()\fP, +a function which is still supported thought it refers only +to the .debug_info section. + + +\f(CWdwarf_get_cu_die_offset_given_cu_header_offset()\fP +added Rev 1.45, June, 2001. + +This function is declared as 'optional' in libdwarf.h +on IRIX systems so the _MIPS_SYMBOL_PRESENT +predicate may be used at run time to determine if the version of +libdwarf linked into an application has this function. + +.H 4 "dwarf_global_name_offsets()" +.DS +\f(CWint dwarf_global_name_offsets( + Dwarf_Global global, + char **return_name, + Dwarf_Off *die_offset, + Dwarf_Off *cu_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_global_name_offsets()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_name\fP to +a pointer to +a null-terminated string that gives the name of the pubname +described by the \f(CWDwarf_Global\fP descriptor \f(CWglobal\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +It also returns in the locations +pointed to by \f(CWdie_offset\fP, and \f(CWcu_offset\fP, the offsets +of the DIE representing the +pubname, and the DIE +representing the compilation-unit containing the +pubname, respectively. +On a +successful return from \f(CWdwarf_global_name_offsets()\fP the storage +pointed to by \f(CWreturn_name\fP +should be freed using \f(CWdwarf_dealloc()\fP, +with the allocation type \f(CWDW_DLA_STRING\fP when no longer of interest. + + +.H 2 "DWARF3 Type Names Operations" +Section ".debug_pubtypes" is new in DWARF3. +.P +These functions operate on the .debug_pubtypes section of the debugging +information. The .debug_pubtypes section contains the names of file-scope +user-defined types, the offsets of the \f(CWDIE\fPs that represent the +definitions of those types, and the offsets of the compilation-units +that contain the definitions of those types. + +.H 3 "Debugger Interface Operations" + +.H 4 "dwarf_get_pubtypes()" +.DS +\f(CWint dwarf_get_pubtypes( + Dwarf_Debug dbg, + Dwarf_Type **types, + Dwarf_Signed *typecount, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_pubtypes()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*typecount\fP to +the count of user-defined +type names represented in the section containing user-defined type names, +i.e. .debug_pubtypes. +It also stores at \f(CW*types\fP, +a pointer to a list of \f(CWDwarf_Pubtype\fP descriptors, one for each of the +user-defined type names in the .debug_pubtypes section. +The returned results are for the entire section. +It returns \f(CWDW_DLV_NOCOUNT\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if +the .debug_pubtypes section does not exist. + +.P +On a successful +return from \f(CWdwarf_get_pubtypes()\fP, +the \f(CWDwarf_Type\fP descriptors should be +freed using \f(CWdwarf_types_dealloc()\fP. +\f(CWdwarf_types_dealloc()\fP is used for both +\f(CWdwarf_get_pubtypes()\fP and \f(CWdwarf_get_types()\fP +as the data types are the same. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Pubtype *types; +int res; + +res = dwarf_get_pubtypes(dbg, &types,&cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use types[i] */ + } + dwarf_types_dealloc(dbg, types, cnt); +}\fP +.DE +.in -2 + +.H 4 "dwarf_pubtypename()" +.DS +\f(CWint dwarf_pubtypename( + Dwarf_Pubtype type, + char **return_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_pubtypename()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_name\fP to +a pointer to a +null-terminated string that names the user-defined type represented by the +\f(CWDwarf_Pubtype\fP descriptor, \f(CWtype\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from this function, the string should +be freed using \f(CWdwarf_dealloc()\fP, with the allocation type +\f(CWDW_DLA_STRING\fP when no longer of interest. + +.H 4 "dwarf_pubtype_die_offset()" +.DS +\f(CWint dwarf_pubtype_die_offset( + Dwarf_Pubtype type, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_pubtype_die_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the DIE representing +the user-defined type that is described by the \f(CWDwarf_Pubtype\fP +descriptor, \f(CWtype\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_pubtype_cu_offset()" +.DS +\f(CWint dwarf_pubtype_cu_offset( + Dwarf_Pubtype type, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_pubtype_cu_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the compilation-unit +header of the compilation-unit that contains the user-defined type +described by the \f(CWDwarf_Pubtype\fP descriptor, \f(CWtype\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_pubtype_name_offsets()" +.DS +\f(CWint dwarf_pubtype_name_offsets( + Dwarf_Pubtype type, + char ** returned_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_pubtype_name_offsets()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_name\fP to +a pointer to +a null-terminated string that gives the name of the user-defined +type described by the \f(CWDwarf_Pubtype\fP descriptor \f(CWtype\fP. +It also returns in the locations +pointed to by \f(CWdie_offset\fP, and \f(CWcu_offset\fP, the offsets +of the DIE representing the +user-defined type, and the DIE +representing the compilation-unit containing the +user-defined type, respectively. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from \f(CWdwarf_pubtype_name_offsets()\fP +the storage pointed to by \f(CWreturned_name\fP should +be freed using +\f(CWdwarf_dealloc()\fP, with the allocation type \f(CWDW_DLA_STRING\fP +when no longer of interest. + + +.H 2 "User Defined Static Variable Names Operations" +This section is SGI specific and is not part of standard DWARF version 2. +.P +These functions operate on the .debug_varnames section of the debugging +information. The .debug_varnames section contains the names of file-scope +static variables, the offsets of the \f(CWDIE\fPs that represent the +definitions of those variables, and the offsets of the compilation-units +that contain the definitions of those variables. +.P + + +.H 2 "Weak Name Space Operations" +These operations operate on the .debug_weaknames section of the debugging +information. +.P +These operations are SGI specific, not part of standard DWARF. +.P + +.H 3 "Debugger Interface Operations" + +.H 4 "dwarf_get_weaks()" +.DS +\f(CWint dwarf_get_weaks( + Dwarf_Debug dbg, + Dwarf_Weak **weaks, + Dwarf_Signed *weak_count, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_weaks()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*weak_count\fP to +the count of weak names +represented in the section containing weak names i.e. .debug_weaknames. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if the section does not exist. +It also stores in \f(CW*weaks\fP, a pointer to +a list of \f(CWDwarf_Weak\fP descriptors, one for each of the weak names +in the .debug_weaknames section. +The returned results are for the entire section. + +.P +On a successful return from this function, +the \f(CWDwarf_Weak\fP descriptors should be freed using +\f(CWdwarf_weaks_dealloc()\fP when the data is no longer of +interest. \f(CWdwarf_weaks_dealloc()\fPis new as of July 15, 2005. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Weak *weaks; +int res; + +res = dwarf_get_weaks(dbg, &weaks, &cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use weaks[i] */ + } + dwarf_weaks_dealloc(dbg, weaks, cnt); +}\fP +.DE +.in -2 + + + +.P +The following code is deprecated as of July 15, 2005 as it does not +free all relevant memory. +This approach still works as well as it ever did. +On a successful return from \f(CWdwarf_get_weaks()\fP +the \f(CWDwarf_Weak\fP descriptors should be individually freed using +\f(CWdwarf_dealloc()\fP with the allocation type +\f(CWDW_DLA_WEAK_CONTEXT\fP, +(or +\f(CWDW_DLA_WEAK\fP, an older name, supported for compatibility) +followed by the deallocation of the list itself with the allocation type +\f(CWDW_DLA_LIST\fP when the descriptors are no longer of interest. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Weak *weaks; +int res; + +res = dwarf_get_weaks(dbg, &weaks, &cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use weaks[i] */ + dwarf_dealloc(dbg, weaks[i], DW_DLA_WEAK_CONTEXT); + } + dwarf_dealloc(dbg, weaks, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.H 4 "dwarf_weakname()" +.DS +\f(CWint dwarf_weakname( + Dwarf_Weak weak, + char ** return_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_weakname()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_name\fP to +a pointer to a null-terminated +string that names the weak name represented by the +\f(CWDwarf_Weak\fP descriptor, \f(CWweak\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from this function, the string should +be freed using \f(CWdwarf_dealloc()\fP, with the allocation type +\f(CWDW_DLA_STRING\fP when no longer of interest. + +.DS +\f(CWint dwarf_weak_die_offset( + Dwarf_Weak weak, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_weak_die_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to the offset in +the section containing DIEs, i.e. .debug_info, of the DIE representing +the weak name that is described by the \f(CWDwarf_Weak\fP descriptor, +\f(CWweak\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_weak_cu_offset()" +.DS +\f(CWint dwarf_weak_cu_offset( + Dwarf_Weak weak, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_weak_cu_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to the offset in +the section containing DIEs, i.e. .debug_info, of the compilation-unit +header of the compilation-unit that contains the weak name described +by the \f(CWDwarf_Weak\fP descriptor, \f(CWweak\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_weak_name_offsets()" +.DS +\f(CWint dwarf_weak_name_offsets( + Dwarf_Weak weak, + char ** weak_name, + Dwarf_Off *die_offset, + Dwarf_Off *cu_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_weak_name_offsets()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*weak_name\fP to +a pointer to +a null-terminated string that gives the name of the weak name +described by the \f(CWDwarf_Weak\fP descriptor \f(CWweak\fP. +It also returns in the locations +pointed to by \f(CWdie_offset\fP, and \f(CWcu_offset\fP, the offsets +of the DIE representing the +weakname, and the DIE +representing the compilation-unit containing the +weakname, respectively. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a +successful return from \f(CWdwarf_weak_name_offsets()\fP the storage +pointed to by \f(CWweak_name\fP +should be freed using \f(CWdwarf_dealloc()\fP, +with the allocation type \f(CWDW_DLA_STRING\fP when no longer of interest. + +.H 2 "Static Function Names Operations" +This section is SGI specific and is not part of standard DWARF version 2. +.P +These function operate on the .debug_funcnames section of the debugging +information. The .debug_funcnames section contains the names of static +functions defined in the object, the offsets of the \f(CWDIE\fPs that +represent the definitions of the corresponding functions, and the offsets +of the start of the compilation-units that contain the definitions of +those functions. + +.H 3 "Debugger Interface Operations" + +.H 4 "dwarf_get_funcs()" +.DS +\f(CWint dwarf_get_funcs( + Dwarf_Debug dbg, + Dwarf_Func **funcs, + Dwarf_Signed *func_count, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_funcs()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*func_count\fP to +the count of static +function names represented in the section containing static function +names, i.e. .debug_funcnames. +It also +stores, at \f(CW*funcs\fP, a pointer to a list of \f(CWDwarf_Func\fP +descriptors, one for each of the static functions in the .debug_funcnames +section. +The returned results are for the entire section. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP +if the .debug_funcnames section does not exist. +.P +On a successful return from \f(CWdwarf_get_funcs()\fP, +the \f(CWDwarf_Func\fP +descriptors should be freed using \f(CWdwarf_funcs_dealloc()\fP. +\f(CWdwarf_funcs_dealloc()\fP is new as of July 15, 2005. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Func *funcs; +int fres; + +fres = dwarf_get_funcs(dbg, &funcs, &cnt, &error); +if (fres == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use funcs[i] */ + } + dwarf_funcs_dealloc(dbg, funcs, cnt); +}\fP +.DE +.in -2 + + +.P +The following code is deprecated as of July 15, 2005 as it does not +free all relevant memory. +This approach still works as well as it ever did. +On a successful return from \f(CWdwarf_get_funcs()\fP, +the \f(CWDwarf_Func\fP +descriptors should be individually freed using \f(CWdwarf_dealloc()\fP +with the allocation type +\f(CWDW_DLA_FUNC_CONTEXT\fP, +(or +\f(CWDW_DLA_FUNC\fP, an older name, supported for compatibility) +followed by the deallocation +of the list itself with the allocation type \f(CWDW_DLA_LIST\fP when +the descriptors are no longer of interest. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Func *funcs; +int fres; + +fres = dwarf_get_funcs(dbg, &funcs, &error); +if (fres == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use funcs[i] */ + dwarf_dealloc(dbg, funcs[i], DW_DLA_FUNC_CONTEXT); + } + dwarf_dealloc(dbg, funcs, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.H 4 "dwarf_funcname()" +.DS +\f(CWint dwarf_funcname( + Dwarf_Func func, + char ** return_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_funcname()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_name\fP to +a pointer to a +null-terminated string that names the static function represented by the +\f(CWDwarf_Func\fP descriptor, \f(CWfunc\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from this function, the string should +be freed using \f(CWdwarf_dealloc()\fP, with the allocation type +\f(CWDW_DLA_STRING\fP when no longer of interest. + +.H 4 "dwarf_func_die_offset()" +.DS +\f(CWint dwarf_func_die_offset( + Dwarf_Func func, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_func_die_offset()\fP, returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the DIE representing +the static function that is described by the \f(CWDwarf_Func\fP +descriptor, \f(CWfunc\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_func_cu_offset()" +.DS +\f(CWint dwarf_func_cu_offset( + Dwarf_Func func, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_func_cu_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the compilation-unit +header of the +compilation-unit that contains the static function +described by the \f(CWDwarf_Func\fP descriptor, \f(CWfunc\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_func_name_offsets()" +.DS +\f(CWint dwarf_func_name_offsets( + Dwarf_Func func, + char **func_name, + Dwarf_Off *die_offset, + Dwarf_Off *cu_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_func_name_offsets()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*func_name\fP to +a pointer to +a null-terminated string that gives the name of the static +function described by the \f(CWDwarf_Func\fP descriptor \f(CWfunc\fP. +It also returns in the locations +pointed to by \f(CWdie_offset\fP, and \f(CWcu_offset\fP, the offsets +of the DIE representing the +static function, and the DIE +representing the compilation-unit containing the +static function, respectively. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from \f(CWdwarf_func_name_offsets()\fP +the storage pointed to by \f(CWfunc_name\fP should be freed using +\f(CWdwarf_dealloc()\fP, with the allocation type \f(CWDW_DLA_STRING\fP +when no longer of interest. + +.H 2 "User Defined Type Names Operations" +Section "debug_typenames" is SGI specific +and is not part of standard DWARF version 2. +(However, an identical section is part of DWARF version 3 +named ".debug_pubtypes", see \f(CWdwarf_get_pubtypes()\fP above.) +.P +These functions operate on the .debug_typenames section of the debugging +information. The .debug_typenames section contains the names of file-scope +user-defined types, the offsets of the \f(CWDIE\fPs that represent the +definitions of those types, and the offsets of the compilation-units +that contain the definitions of those types. + +.H 3 "Debugger Interface Operations" + +.H 4 "dwarf_get_types()" +.DS +\f(CWint dwarf_get_types( + Dwarf_Debug dbg, + Dwarf_Type **types, + Dwarf_Signed *typecount, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_types()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*typecount\fP to +the count of user-defined +type names represented in the section containing user-defined type names, +i.e. .debug_typenames. +It also stores at \f(CW*types\fP, +a pointer to a list of \f(CWDwarf_Type\fP descriptors, one for each of the +user-defined type names in the .debug_typenames section. +The returned results are for the entire section. +It returns \f(CWDW_DLV_NOCOUNT\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if +the .debug_typenames section does not exist. + +.P + +On a successful +return from \f(CWdwarf_get_types()\fP, +the \f(CWDwarf_Type\fP descriptors should be +freed using \f(CWdwarf_types_dealloc()\fP. +\f(CWdwarf_types_dealloc()\fP is new as of July 15, 2005 +and frees all memory allocated by \f(CWdwarf_get_types()\fP. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Type *types; +int res; + +res = dwarf_get_types(dbg, &types,&cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use types[i] */ + } + dwarf_types_dealloc(dbg, types, cnt); +}\fP +.DE +.in -2 + + + +.P +The following code is deprecated as of July 15, 2005 as it does not +free all relevant memory. +This approach still works as well as it ever did. +On a successful +return from \f(CWdwarf_get_types()\fP, +the \f(CWDwarf_Type\fP descriptors should be +individually freed using \f(CWdwarf_dealloc()\fP with the allocation type +\f(CWDW_DLA_TYPENAME_CONTEXT\fP, +(or +\f(CWDW_DLA_TYPENAME\fP, an older name, supported for compatibility) +followed by the deallocation of the list itself +with the allocation type \f(CWDW_DLA_LIST\fP when the descriptors are no +longer of interest. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Type *types; +int res; + +res = dwarf_get_types(dbg, &types,&cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use types[i] */ + dwarf_dealloc(dbg, types[i], DW_DLA_TYPENAME_CONTEXT); + } + dwarf_dealloc(dbg, types, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.H 4 "dwarf_typename()" +.DS +\f(CWint dwarf_typename( + Dwarf_Type type, + char **return_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_typename()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_name\fP to +a pointer to a +null-terminated string that names the user-defined type represented by the +\f(CWDwarf_Type\fP descriptor, \f(CWtype\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from this function, the string should +be freed using \f(CWdwarf_dealloc()\fP, with the allocation type +\f(CWDW_DLA_STRING\fP when no longer of interest. + +.H 4 "dwarf_type_die_offset()" +.DS +\f(CWint dwarf_type_die_offset( + Dwarf_Type type, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_type_die_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the DIE representing +the user-defined type that is described by the \f(CWDwarf_Type\fP +descriptor, \f(CWtype\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_type_cu_offset()" +.DS +\f(CWint dwarf_type_cu_offset( + Dwarf_Type type, + Dwarf_Off *return_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_type_cu_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the compilation-unit +header of the compilation-unit that contains the user-defined type +described by the \f(CWDwarf_Type\fP descriptor, \f(CWtype\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_type_name_offsets()" +.DS +\f(CWint dwarf_type_name_offsets( + Dwarf_Type type, + char ** returned_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_type_name_offsets()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_name\fP to +a pointer to +a null-terminated string that gives the name of the user-defined +type described by the \f(CWDwarf_Type\fP descriptor \f(CWtype\fP. +It also returns in the locations +pointed to by \f(CWdie_offset\fP, and \f(CWcu_offset\fP, the offsets +of the DIE representing the +user-defined type, and the DIE +representing the compilation-unit containing the +user-defined type, respectively. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from \f(CWdwarf_type_name_offsets()\fP +the storage pointed to by \f(CWreturned_name\fP should +be freed using +\f(CWdwarf_dealloc()\fP, with the allocation type \f(CWDW_DLA_STRING\fP +when no longer of interest. + + +.H 2 "User Defined Static Variable Names Operations" +This section is SGI specific and is not part of standard DWARF version 2. +.P +These functions operate on the .debug_varnames section of the debugging +information. The .debug_varnames section contains the names of file-scope +static variables, the offsets of the \f(CWDIE\fPs that represent the +definitions of those variables, and the offsets of the compilation-units +that contain the definitions of those variables. +.P + +.H 3 "Debugger Interface Operations" + +.H 4 "dwarf_get_vars()" + +.DS +\f(CWint dwarf_get_vars( + Dwarf_Debug dbg, + Dwarf_Var **vars, + Dwarf_Signed *var_count, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_vars()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*var_count\fP to +the count of file-scope +static variable names represented in the section containing file-scope +static variable names, i.e. .debug_varnames. +It also stores, at \f(CW*vars\fP, a pointer to a list of +\f(CWDwarf_Var\fP descriptors, one for each of the file-scope static +variable names in the .debug_varnames section. +The returned results are for the entire section. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if the .debug_varnames section does +not exist. + +.P +The following is new as of July 15, 2005. +On a successful return +from \f(CWdwarf_get_vars()\fP, the \f(CWDwarf_Var\fP descriptors should be +freed using \f(CWdwarf_vars_dealloc()\fP. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Var *vars; +int res; + +res = dwarf_get_vars(dbg, &vars,&cnt &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use vars[i] */ + } + dwarf_vars_dealloc(dbg, vars, cnt); +}\fP +.DE +.in -2 + +.P +The following code is deprecated as of July 15, 2005 as it does not +free all relevant memory. +This approach still works as well as it ever did. +On a successful return +from \f(CWdwarf_get_vars()\fP, the \f(CWDwarf_Var\fP descriptors should be individually +freed using \f(CWdwarf_dealloc()\fP with the allocation type +\f(CWDW_DLA_VAR_CONTEXT\fP, +(or +\f(CWDW_DLA_VAR\fP, an older name, supported for compatibility) +followed by the deallocation of the list itself with +the allocation type \f(CWDW_DLA_LIST\fP when the descriptors are no +longer of interest. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Var *vars; +int res; + +res = dwarf_get_vars(dbg, &vars,&cnt &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use vars[i] */ + dwarf_dealloc(dbg, vars[i], DW_DLA_VAR_CONTEXT); + } + dwarf_dealloc(dbg, vars, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.H 4 "dwarf_varname()" +.DS +\f(CWint dwarf_varname( + Dwarf_Var var, + char ** returned_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_varname()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_name\fP to +a pointer to a +null-terminated string that names the file-scope static variable represented +by the \f(CWDwarf_Var\fP descriptor, \f(CWvar\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from this function, the string should +be freed using \f(CWdwarf_dealloc()\fP, with the allocation type +\f(CWDW_DLA_STRING\fP when no longer of interest. + +.H 4 "dwarf_var_die_offset()" +.DS +\f(CWint dwarf_var_die_offset( + Dwarf_Var var, + Dwarf_Off *returned_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_var_die_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the DIE representing +the file-scope static variable that is described by the \f(CWDwarf_Var\fP +descriptor, \f(CWvar\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_var_cu_offset()" +.DS +\f(CWint dwarf_var_cu_offset( + Dwarf_Var var, + Dwarf_Off *returned_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_var_cu_offset()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_offset\fP to +the offset in +the section containing DIEs, i.e. .debug_info, of the compilation-unit +header of the compilation-unit that contains the file-scope static +variable described by the \f(CWDwarf_Var\fP descriptor, \f(CWvar\fP. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 4 "dwarf_var_name_offsets()" +.DS +\f(CWint dwarf_var_name_offsets( + Dwarf_Var var, + char **returned_name, + Dwarf_Off *die_offset, + Dwarf_Off *cu_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_var_name_offsets()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_name\fP to +a pointer to +a null-terminated string that gives the name of the file-scope +static variable described by the \f(CWDwarf_Var\fP descriptor \f(CWvar\fP. +It also returns in the locations +pointed to by \f(CWdie_offset\fP, and \f(CWcu_offset\fP, the offsets +of the DIE representing the +file-scope static variable, and the DIE +representing the compilation-unit containing the +file-scope static variable, respectively. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +On a successful return from +\f(CWdwarf_var_name_offsets()\fP the storage pointed to by +\f(CWreturned_name\fP +should be freed using \f(CWdwarf_dealloc()\fP, with the allocation +type \f(CWDW_DLA_STRING\fP when no longer of interest. + +.H 2 "Macro Information Operations" +.H 3 "General Macro Operations" +.H 4 "dwarf_find_macro_value_start()" +.DS +\f(CWchar *dwarf_find_macro_value_start(char * macro_string);\fP +.DE +Given a macro string in the standard form defined in the DWARF +document ("name <space> value" or "name(args)<space>value") +this returns a pointer to the first byte of the macro value. +It does not alter the string pointed to by macro_string or copy +the string: it returns a pointer into the string whose +address was passed in. +.H 3 "Debugger Interface Macro Operations" +Macro information is accessed from the .debug_info section via the +DW_AT_macro_info attribute (whose value is an offset into .debug_macinfo). +.P +No Functions yet defined. +.H 3 "Low Level Macro Information Operations" +.H 4 "dwarf_get_macro_details()" +.DS +\f(CWint dwarf_get_macro_details(Dwarf_Debug /*dbg*/, + Dwarf_Off macro_offset, + Dwarf_Unsigned maximum_count, + Dwarf_Signed * entry_count, + Dwarf_Macro_Details ** details, + Dwarf_Error * err);\fP +.DE +\f(CWdwarf_get_macro_details()\fP +returns +\f(CWDW_DLV_OK\fP and sets +\f(CWentry_count\fP to the number of \f(CWdetails\fP records +returned through the \f(CWdetails\fP pointer. +The data returned through \f(CWdetails\fP should be freed +by a call to \f(CWdwarf_dealloc()\fP with the allocation type +\f(CWDW_DLA_STRING\fP. +If \f(CWDW_DLV_OK\fP is returned, the \f(CWentry_count\fP will +be at least 1, since +a compilation unit with macro information but no macros will +have at least one macro data byte of 0. +.P +\f(CWdwarf_get_macro_details()\fP +begins at the \f(CWmacro_offset\fP offset you supply +and ends at the end of a compilation unit or at \f(CWmaximum_count\fP +detail records (whichever comes first). +If \f(CWmaximum_count\fP is 0, it is treated as if it were the maximum +possible unsigned integer. +.P +\f(CWdwarf_get_macro_details()\fP +attempts to set \f(CWdmd_fileindex\fP to the correct file in every +\f(CWdetails\fP record. If it is unable to do so (or whenever +the current file index is unknown, it sets \f(CWdmd_fileindex\fP +to -1. +.P +\f(CWdwarf_get_macro_details()\fP returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if there is no more +macro information at that \f(CWmacro_offset\fP. If \f(CWmacro_offset\fP +is passed in as 0, a \f(CWDW_DLV_NO_ENTRY\fP return means there is +no macro information. +.P +.in +2 +.DS +\f(CWDwarf_Unsigned max = 0; +Dwarf_Off cur_off = 0; +Dwarf_Signed count = 0; +Dwarf_Macro_Details *maclist; +int errv; + +/* Loop through all the compilation units macro info. + This is not guaranteed to work because DWARF does not + guarantee every byte in the section is meaningful: + there can be garbage between the macro info + for CUs. But this loop will usually work. +*/ +while((errv = dwarf_get_macro_details(dbg, cur_off,max, + &count,&maclist,&error))== DW_DLV_OK) { + for (i = 0; i < count; ++i) { + /* use maclist[i] */ + } + cur_off = maclist[count-1].dmd_offset + 1; + dwarf_dealloc(dbg, maclist, DW_DLA_STRING); +}\fP +.DE + + +.H 2 "Low Level Frame Operations" +These functions provide information about stack frames to be +used to perform stack traces. The information is an abstraction +of a table with a row per instruction and a column per register +and a column for the canonical frame address (CFA, which corresponds +to the notion of a frame pointer), +as well as a column for the return address. +.P +From 1993-2006 the interface we'll here refer to as DWARF2 +made the CFA be a column in the matrix, but left +DW_FRAME_UNDEFINED_VAL, and DW_FRAME_SAME_VAL out of the matrix +(giving them high numbers). As of the DWARF3 interfaces +introduced in this document in April 2006, there are *two* +interfaces (the original set and a new set). +Several frame functions work transparently for either set, we +will focus on the ones that are not equally suitable +now. +.P +The original DWARF2 interface set still exists (dwarf_get_fde_info_for_reg(), +dwarf_get_fde_info_for_cfa_reg(), and dwarf_get_fde_info_for_all_regs()) +and works adequately for MIPS/IRIX DWARF2 and ABI/ISA sets +that are sufficiently similar to MIPS. +These functions not a good choice for non-MIPS architectures nor +were they a good design for MIPS either. +It's better to switch entirely to the new functions mentioned +in the next paragraph. +This DWARF2 interface set assumes and uses DW_FRAME_CFA_COL +and that is assumed when libdwarf is configured with --enable-oldframecol . +.P +A new DWARF3 interface set of dwarf_get_fde_info_for_reg3(), +dwarf_get_fde_info_for_cfa_reg3(), dwarf_get_fde_info_for_all_regs3(), +dwarf_set_frame_rule_table_size() +dwarf_set_frame_cfa_value(), +dwarf_set_frame_same_value(), +dwarf_set_frame_undefined_value(), and +dwarf_set_frame_rule_initial_value() +is more flexible +and will work for many more architectures. +It is also entirely suitable for use with DWARF2 and DWARF4. +The setting of the 'frame cfa column number' +defaults to DW_FRAME_CFA_COL3 +and it can be set at runtime with dwarf_set_frame_cfa_value(). +.P +Mixing use of the DWARF2 interface set with use +of the new DWARF3 interface set +on a single open Dwarf_Debug instance is a mistake. +Do not do it. +.P +We will pretend, from here on unless otherwise +specified, that +DW_FRAME_CFA_COL3, DW_FRAME_UNDEFINED_VAL, +and DW_FRAME_SAME_VAL are the synthetic column numbers. +These columns may be user-chosen by calls of +dwarf_set_frame_cfa_value() +dwarf_set_frame_undefined_value(), and +dwarf_set_frame_same_value() respectively. + +.P +Each cell in the table contains one of the following: + +.AL +.LI +A register + offset(a)(b) + +.LI +A register(c)(d) + + +.LI +A marker (DW_FRAME_UNDEFINED_VAL) meaning \fIregister value undefined\fP + +.LI +A marker (DW_FRAME_SAME_VAL) meaning +\fIregister value same as in caller\fP +.LE +.P +(a old DWARF2 interface) When the column is DW_FRAME_CFA_COL: +the register +number is a real hardware register, not a reference +to DW_FRAME_CFA_COL, not DW_FRAME_UNDEFINED_VAL, +and not DW_FRAME_SAME_VAL. +The CFA rule value should be the stack pointer +plus offset 0 when no other value makes sense. +A value of DW_FRAME_SAME_VAL would +be semi-logical, but since the CFA is not a real register, +not really correct. +A value of DW_FRAME_UNDEFINED_VAL would imply +the CFA is undefined -- +this seems to be a useless notion, as +the CFA is a means to finding real registers, +so those real registers should be marked DW_FRAME_UNDEFINED_VAL, +and the CFA column content (whatever register it +specifies) becomes unreferenced by anything. +.P +(a new April 2006 DWARF2/3 interface): The CFA is +separately accessible and not part of the table. +The 'rule number' for the CFA is a number outside the table. +So the CFA is a marker, not a register number. +See DW_FRAME_CFA_COL3 in libdwarf.h and +dwarf_get_fde_info_for_cfa_reg3() and +dwarf_set_frame_rule_cfa_value(). +.P +(b) When the column is not DW_FRAME_CFA_COL3, the 'register' +will and must be DW_FRAME_CFA_COL3(COL), implying that +to get the final location for the column one must add +the offset here plus the DW_FRAME_CFA_COL3 rule value. +.P +(c) When the column is DW_FRAME_CFA_COL3, then the 'register' +number is (must be) a real hardware register . +(This paragraph does not apply to the April 2006 new interface). +If it were DW_FRAME_UNDEFINED_VAL or DW_FRAME_SAME_VAL +it would be a marker, not a register number. +.P +(d) When the column is not DW_FRAME_CFA_COL3, the register +may be a hardware register. +It will not be DW_FRAME_CFA_COL3. +.P +There is no 'column' for DW_FRAME_UNDEFINED_VAL or DW_FRAME_SAME_VAL. +Nor for DW_FRAME_CFA_COL3. + +Figure \n(aX +is machine dependent and represents MIPS CPU register +assignments. The DW_FRAME_CFA_COL define in dwarf.h +is historical and really belongs +in libdwarf.h, not dwarf.h. +.DS +.TS +center box, tab(:); +lfB lfB lfB +l c l. +NAME:value:PURPOSE +_ +DW_FRAME_CFA_COL:0:column used for CFA +DW_FRAME_REG1:1:integer register 1 +DW_FRAME_REG2:2:integer register 2 +---::obvious names and values here +DW_FRAME_REG30:30:integer register 30 +DW_FRAME_REG31:31:integer register 31 +DW_FRAME_FREG0:32:floating point register 0 +DW_FRAME_FREG1:33:floating point register 1 +---::obvious names and values here +DW_FRAME_FREG30:62:floating point register 30 +DW_FRAME_FREG31:63:floating point register 31 +DW_FRAME_RA_COL:64:column recording ra +DW_FRAME_UNDEFINED_VAL:1034:register val undefined +DW_FRAME_SAME_VAL:1035:register same as in caller +.TE + +.FG "Frame Information Rule Assignments MIPS" +.DE +.P +The following table shows SGI/MIPS specific +special cell values: these values mean +that the cell has the value \fIundefined\fP or \fIsame value\fP +respectively, rather than containing a \fIregister\fP or +\fIregister+offset\fP. +It assumes DW_FRAME_CFA_COL is a table rule, which +is not readily accomplished or even sensible for some architectures. +.P +.DS +.TS +center box, tab(:); +lfB lfB lfB +l c l. +NAME:value:PURPOSE +_ +DW_FRAME_UNDEFINED_VAL:1034:means undefined value. +::Not a column or register value +DW_FRAME_SAME_VAL:1035:means 'same value' as +::caller had. Not a column or +::register value +DW_FRAME_CFA_COL:0:means register zero is +::usurped by the CFA column. +:: +.TE +.FG "Frame Information Special Values any architecture" +.DE + +.P +The following table shows more general special cell values. +These values mean +that the cell register-number refers to the \fIcfa-register\fP or +\fIundefined-value\fP or \fIsame-value\fP +respectively, rather than referring to a \fIregister in the table\fP. +The generality arises from making DW_FRAME_CFA_COL3 be +outside the set of registers and making the cfa rule accessible +from outside the rule-table. +.P +.DS +.TS +center box, tab(:); +lfB lfB lfB +l c l. +NAME:value:PURPOSE +_ +DW_FRAME_UNDEFINED_VAL:1034:means undefined value. +::Not a column or register value +DW_FRAME_SAME_VAL:1035:means 'same value' as +::caller had. Not a column or +::register value +DW_FRAME_CFA_COL3:1436:means 'cfa register' is referred to, +::not a real register, not a column, but the cfa (the cfa +::does have a value, but in the DWARF3 libdwarf interface +::it does not have a 'real register number'). +.TE +.DE + +.P +.H 4 "dwarf_get_fde_list()" +.DS +\f(CWint dwarf_get_fde_list( + Dwarf_Debug dbg, + Dwarf_Cie **cie_data, + Dwarf_Signed *cie_element_count, + Dwarf_Fde **fde_data, + Dwarf_Signed *fde_element_count, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_fde_list()\fP stores a pointer to a list of +\f(CWDwarf_Cie\fP descriptors in \f(CW*cie_data\fP, and the +count of the number of descriptors in \f(CW*cie_element_count\fP. +There is a descriptor for each CIE in the .debug_frame section. +Similarly, it stores a pointer to a list of \f(CWDwarf_Fde\fP +descriptors in \f(CW*fde_data\fP, and the count of the number +of descriptors in \f(CW*fde_element_count\fP. There is one +descriptor per FDE in the .debug_frame section. +\f(CWdwarf_get_fde_list()\fP returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if it cannot find frame entries. +It returns \f(CWDW_DLV_OK\fP on a successful return. +.P +On successful return, structures pointed to by a +descriptor should be freed using \f(CWdwarf_fde_cie_list_dealloc()\fP. +This dealloc approach is new as of July 15, 2005. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Cie *cie_data; +Dwarf_Signed cie_count; +Dwarf_Fde *fde_data; +Dwarf_Signed fde_count; +int fres; + +fres = dwarf_get_fde_list(dbg,&cie_data,&cie_count, + &fde_data,&fde_count,&error); +if (fres == DW_DLV_OK) { + dwarf_fde_cie_list_dealloc(dbg, cie_data, cie_count, + fde_data,fde_count); +}\fP +.DE +.in -2 + + + +.P +The following code is deprecated as of July 15, 2005 as it does not +free all relevant memory. +This approach still works as well as it ever did. +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Cie *cie_data; +Dwarf_Signed cie_count; +Dwarf_Fde *fde_data; +Dwarf_Signed fde_count; +int fres; + +fres = dwarf_get_fde_list(dbg,&cie_data,&cie_count, + &fde_data,&fde_count,&error); +if (fres == DW_DLV_OK) { + + for (i = 0; i < cie_count; ++i) { + /* use cie[i] */ + dwarf_dealloc(dbg, cie_data[i], DW_DLA_CIE); + } + for (i = 0; i < fde_count; ++i) { + /* use fde[i] */ + dwarf_dealloc(dbg, fde_data[i], DW_DLA_FDE); + } + dwarf_dealloc(dbg, cie_data, DW_DLA_LIST); + dwarf_dealloc(dbg, fde_data, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.P +.H 4 "dwarf_get_fde_list_eh()" +.DS +\f(CWint dwarf_get_fde_list_eh( + Dwarf_Debug dbg, + Dwarf_Cie **cie_data, + Dwarf_Signed *cie_element_count, + Dwarf_Fde **fde_data, + Dwarf_Signed *fde_element_count, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_fde_list_eh()\fP is identical to +\f(CWdwarf_get_fde_list()\fP except that +\f(CWdwarf_get_fde_list_eh()\fP reads the GNU gcc +section named .eh_frame (C++ exception handling information). + +\f(CWdwarf_get_fde_list_eh()\fP stores a pointer to a list of +\f(CWDwarf_Cie\fP descriptors in \f(CW*cie_data\fP, and the +count of the number of descriptors in \f(CW*cie_element_count\fP. +There is a descriptor for each CIE in the .debug_frame section. +Similarly, it stores a pointer to a list of \f(CWDwarf_Fde\fP +descriptors in \f(CW*fde_data\fP, and the count of the number +of descriptors in \f(CW*fde_element_count\fP. There is one +descriptor per FDE in the .debug_frame section. +\f(CWdwarf_get_fde_list()\fP returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if it cannot find +exception handling entries. +It returns \f(CWDW_DLV_OK\fP on a successful return. + +.P +On successful return, structures pointed to by a +descriptor should be freed using \f(CWdwarf_fde_cie_list_dealloc()\fP. +This dealloc approach is new as of July 15, 2005. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Cie *cie_data; +Dwarf_Signed cie_count; +Dwarf_Fde *fde_data; +Dwarf_Signed fde_count; +int fres; + +fres = dwarf_get_fde_list(dbg,&cie_data,&cie_count, + &fde_data,&fde_count,&error); +if (fres == DW_DLV_OK) { + dwarf_fde_cie_list_dealloc(dbg, cie_data, cie_count, + fde_data,fde_count); +}\fP +.DE +.in -2 + + +.P +.H 4 "dwarf_get_cie_of_fde()" +.DS +\f(CWint dwarf_get_cie_of_fde(Dwarf_Fde fde, + Dwarf_Cie *cie_returned, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_cie_of_fde()\fP stores a \f(CWDwarf_Cie\fP +into the \f(CWDwarf_Cie\fP that \f(CWcie_returned\fP points at. + +If one has called dwarf_get_fde_list and does not wish +to dwarf_dealloc() all the individual FDEs immediately, one +must also avoid dwarf_dealloc-ing the CIEs for those FDEs +not immediately dealloc'd. +Failing to observe this restriction will cause the FDE(s) not +dealloc'd to become invalid: an FDE contains (hidden in it) +a CIE pointer which will be be invalid (stale, pointing to freed memory) +if the CIE is dealloc'd. +The invalid CIE pointer internal to the FDE cannot be detected +as invalid by libdwarf. +If one later passes an FDE with a stale internal CIE pointer +to one of the routines taking an FDE as input the result will +be failure of the call (returning DW_DLV_ERROR) at best and +it is possible a coredump or worse will happen (eventually). + + +\f(CWdwarf_get_cie_of_fde()\fP returns +\f(CWDW_DLV_OK\fP if it is successful (it will be +unless fde is the NULL pointer). +It returns \f(CWDW_DLV_ERROR\fP if the fde is invalid (NULL). + +.P +Each \f(CWDwarf_Fde\fP descriptor describes information about the +frame for a particular subroutine or function. + +\f(CWint dwarf_get_fde_for_die\fP is SGI/MIPS specific. + +.H 4 "dwarf_get_fde_for_die()" +.DS +\f(CWint dwarf_get_fde_for_die( + Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Fde * return_fde, + Dwarf_Error *error)\fP +.DE +When it succeeds, +\f(CWdwarf_get_fde_for_die()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_fde\fP +to +a \f(CWDwarf_Fde\fP +descriptor representing frame information for the given \f(CWdie\fP. It +looks for the \f(CWDW_AT_MIPS_fde\fP attribute in the given \f(CWdie\fP. +If it finds it, is uses the value of the attribute as the offset in +the .debug_frame section where the FDE begins. +If there is no \f(CWDW_AT_MIPS_fde\fP it returns \f(CWDW_DLV_NO_ENTRY\fP. +If there is an error it returns \f(CWDW_DLV_ERROR\fP. + +.H 4 "dwarf_get_fde_range()" +.DS +\f(CWint dwarf_get_fde_range( + Dwarf_Fde fde, + Dwarf_Addr *low_pc, + Dwarf_Unsigned *func_length, + Dwarf_Ptr *fde_bytes, + Dwarf_Unsigned *fde_byte_length, + Dwarf_Off *cie_offset, + Dwarf_Signed *cie_index, + Dwarf_Off *fde_offset, + Dwarf_Error *error);\fP +.DE +On success, +\f(CWdwarf_get_fde_range()\fP returns +\f(CWDW_DLV_OK\fP. + +The location pointed to by \f(CWlow_pc\fP is set to the low pc value for +this function. + +The location pointed to by \f(CWfunc_length\fP is +set to the length of the function in bytes. +This is essentially the +length of the text section for the function. + +The location pointed +to by \f(CWfde_bytes\fP is set to the address where the FDE begins +in the .debug_frame section. + +The location pointed to by +\f(CWfde_byte_length\fP is set to the length in bytes of the portion +of .debug_frame for this FDE. +This is the same as the value returned +by \f(CWdwarf_get_fde_range\fP. + +The location pointed to by +\f(CWcie_offset\fP is set to the offset in the .debug_frame section +of the CIE used by this FDE. + +The location pointed to by \f(CWcie_index\fP +is set to the index of the CIE used by this FDE. +The index is the +index of the CIE in the list pointed to by \f(CWcie_data\fP as set +by the function \f(CWdwarf_get_fde_list()\fP. +However, if the function +\f(CWdwarf_get_fde_for_die()\fP was used to obtain the given \f(CWfde\fP, +this index may not be correct. + +The location pointed to by +\f(CWfde_offset\fP is set to the offset of the start of this FDE in +the .debug_frame section. + +\f(CWdwarf_get_fde_range()\fP returns \f(CWDW_DLV_ERROR\fP on error. + +.H 4 "dwarf_get_cie_info()" +.DS +\f(CWint dwarf_get_cie_info( + Dwarf_Cie cie, + Dwarf_Unsigned *bytes_in_cie, + Dwarf_Small *version, + char **augmenter, + Dwarf_Unsigned *code_alignment_factor, + Dwarf_Signed *data_alignment_factor, + Dwarf_Half *return_address_register_rule, + Dwarf_Ptr *initial_instructions, + Dwarf_Unsigned *initial_instructions_length, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_cie_info()\fP is primarily for Internal-level Interface +consumers. +If successful, +it returns +\f(CWDW_DLV_OK\fP and sets \f(CW*bytes_in_cie\fP to +the number of bytes in the portion of the +frames section for the CIE represented by the given \f(CWDwarf_Cie\fP +descriptor, \f(CWcie\fP. +The other fields are directly taken from +the cie and returned, via the pointers to the caller. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 4 "dwarf_get_cie_index()" +.DS +\f(CWint dwarf_get_cie_index( + Dwarf_Cie cie, + Dwarf_Signed *cie_index, + Dwarf_Error *error);\fP +.DE +On success, +\f(CWdwarf_get_cie_index()\fP returns +\f(CWDW_DLV_OK\fP. +On error this function returns \f(CWDW_DLV_ERROR\fP. + +The location pointed to by \f(CWcie_index\fP +is set to the index of the CIE of this FDE. +The index is the +index of the CIE in the list pointed to by \f(CWcie_data\fP as set +by the function \f(CWdwarf_get_fde_list()\fP. + +So one must have used \f(CWdwarf_get_fde_list()\fP or +\f(CWdwarf_get_fde_list_eh()\fP to get +a cie list before this is meaningful. + +This function is occasionally useful, but is +little used. + +.H 4 "dwarf_get_fde_instr_bytes()" +.DS +\f(CWint dwarf_get_fde_instr_bytes( + Dwarf_Fde fde, + Dwarf_Ptr *outinstrs, + Dwarf_Unsigned *outlen, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_fde_instr_bytes()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*outinstrs\fP to +a pointer to a set of bytes which are the +actual frame instructions for this fde. +It also sets \f(CW*outlen\fP to the length, in +bytes, of the frame instructions. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +The intent is to allow low-level consumers like a dwarf-dumper +to print the bytes in some fashion. +The memory pointed to by \f(CWoutinstrs\fP +must not be changed and there +is nothing to free. + +.H 4 "dwarf_get_fde_info_for_reg()" +This interface is suitable for DWARF2 but is not +sufficient for DWARF3. See \f(CWint dwarf_get_fde_info_for_reg3\fP. +.DS +\f(CWint dwarf_get_fde_info_for_reg( + Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr pc_requested, + Dwarf_Signed *offset_relevant, + Dwarf_Signed *register_num, + Dwarf_Signed *offset, + Dwarf_Addr *row_pc, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_fde_info_for_reg()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*offset_relevant\fP to +non-zero if the offset is relevant for the +row specified by \f(CWpc_requested\fP and column specified by +\f(CWtable_column\fP, for the FDE specified by \f(CWfde\fP. +The +intent is to return the rule for the given pc value and register. +The location pointed to by \f(CWregister_num\fP is set to the register +value for the rule. +The location pointed to by \f(CWoffset\fP +is set to the offset value for the rule. +If offset is not relevant for this rule, \f(CW*offset_relevant\fP is +set to zero. +Since more than one pc +value will have rows with identical entries, the user may want to +know the earliest pc value after which the rules for all the columns +remained unchanged. +Recall that in the virtual table that the frame information +represents there may be one or more table rows with identical data +(each such table row at a different pc value). +Given a \f(CWpc_requested\fP which refers to a pc in such a group +of identical rows, +the location pointed to by \f(CWrow_pc\fP is set +to the lowest pc value +within the group of identical rows. +The value put in \f(CW*register_num\fP any of the +\f(CWDW_FRAME_*\fP table columns values specified in \f(CWlibdwarf.h\fP +or \f(CWdwarf.h\fP. + +\f(CWdwarf_get_fde_info_for_reg\fP returns \f(CWDW_DLV_ERROR\fP if there is an error. + +It is usable with either +\f(CWdwarf_get_fde_n()\fP or \f(CWdwarf_get_fde_at_pc()\fP. + +\f(CWdwarf_get_fde_info_for_reg()\fP is tailored to MIPS, please use +\f(CWdwarf_get_fde_info_for_reg3()\fP instead for all architectures. + + +.H 4 "dwarf_get_fde_info_for_all_regs()" +.DS +\f(CWint dwarf_get_fde_info_for_all_regs( + Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Regtable *reg_table, + Dwarf_Addr *row_pc, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_fde_info_for_all_regs()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*reg_table\fP for the row specified by +\f(CWpc_requested\fP for the FDE specified by \f(CWfde\fP. +.P +The intent is +to return the rules for decoding all the registers, given a pc value. +\f(CWreg_table\fP is an array of rules, one for each register specified in +\f(CWdwarf.h\fP. The rule for each register contains three items - +\f(CWdw_regnum\fP which denotes the register value for that rule, +\f(CWdw_offset\fP which denotes the offset value for that rule and +\f(CWdw_offset_relevant\fP which is set to zero if offset is not relevant +for that rule. See \f(CWdwarf_get_fde_info_for_reg()\fP for a description +of \f(CWrow_pc\fP. +.P +\f(CWdwarf_get_fde_info_for_all_regs\fP returns \f(CWDW_DLV_ERROR\fP if there is an error. +.P +\f(CWint dwarf_get_fde_info_for_all_regs\fP is tailored to SGI/MIPS, +please use dwarf_get_fde_info_for_all_regs3() instead for all architectures. + + +.H 4 "dwarf_set_frame_rule_table_size()" +.P +This allows consumers to set the size of the (internal to libdwarf) +rule table when using the 'reg3' interfaces (these interfaces +are strongly preferred over the older 'reg' interfaces). +It should be at least as large as the +number of real registers in the ABI which is to be read in +for the dwarf_get_fde_info_for_reg3() or dwarf_get_fde_info_for_all_regs3() +functions to work properly. + +The frame rule table size must be less than the marker values +DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL, DW_FRAME_CFA_COL3 +(dwarf_set_frame_rule_undefined_value() +dwarf_set_frame_same_value() +dwarf_set_frame_cfa_value() +effectively set these markers so +the frame rule table size can actually be any value regardless +of the macro values in libdwarf.h as long as the table size +does not overlap these markers). +.P +.DS +\f(CWDwarf_Half +dwarf_set_frame_rule_table_size(Dwarf_Debug dbg, + Dwarf_Half value);\fP + +.DE +\f(CWdwarf_set_frame_rule_table_size()\fP sets the +value \f(CWvalue\fP as the size of libdwarf-internal +rules tables of \f(CWdbg\fP. +.P +The function returns +the previous value of the rules table size setting (taken from the +\f(CWdbg\fP structure). + +.H 4 "dwarf_set_frame_rule_initial_value()" +This allows consumers to set the initial value +for rows in the frame tables. By default it +is taken from libdwarf.h and is DW_FRAME_REG_INITIAL_VALUE +(which itself is either DW_FRAME_SAME_VAL or DW_FRAME_UNDEFINED_VAL). +The MIPS/IRIX default is DW_FRAME_SAME_VAL. +Consumer code should set this appropriately and for +many architectures (but probably not MIPS) DW_FRAME_UNDEFINED_VAL is an +appropriate setting. +Note: an earlier spelling of dwarf_set_frame_rule_inital_value() +is still supported as an interface, but please change to use +the new correctly spelled name. +.DS +\f(CWDwarf_Half +dwarf_set_frame_rule_initial_value(Dwarf_Debug dbg, + Dwarf_Half value);\fP + +.DE +\f(CWdwarf_set_frame_rule_initial_value()\fP sets the +value \f(CWvalue\fP as the initial value for this \f(CWdbg\fP +when initializing rules tables. +.P +The function returns +the previous value of initial value (taken from the +\f(CWdbg\fP structure). + +.H 4 "dwarf_set_frame_cfa_value()" +This allows consumers to set the number of the CFA register +for rows in the frame tables. By default it +is taken from libdwarf.h and is \f(CWDW_FRAME_CFA_COL\fP. +Consumer code should set this appropriately and for +nearly all architectures \f(CWDW_FRAME_CFA_COL3\fP is an +appropriate setting. +.DS +\f(CWDwarf_Half +dwarf_set_frame_rule_cfa_value(Dwarf_Debug dbg, + Dwarf_Half value);\fP + +.DE +\f(CWdwarf_set_frame_rule_cfa_value()\fP sets the +value \f(CWvalue\fP as the number of the cfa 'register rule' +for this \f(CWdbg\fP +when initializing rules tables. +.P +The function returns +the previous value of the pseudo-register (taken from the +\f(CWdbg\fP structure). + +.H 4 "dwarf_set_frame_same_value()" +This allows consumers to set the number of the pseudo-register +when DW_CFA_same_value is the operation. By default it +is taken from libdwarf.h and is \f(CWDW_FRAME_SAME_VAL\fP. +Consumer code should set this appropriately, though for +many architectures \f(CWDW_FRAME_SAME_VAL\fP is an +appropriate setting. +.DS +\f(CWDwarf_Half +dwarf_set_frame_rule_same_value(Dwarf_Debug dbg, + Dwarf_Half value);\fP + +.DE +\f(CWdwarf_set_frame_rule_same_value()\fP sets the +value \f(CWvalue\fP as the number of the register +that is the pseudo-register set by the DW_CFA_same_value +frame operation. +.P +The function returns +the previous value of the pseudo-register (taken from the +\f(CWdbg\fP structure). + + +.H 4 "dwarf_set_frame_undefined_value()" +This allows consumers to set the number of the pseudo-register + when DW_CFA_undefined_value is the operation. By default it +is taken from libdwarf.h and is \f(CWDW_FRAME_UNDEFINED_VAL\fP. +Consumer code should set this appropriately, though for +many architectures \f(CWDW_FRAME_UNDEFINED_VAL\fP is an +appropriate setting. +.DS +\f(CWDwarf_Half +dwarf_set_frame_rule_undefined_value(Dwarf_Debug dbg, + Dwarf_Half value);\fP + +.DE +\f(CWdwarf_set_frame_rule_undefined_value()\fP sets the +value \f(CWvalue\fP as the number of the register +that is the pseudo-register set by the DW_CFA_undefined_value +frame operation. +.P +The function returns +the previous value of the pseudo-register (taken from the +\f(CWdbg\fP structure). + +.H 4 "dwarf_set_default_address_size()" +This allows consumers to set a default address size. +When one has an object where the +default address_size does not match the frame address +size where there is no debug_info available to get a +frame-specific address-size, this function is useful. +For example, if an Elf64 object has a .debug_frame whose +real address_size is 4 (32 bits). This a very rare +situation. +.DS +\f(CWDwarf_Small +dwarf_set_default_address_size(Dwarf_Debug dbg, + Dwarf_Small value);\fP + +.DE +\f(CWdwarf_set_default_address_size()\fP sets the +value \f(CWvalue\fP as the default address size for +this activation of the reader, but only if \f(CWvalue\fP +is greater than zero (otherwise the default address size +is not changed). +.P +The function returns +the previous value of the default address size (taken from the +\f(CWdbg\fP structure). + + + +.H 4 "dwarf_get_fde_info_for_reg3()" +This interface is suitable for DWARF3 and DWARF2. +It returns the values for a particular real register +(Not for the CFA register, see dwarf_get_fde_info_for_cfa_reg3() +below). +If the application is going to retrieve the value for more +than a few \f(CWtable_column\fP values at this \f(CWpc_requested\fP +(by calling this function multiple times) +it is much more efficient to +call dwarf_get_fde_info_for_all_regs3() (in spite +of the additional setup that requires of the caller). + +.DS +\f(CWint dwarf_get_fde_info_for_reg3( + Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr pc_requested, + Dwarf_Small *value_type, + Dwarf_Signed *offset_relevant, + Dwarf_Signed *register_num, + Dwarf_Signed *offset_or_block_len, + Dwarf_Ptr *block_ptr, + Dwarf_Addr *row_pc, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_get_fde_info_for_reg3()\fP returns +\f(CWDW_DLV_OK\fP on success. +It sets \f(CW*value_type\fP +to one of DW_EXPR_OFFSET (0), +DW_EXPR_VAL_OFFSET(1), DW_EXPR_EXPRESSION(2) or +DW_EXPR_VAL_EXPRESSION(3). +On call, \f(CWtable_column\fP must be set to the +register number of a real register. Not +the cfa 'register' or DW_FRAME_SAME_VALUE or +DW_FRAME_UNDEFINED_VALUE. + + +if \f(CW*value_type\fP has the value DW_EXPR_OFFSET (0) then: +.in +4 +.P +It sets \f(CW*offset_relevant\fP to +non-zero if the offset is relevant for the +row specified by \f(CWpc_requested\fP and column specified by +\f(CWtable_column\fP or, for the FDE specified by \f(CWfde\fP. +In this case the \f(CW*register_num\fP will be set +to DW_FRAME_CFA_COL3 (. This is an offset(N) rule +as specified in the DWARF3/2 documents. +Adding the value of \f(CW*offset_or_block_len\fP +to the value of the CFA register gives the address +of a location holding the previous value of +register \f(CWtable_column\fP. + +.P +If offset is not relevant for this rule, \f(CW*offset_relevant\fP is +set to zero. \f(CW*register_num\fP will be set +to the number of the real register holding the value of +the \f(CWtable_column\fP register. +This is the register(R) rule as specified in DWARF3/2 documents. +.P +The +intent is to return the rule for the given pc value and register. +The location pointed to by \f(CWregister_num\fP is set to the register +value for the rule. +The location pointed to by \f(CWoffset\fP +is set to the offset value for the rule. +Since more than one pc +value will have rows with identical entries, the user may want to +know the earliest pc value after which the rules for all the columns +remained unchanged. +Recall that in the virtual table that the frame information +represents there may be one or more table rows with identical data +(each such table row at a different pc value). +Given a \f(CWpc_requested\fP which refers to a pc in such a group +of identical rows, +the location pointed to by \f(CWrow_pc\fP is set +to the lowest pc value +within the group of identical rows. + +.in -4 + +.P +If \f(CW*value_type\fP has the value DW_EXPR_VAL_OFFSET (1) then: +.in +4 +This will be a val_offset(N) rule as specified in the +DWARF3/2 documents so \f(CW*offset_relevant\fP will +be non zero. +The calculation is identical to the DW_EXPR_OFFSET (0) +calculation with \f(CW*offset_relevant\fP non-zero, +but the value resulting is the actual \f(CWtable_column\fP +value (rather than the address where the value may be found). +.in -4 +.P +If \f(CW*value_type\fP has the value DW_EXPR_EXPRESSION (1) then: +.in +4 + \f(CW*offset_or_block_len\fP +is set to the length in bytes of a block of memory +with a DWARF expression in the block. +\f(CW*block_ptr\fP is set to point at the block of memory. +The consumer code should evaluate the block as +a DWARF-expression. The result is the address where +the previous value of the register may be found. +This is a DWARF3/2 expression(E) rule. +.in -4 +.P +If \f(CW*value_type\fP has the value DW_EXPR_VAL_EXPRESSION (1) then: +.in +4 +The calculation is exactly as for DW_EXPR_EXPRESSION (1) +but the result of the DWARF-expression evaluation is +the value of the \f(CWtable_column\fP (not +the address of the value). +This is a DWARF3/2 val_expression(E) rule. +.in -4 + +\f(CWdwarf_get_fde_info_for_reg\fP +returns \f(CWDW_DLV_ERROR\fP if there is an error and +if there is an error only the \f(CWerror\fP pointer is set, none +of the other output arguments are touched. + +It is usable with either +\f(CWdwarf_get_fde_n()\fP or \f(CWdwarf_get_fde_at_pc()\fP. + + +.H 4 "dwarf_get_fde_info_for_cfa_reg3()" +.DS + \f(CWint dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Small * value_type, + Dwarf_Signed* offset_relevant, + Dwarf_Signed* register_num, + Dwarf_Signed* offset_or_block_len, + Dwarf_Ptr * block_ptr , + Dwarf_Addr * row_pc_out, + Dwarf_Error * error)\fP +.DE +.P +This is identical to \f(CWdwarf_get_fde_info_for_reg3()\fP +except the returned values are for the CFA rule. +So register number \f(CW*register_num\fP will be set +to a real register, not one of the pseudo registers +(which are usually +DW_FRAME_CFA_COL3, DW_FRAME_SAME_VALUE, or +DW_FRAME_UNDEFINED_VALUE). + + + +.H 4 "dwarf_get_fde_info_for_all_regs3()" +.DS +\f(CWint dwarf_get_fde_info_for_all_regs3( + Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Regtable3 *reg_table, + Dwarf_Addr *row_pc, + Dwarf_Error *error)\fP +.DE +\f(CWdwarf_get_fde_info_for_all_regs3()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*reg_table\fP +for the row specified by +\f(CWpc_requested\fP for the FDE specified by \f(CWfde\fP. +The intent is +to return the rules for decoding all the registers, given a pc +value. +\f(CWreg_table\fP is an array of rules, the +array size specified by the caller. +plus a rule for the CFA. +The rule for the cfa returned in \f(CW*reg_table\fP +defines the CFA value at \f(CWpc_requested\fP +The rule for each +register contains several values that enable +the consumer to determine the previous value +of the register (see the earlier documentation of Dwarf_Regtable3). +\f(CWdwarf_get_fde_info_for_reg3()\fP and +the Dwarf_Regtable3 documentation above for a description of +the values for each row. + +\f(CWdwarf_get_fde_info_for_all_regs3\fP returns \f(CWDW_DLV_ERROR\fP if there is an error. + +It is up to the caller to allocate space for +\f(CW*reg_table\fP and initialize it properly. + + + +.H 4 "dwarf_get_fde_n()" +.DS +\f(CWint dwarf_get_fde_n( + Dwarf_Fde *fde_data, + Dwarf_Unsigned fde_index, + Dwarf_Fde *returned_fde + Dwarf_Error *error)\fP +.DE +\f(CWdwarf_get_fde_n()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CWreturned_fde\fP to +the \f(CWDwarf_Fde\fP descriptor whose +index is \f(CWfde_index\fP in the table of \f(CWDwarf_Fde\fP descriptors +pointed to by \fPfde_data\fP. +The index starts with 0. +The table pointed to by fde_data is required to contain +at least one entry. If the table has no entries at all +the error checks may refer to uninitialized memory. +Returns \f(CWDW_DLV_NO_ENTRY\fP if the index does not +exist in the table of \f(CWDwarf_Fde\fP +descriptors. +Returns \f(CWDW_DLV_ERROR\fP if there is an error. +This function cannot be used unless +the block of \f(CWDwarf_Fde\fP descriptors has been created by a call to +\f(CWdwarf_get_fde_list()\fP. + +.H 4 "dwarf_get_fde_at_pc()" +.DS +\f(CWint dwarf_get_fde_at_pc( + Dwarf_Fde *fde_data, + Dwarf_Addr pc_of_interest, + Dwarf_Fde *returned_fde, + Dwarf_Addr *lopc, + Dwarf_Addr *hipc, + Dwarf_Error *error)\fP +.DE +\f(CWdwarf_get_fde_at_pc()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CWreturned_fde\fP to +a \f(CWDwarf_Fde\fP descriptor +for a function which contains the pc value specified by \f(CWpc_of_interest\fP. +In addition, it sets the locations pointed to +by \f(CWlopc\fP and \f(CWhipc\fP to the low address and the high address +covered by this FDE, respectively. +The table pointed to by fde_data is required to contain +at least one entry. If the table has no entries at all +the error checks may refer to uninitialized memory. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP +if \f(CWpc_of_interest\fP is not in any of the +FDEs represented by the block of \f(CWDwarf_Fde\fP descriptors pointed +to by \f(CWfde_data\fP. +This function cannot be used unless +the block of \f(CWDwarf_Fde\fP descriptors has been created by a call to +\f(CWdwarf_get_fde_list()\fP. + +.H 4 "dwarf_expand_frame_instructions()" +.DS +\f(CWint dwarf_expand_frame_instructions( + Dwarf_Cie cie, + Dwarf_Ptr instruction, + Dwarf_Unsigned i_length, + Dwarf_Frame_Op **returned_op_list, + Dwarf_Signed * returned_op_count, + Dwarf_Error *error);\fP +.DE +\f(CWdwarf_expand_frame_instructions()\fP is a High-level interface +function which expands a frame instruction byte stream into an +array of \f(CWDwarf_Frame_Op\fP structures. +To indicate success, it returns \f(CWDW_DLV_OK\fP. +The address where +the byte stream begins is specified by \f(CWinstruction\fP, and +the length of the byte stream is specified by \f(CWi_length\fP. +The location pointed to by \f(CWreturned_op_list\fP is set to +point to a table of +\f(CWreturned_op_count\fP +pointers to \f(CWDwarf_Frame_Op\fP which +contain the frame instructions in the byte stream. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. +After a successful return, the +array of structures should be freed using +\f(CWdwarf_dealloc()\fP with the allocation type \f(CWDW_DLA_FRAME_BLOCK\fP +(when they are no longer of interest). +.P +Not all CIEs have the same address-size, so it is crucial +that a CIE pointer to the frame's CIE be passed in. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Frame_Op *frameops; +Dwarf_Ptr instruction; +Dwarf_Unsigned len; +int res; + +res = expand_frame_instructions(dbg,instruction,len, &frameops,&cnt, &error); +if (res == DW_DLV_OK) { + for (i = 0; i < cnt; ++i) { + /* use frameops[i] */ + } + dwarf_dealloc(dbg, frameops, DW_DLA_FRAME_BLOCK); +}\fP +.DE +.in -2 +.H 4 "dwarf_get_fde_exception_info()" +.DS +\f(CWint dwarf_get_fde_exception_info( + Dwarf_Fde fde, + Dwarf_Signed * offset_into_exception_tables, + Dwarf_Error * error); +.DE +\f(CWdwarf_get_fde_exception_info()\fP is an IRIX specific +function which returns an exception table signed offset +through \f(CWoffset_into_exception_tables\fP. +The function never returns \f(CWDW_DLV_NO_ENTRY\fP. +If \f(CWDW_DLV_NO_ENTRY\fP is NULL the function returns +\f(CWDW_DLV_ERROR\fP. +For non-IRIX objects the offset returned will always be zero. +For non-C++ objects the offset returned will always be zero. +The meaning of the offset and the content of the tables +is not defined in this document. +The applicable CIE augmentation string (see above) +determines whether the value returned has meaning. + +.H 2 "Location Expression Evaluation" + +An "interpreter" which evaluates a location expression +is required in any debugger. There is no interface defined +here at this time. + +.P +One problem with defining an interface is that operations are +machine dependent: they depend on the interpretation of +register numbers and the methods of getting values from the +environment the expression is applied to. + +.P +It would be desirable to specify an interface. + +.H 3 "Location List Internal-level Interface" + +.H 4 "dwarf_get_loclist_entry()" +.DS +\f(CWint dwarf_get_loclist_entry( + Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Addr *hipc_offset, + Dwarf_Addr *lopc_offset, + Dwarf_Ptr *data, + Dwarf_Unsigned *entry_len, + Dwarf_Unsigned *next_entry, + Dwarf_Error *error)\fP +.DE +The function reads +a location list entry starting at \f(CWoffset\fP and returns +through pointers (when successful) +the high pc \f(CWhipc_offset\fP, low pc +\f(CWlopc_offset\fP, a pointer to the location description data +\f(CWdata\fP, the length of the location description data +\f(CWentry_len\fP, and the offset of the next location description +entry \f(CWnext_entry\fP. +.P +This function will usually work correctly (meaning with most +objects) but will not work correctly (and can crash +an application calling it) if either +some location list applies to a compilation unit with +an address_size different from the overall address_size +of the object file being read or if the .debug_loc section +being read has random padding bytes between loclists. +Neither of these characteristics necessarily represents +a bug in the compiler/linker toolset that produced the +object file being read. The DWARF standard +allows both characteristics. +.P +\f(CWdwarf_dwarf_get_loclist_entry()\fP returns +\f(CWDW_DLV_OK\fP if successful. +\f(CWDW_DLV_NO_ENTRY\fP is returned when the offset passed +in is beyond the end of the .debug_loc section (expected if +you start at offset zero and proceed through all the entries). +\f(CWDW_DLV_ERROR\fP is returned on error. +.P +The \f(CWhipc_offset\fP, +low pc \f(CWlopc_offset\fP are offsets from the beginning of the +current procedure, not genuine pc values. +.in +2 +.DS +\f(CW +/* Looping through the dwarf_loc section finding loclists: + an example. */ +int res; +Dwarf_Unsigned next_entry; +Dwarf_unsigned offset=0; +Dwarf_Addr hipc_off; +Dwarf_Addr lopc_off; +Dwarf_Ptr data; +Dwarf_Unsigned entry_len; +Dwarf_Unsigned next_entry; +Dwarf_Error err; + + for(;;) { + res = dwarf_get_loclist_entry(dbg,newoffset,&hipc_off, + &lowpc_off, &data, &entry_len,&next_entry,&err); + if (res == DW_DLV_OK) { + /* A valid entry. */ + newoffset = next_entry; + continue; + } else if (res ==DW_DLV_NO_ENTRY) { + /* Done! */ + break; + } else { + /* Error! */ + break; + } + + + } +}\fP +.DE +.in -2 + + +.H 2 "Abbreviations access" +These are Internal-level Interface functions. +Debuggers can ignore this. + +.H 3 "dwarf_get_abbrev()" +.DS +\f(CWint dwarf_get_abbrev( + Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Abbrev *returned_abbrev, + Dwarf_Unsigned *length, + Dwarf_Unsigned *attr_count, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_abbrev()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_abbrev\fP to +\f(CWDwarf_Abbrev\fP +descriptor for an abbreviation at offset \f(CW*offset\fP in the abbreviations +section (i.e .debug_abbrev) on success. +The user is responsible for making sure that +a valid abbreviation begins at \f(CWoffset\fP in the abbreviations section. +The location pointed to by \f(CWlength\fP +is set to the length in bytes of the abbreviation in the abbreviations +section. +The location pointed to by \f(CWattr_count\fP is set to the +number of attributes in the abbreviation. +An abbreviation entry with a +length of 1 is the 0 byte of the last abbreviation entry of a compilation +unit. +\f(CWdwarf_get_abbrev()\fP returns \f(CWDW_DLV_ERROR\fP on error. +If the call succeeds, the storage pointed to +by \f(CW*returned_abbrev\fP +should be freed, using \f(CWdwarf_dealloc()\fP with the +allocation type \f(CWDW_DLA_ABBREV\fP when no longer needed. + + +.H 3 "dwarf_get_abbrev_tag()" +.DS +\f(CWint dwarf_get_abbrev_tag( + Dwarf_abbrev abbrev, + Dwarf_Half *return_tag, + Dwarf_Error *error);\fP +.DE +If successful, +\f(CWdwarf_get_abbrev_tag()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_tag\fP to +the \fItag\fP of +the given abbreviation. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 3 "dwarf_get_abbrev_code()" +.DS +\f(CWint dwarf_get_abbrev_code( + Dwarf_abbrev abbrev, + Dwarf_Unsigned *return_code, + Dwarf_Error *error);\fP +.DE +If successful, +\f(CWdwarf_get_abbrev_code()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*return_code\fP to +the abbreviation code of +the given abbreviation. +It returns \f(CWDW_DLV_ERROR\fP on error. +It never returns \f(CWDW_DLV_NO_ENTRY\fP. + +.H 3 "dwarf_get_abbrev_children_flag()" +.DS +\f(CWint dwarf_get_abbrev_children_flag( + Dwarf_Abbrev abbrev, + Dwarf_Signed *returned_flag, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_abbrev_children_flag()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CWreturned_flag\fP to +\f(CWDW_children_no\fP (if the given abbreviation indicates that +a die with that abbreviation has no children) or +\f(CWDW_children_yes\fP (if the given abbreviation indicates that +a die with that abbreviation has a child). +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 3 "dwarf_get_abbrev_entry()" +.DS +\f(CWint dwarf_get_abbrev_entry( + Dwarf_Abbrev abbrev, + Dwarf_Signed index, + Dwarf_Half *attr_num, + Dwarf_Signed *form, + Dwarf_Off *offset, + Dwarf_Error *error)\fP + +.DE +If successful, +\f(CWdwarf_get_abbrev_entry()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*attr_num\fP to the attribute code of +the attribute +whose index is specified by \f(CWindex\fP in the given abbreviation. +The index starts at 0. +The location pointed to by \f(CWform\fP is set +to the form of the attribute. +The location pointed to by \f(CWoffset\fP +is set to the byte offset of the attribute in the abbreviations section. +It returns \f(CWDW_DLV_NO_ENTRY\fP if the index specified is outside +the range of attributes in this abbreviation. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 2 "String Section Operations" +The .debug_str section contains only strings. Debuggers need +never use this interface: it is only for debugging problems with +the string section itself. + +.H 3 "dwarf_get_str()" +.DS +\f(CWint dwarf_get_str( + Dwarf_Debug dbg, + Dwarf_Off offset, + char **string, + Dwarf_Signed *returned_str_len, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_str()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_str_len\fP to +the length of +the string, not counting the null terminator, that begins at the offset +specified by \f(CWoffset\fP in the .debug_str section. +The location +pointed to by \f(CWstring\fP is set to a pointer to this string. +The next string in the .debug_str +section begins at the previous \f(CWoffset\fP + 1 + \f(CW*returned_str_len\fP. +A zero-length string is NOT the end of the section. +If there is no .debug_str section, \f(CWDW_DLV_NO_ENTRY\fP is returned. +If there is an error, \f(CWDW_DLV_ERROR\fP is returned. +If we are at the end of the section (that is, \f(CWoffset\fP +is one past the end of the section) \f(CWDW_DLV_NO_ENTRY\fP is returned. +If the \f(CWoffset\fP is some other too-large value then +\f(CWDW_DLV_ERROR\fP is returned. + +.H 2 "Address Range Operations" +These functions provide information about address ranges. Address +ranges map ranges of pc values to the corresponding compilation-unit +die that covers the address range. + +.H 3 "dwarf_get_aranges()" +.DS +\f(CWint dwarf_get_aranges( + Dwarf_Debug dbg, + Dwarf_Arange **aranges, + Dwarf_Signed * returned_arange_count, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_aranges()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_arange_count\fP to +the count of the +number of address ranges in the .debug_aranges section +(for all compilation units). +It sets +\f(CW*aranges\fP to point to a block of \f(CWDwarf_Arange\fP +descriptors, one for each address range. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if there is no .debug_aranges +section. + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Arange *arang; +int res; + +res = dwarf_get_aranges(dbg, &arang,&cnt, &error); +if (res == DW_DLV_OK) { + + for (i = 0; i < cnt; ++i) { + /* use arang[i] */ + dwarf_dealloc(dbg, arang[i], DW_DLA_ARANGE); + } + dwarf_dealloc(dbg, arang, DW_DLA_LIST); +}\fP +.DE +.in -2 + +.H 3 "dwarf_get_arange()" +.DS +\f(CWint dwarf_get_arange( + Dwarf_Arange *aranges, + Dwarf_Unsigned arange_count, + Dwarf_Addr address, + Dwarf_Arange *returned_arange, + Dwarf_Error *error);\fP +.DE +The function \f(CWdwarf_get_arange()\fP takes as input a pointer +to a block of \f(CWDwarf_Arange\fP pointers, and a count of the +number of descriptors in the block. +It then searches for the +descriptor that covers the given \f(CWaddress\fP. +If it finds +one, it returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_arange\fP to +the descriptor. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if there is no .debug_aranges +entry covering that address. + + + + + +.H 3 "dwarf_get_cu_die_offset()" +.DS +\f(CWint dwarf_get_cu_die_offset( + Dwarf_Arange arange, + Dwarf_Off *returned_cu_die_offset, + Dwarf_Error *error);\fP +.DE +The function \f(CWdwarf_get_cu_die_offset()\fP takes a +\f(CWDwarf_Arange\fP descriptor as input, and +if successful returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_cu_die_offset\fP to +the offset +in the .debug_info section of the compilation-unit DIE for the +compilation-unit represented by the given address range. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 3 "dwarf_get_arange_cu_header_offset()" +.DS +\f(CWint dwarf_get_arange_cu_header_offset( + Dwarf_Arange arange, + Dwarf_Off *returned_cu_header_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_arange_cu_header_offset()\fP takes a +\f(CWDwarf_Arange\fP descriptor as input, and +if successful returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_cu_header_offset\fP to +the offset +in the .debug_info section of the compilation-unit header for the +compilation-unit represented by the given address range. +It returns \f(CWDW_DLV_ERROR\fP on error. + +This function added Rev 1.45, June, 2001. + +This function is declared as 'optional' in libdwarf.h +on IRIX systems so the _MIPS_SYMBOL_PRESENT +predicate may be used at run time to determine if the version of +libdwarf linked into an application has this function. + + + +.H 3 "dwarf_get_arange_info()" +.DS +\f(CWint dwarf_get_arange_info( + Dwarf_Arange arange, + Dwarf_Addr *start, + Dwarf_Unsigned *length, + Dwarf_Off *cu_die_offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_arange_info()\fP returns +\f(CWDW_DLV_OK\fP +and +stores the starting value of the address range in the location pointed +to by \f(CWstart\fP, the length of the address range in the location +pointed to by \f(CWlength\fP, and the offset in the .debug_info section +of the compilation-unit DIE for the compilation-unit represented by the +address range. +It returns \f(CWDW_DLV_ERROR\fP on error. + +.H 2 "General Low Level Operations" +This function is low-level and intended for use only +by programs such as dwarf-dumpers. + +.H 3 "dwarf_get_address_size()" +.DS +\f(CWint dwarf_get_address_size(Dwarf_Debug dbg, + Dwarf_Half *addr_size, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_address_size()\fP +returns \f(CWDW_DLV_OK\fP on success and sets +the \f(CW*addr_size\fP +to the size in bytes of an address. +In case of error, it returns \f(CWDW_DLV_ERROR\fP +and does not set \f(CW*addr_size\fP. + +The address size returned is the overall address size, +which can be misleading if different compilation +units have different address sizes. +Many ABIs have only a single address size per +executable, but differing address sizes are +becoming more common. + +Use \f(CWdwarf_get_die_address_size()\fP +instead whenever possible. + +.H 3 "dwarf_get_die_address_size()" +.DS +\f(CWint dwarf_get_die_address_size(Dwarf_Die die, + Dwarf_Half *addr_size, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_die_address_size()\fP +returns \f(CWDW_DLV_OK\fP on success and sets +the \f(CW*addr_size\fP +to the size in bytes of an address. +In case of error, it returns \f(CWDW_DLV_ERROR\fP +and does not set \f(CW*addr_size\fP. + +The address size returned is the address size +of the compilation unit owning the \f(CWdie\fP + +This is the preferred way to get address size when the +\f(CWDwarf_Die\fP is known. + + +.H 2 "Ranges Operations (.debug_ranges)" + + +.H 2 "Ranges Operations (.debug_ranges)" +These functions provide information about the address ranges +indicated by a \f(CWDW_AT_ranges\fP attribute (the ranges are recorded +in the \f(CW.debug_ranges\fP section) of a DIE. +Each call of \f(CWdwarf_get_ranges_a()\fP +or \f(CWdwarf_get_ranges()\fP +returns a an array +of Dwarf_Ranges structs, each of which represents a single ranges +entry. The struct is defined in \f(CWlibdwarf.h\fP. + + +.H 3 "dwarf_get_ranges()" +This is the original call and it will work fine when +all compilation units have the same address_size. +There is no \f(CWdie\fP argument to this original +version of the function. +Other arguments (and deallocation) match the use +of \f(CWdwarf_get_ranges_a()\fP ( described next). + +.H 3 "dwarf_get_ranges_a()" +.DS +\f(CWint dwarf_get_ranges_a( + Dwarf_Debug dbg, + Dwarf_Off offset, + Dwarf_Die die, + Dwarf_Ranges **ranges, + Dwarf_Signed * returned_ranges_count, + Dwarf_Unsigned * returned_byte_count, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_ranges_a()\fP returns +\f(CWDW_DLV_OK\fP and sets \f(CW*returned_ranges_count\fP to +the count of the +number of address ranges in the group of ranges +in the .debug_ranges section at offset \f(CWoffset\fP +(which ends with a pair of zeros of pointer-size). +This function is new as of 27 April 2009. + +The +\f(CWoffset\fP argument should be the value of +a \f(CWDW_AT_ranges\fP attribute of a Debugging Information Entry. + +The +\f(CWdie\fP argument should be the value of +a \f(CWDwarf_Die\fP pointer of a \f(CWDwarf_Die\fP with +the attribute containing +this range set offset. Because each compilation unit +has its own address_size field this argument is necessary to +to correctly read ranges. (Most executables have the +same address_size in every compilation unit, but +some ABIs allow multiple address sized in an executable). +If a NULL pointer is passed in libdwarf assumes +a single address_size is appropriate for all ranges records. + +The call sets +\f(CW*ranges\fP to point to a block of \f(CWDwarf_Ranges\fP +structs, one for each address range. +It returns \f(CWDW_DLV_ERROR\fP on error. +It returns \f(CWDW_DLV_NO_ENTRY\fP if there is no \f(CW.debug_ranges\fP +section or if \f(CWoffset\fP is past the end of the +\f(CW.debug_ranges\fP section. + +If the \f(CW*returned_byte_count\fP pointer is passed as non-NULL +the number of bytes that the returned ranges +were taken from is returned through the pointer +(for example if the returned_ranges_count is 2 and the pointer-size +is 4, then returned_byte_count will be 8). +If the \f(CW*returned_byte_count\fP pointer is passed as NULL +the parameter is ignored. +The \f(CW*returned_byte_count\fP is only of use to certain +dumper applications, most applications will not use it. + + +.in +2 +.DS +\f(CWDwarf_Signed cnt; +Dwarf_Ranges *ranges; +Dwarf_Unsigned bytes; +int res; +res = dwarf_get_ranges_a(dbg,off,dieptr, &ranges,&cnt,&bytes,&error); +if (res == DW_DLV_OK) { + Dwarf_Signed i; + for( i = 0; i < cnt; ++i ) { + Dwarf_Ranges *cur = ranges+i; + /* Use cur. */ + } + dwarf_ranges_dealloc(dbg,ranges,cnt); +}\fP +.DE +.in -2 + +.H 3 "dwarf_ranges_dealloc()" +.DS +\f(CWint dwarf_ranges_dealloc( + Dwarf_Debug dbg, + Dwarf_Ranges *ranges, + Dwarf_Signed range_count, + );\fP +.DE +The function \f(CWdwarf_ranges_dealloc()\fP takes as input a pointer +to a block of \f(CWDwarf_Ranges\fP array and the +number of structures in the block. +It frees all the data in the array of structures. + +.H 2 "TAG ATTR etc names as strings" +These functions turn a value into a string. +So applications wanting the string "DW_TAG_compile_unit" +given the value 0x11 (the value defined for this TAG) can do so easily. + +The general form is +.in +2 +.DS +\f(CWint dwarf_get_<something>_name( + unsigned value, + char **s_out, + );\fP +.DE +.in -2 + +If the \f(CWvalue\fP passed in is known, the function +returns \f(CWDW_DLV_OK\fP and places a pointer to the appropriate string +into \f(CW*s_out\fP. The string is in static storage +and applications must never free the string. +If the \f(CWvalue\fP is not known, \f(CWDW_DLV_NO_ENTRY\fP is returned +and \f(CW*s_out\fP is not set. \f(CWDW_DLV_ERROR\fP is never returned. + +\f(CWLibdwarf\fP generates these functions at libdwarf build time +by reading dwarf.h. + +All these follow this pattern rigidly, so the details of each +are not repeated for each function. + +The choice of 'unsigned' for the value type argument (the code value) +argument is somewhat arbitrary, 'int' could have been used. + +The library simply assumes the value passed in is applicable. +So, for example, +passing a TAG value code to \f(CWdwarf_get_ACCESS_name()\fP +is a coding error which libdwarf will process as if it was +an accessibility code value. +Examples of bad and good usage are: + +.in +2 +.DS +\f(CW + const char * out; + int res; + /* The following is wrong, do not do it! */ + res = dwarf_get_ACCESS_name(DW_TAG_entry_point,&out); + /* Nothing one does here with 'res' or 'out' + is meaningful. */ + + /* The following is meaningful.*/ + res = dwarf_get_TAG_name(DW_TAG_entry_point,&out); + if( res == DW_DLV_OK) { + /* Here 'out' is a pointer one can use which + points to the string "DW_TAG_entry_point". */ + } else { + /* Here 'out' has not been touched, it is + uninitialized. Do not use it. */ + } +\fP +.DE +.in -2 + + + + +.H 2 "dwarf_get_ACCESS_name()" +Returns an accessibility code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_AT_name()" +Returns an attribute code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_ATE_name()" +Returns a base type encoding name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_ADDR_name()" +Returns an address type encoding name through the \f(CWs_out\fP pointer. +As of this writing only \f(CWDW_ADDR_none\fP is defined in \f(CWdwarf.h\fP. +.H 2 "dwarf_get_ATCF_name()" +Returns a SUN code flag encoding name through the \f(CWs_out\fP pointer. +This code flag is entirely a DWARF extension. +.H 2 "dwarf_get_CHILDREN_name()" +Returns a child determination name (which +is seen in the abbreviations section data) through the \f(CWs_out\fP pointer. +The only value this recognizes for a 'yes' value is 1. +As a flag value this is not quite correct (any non-zero value means +yes) but dealing with this is left up to client code (normally +compilers really do emit a value of 1 for a flag). +.H 2 "dwarf_get_children_name()" +Returns a child determination name through the \f(CWs_out\fP pointer, +though this version is really a libdwarf artifact. +The standard function is \f(CWdwarf_get_CHILDREN_name()\fP +which appears just above. +As a flag value this is not quite correct (any non-zero value means +yes) but dealing with this is left up to client code (normally +compilers really do emit a value of 1 for a flag). +.H 2 "dwarf_get_CC_name()" +Returns a calling convention case code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_CFA_name()" +Returns a call frame information instruction +name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_DS_name()" +Returns a decimal sign code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_DSC_name()" +Returns a discriminant descriptor code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_EH_name()" +Returns a GNU exception header +code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_END_name()" +Returns an endian code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_FORM_name()" +Returns an form code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_FRAME_name()" +Returns a frame code name through the \f(CWs_out\fP pointer. +These are dependent on the particular ABI, so unless the +\f(CWdwarf.h\fP used to generate libdwarf matches your ABI +these names are unlikely to be very useful and certainly +won't be entirely appropriate. +.H 2 "dwarf_get_ID_name()" +Returns an identifier case code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_INL_name()" +Returns an inline code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_LANG_name()" +Returns a language code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_LNE_name()" +Returns a line table extended +opcode code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_LNS_name()" +Returns a line table standard +opcode code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_MACINFO_name()" +Returns a macro information macinfo +code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_OP_name()" +Returns a DWARF expression operation +code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_ORD_name()" +Returns an array ordering code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_TAG_name()" +Returns a TAG name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_VIRTUALITY_name()" +Returns a virtuality code name through the \f(CWs_out\fP pointer. +.H 2 "dwarf_get_VIS_name()" +Returns a visibility code name through the \f(CWs_out\fP pointer. + + +.H 2 "Section Operations" +In checking DWARF in linkonce sections for correctness +it has been found useful to have certain section-oriented +operations when processing object files. +Normally these operations are not needed or useful +in a fully-linked executable or shared library. + +While the code is written with Elf sections in mind, +it is quite possible to process non-Elf objects +with code that implements certain function pointers +(see \f(CWstruct Dwarf_Obj_Access_interface_s\fP). + +So far no one with such non-elf code has come forward +to open-source it. + +.H 3 "dwarf_get_section_count()" +.DS +\f(CWint dwarf_get_section_count( + Dwarf_Debug dbg) \fP +.DE + +Returns a count of the number of object sections found. + + + +.H 3 "dwarf_get_section_info_by_name()" +.DS +\f(CWint dwarf_get_section_info_by_name( + const char *section_name, + Dwarf_Addr *section_addr, + Dwarf_Unsigned *section_size, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_section_info_by_name()\fP +returns \f(CWDW_DLV_OK\fP if the section given by \f(CWsection_name\fP +was seen by libdwarf. +On success it sets \f(CW*section_addr\fP to the virtual address +assigned to the section by the linker or compiler and \f(CW*section_size\fP +to the size of the object section. + +It returns DW_DLV_ERROR on error. +.H 3 "dwarf_get_section_info_by_index()" +.DS +\f(CWint dwarf_get_section_info_by_index( + int section_index, + const char **section_name, + Dwarf_Addr *section_addr, + Dwarf_Unsigned *section_size, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_get_section_info_by_index()\fP +returns \f(CWDW_DLV_OK\fP if the section given by \f(CWsection_index\fP +was seen by libdwarf. +\f(CW*section_addr\fP to the virtual address +assigned to the section by the linker or compiler +and \f(CW*section_size\fP +to the size of the object section. + +No free or deallocate of information returned should be done by +callers. + + +.H 2 "Utility Operations" +These functions aid in the management of errors encountered when using +functions in the \fIlibdwarf\fP library and releasing memory allocated +as a result of a \fIlibdwarf\fP operation. + +.H 3 "dwarf_errno()" +.DS +\f(CWDwarf_Unsigned dwarf_errno( + Dwarf_Error error)\fP +.DE +The function \f(CWdwarf_errno()\fP returns the error number corresponding +to the error specified by \f(CWerror\fP. + +.H 3 "dwarf_errmsg()" +.DS +\f(CWconst char* dwarf_errmsg( + Dwarf_Error error)\fP +.DE +The function \f(CWdwarf_errmsg()\fP returns a pointer to a +null-terminated error message string corresponding to the error specified by +\f(CWerror\fP. +The string returned by \f(CWdwarf_errmsg()\fP +should not be deallocated using \f(CWdwarf_dealloc()\fP. + +.H 3 "dwarf_get_harmless_error_list()" +.DS +\f(CWint dwarf_get_harmless_error_list(Dwarf_Debug dbg, + unsigned count, + const char ** errmsg_ptrs_array, + unsigned * newerr_count);\fP +.DE +The harmless errors are not denoted by error returns from +the other libdwarf functions. Instead, this function +returns strings of any harmless errors that have been +seen in the current object. Clients never need call this, but +if a client wishes to report any such errors it may call. + +Only a fixed number of harmless errors are recorded. It +is a circular list, so if more than the current maximum +is encountered older harmless error messages are lost. + +The caller passes in a pointer to an array of pointer-to-char +as the argument \f(CWerrmsg_ptrs_array\fP. The caller +must provide this array, libdwarf does not provide it. +The caller need not initialize the array elements. + +The caller passes in the number of elements of the array of +pointer-to-char thru \f(CWcount\fP. Since the + +If there are no unreported harmless errors the function +returns \f(CWDW_DLV_NO_ENTRY\fP and the function arguments +are ignored. +Otherwise the function returns \f(CWDW_DLV_OK\fP +and uses the arguments. + +\f(CWlibdwarf\fP assigns error strings to the errmsg_ptrs_array. +The MININUM(count-1, number of messages recorded) pointers are assigned +to the array. The array is terminated with a NULL pointer. +(That is, one array entry is reserved for a NULL pointer). +So if \f(CWcount\fP is 5 up to 4 strings may be returned through +the array, and one array entry is set to NULL. + +Because the list is circular and messages may have been dropped +the function also returns the actual error count of harmless +errors encountered through \f(CWnewerr_count\fP +(unless the argument is NULL, in which case it is ignored). + +Each call to this function resets the circular error buffer and +the error count. +So think of this call as reporting harmless errors since the +last call to it. + +The pointers returned through \f(CWerrmsg_ptrs_array\fP +are only valid till the next call to libdwarf. +Do not save the pointers, they become invalid. Copy the strings +if you wish to save them. + +Calling this function neither allocates any space in memory nor +frees any space in memory. + + +.H 3 "dwarf_insert_harmless_error()" +.DS +void dwarf_insert_harmless_error(Dwarf_Debug dbg, + char * newerror); +.DE +This function is used to test +\f(CWdwarf_get_harmless_error_list\fP. It simply adds +a harmless error string. +There is little reason client code should use this function. +It exists so that the harmless error functions can be +easily tested for correctness and leaks. + +.H 3 "dwarf_set_harmless_error_list_size()" +.DS +\f(CWunsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg, + unsigned maxcount)\fP +.DE +\f(CWdwarf_set_harmless_error_list_size\fP returns the +number of harmless error strings the library is currently +set to hold. +If \f(CWmaxcount\fP is non-zero the library changes the +maximum it will record to be \f(CWmaxcount\fP. + +It is extremely unwise to make \f(CWmaxcount\fP large because +\f(CWlibdwarf\fP allocates space for \f(CWmaxcount\fP +strings immediately. + +.P +The set of errors +enumerated in Figure \n(aX below were defined in Dwarf 1. +These errors are not used by the \f(CWlibdwarf\fP implementation +for Dwarf 2 or later. +.DS +.TS +center box, tab(:); +lfB lfB +l l. +SYMBOLIC NAME:DESCRIPTION +_ +DW_DLE_NE:No error (0) +DW_DLE_VMM:Version of DWARF information newer than libdwarf +DW_DLE_MAP:Memory map failure +DW_DLE_LEE:Propagation of libelf error +DW_DLE_NDS:No debug section +DW_DLE_NLS:No line section +DW_DLE_ID:Requested information not associated with descriptor +DW_DLE_IOF:I/O failure +DW_DLE_MAF:Memory allocation failure +DW_DLE_IA:Invalid argument +DW_DLE_MDE:Mangled debugging entry +DW_DLE_MLE:Mangled line number entry +DW_DLE_FNO:File descriptor does not refer to an open file +DW_DLE_FNR:File is not a regular file +DW_DLE_FWA:File is opened with wrong access +DW_DLE_NOB:File is not an object file +DW_DLE_MOF:Mangled object file header +DW_DLE_EOLL:End of location list entries +DW_DLE_NOLL:No location list section +DW_DLE_BADOFF:Invalid offset +DW_DLE_EOS:End of section +DW_DLE_ATRUNC:Abbreviations section appears truncated +DW_DLE_BADBITC:Address size passed to dwarf bad +.TE +.FG "List of Dwarf Error Codes" +.DE + +The set of errors returned by \f(CWLibdwarf\fP functions +is listed below. +Some of the errors are SGI specific. + +.DS +.TS +center box, tab(:); +lfB lfB +l l. +SYMBOLIC NAME:DESCRIPTION +_ +DW_DLE_DBG_ALLOC:Could not allocate Dwarf_Debug struct +DW_DLE_FSTAT_ERROR:Error in fstat()-ing object +DW_DLE_FSTAT_MODE_ERROR:Error in mode of object file +DW_DLE_INIT_ACCESS_WRONG:Incorrect access to dwarf_init() +DW_DLE_ELF_BEGIN_ERROR:Error in elf_begin() on object +DW_DLE_ELF_GETEHDR_ERROR:Error in elf_getehdr() on object +DW_DLE_ELF_GETSHDR_ERROR:Error in elf_getshdr() on object +DW_DLE_ELF_STRPTR_ERROR:Error in elf_strptr() on object +DW_DLE_DEBUG_INFO_DUPLICATE:Multiple .debug_info sections +DW_DLE_DEBUG_INFO_NULL:No data in .debug_info section +DW_DLE_DEBUG_ABBREV_DUPLICATE:Multiple .debug_abbrev sections +DW_DLE_DEBUG_ABBREV_NULL:No data in .debug_abbrev section +DW_DLE_DEBUG_ARANGES_DUPLICATE:Multiple .debug_arange sections +DW_DLE_DEBUG_ARANGES_NULL:No data in .debug_arange section +DW_DLE_DEBUG_LINE_DUPLICATE:Multiple .debug_line sections +DW_DLE_DEBUG_LINE_NULL:No data in .debug_line section +DW_DLE_DEBUG_LOC_DUPLICATE:Multiple .debug_loc sections +DW_DLE_DEBUG_LOC_NULL:No data in .debug_loc section +DW_DLE_DEBUG_MACINFO_DUPLICATE:Multiple .debug_macinfo sections +DW_DLE_DEBUG_MACINFO_NULL:No data in .debug_macinfo section +DW_DLE_DEBUG_PUBNAMES_DUPLICATE:Multiple .debug_pubnames sections +DW_DLE_DEBUG_PUBNAMES_NULL:No data in .debug_pubnames section +DW_DLE_DEBUG_STR_DUPLICATE:Multiple .debug_str sections +DW_DLE_DEBUG_STR_NULL:No data in .debug_str section +DW_DLE_CU_LENGTH_ERROR:Length of compilation-unit bad +DW_DLE_VERSION_STAMP_ERROR:Incorrect Version Stamp +DW_DLE_ABBREV_OFFSET_ERROR:Offset in .debug_abbrev bad +DW_DLE_ADDRESS_SIZE_ERROR:Size of addresses in target bad +DW_DLE_DEBUG_INFO_PTR_NULL:Pointer into .debug_info in DIE null +DW_DLE_DIE_NULL:Null Dwarf_Die +DW_DLE_STRING_OFFSET_BAD:Offset in .debug_str bad +DW_DLE_DEBUG_LINE_LENGTH_BAD:Length of .debug_line segment bad +DW_DLE_LINE_PROLOG_LENGTH_BAD:Length of .debug_line prolog bad +DW_DLE_LINE_NUM_OPERANDS_BAD:Number of operands to line instr bad +DW_DLE_LINE_SET_ADDR_ERROR:Error in DW_LNE_set_address instruction +DW_DLE_LINE_EXT_OPCODE_BAD:Error in DW_EXTENDED_OPCODE instruction +DW_DLE_DWARF_LINE_NULL:Null Dwarf_line argument +DW_DLE_INCL_DIR_NUM_BAD:Error in included directory for given line +DW_DLE_LINE_FILE_NUM_BAD:File number in .debug_line bad +DW_DLE_ALLOC_FAIL:Failed to allocate required structs +DW_DLE_DBG_NULL:Null Dwarf_Debug argument +DW_DLE_DEBUG_FRAME_LENGTH_BAD:Error in length of frame +DW_DLE_FRAME_VERSION_BAD:Bad version stamp for frame +DW_DLE_CIE_RET_ADDR_REG_ERROR:Bad register specified for return address +DW_DLE_FDE_NULL:Null Dwarf_Fde argument +DW_DLE_FDE_DBG_NULL:No Dwarf_Debug associated with FDE +DW_DLE_CIE_NULL:Null Dwarf_Cie argument +DW_DLE_CIE_DBG_NULL:No Dwarf_Debug associated with CIE +DW_DLE_FRAME_TABLE_COL_BAD:Bad column in frame table specified +.TE +.FG "List of Dwarf 2 Error Codes (continued)" +.DE + +.DS +.TS +center box, tab(:); +lfB lfB +l l. +SYMBOLIC NAME:DESCRIPTION +_ +DW_DLE_PC_NOT_IN_FDE_RANGE:PC requested not in address range of FDE +DW_DLE_CIE_INSTR_EXEC_ERROR:Error in executing instructions in CIE +DW_DLE_FRAME_INSTR_EXEC_ERROR:Error in executing instructions in FDE +DW_DLE_FDE_PTR_NULL:Null Pointer to Dwarf_Fde specified +DW_DLE_RET_OP_LIST_NULL:No location to store pointer to Dwarf_Frame_Op +DW_DLE_LINE_CONTEXT_NULL:Dwarf_Line has no context +DW_DLE_DBG_NO_CU_CONTEXT:dbg has no CU context for dwarf_siblingof() +DW_DLE_DIE_NO_CU_CONTEXT:Dwarf_Die has no CU context +DW_DLE_FIRST_DIE_NOT_CU:First DIE in CU not DW_TAG_compilation_unit +DW_DLE_NEXT_DIE_PTR_NULL:Error in moving to next DIE in .debug_info +DW_DLE_DEBUG_FRAME_DUPLICATE:Multiple .debug_frame sections +DW_DLE_DEBUG_FRAME_NULL:No data in .debug_frame section +DW_DLE_ABBREV_DECODE_ERROR:Error in decoding abbreviation +DW_DLE_DWARF_ABBREV_NULL:Null Dwarf_Abbrev specified +DW_DLE_ATTR_NULL:Null Dwarf_Attribute specified +DW_DLE_DIE_BAD:DIE bad +DW_DLE_DIE_ABBREV_BAD:No abbreviation found for code in DIE +DW_DLE_ATTR_FORM_BAD:Inappropriate attribute form for attribute +DW_DLE_ATTR_NO_CU_CONTEXT:No CU context for Dwarf_Attribute struct +DW_DLE_ATTR_FORM_SIZE_BAD:Size of block in attribute value bad +DW_DLE_ATTR_DBG_NULL:No Dwarf_Debug for Dwarf_Attribute struct +DW_DLE_BAD_REF_FORM:Inappropriate form for reference attribute +DW_DLE_ATTR_FORM_OFFSET_BAD:Offset reference attribute outside current CU +DW_DLE_LINE_OFFSET_BAD:Offset of lines for current CU outside .debug_line +DW_DLE_DEBUG_STR_OFFSET_BAD:Offset into .debug_str past its end +DW_DLE_STRING_PTR_NULL:Pointer to pointer into .debug_str NULL +DW_DLE_PUBNAMES_VERSION_ERROR:Version stamp of pubnames incorrect +DW_DLE_PUBNAMES_LENGTH_BAD:Read pubnames past end of .debug_pubnames +DW_DLE_GLOBAL_NULL:Null Dwarf_Global specified +DW_DLE_GLOBAL_CONTEXT_NULL:No context for Dwarf_Global given +DW_DLE_DIR_INDEX_BAD:Error in directory index read +DW_DLE_LOC_EXPR_BAD:Bad operator read for location expression +DW_DLE_DIE_LOC_EXPR_BAD:Expected block value for attribute not found +DW_DLE_OFFSET_BAD:Offset for next compilation-unit in .debug_info bad +DW_DLE_MAKE_CU_CONTEXT_FAIL:Could not make CU context +DW_DLE_ARANGE_OFFSET_BAD:Offset into .debug_info in .debug_aranges bad +DW_DLE_SEGMENT_SIZE_BAD:Segment size will be 0 for MIPS processors and should always be < 8. +DW_DLE_ARANGE_LENGTH_BAD:Length of arange section in .debug_arange bad +DW_DLE_ARANGE_DECODE_ERROR:Aranges do not end at end of .debug_aranges +DW_DLE_ARANGES_NULL:NULL pointer to Dwarf_Arange specified +DW_DLE_ARANGE_NULL:NULL Dwarf_Arange specified +DW_DLE_NO_FILE_NAME:No file name for Dwarf_Line struct +DW_DLE_NO_COMP_DIR:No Compilation directory for compilation-unit +DW_DLE_CU_ADDRESS_SIZE_BAD:CU header address size not match Elf class +DW_DLE_ELF_GETIDENT_ERROR:Error in elf_getident() on object +DW_DLE_NO_AT_MIPS_FDE:DIE does not have DW_AT_MIPS_fde attribute +DW_DLE_NO_CIE_FOR_FDE:No CIE specified for FDE +DW_DLE_DIE_ABBREV_LIST_NULL:No abbreviation for the code in DIE found +DW_DLE_DEBUG_FUNCNAMES_DUPLICATE:Multiple .debug_funcnames sections +DW_DLE_DEBUG_FUNCNAMES_NULL:No data in .debug_funcnames section +.TE +.FG "List of Dwarf 2 Error Codes (continued)" +.DE + +.DS +.TS +center box, tab(:); +lfB lfB +l l. +SYMBOLIC NAME:DESCRIPTION +_ +DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR:Version stamp in .debug_funcnames bad +DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD:Length error in reading .debug_funcnames +DW_DLE_FUNC_NULL:NULL Dwarf_Func specified +DW_DLE_FUNC_CONTEXT_NULL:No context for Dwarf_Func struct +DW_DLE_DEBUG_TYPENAMES_DUPLICATE:Multiple .debug_typenames sections +DW_DLE_DEBUG_TYPENAMES_NULL:No data in .debug_typenames section +DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR:Version stamp in .debug_typenames bad +DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD:Length error in reading .debug_typenames +DW_DLE_TYPE_NULL:NULL Dwarf_Type specified +DW_DLE_TYPE_CONTEXT_NULL:No context for Dwarf_Type given +DW_DLE_DEBUG_VARNAMES_DUPLICATE:Multiple .debug_varnames sections +DW_DLE_DEBUG_VARNAMES_NULL:No data in .debug_varnames section +DW_DLE_DEBUG_VARNAMES_VERSION_ERROR:Version stamp in .debug_varnames bad +DW_DLE_DEBUG_VARNAMES_LENGTH_BAD:Length error in reading .debug_varnames +DW_DLE_VAR_NULL:NULL Dwarf_Var specified +DW_DLE_VAR_CONTEXT_NULL:No context for Dwarf_Var given +DW_DLE_DEBUG_WEAKNAMES_DUPLICATE:Multiple .debug_weaknames section +DW_DLE_DEBUG_WEAKNAMES_NULL:No data in .debug_varnames section +DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR:Version stamp in .debug_varnames bad +DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD:Length error in reading .debug_weaknames +DW_DLE_WEAK_NULL:NULL Dwarf_Weak specified +DW_DLE_WEAK_CONTEXT_NULL:No context for Dwarf_Weak given +.TE +.FG "List of Dwarf 2 Error Codes" +.DE + +This list of errors is not complete; +additional errors have been added. +Some of the above errors may be unused. +Errors may not have the same meaning in different releases. +Since most error codes are returned from only one place +(or a very small number of places) in the source +it is normally very useful to simply search the +\f(CWlibdwarf\fP source to find +out where a particular error code is generated. + +.H 3 "dwarf_seterrhand()" +.DS +\f(CWDwarf_Handler dwarf_seterrhand( + Dwarf_Debug dbg, + Dwarf_Handler errhand)\fP +.DE +The function \f(CWdwarf_seterrhand()\fP replaces the error handler +(see \f(CWdwarf_init()\fP) with \f(CWerrhand\fP. The old error handler +is returned. This function is currently unimplemented. + +.H 3 "dwarf_seterrarg()" +.DS +\f(CWDwarf_Ptr dwarf_seterrarg( + Dwarf_Debug dbg, + Dwarf_Ptr errarg)\fP +.DE +The function \f(CWdwarf_seterrarg()\fP replaces the pointer to the +error handler communication area (see \f(CWdwarf_init()\fP) with +\f(CWerrarg\fP. A pointer to the old area is returned. This +function is currently unimplemented. + +.H 3 "dwarf_dealloc()" +.DS +\f(CWvoid dwarf_dealloc( + Dwarf_Debug dbg, + void* space, + Dwarf_Unsigned type)\fP +.DE +The function \f(CWdwarf_dealloc\fP frees the dynamic storage pointed +to by \f(CWspace\fP, and allocated to the given \f(CWDwarf_Debug\fP. +The argument \f(CWtype\fP is an integer code that specifies the allocation +type of the region pointed to by the \f(CWspace\fP. Refer to section +4 for details on \fIlibdwarf\fP memory management. + +.SK +.S +.TC 1 1 4 +.CS diff --git a/libdwarf/libdwarf2.1.pdf b/libdwarf/libdwarf2.1.pdf Binary files differnew file mode 100644 index 0000000..a88752b --- /dev/null +++ b/libdwarf/libdwarf2.1.pdf diff --git a/libdwarf/libdwarf2p.1.mm b/libdwarf/libdwarf2p.1.mm new file mode 100644 index 0000000..037b813 --- /dev/null +++ b/libdwarf/libdwarf2p.1.mm @@ -0,0 +1,2748 @@ +\." $Revision: 1.12 $ +\." $Date: 2002/01/14 23:40:11 $ +\." +\." +\." the following line may be removed if the ff ligature works on your machine +.lg 0 +\." set up heading formats +.ds HF 3 3 3 3 3 2 2 +.ds HP +2 +2 +1 +0 +0 +.nr Hs 5 +.nr Hb 5 +\." ============================================== +\." Put current date in the following at each rev +.ds vE rev 1.32, 13 December 2011 +\." ============================================== +\." ============================================== +.ds | | +.ds ~ ~ +.ds ' ' +.if t .ds Cw \&\f(CW +.if n .ds Cw \fB +.de Cf \" Place every other arg in Cw font, beginning with first +.if \\n(.$=1 \&\*(Cw\\$1\fP +.if \\n(.$=2 \&\*(Cw\\$1\fP\\$2 +.if \\n(.$=3 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP +.if \\n(.$=4 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4 +.if \\n(.$=5 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP +.if \\n(.$=6 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6 +.if \\n(.$=7 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP +.if \\n(.$=8 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8 +.if \\n(.$=9 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8\ +*(Cw +.. +.nr Cl 3 +.SA 1 +.TL +A Producer Library Interface to DWARF +.AF "" +.AU "David Anderson" +.PF "'\*(vE '- \\\\nP -''" +.AS 1 +This document describes an interface to a library of functions +to create DWARF debugging information entries and DWARF line number +information. It does not make recommendations as to how the functions +described in this document should be implemented nor does it +suggest possible optimizations. +.P +The document is oriented to creating DWARF version 2. +Support for creating DWARF3 is intended but such support +is not yet fully present. +DWARF4 support is also intended. +.P +\*(vE +.AE +.MT 4 +.H 1 "INTRODUCTION" +This document describes an interface to \f(CWlibdwarf\fP, a +library of functions to provide creation of DWARF debugging information +records, DWARF line number information, DWARF address range and +pubnames information, weak names information, and DWARF frame description +information. + + +.H 2 "Copyright" +Copyright 1993-2006 Silicon Graphics, Inc. + +Copyright 2007-2010 David Anderson. + +Permission is hereby granted to +copy or republish or use any or all of this document without +restriction except that when publishing more than a small amount +of the document +please acknowledge Silicon Graphics, Inc and David Anderson. + +This document 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. +.H 2 "Purpose and Scope" +The purpose of this document is to propose a library of functions to +create DWARF debugging information. Reading (consuming) of such records +is discussed in a separate document. + +The functions in this document have mostly been implemented at +Silicon Graphics +and are being used by the code generator to provide debugging information. +Some functions (and support for some extensions) were provided +by Sun Microsystems. + +Example code showing one use of the functionality +may be found in the dwarfgen \f(CWdwarfgen\fP application +(provided in the source distribution along with libdwarf). + +.P +The focus of this document is the functional interface, +and as such, implementation and optimization issues are +intentionally ignored. + +.P +Error handling, error codes, and certain \f(CWLibdwarf\fP codes are discussed +in the "\fIA Consumer Library Interface to DWARF\fP", which should +be read (or at least skimmed) before reading this document. +.P +However the general style of functions here +in the producer library is rather C-traditional +with various types as return values (quite different +from the consumer library interfaces). The style +generally follows the style of the original DWARF1 reader +proposed as an interface to DWARF. +When the style of the reader interfaces was changed (1994) in the +dwarf reader ( See the "Document History" +section of "A Consumer Library Interface to DWARF") +the interfaces here were not changed as it seemed like +too much of a change for the two applications then using +the interface! So this interface remains in the traditional C style +of returning various data types with various (somewhat inconsistent) +means of indicating failure. +.P +The error handling code in the library may either +return a value or abort. +The library user can provide a function that the producer code +will call on errors (which would allow callers avoid testing +for error returns if the user function exits or aborts). +See the \f(CWdwarf_producer_init_c()\fP +description below for more details +(possibly the older forms \f(CWdwarf_producer_init_b()\fP +and \f(CWdwarf_producer_init()\fP may be of interest). + + +.H 2 "Document History" +This document originally prominently referenced +"UNIX International Programming Languages Special Interest Group " +(PLSIG). +Both UNIX International and the +affiliated Programming Languages Special Interest Group +are defunct +(UNIX is a registered trademark of UNIX System Laboratories, Inc. +in the United States and other countries). +Nothing except the general interface style is actually +related to anything shown to the PLSIG +(this document was open sourced with libdwarf in the mid 1990's). +.P +See "http://www.dwarfstd.org" for information on current +DWARF standards and committee activities. + +.H 2 "Definitions" +DWARF debugging information entries (DIEs) are the segments of information +placed in the \f(CW.debug_info\fP and related +sections by compilers, assemblers, and linkage +editors that, in conjunction with line number entries, are necessary for +symbolic source-level debugging. +Refer to the document +"\fIDWARF Debugging Information Format\fP" from UI PLSIG for a more complete +description of these entries. + +.P +This document adopts all the terms and definitions in +"\fIDWARF Debugging Information Format\fP" version 2. +and the "\fIA Consumer Library Interface to DWARF\fP". + +.P +In addition, this document refers to Elf, the ATT/USL System V +Release 4 object format. +This is because the library was first developed for that object +format. +Hopefully the functions defined here can easily be +applied to other object formats. + +.H 2 "Overview" +The remaining sections of this document describe a proposed producer +(compiler or assembler) interface to \fILibdwarf\fP, first by describing +the purpose of additional types defined by the interface, followed by +descriptions of the available operations. +This document assumes you +are thoroughly familiar with the information contained in the +\fIDWARF +Debugging Information Format\fP document, and +"\fIA Consumer Library Interface to DWARF\fP". + +.P +The interface necessarily knows a little bit about the object format +(which is assumed to be Elf). We make an attempt to make this knowledge +as limited as possible. For example, \fILibdwarf\fP does not do the +writing of object data to the disk. The producer program does that. + +.H 2 "Revision History" +.VL 15 +.LI "March 1993" +Work on dwarf2 sgi producer draft begins +.LI "March 1999" +Adding a function to allow any number of trips +through the dwarf_get_section_bytes() call. +.LI "April 10 1999" +Added support for assembler text output of dwarf +(as when the output must pass through an assembler). +Revamped internals for better performance and +simpler provision for differences in ABI. +.LI "Sep 1, 1999" +Added support for little- and cross- endian +debug info creation. +.LI "May 7 2007" +This library interface now cleans up, deallocating +all memory it uses (the application simply calls +dwarf_producer_finish(dbg)). +.LI "September 20 2010" +Now documents the marker feature of DIE creation. +.LE + +.H 1 "Type Definitions" + +.H 2 "General Description" +The \fIlibdwarf.h\fP +header file contains typedefs and preprocessor +definitions of types and symbolic names +used to reference objects of \fI Libdwarf \fP . +The types defined by typedefs contained in \fI libdwarf.h\fP +all use the convention of adding \fI Dwarf_ \fP +as a prefix to +indicate that they refer to objects used by Libdwarf. +The prefix \fI Dwarf_P_\fP is used for objects +referenced by the \fI Libdwarf\fP +Producer when there are similar but distinct +objects used by the Consumer. + +.H 2 "Namespace issues" +Application programs should avoid creating names +beginning with +\f(CWDwarf_\fP +\f(CWdwarf_\fP +or +\f(CWDW_\fP +as these are reserved to dwarf and libdwarf. + +.H 1 "libdwarf and Elf and relocations" +Much of the description below presumes that Elf is the object +format in use. +The library is probably usable with other object formats +that allow arbitrary sections to be created. + +.H 2 "binary or assembler output" +With +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +(see below) +it is assumed that the calling app will simply +write the streams and relocations directly into +an Elf file, without going through an assembler. + +With +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +the calling app must either +A) generate binary relocation streams and write +the generated debug information streams and +the relocation streams direct to an elf file +or +B) generate assembler output text for an assembler +to read and produce an object file. + +With case B) the libdwarf-calling application must +use the relocation information to change +points of each binary stream into references to +symbolic names. +It is necessary for the assembler to be +willing to accept and generate relocations +for references from arbitrary byte boundaries. +For example: +.sp +.nf +.in +4 + .data 0a0bcc #producing 3 bytes of data. + .word mylabel #producing a reference + .word endlabel - startlable #producing absolute length +.in -4 +.fi +.sp + + + + +.H 2 "libdwarf relationship to Elf" +When the documentation below refers to 'an elf section number' +it is really only dependent on getting (via the callback +function passed by the caller of +\f(CWdwarf_producer_init_c()\fP and +the older forms, \f(CWdwarf_producer_init_b()\fP or +\f(CWdwarf_producer_init()\fP) +a sequence of integers back (with 1 as the lowest). + +When the documentation below refers to 'an Elf symbol index' +it is really dependent on +Elf symbol numbers +only if +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +are being generated (see below). +With +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +the library is generating Elf relocations +and the section numbers in binary form so +the section numbers and symbol indices must really +be Elf (or elf-like) numbers. + + +With +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +the values passed as symbol indexes can be any +integer set or even pointer set. +All that libdwarf assumes is that where values +are unique they get unique values. +Libdwarf does not generate any kind of symbol table +from the numbers and does not check their +uniqueness or lack thereof. + +.H 2 "libdwarf and relocations" +With +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +libdwarf creates binary streams of debug information +and arrays of relocation information describing +the necessary relocation. +The Elf section numbers and symbol numbers appear +nowhere in the binary streams. Such appear +only in the relocation information and the passed-back +information from calls requesting the relocation information. +As a consequence, the 'symbol indices' can be +any pointer or integer value as the caller must +arrange that the output deal with relocations. + +With +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +all the relocations are directly created by libdwarf +as binary streams (libdwarf only creates the streams +in memory, +it does not write them to disk). + +.H 2 "symbols, addresses, and offsets" +The following applies to calls that +pass in symbol indices, addresses, and offsets, such +as +\f(CWdwarf_add_AT_targ_address() \fP +\f(CWdwarf_add_arange_b()\fP +and +\f(CWdwarf_add_frame_fde_b()\fP. + +With +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +a passed in address is one of: +a) a section offset and the (non-global) symbol index of +a section symbol. +b) A symbol index (global symbol) and a zero offset. + +With \f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +the same approach can be used, or, instead, +a passed in address may be +c) a symbol handle and an offset. +In this case, since it is up to the calling app to +generate binary relocations (if appropriate) +or to turn the binary stream into +a text stream (for input to an assembler, if appropriate) +the application has complete control of the interpretation +of the symbol handles. + + + +.H 1 "Memory Management" + +Several of the functions that comprise the \fILibdwarf\fP +producer interface dynamically allocate values and some +return pointers to those spaces. +The dynamically allocated spaces +can not be reclaimed (and must +not be freed) except by \f(CWdwarf_producer_finish(dbg)\fP. + +All data for a particular \f(CWDwarf_P_Debug\fP descriptor +is separate from the data for any other +\f(CWDwarf_P_Debug\fP descriptor in use in the library-calling +application. + +.H 2 "Read-only Properties" +All pointers returned by or as a result of a \fILibdwarf\fP call should +be assumed to point to read-only memory. +Except as defined by this document, the results are undefined for +\fILibdwarf\fP clients that attempt to write to a region pointed to by a +return value from a \fILibdwarf\fP call. + +.H 2 "Storage Deallocation" +Calling \f(CWdwarf_producer_finish(dbg)\fP frees all the space, and +invalidates all pointers returned from \f(CWLibdwarf\fP functions on +or descended from \f(CWdbg\fP). + +.H 1 "Functional Interface" +This section describes the functions available in the \fILibdwarf\fP +library. Each function description includes its definition, followed +by a paragraph describing the function's operation. + +.P +The functions may be categorized into groups: +\fIinitialization and termination operations\fP, +\fIdebugging information entry creation\fP, +\fIElf section callback function\fP, +\fIattribute creation\fP, +\fIexpression creation\fP, +\fIline number creation\fP, +\fIfast-access (aranges) creation\fP, +\fIfast-access (pubnames) creation\fP, +\fIfast-access (weak names) creation\fP, +\fImacro information creation\fP, +\fIlow level (.debug_frame) creation\fP, +and +\fIlocation list (.debug_loc) creation\fP. + +.P +The following sections describe these functions. + +.H 2 "Initialization and Termination Operations" +These functions setup \f(CWLibdwarf\fP to accumulate debugging information +for an object, usually a compilation-unit, provided by the producer. +The actual addition of information is done by functions in the other +sections of this document. Once all the information has been added, +functions from this section are used to transform the information to +appropriate byte streams, and help to write out the byte streams to +disk. + +Typically then, a producer application +would create a \f(CWDwarf_P_Debug\fP +descriptor to gather debugging information for a particular +compilation-unit using \f(CWdwarf_producer_init_c()\fP. +(Older code may use \f(CWdwarf_producer_init_b()\fP or +\f(CWdwarf_producer_init()\fP). +The producer application would +use this \f(CWDwarf_P_Debug\fP descriptor to accumulate debugging +information for this object using functions from other sections of +this document. +Once all the information had been added, it would +call \f(CWdwarf_transform_to_disk_form()\fP to convert the accumulated +information into byte streams in accordance with the \f(CWDWARF\fP +standard. +The application would then repeatedly call +\f(CWdwarf_get_section_bytes()\fP +for each of the \f(CW.debug_*\fP created. +This gives the producer +information about the data bytes to be written to disk. +At this point, +the producer would release all resource used by \f(CWLibdwarf\fP for +this object by calling \f(CWdwarf_producer_finish()\fP. + +It is also possible to create assembler-input character streams +from the byte streams created by this library. +This feature requires slightly different interfaces than +direct binary output. +The details are mentioned in the text. + +.H 3 "dwarf_producer_init()" + +.DS +\f(CWDwarf_P_Debug dwarf_producer_init( + Dwarf_Unsigned flags, + Dwarf_Callback_Func func, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Error *error) \fP +.DE +This is the oldest form and code should migrate to the newest form, +\f(CWdwarf_producer_init_c()\fP. +.P +The function \f(CWdwarf_producer_init() \fP returns a new +\f(CWDwarf_P_Debug\fP descriptor that can be used to add \f(CWDwarf\fP +information to the object. +On error it returns \f(CWDW_DLV_BADADDR\fP. +\f(CWflags\fP determine whether the target object is 64-bit or 32-bit. +\f(CWfunc\fP is a pointer to a function called-back from \f(CWLibdwarf\fP +whenever \f(CWLibdwarf\fP needs to create a new object section (as it will +for each .debug_* section and related relocation section). +.P +\f(CWerrhand\fP +is a pointer to a function that will be used as +a default fall-back function for handling errors detected +by \f(CWLibdwarf\fP. +.P +\f(CWerrarg\fP is the default error argument used +by the function pointed to by \f(CWerrhand\fP. +.P +For historical reasons the error handling is complicated +and the following three paragraphs describe the three +possible scenarios when a producer function detects an error. +In all cases a short error message is printed on +stdout if the error number +is negative (as all such should be, see libdwarf.h). +Then further action is taken as follows. +.P +First, +if the Dwarf_Error argument to any specific producer function +(see the functions documented below) is non-null +the \f(CWerrhand\fP argument here is ignored in that call and +the specific producer function sets the Dwarf_Error and returns +some specific value (for dwarf_producer_init it is DW_DLV_BADADDR +as mentioned just above) indicating there is an error. +.P +Second, +if the Dwarf_Error argument to any specific producer function +(see the functions documented below) is NULL and the +\f(CWerrarg\fP to \f(CWdwarf_producer_init() \fP is non-NULL +then on an error in the producer code the Dwarf_Handler function is called +and if that called function returns the producer code returns +a specific value (for dwarf_producer_init it is DW_DLV_BADADDR +as mentioned just above) indicating there is an error. +.P +Third, +if the Dwarf_Error argument to any specific producer function +(see the functions documented below) is NULL and the +\f(CWerrarg\fP to \f(CWdwarf_producer_init() \fP is NULL +then on an error \f(CWabort()\fP is called. +.P +The \f(CWflags\fP +values are as follows: +.in +4 +\f(CWDW_DLC_WRITE\fP +is required. +The values +\f(CWDW_DLC_READ\fP +\f(CWDW_DLC_RDWR\fP +are not supported by the producer and must not be passed. + +If +\f(CWDW_DLC_SIZE_64\fP +is not ORed into \f(CWflags\fP +then +\f(CWDW_DLC_SIZE_32\fP +is assumed. +Oring in both is an error. + +If +\f(CWDW_DLC_OFFSET_SIZE_64\fP +is not ORed into \f(CWflags\fP +then 64 bit offsets (as defined in the 1999 DWARF3) +may be used (see next paragraph) to generate DWARF (if and only if +DW_DLC_SIZE_64 is also ORed into \f(CWflags\fP). + +If \f(CWHAVE_STRICT_32BIT_OFFSET\fP is set at configure time +only 32bit DWARF offsets are generated +(use configure option --enable-dwarf-format-strict-32bit) +and \f(CWDW_DLC_OFFSET_SIZE_64\fP is ignored. +If \f(CWHAVE_SGI_IRIX_OFFSETS\fP is set at configure time +SGI IRIX offsets (standard 32bit, a special 64bit offset +for 64bit address objects) are generated +(use configure option --enable-dwarf-format-sgi-irix) +and \f(CWDW_DLC_OFFSET_SIZE_64\fP is ignored. +If neither \f(CWHAVE_STRICT_32BIT_OFFSET\fP nor \f(CWHAVE_SGI_IRIX_OFFSETS\fP +is set at configure time then standard +offset sizes are used ( and \f(CWHAVE_DWARF2_99_EXTENSION\fP is +set) and \f(CWDW_DLC_OFFSET_SIZE_64\fP is honored. + +If +\f(CWDW_DLC_ISA_IA64\fP +is not ORed into \f(CWflags\fP +then +\f(CWDW_DLC_ISA_MIPS\fP +is assumed. +Oring in both is an error. + +If +\f(CWDW_DLC_TARGET_BIGENDIAN\fP +is not ORed into \f(CWflags\fP +then +endianness the same as the host is assumed. + +If +\f(CWDW_DLC_TARGET_LITTLEENDIAN\fP +is not ORed into \f(CWflags\fP +then +endianness the same as the host is assumed. + +If both +\f(CWDW_DLC_TARGET_LITTLEENDIAN\fP +and +\f(CWDW_DLC_TARGET_BIGENDIAN\fP +are or-d in it is an error. + + + +Either one of two output forms is specifiable: +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +or +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP . + +The default is +\f(CWDW_DLC_STREAM_RELOCATIONS\fP . +The +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +are relocations in a binary stream (as used +in a MIPS Elf object). + +The +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +are the same relocations but expressed in an +array of structures defined by libdwarf, +which the caller of the relevant function +(see below) must deal with appropriately. +This method of expressing relocations allows +the producer-application to easily produce +assembler text output of debugging information. + + +If +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +is ORed into \f(CWflags\fP +then relocations are returned not as streams +but through an array of structures. + +.in -4 +.P +The function \f(CWfunc\fP +must be provided by the user of this library. +Its prototype is: +.DS +\f(CWtypedef int (*Dwarf_Callback_Func)( + char* name, + int size, + Dwarf_Unsigned type, + Dwarf_Unsigned flags, + Dwarf_Unsigned link, + Dwarf_Unsigned info, + int* sect_name_index, + int* error) \fP +.DE +For each section in the object file that \f(CWlibdwarf\fP +needs to create, it calls this function once (calling it +from \f(CWdwarf_transform_to_disk_form()\fP), passing in +the section \f(CWname\fP, the section \f(CWtype\fP, +the section \f(CWflags\fP, the \f(CWlink\fP field, and +the \f(CWinfo\fP field. +For an Elf object file these values +should be appropriate Elf section header values. +For example, for relocation callbacks, the \f(CWlink\fP +field is supposed to be set (by the app) to the index +of the symtab section (the link field passed through the +callback must be ignored by the app). +And, for relocation callbacks, the \f(CWinfo\fP field +is passed as the elf section number of the section +the relocations apply to. +.P +On success +the user function should return the Elf section number of the +newly created Elf section. +.P +On success, the function should also set the integer +pointed to by \f(CWsect_name_index\fP to the +Elf symbol number assigned in the Elf symbol table of the +new Elf section. +This symbol number is needed with relocations +dependent on the relocation of this new section. +Because "int *" is not guaranteed to work with elf 'symbols' +that are really pointers, +It is better to use the +\f(CWdwarf_producer_init_c()\fP +interface. +.P +For example, the \f(CW.debug_line\fP section's third +data element (in a compilation unit) is the offset from the +beginning of the \f(CW.debug_info\fP section of the compilation +unit entry for this \f(CW.debug_line\fP set. +The relocation entry in \f(CW.rel.debug_line\fP +for this offset +must have the relocation symbol index of the +symbol \f(CW.debug_info\fP returned +by the callback of that section-creation through +the pointer \f(CWsect_name_index\fP. +.P +On failure, the function should return -1 and set the \f(CWerror\fP +integer to an error code. +.P +Nothing in libdwarf actually depends on the section index +returned being a real Elf section. +The Elf section is simply useful for generating relocation +records. +Similarly, the Elf symbol table index returned through +the \f(CWsect_name_index\fP must simply be an index +that can be used in relocations against this section. +The application will probably want to note the +values passed to this function in some form, even if +no Elf file is being produced. + +.H 3 "dwarf_producer_init_c()" +.DS + \f(CWDwarf_P_Debug dwarf_producer_init_c( + Dwarf_Unsigned flags, + Dwarf_Callback_Func_c func, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + void * user_data, + Dwarf_Error *error) \fP + .DE + +The function \f(CWdwarf_producer_init_c() \fP +is the same as \f(CWdwarf_producer_init() \fP +except that a) the callback function uses +Dwarf_Unsigned rather than int as the +type of the symbol-index returned to libdwarf +through the pointer argument (see below), and +b) the \f(CWuser_data\fP argument passed in +is passed through (unchanged) to the callback functions. +.P +The \f(CWuser_data\fP argument is not examined by libdwarf and +may be used by consumer code for the consumer's own purposes. +.P +The \f(CWflags\fP +values are as follows: +.in +4 +\f(CWDW_DLC_WRITE\fP +is required. +The values +\f(CWDW_DLC_READ\fP +\f(CWDW_DLC_RDWR\fP +are not supported by the producer and must not be passed. + +If +\f(CWDW_DLC_SIZE_64\fP +is not ORed into \f(CWflags\fP +then +\f(CWDW_DLC_SIZE_32\fP +is assumed. +Oring in both is an error. + +If +\f(CWDW_DLC_ISA_IA64\fP +is not ORed into \f(CWflags\fP +then +\f(CWDW_DLC_ISA_MIPS\fP +is assumed. +Oring in both is an error. + +Either one of two output forms are specifiable: +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +or +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP . +\f(CWdwarf_producer_init_c() \fP +is usable with +either output form. + +Either one of two output forms is specifiable: +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +or +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP . + +The default is +\f(CWDW_DLC_STREAM_RELOCATIONS\fP . +The +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +are relocations in a binary stream (as used +in a MIPS Elf object). + +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +are ORed into flags +to cause +the same relocations to be expressed in an +array of structures defined by libdwarf, +which the caller of the relevant function +(see below) must deal with appropriately. +This method of expressing relocations allows +the producer-application to easily produce +assembler text output of debugging information. + +.in -4 +.P +The function \f(CWfunc\fP +must be provided by the user of this library. +Its prototype is: +.DS +\f(CWtypedef int (*Dwarf_Callback_Func_c)( + char* name, + int size, + Dwarf_Unsigned type, + Dwarf_Unsigned flags, + Dwarf_Unsigned link, + Dwarf_Unsigned info, + Dwarf_Unsigned* sect_name_index, + void * user_data, + int* error) \fP +.DE +For each section in the object file that \f(CWlibdwarf\fP +needs to create, it calls this function once, passing in +the section \f(CWname\fP, the section \f(CWtype\fP, +the section \f(CWflags\fP, the \f(CWlink\fP field, and +the \f(CWinfo\fP field. For an Elf object file these values +should be appropriate Elf section header values. +For example, for relocation callbacks, the \f(CWlink\fP +field is supposed to be set (by the app) to the index +of the symtab section (the link field passed through the +callback must be ignored by the app). +And, for relocation callbacks, the \f(CWinfo\fP field +is passed as the elf section number of the section +the relocations apply to. + +On success +the user function should return the Elf section number of the +newly created Elf section. +.P +On success, the function should also set the integer +pointed to by \f(CWsect_name_index\fP to the +Elf symbol number assigned in the Elf symbol table of the +new Elf section. +This symbol number is needed with relocations +dependent on the relocation of this new section. +.P +For example, the \f(CW.debug_line\fP section's third +data element (in a compilation unit) is the offset from the +beginning of the \f(CW.debug_info\fP section of the compilation +unit entry for this \f(CW.debug_line\fP set. +The relocation entry in \f(CW.rel.debug_line\fP +for this offset +must have the relocation symbol index of the +symbol \f(CW.debug_info\fP returned +by the callback of that section-creation through +the pointer \f(CWsect_name_index\fP. +.P +On failure, the function should return -1 and set the \f(CWerror\fP +integer to an error code. +.P +Nothing in libdwarf actually depends on the section index +returned being a real Elf section. +The Elf section is simply useful for generating relocation +records. +Similarly, the Elf symbol table index returned through +the \f(CWsect_name_index\fP must simply be an index +that can be used in relocations against this section. +The application will probably want to note the +values passed to this function in some form, even if +no Elf file is being produced. + +Note that the \f(CWDwarf_Callback_Func_c() \fP form +passes back the sect_name_index as a Dwarf_Unsigned. +This is guaranteed large enough to hold a pointer. +(the other functional interfaces have versions with +the 'symbol index' as a Dwarf_Unsigned too. See below). + +If \f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +is in use, then the symbol index is simply an arbitrary +value (from the point of view of libdwarf) so the +caller can put anything in it: +a normal elf symbol index, +a pointer to a struct (with arbitrary contents) +(the caller must cast to/from Dwarf_Unsigned +as appropriate), +or some other kind of pointer or value. +The values show up in the +output of \f(CWdwarf_get_relocation_info()\fP +(described below) and are not emitted anywhere else. + +.H 3 "dwarf_producer_init_b()" + +.DS +\f(CWDwarf_P_Debug dwarf_producer_init_b( + Dwarf_Unsigned flags, + Dwarf_Callback_Func_b func, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Error *error) \fP +.DE +This is identical to \f(CWdwarf_producer_init_c()\fP except that +the user_data argument in \f(CWdwarf_producer_init_c()\fP and +in \f(CWDwarf_Callback_Func_c\fP are absent in the _b form. + + +.H 3 "dwarf_transform_to_disk_form()" + +.DS +\f(CWDwarf_Signed dwarf_transform_to_disk_form( + Dwarf_P_Debug dbg, + Dwarf_Error* error) \fP +.DE +The function \f(CWdwarf_transform_to_disk_form() \fP does the actual +conversion of the \f(CWDwarf\fP information provided so far, to the +form that is +normally written out as \f(CWElf\fP sections. +In other words, +once all DWARF information has been passed to \f(CWLibdwarf\fP, call +\f(CWdwarf_transform_to_disk_form() \fP to transform all the accumulated +data into byte streams. +This includes turning relocation information +into byte streams (and possibly relocation arrays). +This function does not write anything to disk. If +successful, it returns a count of the number of \f(CWElf\fP sections +ready to be retrieved (and, normally, written to disk). +In case of error, it returns +\f(CWDW_DLV_NOCOUNT\fP. + + +.H 3 "dwarf_get_section_bytes()" + +.DS +\f(CWDwarf_Ptr dwarf_get_section_bytes( + Dwarf_P_Debug dbg, + Dwarf_Signed dwarf_section, + Dwarf_Signed *elf_section_index, + Dwarf_Unsigned *length, + Dwarf_Error* error)\fP +.DE +The function \f(CWdwarf_get_section_bytes() \fP must be called repetitively, +with the index \f(CWdwarf_section\fP starting at 0 and continuing for the +number of sections +returned by \f(CWdwarf_transform_to_disk_form() \fP. +It returns \f(CWNULL\fP to indicate that there are no more sections of +\f(CWDwarf\fP information. +For each non-NULL return, the return value +points to \f(CW*length\fP bytes of data that are normally +added to the output +object in \f(CWElf\fP section \f(CW*elf_section\fP by the producer application. +It is illegal to call these in any order other than 0 through N-1 where +N is the number of dwarf sections +returned by \f(CWdwarf_transform_to_disk_form() \fP. +The \f(CWdwarf_section\fP +number is actually ignored: the data is returned as if the +caller passed in the correct dwarf_section numbers in the +required sequence. +The \f(CWerror\fP argument is not used. +.P +There is no requirement that the section bytes actually +be written to an elf file. +For example, consider the .debug_info section and its +relocation section (the call back function would resulted in +assigning 'section' numbers and the link field to tie these +together (.rel.debug_info would have a link to .debug_info). +One could examine the relocations, split the .debug_info +data at relocation boundaries, emit byte streams (in hex) +as assembler output, and at each relocation point, +emit an assembler directive with a symbol name for the assembler. +Examining the relocations is awkward though. +It is much better to use \f(CWdwarf_get_section_relocation_info() \fP +.P + +The memory space of the section byte stream is freed +by the \f(CWdwarf_producer_finish() \fP call +(or would be if the \f(CWdwarf_producer_finish() \fP +was actually correct), along +with all the other space in use with that Dwarf_P_Debug. + +.H 3 "dwarf_get_relocation_info_count()" +.DS +\f(CWint dwarf_get_relocation_info_count( + Dwarf_P_Debug dbg, + Dwarf_Unsigned *count_of_relocation_sections , + int *drd_buffer_version, + Dwarf_Error* error)\fP +.DE +The function \f(CWdwarf_get_relocation_info() \fP +returns, through the pointer \f(CWcount_of_relocation_sections\fP, the +number of times that \f(CWdwarf_get_relocation_info() \fP +should be called. + +The function \f(CWdwarf_get_relocation_info() \fP +returns DW_DLV_OK if the call was successful (the +\f(CWcount_of_relocation_sections\fP is therefore meaningful, +though \f(CWcount_of_relocation_sections\fP +could be zero). + +\f(CW*drd_buffer_version\fP +is the value 2. +If the structure pointed to by +the \f(CW*reldata_buffer\fP +changes this number will change. +The application should verify that the number is +the version it understands (that it matches +the value of DWARF_DRD_BUFFER_VERSION (from libdwarf.h)). +The value 1 version was never used in production +MIPS libdwarf (version 1 did exist in source). + +It returns DW_DLV_NO_ENTRY if +\f(CWcount_of_relocation_sections\fP is not meaningful +because \f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP was not +passed to the +\f(CWdwarf_producer_init_c()\fP +\f(CWdwarf_producer_init_b()\fP or +\f(CWdwarf_producer_init()\fP call +(whichever one was used). + +It returns DW_DLV_ERROR if there was an error, +in which case +\f(CWcount_of_relocation_sections\fP is not meaningful. + +.H 3 "dwarf_get_relocation_info()" +.DS +\f(CWint dwarf_get_relocation_info( + Dwarf_P_Debug dbg, + Dwarf_Signed *elf_section_index, + Dwarf_Signed *elf_section_index_link, + Dwarf_Unsigned *relocation_buffer_count, + Dwarf_Relocation_Data *reldata_buffer, + Dwarf_Error* error)\fP +.DE + +The function \f(CWdwarf_get_relocation_info() \fP +should normally be called repetitively, +for the number of relocation sections that +\f(CWdwarf_get_relocation_info_count() \fP +indicated exist. + +It returns \f(CWDW_DLV_OK\fP to indicate that +valid values are returned through the pointer arguments. +The \f(CWerror\fP argument is not set. + +It returns DW_DLV_NO_ENTRY if there are no entries +(the count of relocation arrays is zero.). +The \f(CWerror\fP argument is not set. + +It returns \f(CWDW_DLV_ERROR\fP if there is an error. +Calling \f(CWdwarf_get_relocation_info() \fP +more than the number of times indicated by +\f(CWdwarf_get_relocation_info_count() \fP +(without an intervening call to +\f(CWdwarf_reset_section_bytes() \fP ) +results in a return of \f(CWDW_DLV_ERROR\fP once past +the valid count. +The \f(CWerror\fP argument is set to indicate the error. + +Now consider the returned-through-pointer values for +\f(CWDW_DLV_OK\fP . + +\f(CW*elf_section_index\fP +is the 'elf section index' of the section implied by +this group of relocations. + + +\f(CW*elf_section_index_link\fP +is the section index of the section that these +relocations apply to. + +\f(CW*relocation_buffer_count\fP +is the number of array entries of relocation information +in the array pointed to by +\f(CW*reldata_buffer\fP . + + +\f(CW*reldata_buffer\fP +points to an array of 'struct Dwarf_Relocation_Data_s' +structures. + +The version 2 array information is as follows: + +.nf +enum Dwarf_Rel_Type {dwarf_drt_none, + dwarf_drt_data_reloc, + dwarf_drt_segment_rel, + dwarf_drt_first_of_length_pair, + dwarf_drt_second_of_length_pair +}; +typedef struct Dwarf_Relocation_Data_s * Dwarf_Relocation_Data; +struct Dwarf_Relocation_Data_s { + unsigned char drd_type; /* contains Dwarf_Rel_Type */ + unsigned char drd_length; /* typically 4 or 8 */ + Dwarf_Unsigned drd_offset; /* where the data to reloc is */ + Dwarf_Unsigned drd_symbol_index; +}; + +.fi + +The \f(CWDwarf_Rel_Type\fP enum is encoded (via casts if necessary) +into the single unsigned char \f(CWdrd_type\fP field to control +the space used for this information (keep the space to 1 byte). + +The unsigned char \f(CWdrd_length\fP field +holds the size in bytes of the field to be relocated. +So for elf32 object formats with 32 bit apps, \f(CWdrd_length\fP +will be 4. For objects with MIPS -64 contents, +\f(CWdrd_length\fP will be 8. +For some dwarf 64 bit environments, such as ia64, \f(CWdrd_length\fP +is 4 for some relocations (file offsets, for example) +and 8 for others (run time +addresses, for example). + +If \f(CWdrd_type\fP is \f(CWdwarf_drt_none\fP, this is an unused slot +and it should be ignored. + +If \f(CWdrd_type\fP is \f(CWdwarf_drt_data_reloc\fP +this is an ordinary relocation. +The relocation type means either +(R_MIPS_64) or (R_MIPS_32) (or the like for +the particular ABI. +\f(CWdrd_length\fP gives the length of the field to be relocated. +\f(CWdrd_offset\fP is an offset (of the +value to be relocated) in +the section this relocation stuff is linked to. +\f(CWdrd_symbol_index\fP is the symbol index (if elf symbol +indices were provided) or the handle to arbitrary +information (if that is what the caller passed in +to the relocation-creating dwarf calls) of the symbol +that the relocation is relative to. + + +When \f(CWdrd_type\fP is \f(CWdwarf_drt_first_of_length_pair\fP +the next data record will be \f(CWdrt_second_of_length_pair\fP +and the \f(CWdrd_offset\fP of the two data records will match. +The relevant 'offset' in the section this reloc applies to +should contain a symbolic pair like +.nf +.in +4 + .word second_symbol - first_symbol +.in -4 +.fi +to generate a length. +\f(CWdrd_length\fP gives the length of the field to be relocated. + +\f(CWdrt_segment_rel\fP means (R_MIPS_SCN_DISP) +is the real relocation (R_MIPS_SCN_DISP applies to +exception tables and this part may need further work). +\f(CWdrd_length\fP gives the length of the field to be relocated. + +.P +The memory space of the section byte stream is freed +by the \f(CWdwarf_producer_finish() \fP call +(or would be if the \f(CWdwarf_producer_finish() \fP +was actually correct), along +with all the other space in use with that Dwarf_P_Debug. + +.H 3 "dwarf_reset_section_bytes()" + +.DS +\f(CWvoid dwarf_reset_section_bytes( + Dwarf_P_Debug dbg + ) \fP +.DE +The function \f(CWdwarf_reset_section_bytes() \fP +is used to reset the internal information so that +\f(CWdwarf_get_section_bytes() \fP will begin (on the next +call) at the initial dwarf section again. +It also resets so that calls to +\f(CWdwarf_get_relocation_info() \fP +will begin again at the initial array of relocation information. + +Some dwarf producers need to be able to run through +the \f(CWdwarf_get_section_bytes()\fP +and/or +the \f(CWdwarf_get_relocation_info()\fP +calls more than once and this call makes additional +passes possible. +The set of Dwarf_Ptr values returned is identical to the +set returned by the first pass. +It is acceptable to call this before finishing a pass +of \f(CWdwarf_get_section_bytes()\fP +or +\f(CWdwarf_get_relocation_info()\fP +calls. +No errors are possible as this just resets some +internal pointers. +It is unwise to call this before +\f(CWdwarf_transform_to_disk_form() \fP has been called. +.P + +.H 3 "dwarf_producer_finish()" +.DS +\f(CWDwarf_Unsigned dwarf_producer_finish( + Dwarf_P_Debug dbg, + Dwarf_Error* error) \fP +.DE +The function \f(CWdwarf_producer_finish() \fP should be called after all +the bytes of data have been copied somewhere +(normally the bytes are written to disk). +It frees all dynamic space +allocated for \f(CWdbg\fP, include space for the structure pointed to by +\f(CWdbg\fP. +This should not be called till the data have been +copied or written +to disk or are no longer of interest. +It returns non-zero if successful, and \f(CWDW_DLV_NOCOUNT\fP +if there is an error. + +.H 2 "Debugging Information Entry Creation" +The functions in this section add new \f(CWDIE\fPs to the object, +and also the relationships among the \f(CWDIE\fP to be specified +by linking them up as parents, children, left or right siblings +of each other. +In addition, there is a function that marks the +root of the graph thus created. + +.H 3 "dwarf_add_die_to_debug()" +.DS +\f(CWDwarf_Unsigned dwarf_add_die_to_debug( + Dwarf_P_Debug dbg, + Dwarf_P_Die first_die, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_die_to_debug() \fP indicates to \f(CWLibdwarf\fP +the root \f(CWDIE\fP of the \f(CWDIE\fP graph that has been built so +far. +It is intended to mark the compilation-unit \f(CWDIE\fP for the +object represented by \f(CWdbg\fP. +The root \f(CWDIE\fP is specified +by \f(CWfirst_die\fP. + +It returns \f(CW0\fP on success, and \f(CWDW_DLV_NOCOUNT\fP on error. + +.H 3 "dwarf_new_die()" +.DS +\f(CWDwarf_P_Die dwarf_new_die( + Dwarf_P_Debug dbg, + Dwarf_Tag new_tag, + Dwarf_P_Die parent, + Dwarf_P_Die child, + Dwarf_P_Die left_sibling, + Dwarf_P_Die right_sibling, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_new_die() \fP creates a new \f(CWDIE\fP with +its parent, child, left sibling, and right sibling \f(CWDIE\fPs +specified by \f(CWparent\fP, \f(CWchild\fP, \f(CWleft_sibling\fP, +and \f(CWright_sibling\fP, respectively. +There is no requirement +that all of these \f(CWDIE\fPs be specified, i.e. any of these +descriptors may be \f(CWNULL\fP. +If none is specified, this will +be an isolated \f(CWDIE\fP. +A \f(CWDIE\fP is +transformed to disk form by \f(CWdwarf_transform_to_disk_form() \fP +only if there is a path from +the \f(CWDIE\fP specified by \f(CWdwarf_add_die_to_debug\fP to it. +This function returns \f(CWDW_DLV_BADADDR\fP on error. + +\f(CWnew_tag\fP is the tag which is given to the new \f(CWDIE\fP. +\f(CWparent\fP, \f(CWchild\fP, \f(CWleft_sibling\fP, and +\f(CWright_sibling\fP are pointers to establish links to existing +\f(CWDIE\fPs. Only one of \f(CWparent\fP, \f(CWchild\fP, +\f(CWleft_sibling\fP, and \f(CWright_sibling\fP may be non-NULL. +If \f(CWparent\fP (\f(CWchild\fP) is given, the \f(CWDIE\fP is +linked into the list after (before) the \f(CWDIE\fP pointed to. +If \f(CWleft_sibling\fP (\f(CWright_sibling\fP) is given, the +\f(CWDIE\fP is linked into the list after (before) the \f(CWDIE\fP +pointed to. + +To add attributes to the new \f(CWDIE\fP, use the \f(CWAttribute Creation\fP +functions defined in the next section. + +.H 3 "dwarf_die_link()" +.DS +\f(CWDwarf_P_Die dwarf_die_link( + Dwarf_P_Die die, + Dwarf_P_Die parent, + Dwarf_P_Die child, + Dwarf_P_Die left-sibling, + Dwarf_P_Die right_sibling, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_die_link() \fP links an existing \f(CWDIE\fP +described by the given \f(CWdie\fP to other existing \f(CWDIE\fPs. +The given \f(CWdie\fP can be linked to a parent \f(CWDIE\fP, a child +\f(CWDIE\fP, a left sibling \f(CWDIE\fP, or a right sibling \f(CWDIE\fP +by specifying non-NULL \f(CWparent\fP, \f(CWchild\fP, \f(CWleft_sibling\fP, +and \f(CWright_sibling\fP \f(CWDwarf_P_Die\fP descriptors. +It returns +the given \f(CWDwarf_P_Die\fP descriptor, \f(CWdie\fP, on success, +and \f(CWDW_DLV_BADADDR\fP on error. + +Only one of \f(CWparent\fP, \f(CWchild\fP, \f(CWleft_sibling\fP, +and \f(CWright_sibling\fP may be non-NULL. +If \f(CWparent\fP +(\f(CWchild\fP) is given, the \f(CWDIE\fP is linked into the list +after (before) the \f(CWDIE\fP pointed to. +If \f(CWleft_sibling\fP +(\f(CWright_sibling\fP) is given, the \f(CWDIE\fP is linked into +the list after (before) the \f(CWDIE\fP pointed to. +Non-NULL links +overwrite the corresponding links the given \f(CWdie\fP may have +had before the call to \f(CWdwarf_die_link() \fP. + +.H 2 "DIE Markers" +DIE markers provide a way for a producer to extract DIE offsets +from DIE generation. The markers do not influence the +generation of DWARF, they simply allow a producer to +extract .debug_info offsets for whatever purpose the +producer finds useful (for example, a producer might +want some unique other section unknown +to libdwarf to know a particular DIE offset). + +One marks one or more DIEs as desired any time before +calling \f(CWdwarf_transform_to_disk_form()\fP. + +After calling \f(CWdwarf_transform_to_disk_form()\fP +call +\f(CWdwarf_get_die_markers()\fP +which has the offsets where the marked DIEs were written +in the generated .debug_info data. + + +.H 3 "dwarf_add_die_marker()" +.DS +\f(CWDwarf_Unsigned dwarf_add_die_marker( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + Dwarf_Unsigned marker, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_die_marker() \fP writes the +value \f(CWmarker\fP to the \f(CWDIE\fP descriptor given by +\f(CWdie\fP. +Passing in a marker of 0 means 'there is no marker' +(zero is the default in DIEs). + +It returns \f(CW0\fP, on success. +On error it returns \f(CWDW_DLV_NOCOUNT\fP. + +.H 3 "dwarf_get_die_marker()" +.DS +\f(CWDwarf_Unsigned dwarf_get_die_marker( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + Dwarf_Unsigned *marker, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_get_die_marker() \fP returns the +current marker value for this DIE +through the pointer \f(CWmarker\fP. +A marker value of 0 means 'no marker was set'. + +It returns \f(CW0\fP, on success. +On error it returns \f(CWDW_DLV_NOCOUNT\fP. + +.H 3 "dwarf_get_die_markers()" +.DS +\f(CWDwarf_Unsigned dwarf_get_die_markers( + Dwarf_P_Debug dbg, + Dwarf_P_Marker * marker_list, + Dwarf_Unsigned *marker_count, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_get_die_marker() \fP returns +a pointer to an array of \f(CWDwarf_P_Marker\fP pointers to +\f(CWstruct Dwarf_P_Marker_s\fP structures through +the pointer \f(CWmarker_list\fP. +The array length is returned through the +pointer \f(CWmarker_count\fP. + +The call is only meaningful after +a call to \f(CWdwarf_transform_to_disk_form()\fP as the +transform call creates the \f(CWstruct Dwarf_P_Marker_s\fP +structures, one for each DIE generated for .debug_info +(but only for DIEs that had a non-zero marker value). +The field \f(CWma_offset\fP in the structure is set +during generation of the .debug_info byte stream. +The field \f(CWma_marker\fP in the structure is a copy +of the DIE marker of the DIE given that offset. + +It returns \f(CW0\fP, on success. +On error it returns \f(CWDW_DLV_BADADDR\fP (if there are no +markers it returns \f(CWDW_DLV_BADADDR\fP). + +.H 2 "Attribute Creation" +The functions in this section add attributes to a \f(CWDIE\fP. +These functions return a \f(CWDwarf_P_Attribute\fP descriptor +that represents the attribute added to the given \f(CWDIE\fP. +In most cases the return value is only useful to determine if +an error occurred. + +Some of the attributes have values that are relocatable. +They +need a symbol with respect to which the linker will perform +relocation. +This symbol is specified by means of an index into +the Elf symbol table for the object +(of course, the symbol index can be more general than an index). + +.H 3 "dwarf_add_AT_location_expr()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_location_expr( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_P_Expr loc_expr, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_location_expr() \fP adds the attribute +specified by \f(CWattr\fP to the \f(CWDIE\fP descriptor given by +\f(CWownerdie\fP. The attribute should be one that has a location +expression as its value. The location expression that is the value +is represented by the \f(CWDwarf_P_Expr\fP descriptor \f(CWloc_expr\fP. +It returns the \f(CWDwarf_P_Attribute\fP descriptor for the attribute +given, on success. On error it returns \f(CWDW_DLV_BADADDR\fP. + +.H 3 "dwarf_add_AT_name()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_name( + Dwarf_P_Die ownerdie, + char *name, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_name() \fP adds the string specified +by \f(CWname\fP as the value of the \f(CWDW_AT_name\fP attribute +for the given \f(CWDIE\fP, \f(CWownerdie\fP. It returns the +\f(CWDwarf_P_attribute\fP descriptor for the \f(CWDW_AT_name\fP +attribute on success. On error, it returns \f(CWDW_DLV_BADADDR\fP. + +.H 3 "dwarf_add_AT_comp_dir()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_comp_dir( + Dwarf_P_Die ownerdie, + char *current_working_directory, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_comp_dir() \fP adds the string given by +\f(CWcurrent_working_directory\fP as the value of the \f(CWDW_AT_comp_dir\fP +attribute for the \f(CWDIE\fP described by the given \f(CWownerdie\fP. +It returns the \f(CWDwarf_P_Attribute\fP for this attribute on success. +On error, it returns \f(CWDW_DLV_BADADDR\fP. + +.H 3 "dwarf_add_AT_producer()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_producer( + Dwarf_P_Die ownerdie, + char *producer_string, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_producer() \fP adds the string given by +\f(CWproducer_string\fP as the value of the \f(CWDW_AT_producer\fP +attribute for the \f(CWDIE\fP given by \f(CWownerdie\fP. It returns +the \f(CWDwarf_P_Attribute\fP descriptor representing this attribute +on success. On error, it returns \f(CWDW_DLV_BADADDR\fP. + +.H 3 "dwarf_add_AT_const_value_signedint()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_const_value_signedint( + Dwarf_P_Die ownerdie, + Dwarf_Signed signed_value, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_const_value_signedint() \fP adds the +given \f(CWDwarf_Signed\fP value \f(CWsigned_value\fP as the value +of the \f(CWDW_AT_const_value\fP attribute for the \f(CWDIE\fP +described by the given \f(CWownerdie\fP. It returns the +\f(CWDwarf_P_Attribute\fP descriptor for this attribute on success. +On error, it returns \f(CWDW_DLV_BADADDR\fP. + +.H 3 "dwarf_add_AT_const_value_unsignedint()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_const_value_unsignedint( + Dwarf_P_Die ownerdie, + Dwarf_Unsigned unsigned_value, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_const_value_unsignedint() \fP adds the +given \f(CWDwarf_Unsigned\fP value \f(CWunsigned_value\fP as the value +of the \f(CWDW_AT_const_value\fP attribute for the \f(CWDIE\fP described +by the given \f(CWownerdie\fP. It returns the \f(CWDwarf_P_Attribute\fP +descriptor for this attribute on success. On error, it returns +\f(CWDW_DLV_BADADDR\fP. + +.H 3 "dwarf_add_AT_const_value_string()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_const_value_string( + Dwarf_P_Die ownerdie, + char *string_value, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_const_value_string() \fP adds the +string value given by \f(CWstring_value\fP as the value of the +\f(CWDW_AT_const_value\fP attribute for the \f(CWDIE\fP described +by the given \f(CWownerdie\fP. It returns the \f(CWDwarf_P_Attribute\fP +descriptor for this attribute on success. On error, it returns +\f(CWDW_DLV_BADADDR\fP. + +.H 3 "dwarf_add_AT_targ_address()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_targ_address( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Signed sym_index, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_targ_address() \fP adds an attribute that +belongs to the "address" class to the die specified by \f(CWownerdie\fP. +The attribute is specified by \f(CWattr\fP, and the object that the +\f(CWDIE\fP belongs to is specified by \f(CWdbg\fP. The relocatable +address that is the value of the attribute is specified by \f(CWpc_value\fP. +The symbol to be used for relocation is specified by the \f(CWsym_index\fP, +which is the index of the symbol in the Elf symbol table. + +It returns the \f(CWDwarf_P_Attribute\fP descriptor for the attribute +on success, and \f(CWDW_DLV_BADADDR\fP on error. + + +.H 3 "dwarf_add_AT_targ_address_b()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_targ_address_b( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_targ_address_b() \fP +is identical to \f(CWdwarf_add_AT_targ_address_b() \fP +except that \f(CWsym_index() \fP is guaranteed to +be large enough that it can contain a pointer to +arbitrary data (so the caller can pass in a real elf +symbol index, an arbitrary number, or a pointer +to arbitrary data). +The ability to pass in a pointer through \f(CWsym_index() \fP +is only usable with +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP. + +The \f(CWpc_value\fP +is put into the section stream output and +the \f(CWsym_index\fP is applied to the relocation +information. + +Do not use this function for attr \f(CWDW_AT_high_pc\fP +if the value to be recorded is an offset (not a pc) +[ use \f(CWdwarf_add_AT_unsigned_const()\fP (for example) +instead]. + +.H 3 "dwarf_add_AT_dataref()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_dataref( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error *error) \fP +.DE +This is very similar to \f(CWdwarf_add_AT_targ_address_b() \fP +but results in a different FORM (results in DW_FORM_data4 +or DW_FORM_data8). + +Useful for adding relocatable addresses in location lists. + +\f(CWsym_index() \fP is guaranteed to +be large enough that it can contain a pointer to +arbitrary data (so the caller can pass in a real elf +symbol index, an arbitrary number, or a pointer +to arbitrary data). +The ability to pass in a pointer through \f(CWsym_index() \fP +is only usable with +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP. + +The \f(CWpc_value\fP +is put into the section stream output and +the \f(CWsym_index\fP is applied to the relocation +information. + +Do not use this function for \f(CWDW_AT_high_pc\fP, use +\f(CWdwarf_add_AT_unsigned_const()\fP [ (for example) +if the value to be recorded is +an offset of \f(CWDW_AT_low_pc\fP] +or \f(CWdwarf_add_AT_targ_address_b()\fP [ if the value +to be recorded is an address]. + +.H 3 "dwarf_add_AT_ref_address()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_ref_address( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error *error) \fP +.DE + +This is very similar to \f(CWdwarf_add_AT_targ_address_b() \fP +but results in a different FORM (results in \f(CWDW_FORM_ref_addr\fP +being generated). + +Useful for \f(CWDW_AT_type\fP and \f(CWDW_AT_import\fP attributes. + +\f(CWsym_index() \fP is guaranteed to +be large enough that it can contain a pointer to +arbitrary data (so the caller can pass in a real elf +symbol index, an arbitrary number, or a pointer +to arbitrary data). +The ability to pass in a pointer through \f(CWsym_index() \fP +is only usable with +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP. + +The \f(CWpc_value\fP +is put into the section stream output and +the \f(CWsym_index\fP is applied to the relocation +information. + +Do not use this function for \f(CWDW_AT_high_pc\fP. + + +.H 3 "dwarf_add_AT_unsigned_const()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_unsigned_const( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned value, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_unsigned_const() \fP adds an attribute +with a \f(CWDwarf_Unsigned\fP value belonging to the "constant" class, +to the \f(CWDIE\fP specified by \f(CWownerdie\fP. The object that +the \f(CWDIE\fP belongs to is specified by \f(CWdbg\fP. The attribute +is specified by \f(CWattr\fP, and its value is specified by \f(CWvalue\fP. + +It returns the \f(CWDwarf_P_Attribute\fP descriptor for the attribute +on success, and \f(CWDW_DLV_BADADDR\fP on error. + +.H 3 "dwarf_add_AT_signed_const()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_signed_const( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Signed value, + Dwarf_Error *error) \fP +.DE +The function \f(CWdwarf_add_AT_signed_const() \fP adds an attribute +with a \f(CWDwarf_Signed\fP value belonging to the "constant" class, +to the \f(CWDIE\fP specified by \f(CWownerdie\fP. The object that +the \f(CWDIE\fP belongs to is specified by \f(CWdbg\fP. The attribute +is specified by \f(CWattr\fP, and its value is specified by \f(CWvalue\fP. + +It returns the \f(CWDwarf_P_Attribute\fP descriptor for the attribute +on success, and \f(CWDW_DLV_BADADDR\fP on error. + +.H 3 "dwarf_add_AT_reference()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_reference( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_P_Die otherdie, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_AT_reference()\fP adds an attribute +with a value that is a reference to another \f(CWDIE\fP in the +same compilation-unit to the \f(CWDIE\fP specified by \f(CWownerdie\fP. +The object that the \f(CWDIE\fP belongs to is specified by \f(CWdbg\fP. +The attribute is specified by \f(CWattr\fP, and the other \f(CWDIE\fP +being referred to is specified by \f(CWotherdie\fP. + +This cannot generate DW_FORM_ref_addr references to +\f(CWDIE\fPs in other compilation units. + +It returns the \f(CWDwarf_P_Attribute\fP descriptor for the attribute +on success, and \f(CWDW_DLV_BADADDR\fP on error. + +.H 3 "dwarf_add_AT_flag()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_flag( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Small flag, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_AT_flag()\fP adds an attribute with +a \f(CWDwarf_Small\fP value belonging to the "flag" class, to the +\f(CWDIE\fP specified by \f(CWownerdie\fP. The object that the +\f(CWDIE\fP belongs to is specified by \f(CWdbg\fP. The attribute +is specified by \f(CWattr\fP, and its value is specified by \f(CWflag\fP. + +It returns the \f(CWDwarf_P_Attribute\fP descriptor for the attribute +on success, and \f(CWDW_DLV_BADADDR\fP on error. + +.H 3 "dwarf_add_AT_string()" +.DS +\f(CWDwarf_P_Attribute dwarf_add_AT_string( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + char *string, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_AT_string()\fP adds an attribute with a +value that is a character string to the \f(CWDIE\fP specified by +\f(CWownerdie\fP. The object that the \f(CWDIE\fP belongs to is +specified by \f(CWdbg\fP. The attribute is specified by \f(CWattr\fP, +and its value is pointed to by \f(CWstring\fP. + +It returns the \f(CWDwarf_P_Attribute\fP descriptor for the attribute +on success, and \f(CWDW_DLV_BADADDR\fP on error. + +.H 2 "Expression Creation" +The following functions are used to convert location expressions into +blocks so that attributes with values that are location expressions +can store their values as a \f(CWDW_FORM_blockn\fP value. This is for +both .debug_info and .debug_loc expression blocks. + +To create an expression, first call \f(CWdwarf_new_expr()\fP to get +a \f(CWDwarf_P_Expr\fP descriptor that can be used to build up the +block containing the location expression. Then insert the parts of +the expression in prefix order (exactly the order they would be +interpreted in in an expression interpreter). The bytes of the +expression are then built-up as specified by the user. + +.H 3 "dwarf_new_expr()" +.DS +\f(CWDwarf_Expr dwarf_new_expr( + Dwarf_P_Debug dbg, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_new_expr()\fP creates a new expression area +in which a location expression stream can be created. It returns +a \f(CWDwarf_P_Expr\fP descriptor that can be used to add operators +to build up a location expression. It returns \f(CWNULL\fP on error. + +.H 3 "dwarf_add_expr_gen()" +.DS +\f(CWDwarf_Unsigned dwarf_add_expr_gen( + Dwarf_P_Expr expr, + Dwarf_Small opcode, + Dwarf_Unsigned val1, + Dwarf_Unsigned val2, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_expr_gen()\fP takes an operator specified +by \f(CWopcode\fP, along with up to 2 operands specified by \f(CWval1\fP, +and \f(CWval2\fP, converts it into the \f(CWDwarf\fP representation and +appends the bytes to the byte stream being assembled for the location +expression represented by \f(CWexpr\fP. The first operand, if present, +to \f(CWopcode\fP is in \f(CWval1\fP, and the second operand, if present, +is in \f(CWval2\fP. Both the operands may actually be signed or unsigned +depending on \f(CWopcode\fP. It returns the number of bytes in the byte +stream for \f(CWexpr\fP currently generated, i.e. after the addition of +\f(CWopcode\fP. It returns \f(CWDW_DLV_NOCOUNT\fP on error. + +The function \f(CWdwarf_add_expr_gen()\fP works for all opcodes except +those that have a target address as an operand. This is because it does +not set up a relocation record that is needed when target addresses are +involved. + +.H 3 "dwarf_add_expr_addr()" +.DS +\f(CWDwarf_Unsigned dwarf_add_expr_addr( + Dwarf_P_Expr expr, + Dwarf_Unsigned address, + Dwarf_Signed sym_index, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_expr_addr()\fP is used to add the +\f(CWDW_OP_addr\fP opcode to the location expression represented +by the given \f(CWDwarf_P_Expr\fP descriptor, \f(CWexpr\fP. The +value of the relocatable address is given by \f(CWaddress\fP. +The symbol to be used for relocation is given by \f(CWsym_index\fP, +which is the index of the symbol in the Elf symbol table. It returns +the number of bytes in the byte stream for \f(CWexpr\fP currently +generated, i.e. after the addition of the \f(CWDW_OP_addr\fP operator. +It returns \f(CWDW_DLV_NOCOUNT\fP on error. + +.H 3 "dwarf_add_expr_addr_b()" +.DS +\f(CWDwarf_Unsigned dwarf_add_expr_addr_b( + Dwarf_P_Expr expr, + Dwarf_Unsigned address, + Dwarf_Unsigned sym_index, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_expr_addr_f()\fP is +identical to \f(CWdwarf_add_expr_addr()\fP +except that \f(CWsym_index() \fP is guaranteed to +be large enough that it can contain a pointer to +arbitrary data (so the caller can pass in a real elf +symbol index, an arbitrary number, or a pointer +to arbitrary data). +The ability to pass in a pointer through \f(CWsym_index() \fP +is only usable with +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP. + + + +.H 3 "dwarf_expr_current_offset()" +.DS +\f(CWDwarf_Unsigned dwarf_expr_current_offset( + Dwarf_P_Expr expr, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_expr_current_offset()\fP returns the number +of bytes currently in the byte stream for the location expression +represented by the given \fCW(Dwarf_P_Expr\fP descriptor, \f(CWexpr\fP. +It returns \f(CWDW_DLV_NOCOUNT\fP on error. + +.H 3 "dwarf_expr_into_block()" +.DS +\f(CWDwarf_Addr dwarf_expr_into_block( + Dwarf_P_Expr expr, + Dwarf_Unsigned *length, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_expr_into_block()\fP returns the address +of the start of the byte stream generated for the location expression +represented by the given \f(CWDwarf_P_Expr\fP descriptor, \f(CWexpr\fP. +The length of the byte stream is returned in the location pointed to +by \f(CWlength\fP. It returns \f(CWDW_DLV_BADADDR\fP on error. + +.H 2 "Line Number Operations" +These are operations on the .debug_line section. +They provide +information about instructions in the program and the source +lines the instruction come from. +Typically, code is generated +in contiguous blocks, which may then be relocated as contiguous +blocks. +To make the provision of relocation information more +efficient, the information is recorded in such a manner that only +the address of the start of the block needs to be relocated. +This is done by providing the address of the first instruction +in a block using the function \f(CWdwarf_lne_set_address()\fP. +Information about the instructions in the block are then added +using the function \f(CWdwarf_add_line_entry()\fP, which specifies +offsets from the address of the first instruction. +The end of +a contiguous block is indicated by calling the function +\f(CWdwarf_lne_end_sequence()\fP. +.P +Line number operations do not support +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP. + +.H 3 "dwarf_add_line_entry_b()" +.DS +\f(CWDwarf_Unsigned dwarf_add_line_entry_b( + Dwarf_P_Debug dbg, + Dwarf_Unsigned file_index, + Dwarf_Addr code_offset, + Dwarf_Unsigned lineno, + Dwarf_Signed column_number, + Dwarf_Bool is_source_stmt_begin, + Dwarf_Bool is_basic_block_begin, + Dwarf_Bool is_epilogue_begin, + Dwarf_Bool is_prologue_end, + Dwarf_Unsigned isa, + Dwarf_Unsigned discriminator, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_line_entry()\fP adds an entry to the +section containing information about source lines. +It specifies +in \f(CWcode_offset\fP, the address of this line. +The function subtracts \f(CWcode_offset\fP from the value given +as the address of a previous line call to compute an offset, +and the offset is what is recorded in the line instructions +so no relocation will be needed on the line instruction generated. +.P +The source file that gave rise +to the instruction is specified by \f(CWfile_index\fP, the source +line number is specified by \f(CWlineno\fP, and the source column +number is specified by \f(CWcolumn_number\fP +(column numbers begin at 1) +(if the source column is unknown, specify 0). +\f(CWfile_index\fP +is the index of the source file in a list of source files which is +built up using the function \f(CWdwarf_add_file_decl()\fP. + +\f(CWis_source_stmt_begin\fP is a boolean flag that is true only if +the instruction at \f(CWcode_address\fP is the first instruction in +the sequence generated for the source line at \f(CWlineno\fP. Similarly, +\f(CWis_basic_block_begin\fP is a boolean flag that is true only if +the instruction at \f(CWcode_address\fP is the first instruction of +a basic block. + +\f(CWis_epilogue_begin\fP is a boolean flag that is true only if +the instruction at \f(CWcode_address\fP is the first instruction in +the sequence generated for the function epilogue code. + +Similarly, \f(CWis_prolgue_end\fP is a boolean flag that is true only if +the instruction at \f(CWcode_address\fP is the last instruction of +the seqence generated for the function prologue. + +\f(CWisa\fP should be zero unless the code +at \f(CWcode_address\fP is generated in a non-standard isa. +The values assigned to non-standard isas are defined by the compiler +implementation. + +\f(CWdiscriminator\fP should be zero unless the line table +needs to distinguish among multiple blocks +associated with the same source file, line, and column. +The values assigned to \f(CWdiscriminator\fP are defined by the compiler +implementation. + +It returns \f(CW0\fP on success, and \f(CWDW_DLV_NOCOUNT\fP on error. + +This function is defined as of December 2011. + +.H 3 "dwarf_add_line_entry()" +.DS +\f(CWDwarf_Unsigned dwarf_add_line_entry( + Dwarf_P_Debug dbg, + Dwarf_Unsigned file_index, + Dwarf_Addr code_offset, + Dwarf_Unsigned lineno, + Dwarf_Signed column_number, + Dwarf_Bool is_source_stmt_begin, + Dwarf_Bool is_basic_block_begin, + Dwarf_Error *error)\fP +.DE +This function is the same as \f(CWdwarf_add_line_entry_b()\fP +except this older version is missing the new +DWARF3/4 line table fields. + +.H 3 "dwarf_lne_set_address()" +.DS +\f(CWDwarf_Unsigned dwarf_lne_set_address( + Dwarf_P_Debug dbg, + Dwarf_Addr offs, + Dwarf_Unsigned symidx, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_lne_set_address()\fP sets the target address +at which a contiguous block of instructions begin. Information about +the instructions in the block is added to .debug_line using calls to +\f(CWdwarfdwarf_add_line_entry()\fP which specifies the offset of each +instruction in the block relative to the start of the block. This is +done so that a single relocation record can be used to obtain the final +target address of every instruction in the block. + +The relocatable address of the start of the block of instructions is +specified by \f(CWoffs\fP. The symbol used to relocate the address +is given by \f(CWsymidx\fP, which is normally the index of the symbol in the +Elf symbol table. + +It returns \f(CW0\fP on success, and \f(CWDW_DLV_NOCOUNT\fP on error. + +.H 3 "dwarf_lne_end_sequence()" +.DS +\f(CWDwarf_Unsigned dwarf_lne_end_sequence( + Dwarf_P_Debug dbg, + Dwarf_Addr address; + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_lne_end_sequence()\fP indicates the end of a +contiguous block of instructions. +\f(CWaddress()\fP +should be just higher than the end of the last address in the +sequence of instructions. +Before the next +block of instructions (if any) a call to \f(CWdwarf_lne_set_address()\fP will +have to be made to set the address of the start of the target address +of the block, followed by calls to \f(CWdwarf_add_line_entry()\fP for +each of the instructions in the block. + +It returns \f(CW0\fP on success, and \f(CWDW_DLV_NOCOUNT\fP on error. + +.H 3 "dwarf_add_directory_decl()" +.DS +\f(CWDwarf_Unsigned dwarf_add_directory_decl( + Dwarf_P_Debug dbg, + char *name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_directory_decl()\fP adds the string +specified by \f(CWname\fP to the list of include directories in +the statement program prologue of the .debug_line section. +The +string should therefore name a directory from which source files +have been used to create the present object. + +It returns the index of the string just added, in the list of include +directories for the object. +This index is then used to refer to this +string. The first successful call of this function +returns one, not zero, to be consistent with the directory indices +that \f(CWdwarf_add_file_decl()\fP (below) expects.. + +\f(CWdwarf_add_directory_decl()\fP +returns \f(CWDW_DLV_NOCOUNT\fP on error. + +.H 3 "dwarf_add_file_decl()" +.DS +\f(CWDwarf_Unsigned dwarf_add_file_decl( + Dwarf_P_Debug dbg, + char *name, + Dwarf_Unsigned dir_idx, + Dwarf_Unsigned time_mod, + Dwarf_Unsigned length, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_file_decl()\fP adds the name of a source +file that contributed to the present object. +The name of the file is +specified by \f(CWname\fP (which must not be the empty string +or a null pointer, it must point to +a string with length greater than 0). + +In case the name is not a fully-qualified +pathname, it is +considered prefixed with the name of the directory specified by +\f(CWdir_idx\fP (which does not mean the \f(CWname\fP +is changed or physically prefixed by +this producer function, we simply describe the meaning here). +\f(CWdir_idx\fP is the index of the directory to be +prefixed in the list builtup using \f(CWdwarf_add_directory_decl()\fP. +As specified by the DWARF spec, a \f(CWdir_idx\fP of zero will be +interpreted as meaning the directory of the compilation and +another index must refer to a valid directory as +FIXME + + +\f(CWtime_mod\fP gives the time at which the file was last modified, +and \f(CWlength\fP gives the length of the file in bytes. + +It returns the index of the source file in the list built up so far +using this function, on success. This index can then be used to +refer to this source file in calls to \f(CWdwarf_add_line_entry()\fP. +On error, it returns \f(CWDW_DLV_NOCOUNT\fP. + +.H 2 "Fast Access (aranges) Operations" +These functions operate on the .debug_aranges section. + +.H 3 "dwarf_add_arange()" +.DS +\f(CWDwarf_Unsigned dwarf_add_arange( + Dwarf_P_Debug dbg, + Dwarf_Addr begin_address, + Dwarf_Unsigned length, + Dwarf_Signed symbol_index, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_arange()\fP adds another address range +to be added to the section +containing address range information, .debug_aranges. +The relocatable start address of the range is +specified by \f(CWbegin_address\fP, and the length of the address +range is specified by \f(CWlength\fP. +The relocatable symbol to be +used to relocate the start of the address range is specified by +\f(CWsymbol_index\fP, which is normally +the index of the symbol in the Elf +symbol table. + +It returns a non-zero value on success, and \f(CW0\fP on error. + +.H 3 "dwarf_add_arange_b()" +.DS +\f(CWDwarf_Unsigned dwarf_add_arange_b( + Dwarf_P_Debug dbg, + Dwarf_Addr begin_address, + Dwarf_Unsigned length, + Dwarf_Unsigned symbol_index, + Dwarf_Unsigned end_symbol_index, + Dwarf_Addr offset_from_end_symbol, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_arange_b()\fP adds another address range +to be added to the section containing +address range information, .debug_aranges. + +If +\f(CWend_symbol_index is not zero\fP +we are using two symbols to create a length +(must be \f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP to be useful) +.sp +.in +2 +\f(CWbegin_address\fP +is the offset from the symbol specified by +\f(CWsymbol_index\fP . +\f(CWoffset_from_end_symbol\fP +is the offset from the symbol specified by +\f(CWend_symbol_index\fP. +\f(CWlength\fP is ignored. +This begin-end pair will be show up in the +relocation array returned by +\f(CWdwarf_get_relocation_info() \fP +as a +\f(CWdwarf_drt_first_of_length_pair\fP +and +\f(CWdwarf_drt_second_of_length_pair\fP +pair of relocation records. +The consuming application will turn that pair into +something conceptually identical to +.sp +.nf +.in +4 + .word end_symbol + offset_from_end - \\ + ( start_symbol + begin_address) +.in -4 +.fi +.sp +The reason offsets are allowed on the begin and end symbols +is to allow the caller to re-use existing labels +when the labels are available +and the corresponding offset is known +(economizing on the number of labels in use). +The 'offset_from_end - begin_address' +will actually be in the binary stream, not the relocation +record, so the app processing the relocation array +must read that stream value into (for example) +net_offset and actually emit something like +.sp +.nf +.in +4 + .word end_symbol - start_symbol + net_offset +.in -4 +.fi +.sp +.in -2 + +If +\f(CWend_symbol_index\fP is zero +we must be given a length +(either +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +or +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +): +.sp +.in +2 +The relocatable start address of the range is +specified by \f(CWbegin_address\fP, and the length of the address +range is specified by \f(CWlength\fP. +The relocatable symbol to be +used to relocate the start of the address range is specified by +\f(CWsymbol_index\fP, which is normally +the index of the symbol in the Elf +symbol table. +The +\f(CWoffset_from_end_symbol\fP +is ignored. +.in -2 + + +It returns a non-zero value on success, and \f(CW0\fP on error. + + +.H 2 "Fast Access (pubnames) Operations" +These functions operate on the .debug_pubnames section. +.sp +.H 3 "dwarf_add_pubname()" +.DS +\f(CWDwarf_Unsigned dwarf_add_pubname( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *pubname_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_pubname()\fP adds the pubname specified +by \f(CWpubname_name\fP to the section containing pubnames, i.e. + .debug_pubnames. The \f(CWDIE\fP that represents the function +being named is specified by \f(CWdie\fP. + +It returns a non-zero value on success, and \f(CW0\fP on error. + +.H 2 "Fast Access (weak names) Operations" +These functions operate on the .debug_weaknames section. + +.H 3 "dwarf_add_weakname()" +.DS +\f(CWDwarf_Unsigned dwarf_add_weakname( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *weak_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_weakname()\fP adds the weak name specified +by \f(CWweak_name\fP to the section containing weak names, i.e. + .debug_weaknames. The \f(CWDIE\fP that represents the function +being named is specified by \f(CWdie\fP. + +It returns a non-zero value on success, and \f(CW0\fP on error. + +.H 2 "Static Function Names Operations" +The .debug_funcnames section contains the names of static function +names defined in the object, and also the offsets of the \f(CWDIE\fPs +that represent the definitions of the functions in the .debug_info +section. + +.H 3 "dwarf_add_funcname()" +.DS +\f(CWDwarf_Unsigned dwarf_add_funcname( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *func_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_funcname()\fP adds the name of a static +function specified by \f(CWfunc_name\fP to the section containing the +names of static functions defined in the object represented by \f(CWdbg\fP. +The \f(CWDIE\fP that represents the definition of the function is +specified by \f(CWdie\fP. + +It returns a non-zero value on success, and \f(CW0\fP on error. + +.H 2 "File-scope User-defined Type Names Operations" +The .debug_typenames section contains the names of file-scope +user-defined types in the given object, and also the offsets +of the \f(CWDIE\fPs that represent the definitions of the types +in the .debug_info section. + +.H 3 "dwarf_add_typename()" +.DS +\f(CWDwarf_Unsigned dwarf_add_typename( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *type_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_typename()\fP adds the name of a file-scope +user-defined type specified by \f(CWtype_name\fP to the section that +contains the names of file-scope user-defined type. The object that +this section belongs to is specified by \f(CWdbg\fP. The \f(CWDIE\fP +that represents the definition of the type is specified by \f(CWdie\fP. + +It returns a non-zero value on success, and \f(CW0\fP on error. + +.H 2 "File-scope Static Variable Names Operations" +The .debug_varnames section contains the names of file-scope static +variables in the given object, and also the offsets of the \f(CWDIE\fPs +that represent the definition of the variables in the .debug_info +section. + +.H 3 "dwarf_add_varname()" +.DS +\f(CWDwarf_Unsigned dwarf_add_varname( + Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *var_name, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_varname()\fP adds the name of a file-scope +static variable specified by \f(CWvar_name\fP to the section that +contains the names of file-scope static variables defined by the +object represented by \f(CWdbg\fP. The \f(CWDIE\fP that represents +the definition of the static variable is specified by \f(CWdie\fP. + +It returns a non-zero value on success, and \f(CW0\fP on error. + +.H 2 "Macro Information Creation" +All strings passed in by the caller are copied by these +functions, so the space in which the caller provides the strings +may be ephemeral (on the stack, or immediately reused or whatever) +without this causing any difficulty. + +.H 3 "dwarf_def_macro()" +.DS +\f(CWint dwarf_def_macro(Dwarf_P_Debug dbg, + Dwarf_Unsigned lineno, + char *name + char *value, + Dwarf_Error *error);\fP +.DE +Adds a macro definition. +The \f(CWname\fP argument should include the parentheses +and parameter names if this is a function-like macro. +Neither string should contain extraneous whitespace. +\f(CWdwarf_def_macro()\fP adds the mandated space after the +name and before the value in the +output DWARF section(but does not change the +strings pointed to by the arguments). +If this is a definition before any files are read, +\f(CWlineno\fP should be 0. +Returns \f(CWDW_DLV_ERROR\fP +and sets \f(CWerror\fP +if there is an error. +Returns \f(CWDW_DLV_OK\fP if the call was successful. + + +.H 3 "dwarf_undef_macro()" +.DS +\f(CWint dwarf_undef_macro(Dwarf_P_Debug dbg, + Dwarf_Unsigned lineno, + char *name, + Dwarf_Error *error);\fP +.DE +Adds a macro un-definition note. +If this is a definition before any files are read, +\f(CWlineno\fP should be 0. +Returns \f(CWDW_DLV_ERROR\fP +and sets \f(CWerror\fP +if there is an error. +Returns \f(CWDW_DLV_OK\fP if the call was successful. + + +.H 3 "dwarf_start_macro_file()" +.DS +\f(CWint dwarf_start_macro_file(Dwarf_P_Debug dbg, + Dwarf_Unsigned lineno, + Dwarf_Unsigned fileindex, + Dwarf_Error *error);\fP +.DE +\f(CWfileindex\fP is an index in the .debug_line header: +the index of +the file name. +See the function \f(CWdwarf_add_file_decl()\fP. +The \f(CWlineno\fP should be 0 if this file is +the file of the compilation unit source itself +(which, of course, is not a #include in any +file). +Returns \f(CWDW_DLV_ERROR\fP +and sets \f(CWerror\fP +if there is an error. +Returns \f(CWDW_DLV_OK\fP if the call was successful. + + +.H 3 "dwarf_end_macro_file()" +.DS +\f(CWint dwarf_end_macro_file(Dwarf_P_Debug dbg, + Dwarf_Error *error);\fP +.DE +Returns \f(CWDW_DLV_ERROR\fP +and sets \f(CWerror\fP +if there is an error. +Returns \f(CWDW_DLV_OK\fP if the call was successful. + +.H 3 "dwarf_vendor_ext()" +.DS +\f(CWint dwarf_vendor_ext(Dwarf_P_Debug dbg, + Dwarf_Unsigned constant, + char * string, + Dwarf_Error* error); \fP +.DE +The meaning of the \f(CWconstant\fP and the\f(CWstring\fP +in the macro info section +are undefined by DWARF itself, but the string must be +an ordinary null terminated string. +This call is not an extension to DWARF. +It simply enables storing +macro information as specified in the DWARF document. +Returns \f(CWDW_DLV_ERROR\fP +and sets \f(CWerror\fP +if there is an error. +Returns \f(CWDW_DLV_OK\fP if the call was successful. + + +.H 2 "Low Level (.debug_frame) operations" +These functions operate on the .debug_frame section. Refer to +\f(CWlibdwarf.h\fP for the register names and register assignment +mapping. Both of these are necessarily machine dependent. + +.H 3 "dwarf_new_fde()" +.DS +\f(CWDwarf_P_Fde dwarf_new_fde( + Dwarf_P_Debug dbg, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_new_fde()\fP returns a new \f(CWDwarf_P_Fde\fP +descriptor that should be used to build a complete \f(CWFDE\fP. +Subsequent calls to routines that build up the \f(CWFDE\fP should use +the same \f(CWDwarf_P_Fde\fP descriptor. + +It returns a valid \f(CWDwarf_P_Fde\fP descriptor on success, and +\f(CWDW_DLV_BADADDR\fP on error. + +.H 3 "dwarf_add_frame_cie()" +.DS +\f(CWDwarf_Unsigned dwarf_add_frame_cie( + Dwarf_P_Debug dbg, + char *augmenter, + Dwarf_Small code_align, + Dwarf_Small data_align, + Dwarf_Small ret_addr_reg, + Dwarf_Ptr init_bytes, + Dwarf_Unsigned init_bytes_len, + Dwarf_Error *error);\fP +.DE +The function +\f(CWdwarf_add_frame_cie()\fP +creates a \f(CWCIE\fP, +and returns an index to it, that should be used to refer to this +\f(CWCIE\fP. +\f(CWCIE\fPs are used by \f(CWFDE\fPs to setup +initial values for frames. +The augmentation string for the \f(CWCIE\fP +is specified by \f(CWaugmenter\fP. +The code alignment factor, +data alignment factor, and the return address register for the +\f(CWCIE\fP are specified by \f(CWcode_align\fP, \f(CWdata_align\fP, +and \f(CWret_addr_reg\fP respectively. +\f(CWinit_bytes\fP points +to the bytes that represent the instructions for the \f(CWCIE\fP +being created, and \f(CWinit_bytes_len\fP specifies the number +of bytes of instructions. + +There is no convenient way to generate the \f(CWinit_bytes\fP +stream. +One just +has to calculate it by hand or separately +generate something with the +correct sequence and use dwarfdump -v and readelf (or objdump) +and some +kind of hex dumper to see the bytes. +This is a serious inconvenience! + +It returns an index to the \f(CWCIE\fP just created on success. +On error it returns \f(CWDW_DLV_NOCOUNT\fP. + +.H 3 "dwarf_add_frame_fde()" +.DS +\f(CWDwarf_Unsigned dwarf_add_frame_fde( + Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Addr virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned sym_idx, + Dwarf_Error* error)\fP +.DE +The function \f(CWdwarf_add_frame_fde()\fP adds the \f(CWFDE\fP +specified by \f(CWfde\fP to the list of \f(CWFDE\fPs for the +object represented by the given \f(CWdbg\fP. +\f(CWdie\fP specifies +the \f(CWDIE\fP that represents the function whose frame information +is specified by the given \f(CWfde\fP. +\f(CWcie\fP specifies the +index of the \f(CWCIE\fP that should be used to setup the initial +conditions for the given frame. + +If the MIPS/IRIX specific DW_AT_MIPS_fde attribute is not +needed in .debug_info pass in 0 as the \f(CWdie\fP argument. + +It returns an index to the given \f(CWfde\fP. + + +.H 3 "dwarf_add_frame_fde_b()" +.DS +\f(CWDwarf_Unsigned dwarf_add_frame_fde_b( + Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Addr virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned sym_idx, + Dwarf_Unsigned sym_idx_of_end, + Dwarf_Addr offset_from_end_sym, + Dwarf_Error* error)\fP +.DE +This function is like +\f(CWdwarf_add_frame_fde()\fP +except that +\f(CWdwarf_add_frame_fde_b()\fP +has new arguments to allow use +with +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP. + +The function \f(CWdwarf_add_frame_fde_b()\fP +adds the +\f(CWFDE\fP +specified by \f(CWfde\fP to the list of \f(CWFDE\fPs for the +object represented by the given \f(CWdbg\fP. + +\f(CWdie\fP specifies +the \f(CWDIE\fP that represents the function whose frame information +is specified by the given \f(CWfde\fP. +If the MIPS/IRIX specific DW_AT_MIPS_fde attribute is not +needed in .debug_info pass in 0 as the \f(CWdie\fP argument. + +\f(CWcie\fP specifies the +index of the \f(CWCIE\fP that should be used to setup the initial +conditions for the given frame. +\f(CWvirt_addr\fP represents the +relocatable address at which the code for the given function begins, +and \f(CWsym_idx\fP gives the index of the relocatable symbol to +be used to relocate this address (\f(CWvirt_addr\fP that is). +\f(CWcode_len\fP specifies the size in bytes of the machine instructions +for the given function. + +If \f(CWsym_idx_of_end\fP is zero +(may be +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +or +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +): +.sp +.in +2 +\f(CWvirt_addr\fP represents the +relocatable address at which the code for the given function begins, +and \f(CWsym_idx\fP gives the index of the relocatable symbol to +be used to relocate this address (\f(CWvirt_addr\fP that is). +\f(CWcode_len\fP +specifies the size in bytes of the machine instructions +for the given function. +\f(CWsym_idx_of_end\fP +and +\f(CWoffset_from_end_sym\fP +are unused. +.in -2 +.sp + + +If \f(CWsym_idx_of_end\fP is non-zero +(must be \f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP to be useful): +.sp +.in +2 +\f(CWvirt_addr\fP +is the offset from the symbol specified by +\f(CWsym_idx\fP . +\f(CWoffset_from_end_sym\fP +is the offset from the symbol specified by +\f(CWsym_idx_of_end\fP. +\f(CWcode_len\fP is ignored. +This begin-end pair will be show up in the +relocation array returned by +\f(CWdwarf_get_relocation_info() \fP +as a +\f(CWdwarf_drt_first_of_length_pair\fP +and +\f(CWdwarf_drt_second_of_length_pair\fP +pair of relocation records. +The consuming application will turn that pair into +something conceptually identical to +.sp +.nf +.in +4 + .word end_symbol + begin - \\ + ( start_symbol + offset_from_end) +.in -4 +.fi +.sp +The reason offsets are allowed on the begin and end symbols +is to allow the caller to re-use existing labels +when the labels are available +and the corresponding offset is known +(economizing on the number of labels in use). +The 'offset_from_end - begin_address' +will actually be in the binary stream, not the relocation +record, so the app processing the relocation array +must read that stream value into (for example) +net_offset and actually emit something like +.sp +.nf +.in +4 + .word end_symbol - start_symbol + net_offset +.in -4 +.fi +.sp +.in -2 + +It returns an index to the given \f(CWfde\fP. + +On error, it returns \f(CWDW_DLV_NOCOUNT\fP. + +.H 3 "dwarf_add_frame_info_b()" +.DS +\f(CWDwarf_Unsigned dwarf_add_frame_info_b( + Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Addr virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned sym_idx, + Dwarf_Unsigned end_symbol_index, + Dwarf_Addr offset_from_end_symbol, + Dwarf_Signed offset_into_exception_tables, + Dwarf_Unsigned exception_table_symbol, + Dwarf_Error* error)\fP +.DE +The function \f(CWdwarf_add_frame_fde()\fP adds the \f(CWFDE\fP +specified by \f(CWfde\fP to the list of \f(CWFDE\fPs for the +object represented by the given \f(CWdbg\fP. + +This function refers to MIPS/IRIX specific exception tables +and is not a function other targets need. + +\f(CWdie\fP specifies +the \f(CWDIE\fP that represents the function whose frame information +is specified by the given \f(CWfde\fP. +If the MIPS/IRIX specific DW_AT_MIPS_fde attribute is not +needed in .debug_info pass in 0 as the \f(CWdie\fP argument. + +\f(CWcie\fP specifies the +index of the \f(CWCIE\fP that should be used to setup the initial +conditions for the given frame. + +\f(CWoffset_into_exception_tables\fP specifies the +MIPS/IRIX specific +offset into \f(CW.MIPS.eh_region\fP elf section where the exception tables +for this function begins. +\f(CWexception_table_symbol\fP is also MIPS/IRIX +specific and it specifies the index of +the relocatable symbol to be used to relocate this offset. + + +If +\f(CWend_symbol_index is not zero\fP +we are using two symbols to create a length +(must be \f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP to be useful) +.sp +.in +2 +\f(CWvirt_addr\fP +is the offset from the symbol specified by +\f(CWsym_idx\fP . +\f(CWoffset_from_end_symbol\fP +is the offset from the symbol specified by +\f(CWend_symbol_index\fP. +\f(CWcode_len\fP is ignored. +This begin-end pair will be show up in the +relocation array returned by +\f(CWdwarf_get_relocation_info() \fP +as a +\f(CWdwarf_drt_first_of_length_pair\fP +and +\f(CWdwarf_drt_second_of_length_pair\fP +pair of relocation records. +The consuming application will turn that pair into +something conceptually identical to +.sp +.nf +.in +4 + .word end_symbol + offset_from_end_symbol - \\ + ( start_symbol + virt_addr) +.in -4 +.fi +.sp +The reason offsets are allowed on the begin and end symbols +is to allow the caller to re-use existing labels +when the labels are available +and the corresponding offset is known +(economizing on the number of labels in use). +The 'offset_from_end - begin_address' +will actually be in the binary stream, not the relocation +record, so the app processing the relocation array +must read that stream value into (for example) +net_offset and actually emit something like +.sp +.nf +.in +4 + .word end_symbol - start_symbol + net_offset +.in -4 +.fi +.sp +.in -2 + +If +\f(CWend_symbol_index\fP is zero +we must be given a code_len value +(either +\f(CWDW_DLC_STREAM_RELOCATIONS\fP +or +\f(CWDW_DLC_SYMBOLIC_RELOCATIONS\fP +): +.sp +.in +2 +The relocatable start address of the range is +specified by \f(CWvirt_addr\fP, and the length of the address +range is specified by \f(CWcode_len\fP. +The relocatable symbol to be +used to relocate the start of the address range is specified by +\f(CWsymbol_index\fP, which is normally +the index of the symbol in the Elf +symbol table. +The +\f(CWoffset_from_end_symbol\fP +is ignored. +.in -2 + + +It returns an index to the given \f(CWfde\fP. + +On error, it returns \f(CWDW_DLV_NOCOUNT\fP. + + +.H 3 "dwarf_add_frame_info()" + +.DS +\f(CWDwarf_Unsigned dwarf_add_frame_info( + Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Addr virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned sym_idx, + Dwarf_Signed offset_into_exception_tables, + Dwarf_Unsigned exception_table_symbol, + Dwarf_Error* error)\fP +.DE +The function \f(CWdwarf_add_frame_fde()\fP adds the \f(CWFDE\fP +specified by \f(CWfde\fP to the list of \f(CWFDE\fPs for the +object represented by the given \f(CWdbg\fP. + +\f(CWdie\fP specifies +the \f(CWDIE\fP that represents the function whose frame information +is specified by the given \f(CWfde\fP. +If the MIPS/IRIX specific DW_AT_MIPS_fde attribute is not +needed in .debug_info pass in 0 as the \f(CWdie\fP argument. + +\f(CWcie\fP specifies the +index of the \f(CWCIE\fP that should be used to setup the initial +conditions for the given frame. \f(CWvirt_addr\fP represents the +relocatable address at which the code for the given function begins, +and \f(CWsym_idx\fP gives the index of the relocatable symbol to +be used to relocate this address (\f(CWvirt_addr\fP that is). +\f(CWcode_len\fP specifies the size in bytes of the machine instructions +for the given function. + +\f(CWoffset_into_exception_tables\fP specifies the +offset into \f(CW.MIPS.eh_region\fP elf section where the exception tables +for this function begins. +\f(CWexception_table_symbol\fP gives the index of +the relocatable symbol to be used to relocate this offset. +These arguments are MIPS/IRIX specific, pass in 0 for +other targets. + +It returns an index to the given \f(CWfde\fP. + +.H 3 "dwarf_fde_cfa_offset()" +.DS +\f(CWDwarf_P_Fde dwarf_fde_cfa_offset( + Dwarf_P_Fde fde, + Dwarf_Unsigned reg, + Dwarf_Signed offset, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_fde_cfa_offset()\fP appends a \f(CWDW_CFA_offset\fP +operation to the \f(CWFDE\fP, specified by \f(CWfde\fP, being constructed. +The first operand of the \f(CWDW_CFA_offset\fP operation is specified by +\f(CWreg\P. The register specified should not exceed 6 bits. The second +operand of the \f(CWDW_CFA_offset\fP operation is specified by \f(CWoffset\fP. + +It returns the given \f(CWfde\fP on success. + +It returns \f(CWDW_DLV_BADADDR\fP on error. + +.H 3 "dwarf_add_fde_inst()" +.DS +\f(CWDwarf_P_Fde dwarf_add_fde_inst( + Dwarf_P_Fde fde, + Dwarf_Small op, + Dwarf_Unsigned val1, + Dwarf_Unsigned val2, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_add_fde_inst()\fP adds the operation specified +by \f(CWop\fP to the \f(CWFDE\fP specified by \f(CWfde\fP. Up to two +operands can be specified in \f(CWval1\fP, and \f(CWval2\fP. Based on +the operand specified \f(CWLibdwarf\fP decides how many operands are +meaningful for the operand. It also converts the operands to the +appropriate datatypes (they are passed to \f(CWdwarf_add_fde_inst\fP +as \f(CWDwarf_Unsigned\fP). + +It returns the given \f(CWfde\fP on success, and \f(CWDW_DLV_BADADDR\fP +on error. + +.H 3 "dwarf_insert_fde_inst_bytes()" +.DS +\f(CWint dwarf_insert_fde_inst_bytes( + Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_Unsigned len, + Dwarf_Ptr ibytes, + Dwarf_Error *error)\fP +.DE +The function \f(CWdwarf_insert_fde_inst_bytes()\fP inserts +the byte array (pointed at by \f(CWibytes\fP and of length \f(CWlen\fP) +of frame instructions into the fde \f(CWfde\fP. +It is incompatible with \f(CWdwarf_add_fde_inst()\fP, do not use +both functions on any given Dwarf_P_Debug. +At present it may only be called once on a given \f(CWfde\fP. +The \f(CWlen\fP bytes \f(CWibytes\fP may be constructed in any way, but +the assumption is they were copied from an object file +such as is returned by the libdwarf consumer function +\f(CWdwarf_get_fde_instr_bytes()\fP. + +It returns \f(CWDW_DLV_OK\fP on success, and \f(CWDW_DLV_ERROR\fP +on error. + + +.S +.TC 1 1 4 +.CS diff --git a/libdwarf/libdwarf2p.1.pdf b/libdwarf/libdwarf2p.1.pdf Binary files differnew file mode 100644 index 0000000..c353ff8 --- /dev/null +++ b/libdwarf/libdwarf2p.1.pdf diff --git a/libdwarf/libdwarfdefs.h b/libdwarf/libdwarfdefs.h new file mode 100644 index 0000000..83c8a42 --- /dev/null +++ b/libdwarf/libdwarfdefs.h @@ -0,0 +1,91 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +/* libdwarfdefs.h +*/ + +#ifndef LIBDWARFDEFS_H +#define LIBDWARFDEFS_H + +/* We want __uint32_t and __uint64_t and __int32_t __int64_t + properly defined but not duplicated, since duplicate typedefs + are not legal C. +*/ +/* + HAVE___UINT32_T + HAVE___UINT64_T will be set by configure if + our 4 types are predefined in compiler +*/ + + +#if (!defined(HAVE___UINT32_T)) && defined(HAVE___UINT32_T_IN_SGIDEFS_H) +#include <sgidefs.h> /* sgidefs.h defines them */ +#define HAVE___UINT32_T 1 +#endif + +#if (!defined(HAVE___UINT64_T)) && defined(HAVE___UINT64_T_IN_SGIDEFS_H) +#include <sgidefs.h> /* sgidefs.h defines them */ +#define HAVE___UINT64_T 1 +#endif + + +#if (!defined(HAVE___UINT32_T)) && \ + defined(HAVE_SYS_TYPES_H) && \ + defined(HAVE___UINT32_T_IN_SYS_TYPES_H) +# include <sys/types.h> +#define HAVE___UINT32_T 1 +#endif + +#if (!defined(HAVE___UINT64_T)) && \ + defined(HAVE_SYS_TYPES_H) && \ + defined(HAVE___UINT64_T_IN_SYS_TYPES_H) +# include <sys/types.h> +#define HAVE___UINT64_T 1 +#endif + +#ifndef HAVE___UINT32_T +typedef int __int32_t; +typedef unsigned __uint32_t; +#define HAVE___UINT32_T 1 +#endif + +#ifndef HAVE___UINT64_T +typedef long long __int64_t; +typedef unsigned long long __uint64_t; +#define HAVE___UINT64_T 1 +#endif + +#endif /* LIBDWARFDEFS_H */ diff --git a/libdwarf/malloc_check.c b/libdwarf/malloc_check.c new file mode 100644 index 0000000..35a1483 --- /dev/null +++ b/libdwarf/malloc_check.c @@ -0,0 +1,339 @@ +/* + + Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +/* malloc_check.c For checking dealloc completeness. + + This code is as simple as possible and works ok for + reasonable size allocation counts. + + It treats allocation as global, and so will not + work very well if an application opens more than one + Dwarf_Debug. + +*/ + +#include <stdio.h> +#include <stdlib.h> /* for exit() and various malloc + prototypes */ +#include "config.h" +#include "dwarf_incl.h" +#include "malloc_check.h" +#ifdef WANT_LIBBDWARF_MALLOC_CHECK + +/* To turn off printing every entry, just change the define + to set PRINT_MALLOC_DETAILS 0. +*/ +#define PRINT_MALLOC_DETAILS 0 + +#define MC_TYPE_UNKNOWN 0 +#define MC_TYPE_ALLOC 1 +#define MC_TYPE_DEALLOC 2 + +struct mc_data_s { + struct mc_data_s *mc_prev; + unsigned long mc_address; /* Assumes this is large enough to hold + a pointer! */ + + long mc_alloc_number; /* Assigned in order by when record + created. */ + unsigned char mc_alloc_code; /* Allocation code, libdwarf. */ + unsigned char mc_type; + unsigned char mc_dealloc_noted; /* Used on an ALLOC node. */ + unsigned char mc_dealloc_noted_count; /* Used on an ALLOC + node. */ +}; + +/* + + +*/ +#define HASH_TABLE_SIZE 10501 +static struct mc_data_s *mc_data_hash[HASH_TABLE_SIZE]; +static long mc_data_list_size = 0; + +static char *alloc_type_name[MAX_DW_DLA + 1] = { + "", + "DW_DLA_STRING", + "DW_DLA_LOC", + "DW_DLA_LOCDESC", + "DW_DLA_ELLIST", + "DW_DLA_BOUNDS", + "DW_DLA_BLOCK", + "DW_DLA_DEBUG", + "DW_DLA_DIE", + "DW_DLA_LINE", + "DW_DLA_ATTR", + "DW_DLA_TYPE", + "DW_DLA_SUBSCR", + "DW_DLA_GLOBAL", + "DW_DLA_ERROR", + "DW_DLA_LIST", + "DW_DLA_LINEBUF", + "DW_DLA_ARANGE", + "DW_DLA_ABBREV", + "DW_DLA_FRAME_OP", + "DW_DLA_CIE", + "DW_DLA_FDE", + "DW_DLA_LOC_BLOCK", + "DW_DLA_FRAME_BLOCK", + "DW_DLA_FUNC", + "DW_DLA_TYPENAME", + "DW_DLA_VAR", + "DW_DLA_WEAK", + "DW_DLA_ADDR", + "DW_DLA_ABBREV_LIST", + "DW_DLA_CHAIN", + "DW_DLA_CU_CONTEXT", + "DW_DLA_FRAME", + "DW_DLA_GLOBAL_CONTEXT", + "DW_DLA_FILE_ENTRY", + "DW_DLA_LINE_CONTEXT", + "DW_DLA_LOC_CHAIN", + "DW_DLA_HASH_TABLE", + "DW_DLA_FUNC_CONTEXT", + "DW_DLA_TYPENAME_CONTEXT", + "DW_DLA_VAR_CONTEXT", + "DW_DLA_WEAK_CONTEXT", + "DW_DLA_PUBTYPES_CONTEXT" + /* Don't forget to expand this list if the list of codes + expands. */ +}; + +static unsigned +hash_address(unsigned long addr) +{ + unsigned long a = addr >> 2; + + return a % HASH_TABLE_SIZE; +} + +#if PRINT_MALLOC_DETAILS +static void +print_alloc_dealloc_detail(unsigned long addr, + int code, char *whichisit) +{ + fprintf(stderr, + "%s addr 0x%lx code %d (%s) entry %ld\n", + whichisit, addr, code, alloc_type_name[code], + mc_data_list_size); +} +#else +#define print_alloc_dealloc_detail(a,b,c) /* nothing */ +#endif + +/* Create a zeroed struct or die. */ +static void * +newone(void) +{ + struct mc_data_s *newd = malloc(sizeof(struct mc_data_s)); + + if (newd == 0) { + fprintf(stderr, "out of memory , # %ld\n", mc_data_list_size); + exit(1); + } + memset(newd, 0, sizeof(struct mc_data_s)); + return newd; +} + +/* Notify checker that get_alloc has allocated user data. */ +void +dwarf_malloc_check_alloc_data(void *addr_in, unsigned char code) +{ + struct mc_data_s *newd = newone(); + unsigned long addr = (unsigned long) addr_in; + struct mc_data_s **base = &mc_data_hash[hash_address(addr)]; + + print_alloc_dealloc_detail(addr, code, "alloc "); + newd->mc_address = addr; + newd->mc_alloc_code = code; + newd->mc_type = MC_TYPE_ALLOC; + newd->mc_alloc_number = mc_data_list_size; + newd->mc_prev = *base; + *base = newd; + newd->mc_alloc_number = mc_data_list_size; + mc_data_list_size += 1; +} + +static void +print_entry(char *msg, struct mc_data_s *data) +{ + fprintf(stderr, + "%s: 0x%08lx code %2d (%s) type %s dealloc noted %u ct %u\n", + msg, + (long) data->mc_address, + data->mc_alloc_code, + alloc_type_name[data->mc_alloc_code], + (data->mc_type == MC_TYPE_ALLOC) ? "alloc " : + (data->mc_type == MC_TYPE_DEALLOC) ? "dealloc" : "unknown", + (unsigned) data->mc_dealloc_noted, + (unsigned) data->mc_dealloc_noted_count); +} + +/* newd is a 'dealloc'. +*/ +static long +balanced_by_alloc_p(struct mc_data_s *newd, + long *addr_match_num, + struct mc_data_s **addr_match, + struct mc_data_s *base) +{ + struct mc_data_s *cur = base; + + for (; cur; cur = cur->mc_prev) { + if (cur->mc_address == newd->mc_address) { + if (cur->mc_type == MC_TYPE_ALLOC) { + if (cur->mc_alloc_code == newd->mc_alloc_code) { + *addr_match = cur; + *addr_match_num = cur->mc_alloc_number; + return cur->mc_alloc_number; + } else { + /* code mismatch */ + *addr_match = cur; + *addr_match_num = cur->mc_alloc_number; + return -1; + } + } else { + /* Unbalanced new/del */ + *addr_match = cur; + *addr_match_num = cur->mc_alloc_number; + return -1; + } + } + } + return -1; +} + +/* A dealloc is to take place. Ensure it balances an alloc. +*/ +void +dwarf_malloc_check_dealloc_data(void *addr_in, unsigned char code) +{ + struct mc_data_s *newd = newone(); + long prev; + long addr_match_num = -1; + struct mc_data_s *addr_match = 0; + unsigned long addr = (unsigned long) addr_in; + struct mc_data_s **base = &mc_data_hash[hash_address(addr)]; + + + print_alloc_dealloc_detail(addr, code, "dealloc "); + newd->mc_address = (unsigned long) addr; + newd->mc_alloc_code = code; + newd->mc_type = MC_TYPE_DEALLOC; + newd->mc_prev = *base; + prev = + balanced_by_alloc_p(newd, &addr_match_num, &addr_match, *base); + if (prev < 0) { + fprintf(stderr, + "Unbalanced dealloc at index %ld\n", mc_data_list_size); + print_entry("new", newd); + fprintf(stderr, "addr-match_num? %ld\n", addr_match_num); + if (addr_match) { + print_entry("prev entry", addr_match); + if (addr_match->mc_dealloc_noted > 1) { + fprintf(stderr, "Above is Duplicate dealloc!\n"); + } + } + abort(); + exit(3); + } + addr_match->mc_dealloc_noted = 1; + addr_match->mc_dealloc_noted_count += 1; + if (addr_match->mc_dealloc_noted_count > 1) { + fprintf(stderr, "Double dealloc entry %ld\n", addr_match_num); + print_entry("new dealloc entry", newd); + print_entry("bad alloc entry", addr_match); + } + *base = newd; + mc_data_list_size += 1; +} + +/* Final check for leaks. +*/ +void +dwarf_malloc_check_complete(char *msg) +{ + long i = 0; + long total = mc_data_list_size; + long hash_slots_used = 0; + long max_chain_length = 0; + + fprintf(stderr, "Run complete, %s. %ld entries\n", msg, total); + for (; i < HASH_TABLE_SIZE; ++i) { + struct mc_data_s *cur = mc_data_hash[i]; + long cur_chain_length = 0; + + if (cur == 0) + continue; + ++hash_slots_used; + for (; cur; cur = cur->mc_prev) { + ++cur_chain_length; + if (cur->mc_type == MC_TYPE_ALLOC) { + if (cur->mc_dealloc_noted) { + if (cur->mc_dealloc_noted > 1) { + fprintf(stderr, + " Duplicate dealloc! entry %ld\n", + cur->mc_alloc_number); + print_entry("duplicate dealloc", cur); + + } + continue; + } else { + fprintf(stderr, "malloc no dealloc, entry %ld\n", + cur->mc_alloc_number); + print_entry("dangle", cur); + } + } else { + /* mc_type is MC_TYPE_DEALLOC, already checked */ + + } + } + if (cur_chain_length > max_chain_length) { + max_chain_length = cur_chain_length; + } + } + fprintf(stderr, "mc hash table slots=%ld, " + "used=%ld, maxchain=%ld\n", + (long) HASH_TABLE_SIZE, hash_slots_used, max_chain_length); + return; +} + +#else + +extern void *libdwarf_an_unused_function_so_not_empty_c_file(); + +#endif /* WANT_LIBBDWARF_MALLOC_CHECK */ diff --git a/libdwarf/malloc_check.h b/libdwarf/malloc_check.h new file mode 100644 index 0000000..ba1ad3d --- /dev/null +++ b/libdwarf/malloc_check.h @@ -0,0 +1,62 @@ +/* + + Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +/* malloc_check.h */ + +/* A simple libdwarf-aware malloc checker. + define WANT_LIBBDWARF_MALLOC_CHECK and rebuild libdwarf + do make a checking-for-alloc-mistakes libdwarf. + NOT recommended for production use. + + When defined, also add malloc_check.c to the list of + files in Makefile. +*/ + +#undef WANT_LIBBDWARF_MALLOC_CHECK +/*#define WANT_LIBBDWARF_MALLOC_CHECK 1 */ + +#ifdef WANT_LIBBDWARF_MALLOC_CHECK + +void dwarf_malloc_check_alloc_data(void * addr,unsigned char code); +void dwarf_malloc_check_dealloc_data(void * addr,unsigned char code); +void dwarf_malloc_check_complete(char *wheremsg); /* called at exit of app */ + +#else /* !WANT_LIBBDWARF_MALLOC_CHECK */ + +#define dwarf_malloc_check_alloc_data(a,b) /* nothing */ +#define dwarf_malloc_check_dealloc_data(a,b) /* nothing */ +#define dwarf_malloc_check_complete(a) /* nothing */ + +#endif /* WANT_LIBBDWARF_MALLOC_CHECK */ diff --git a/libdwarf/mips_extensions.mm b/libdwarf/mips_extensions.mm new file mode 100644 index 0000000..7a312f0 --- /dev/null +++ b/libdwarf/mips_extensions.mm @@ -0,0 +1,1266 @@ +\." +\." the following line may be removed if the ff ligature works on your machine +.lg 0 +\." set up heading formats +.ds HF 3 3 3 3 3 2 2 +.ds HP +2 +2 +1 +0 +0 +.nr Hs 5 +.nr Hb 5 +\." ============================================== +\." Put current date in the following at each rev +.ds vE rev 1.18, 31 March 2005 +\." ============================================== +\." ============================================== +.ds | | +.ds ~ ~ +.ds ' ' +.if t .ds Cw \&\f(CW +.if n .ds Cw \fB +.de Cf \" Place every other arg in Cw font, beginning with first +.if \\n(.$=1 \&\*(Cw\\$1\fP +.if \\n(.$=2 \&\*(Cw\\$1\fP\\$2 +.if \\n(.$=3 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP +.if \\n(.$=4 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4 +.if \\n(.$=5 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP +.if \\n(.$=6 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6 +.if \\n(.$=7 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP +.if \\n(.$=8 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8 +.if \\n(.$=9 \&\*(Cw\\$1\fP\\$2\*(Cw\\$3\fP\\$4\*(Cw\\$5\fP\\$6\*(Cw\\$7\fP\\$8\ +*(Cw +.. +.nr Cl 4 +.SA 1 +.TL +MIPS Extensions to DWARF Version 2.0 +.AF "" +.AU "Silicon Graphics Computer Systems" +.PF "'\*(vE'- \\\\nP -''" +.AS 1 +This document describes the MIPS/Silicon Graphics extensions +to the "DWARF Information Format" (version 2.0.0 dated July 27, 1993). +DWARF3 draft 8 (or draft 9) is out as of 2005, and +is mentioned below where applicable. +MIPS/IRIX compilers emit DWARF2 (with extensions). +.P +Rather than alter the base documents to describe the extensions +we provide this separate document. +.P +The extensions documented here are subject to change. +.P +It also describes known bugs resulting in incorrect dwarf usage. +.P +\*(vE + +.AE +.MT 4 + +.H 1 "INTRODUCTION" +.P +This +document describes MIPS extensions +to the DWARF debugging information format. +The extensions documented here are subject to change at +any time. +.H 1 "64 BIT DWARF" +.P +The DWARF2 spec has no provision for 64 bit offsets. +SGI-IRIX/MIPS Elf64 objects contain DWARF 2 with all offsets +(and addresses) as 64bit values. +This non-standard extension was adopted in 1992. +Nothing in the dwarf itself identifies the dwarf as 64bit. +This extension 64bit-offset dwarf cannot be mixed with 32bit-offset dwarf +in a single object or executable, and SGI-IRIX/MIPS compilers +and tools do not mix the sizes. +.P +In 2001 DWARF3 adopted a very different 64bit-offset +format which can be mixed usefully with 32bit-offset DWARF2 or DWARF3. +It is not very likely SGI-IRIX/MIPS compilers will switch to the +now-standard +DWARF3 64bit-offset scheme, but such a switch is theoretically +possible and would be a good idea. +.P +SGI-IRIX/MIPS Elf32 objects +contain DWARF2 with all offsets (and addresses) 32 bits. +.H 1 "How much symbol information is emitted" +The following standard DWARF V2 sections may be emitted: +.AL +.LI +Section .debug_abbrev +contains +abbreviations supporting the .debug_info section. +.LI +Section .debug_info +contains +Debug Information Entries (DIEs). +.LI +Section .debug_frame +contains +stack frame descriptions. +.LI +Section .debug_line +contains +line number information. +.LI +Section .debug_aranges +contains +address range descriptions. +.LI +Section .debug_pubnames +contains +names of global functions and data. +.P +The following +are MIPS extensions. +Theses were created to allow debuggers to +know names without having to look at +the .debug_info section. +.LI +Section .debug_weaknames +is a MIPS extension +containing .debug_pubnames-like entries describing weak +symbols. +.LI +Section .debug_funcnames +is a MIPS extension +containing .debug_pubnames-like entries describing file-static +functions (C static functions). +The gcc extension of nested subprograms (like Pascal) +adds non-global non-static functions. These should be treated like +static functions and gcc should add such to this section +so that IRIX libexc(3C) will work correctly. +Similarly, Ada functions which are non-global should be here too +so that libexc(3C) can work. +Putting it another way, every function (other than inline code) +belongs either in .debug_pubnames or in .debug_funcnames +or else libexc(3C) cannot find the function name. +.LI +Section .debug_varnames +is a MIPS extension +containing .debug_pubnames-like entries describing file-static +data symbols (C static variables). +.LI +Section .debug_typenames +is a MIPS extension +containing .debug_pubnames-like entries describing file-level +types. +.P +The following are not currently emitted. +.LI +Section .debug_macinfo +Macro information is not currently emitted. +.LI +Section .debug_loc +Location lists are not currently emitted. +.LI +Section .debug_str +The string section is not currently emitted. +.LE +.H 2 "Overview of information emitted" +We emit debug information in 3 flavors. +We mention C here. +The situation is essentially identical for f77, f90, and C++. +.AL +.LI +"default C" +We emit line information and DIEs for each subprogram. +But no local symbols and no type information. +Frame information is output. +The DW_AT_producer string has the optimization level: for example +"-O2". +We put so much in the DW_AT_producer that the string +is a significant user of space in .debug_info -- +this is perhaps a poor use of space. +When optimizing the IRIX CC/cc option -DEBUG:optimize_space +eliminates such wasted space. +Debuggers only currently use the lack of -g +of DW_AT_producer +as a hint as to how a 'step' command should be interpreted, and +the rest of the string is not used for anything (unless +a human looks at it for some reason), so if space-on-disk +is an issue, it is quite appropriate to use -DEBUG:optimize_space +and save disk space. +Every function definition (not inline instances though) is mentioned +in either .debug_pubnames or .debug_funcnames. +This is crucial to allow libexc(3C) stack-traceback to work and +show function names (for all languages). +.LI +"C with full symbols" +All possible info is emitted. +DW_AT_producer string has all options that might be of interest, +which includes -D's, -U's, and the -g option. +These options look like they came from the command line. +We put so much in the DW_AT_producer that the string +is a significant user of space in .debug_info. +this is perhaps a poor use of space. +Debuggers only currently use the -g +of DW_AT_producer +as a hint as to how a 'step' command should be interpreted, and +the rest of the string is not used for anything (unless +a human looks at it for some reason). +Every function definition (not inline instances though) is mentioned +in either .debug_pubnames or .debug_funcnames. +This is crucial to allow libexc(3C) stack-traceback to work and +show function names (for all languages). +.LI +"Assembler (-g, non -g are the same)" +Frame information is output. +No type information is emitted, but DIEs are prepared +for globals. +.LE +.H 2 "Detecting 'full symbols' (-g)" +The debugger depends on the existence of +the DW_AT_producer string to determine if the +compilation unit has full symbols or not. +It looks for -g or -g[123] and accepts these as +full symbols but an absent -g or a present -g0 +is taken to mean that only basic symbols are defined and there +are no local symbols and no type information. +.P +In various contexts the debugger will think the program is +stripped or 'was not compiled with -g' unless the -g +is in the DW_AT_producer string. +.H 2 "DWARF and strip(1)" +The DWARF section ".debug_frame" is marked SHF_MIPS_NOSTRIP +and is not stripped by the strip(1) program. +This is because the section is needed for doing +stack back traces (essential for C++ +and Ada exception handling). +.P +All .debug_* sections are marked with elf type +SHT_MIPS_DWARF. +Applications needing to access the various DWARF sections +must use the section name to discriminate between them. + +.H 2 "Evaluating location expressions" +When the debugger evaluates location expressions, it does so +in 2 stages. In stage one it simply looks for the trivial +location expressions and treats those as special cases. +.P +If the location expression is not trivial, it enters stage two. +In this case it uses a stack to evaluate the expression. +.P +If the application is a 32-bit application, it does the operations +on 32-bit values (address size values). Even though registers +can be 64 bits in a 32-bit program all evaluations are done in +32-bit quantities, so an attempt to calculate a 32-bit quantity +by taking the difference of 2 64-bit register values will not +work. The notion is that the stack machine is, by the dwarf +definition, working in address size units. +.P +These values are then expanded to 64-bit values (addresses or +offsets). This extension does not involve sign-extension. +.P +If the application is a 64-bit application, then the stack +values are all 64 bits and all operations are done on 64 bits. +.H 3 "The fbreg location op" +Compilers shipped with IRIX 6.0 and 6.1 +do not emit the fbreg location expression +and never emit the DW_AT_frame_base attribute that it +depends on. +However, this changes +with release 6.2 and these are now emitted routinely. + +.H 1 "Frame Information" +.H 2 "Initial Instructions" +The DWARF V2 spec +provides for "initial instructions" in each CIE (page 61, +section 6.4.1). +However, it does not say whether there are default +values for each column (register). +.P +Rather than force every CIE to have a long list +of bytes to initialize all 32 integer registers, +we define that the default values of all registers +(as returned by libdwarf in the frame interface) +are 'same value'. +This is a good choice for many non-register-windows +implementations. +.H 2 "Augmentation string in debug_frame" +The augmentation string we use in shipped compilers (up thru +irix6.2) is the empty string. +IRIX6.2 and later has an augmentation string +the empty string ("") +or "z" or "mti v1" +where the "v1" is a version number (version 1). +.P +We do not believe that "mti v1" was emitted as the +augmentation string in any shipped compiler. +.P +.H 3 "CIE processing based on augmentation string:" +If the augmentation string begins with 'z', then it is followed +immediately by a unsigned_leb_128 number giving the code alignment factor. +Next is a signed_leb_128 number giving the data alignment factor. +Next is a unsigned byte giving the number of the return address register. +Next is an unsigned_leb_128 number giving the length of the 'augmentation' +fields (the length of augmentation bytes, not +including the unsigned_leb_128 length itself). +As of release 6.2, the length of the CIE augmentation fields is 0. +What this means is that it is possible to add new +augmentations, z1, z2, etc and yet an old consumer to +understand the entire CIE as it can bypass the +augmentation it does not understand because the +length of the augmentation fields is present. +Presuming of course that all augmentation fields are +simply additional information, +not some 'changing of the meaning of +an existing field'. +Currently there is no CIE data in the augmentation for things +beginning with 'z'. +.P +If the augmentation string is "mti v1" or "" then it is followed +immediately by a unsigned_leb_128 number giving the code alignment factor. +Next is a signed_leb_128 number giving the data alignment factor. +Next is a unsigned byte giving the number of the return address register. +.P +If the augmentation string is something else, then the +code alignment factor is assumed to be 4 and the data alignment +factor is assumed to be -1 and the return +address register is assumed to be 31. Arbitrarily. +The library (libdwarf) assumes it does not understand the rest of the CIE. +.P +.H 3 "FDE processing based on augmentation" +If the CIE augmentation string +for an fde begins with 'z' +then the next FDE field after the address_range field +is an +unsigned_leb_128 number giving the length of the 'augmentation' +fields, and those fields follow immediately. + +.H 4 "FDE augmentation fields" +.P +If the CIE augmentation string is "mti v1" or "" +then the FDE is exactly as described in the Dwarf Document section 6.4.1. +.P +Else, if the CIE augmentation string begins with "z" +then the next field after the FDE augmentation length field +is a Dwarf_Sword size offset into +exception tables. +If the CIE augmentation string does not begin with "z" +(and is neither "mti v1" nor "") +the FDE augmentation fields are skipped (not understood). +Note that libdwarf actually (as of MIPSpro7.3 and earlier) +only tests that the initial character of the augmentation +string is 'z', and ignores the rest of the string, if any. +So in reality the test is for a _prefix_ of 'z'. +.P +If the CIE augmentation string neither starts with 'z' nor is "" +nor is "mti v1" then libdwarf (incorrectly) assumes that the +table defining instructions start next. +Processing (in libdwarf) will be incorrect. +.H 2 "Stack Pointer recovery from debug_frame" +There is no identifiable means in +DWARF2 to say that the stack register is +recovered by any particular operation. +A 'register rule' works if the caller's +stack pointer was copied to another +register. +An 'offset(N)' rule works if the caller's +stack pointer was stored on the stack. +However if the stack pointer is +some register value plus/minus some offset, +there is no means to say this in an FDE. +For MIPS/IRIX, the recovered stack pointer +of the next frame up the stack (towards main()) +is simply the CFA value of the current +frame, and the CFA value is +precisely a register (value of a register) +or a register plus offset (value of a register +plus offset). This is a software convention. +.H 1 "egcs dwarf extensions (egcs-1.1.2 extensions)" +This and following egcs sections describe +the extensions currently shown in egcs dwarf2. +Note that egcs has chosen to adopt tag and +attribute naming as if their choices were +standard dwarf, not as if they were extensions. +However, they are properly numbered as extensions. + +.H 2 "DW_TAG_format_label 0x4101" +For FORTRAN 77, Fortran 90. +Details of use not defined in egcs source, so +unclear if used. +.H 2 "DW_TAG_function_template 0x4102" +For C++. +Details of use not defined in egcs source, so +unclear if used. +.H 2 "DW_TAG_class_template 0x4103" +For C++. +Details of use not defined in egcs source, so +unclear if used. +.H 2 "DW_AT_sf_names 0x2101" +Apparently only output in DWARF1, not DWARF2. +.H 2 "DW_AT_src_info 0x2102" +Apparently only output in DWARF1, not DWARF2. +.H 2 "DW_AT_mac_info 0x2103" +Apparently only output in DWARF1, not DWARF2. +.H 2 "DW_AT_src_coords 0x2104" +Apparently only output in DWARF1, not DWARF2. +.H 2 "DW_AT_body_begin 0x2105" +Apparently only output in DWARF1, not DWARF2. +.H 2 "DW_AT_body_end 0x2106" +Apparently only output in DWARF1, not DWARF2. + +.H 1 "egcs .eh_frame (non-sgi) (egcs-1.1.2 extensions)" +egcs-1.1.2 (and earlier egcs) +emits by default a section named .eh_frame +for ia32 (and possibly other platforms) which +is nearly identical to .debug_frame in format and content. +This section is used for helping handle C++ exceptions. +.P +Because after linking there are sometimes zero-ed out bytes +at the end of the eh_frame section, the reader code in +dwarf_frame.c considers a zero cie/fde length as an indication +that it is the end of the section. +.P +.H 2 "CIE_id 0" +The section is an ALLOCATED section in an executable, and +is therefore mapped into memory at run time. +The CIE_pointer (aka CIE_id, section 6.4.1 +of the DWARF2 document) is the field that +distinguishes a CIE from an FDE. +The designers of the egcs .eh_frame section +decided to make the CIE_id +be 0 as the CIE_pointer definition is +.in +2 +the number of bytes from the CIE-pointer in the FDE back to the +applicable CIE. +.in -2 +In a dwarf .debug_frame section, the CIE_pointer is the +offset in .debug_frame of the CIE for this fde, and +since an offset can be zero of some CIE, the CIE_id +cannot be 0, but must be all 1 bits . +Note that the dwarf2.0 spec does specify the value of CIE_id +as 0xffffffff +(see section 7.23 of v2.0.0), +though earlier versions of this extensions document +incorrectly said it was not specified in the dwarf +document. +.H 2 "augmentation eh" +The augmentation string in each CIE is "eh" +which, with its following NUL character, aligns +the following word to a 32bit boundary. +Following the augmentation string is a 32bit +word with the address of the __EXCEPTION_TABLE__, +part of the exception handling data for egcs. +.H 2 "DW_CFA_GNU_window_save 0x2d" +This is effectively a flag for architectures with +register windows, and tells the unwinder code that +it must look to a previous frame for the +correct register window set. +As of this writing, egcs gcc/frame.c +indicates this is for SPARC register windows. +.H 2 "DW_CFA_GNU_args_size 0x2e" +DW_CFA_GNU_args_size has a single uleb128 argument +which is the size, in bytes, of the function's stack +at that point in the function. +.H 2 "__EXCEPTION_TABLE__" +A series of 3 32bit word entries by default: +0 word: low pc address +1 word: high pc address +2 word: pointer to exception handler code +The end of the table is +signaled by 2 words of -1 (not 3 words!). +.H 1 "Interpretations of the DWARF V2 spec" +.H 2 "template TAG spellings" +The DWARF V2 spec spells two attributes in two ways. +DW_TAG_template_type_param +(listed in Figure 1, page 7) +is spelled DW_TAG_template_type_parameter +in the body of the document (section 3.3.7, page 28). +We have adopted the spelling +DW_TAG_template_type_param. +.P +DW_TAG_template_value_param +(listed in Figure 1, page 7) +is spelled DW_TAG_template_value_parameter +in the body of the document (section 3.3.7, page 28). +We have adopted the spelling +DW_TAG_template_value_parameter. +.P +We recognize that the choices adopted are neither consistently +the longer nor the shorter name. +This inconsistency was an accident. +.H 2 DW_FORM_ref_addr confusing +Section 7.5.4, Attribute Encodings, describes +DW_FORM_ref_addr. +The description says the reference is the size of an address +on the target architecture. +This is surely a mistake, because on a 16bit-pointer-architecture +it would mean that the reference could not exceed +16 bits, which makes only +a limited amount of sense as the reference is from one +part of the dwarf to another, and could (in theory) +be *on the disk* and not limited to what fits in memory. +Since MIPS is 32 bit pointers (at the smallest) +the restriction is not a problem for MIPS/SGI. +The 32bit pointer ABIs are limited to 32 bit section sizes +anyway (as a result of implementation details). +And the 64bit pointer ABIs currently have the same limit +as a result of how the compilers and tools are built +(this has not proven to be a limit in practice, so far). +.P +This has been clarified in the DWARF3 spec and the IRIX use +of DW_FORM_ref_addr being an offset is correct. +.H 2 "Section .debug_macinfo in a debugger" +It seems quite difficult, in general, to +tie specific text(code) addresses to points in the +stream of macro information for a particular compilation unit. +So it's been difficult to see how to design a consumer +interface to libdwarf for macro information. +.P +The best (simple to implement, easy for a debugger user to +understand) candidate seems to be that +the debugger asks for macros of a given name in a compilation +unit, and the debugger responds with *all* the macros of that name. +.H 3 "only a single choice exists" +If there is exactly one, that is usable in expressions, if the +debugger is able to evaluate such. +.H 3 "multiple macros with same name". +If there are multiple macros with the same name +in a compilation unit, +the debugger (and the debugger user and the application +programmer) have +a problem: confusion is quite possible. +If the macros are simple the +debugger user can simply substitute by hand in an expression. +If the macros are complicated hand substitution will be +impractical, and the debugger will have to identify the +choices and let the debugger user choose an interpretation. +.H 2 "Section 6.1.2 Lookup by address problem" +Each entry is a beginning-address followed by a length. +And the distinguished entry 0,0 is used to denote +the end of a range of entries. +.P +This means that one must be careful not to emit a zero length, +as in a .o (object file) the beginning address of +a normal entry might be 0 (it is a section offset after all), +and the resulting 0,0 would be taken as end-of-range, not +as a valid entry. +A dwarf dumper would have trouble with such data +in an object file. +.P +In an a.out or shared object (dynamic shared object, DSO) +no text will be at address zero so in such this problem does +not arise. +.H 2 "Section 5.10 Subrange Type Entries problem" +It is specified that DW_AT_upper_bound (and lower bound) +must be signed entries if there is no object type +info to specify the bound type (Sec 5.10, end of section). +One cannot tell (with some +dwarf constant types) what the signedness is from the +form itself (like DW_FORM_data1), so it is necessary +to determine the object and type according to the rules +in 5.10 and then if all that fails, the type is signed. +It's a bit complicated and earlier versions of mips_extensions +incorrectly said signedness was not defined. +.H 2 "Section 5.5.6 Class Template Instantiations problem" +Lots of room for implementor to canonicalize +template declarations. Ie various folks won't agree. +This is not serious since a given compiler +will be consistent with itself and debuggers +will have to cope! +.H 2 "Section 2.4.3.4 # 11. operator spelling" +DW_OP_add should be DW_OP_plus (page 14) +(this mistake just one place on the page). +.H 2 "No clear specification of C++ static funcs" +There is no clear way to tell if a C++ member function +is a static member or a non-static member function. +(dwarf2read.c in gdb 4.18, for example, has this observation) +.H 2 "Misspelling of DW_AT_const_value" +Twice in appendix 1, DW_AT_const_value is misspelled +as DW_AT_constant_value. +.H 2 "Mistake in Atribute Encodings" +Section 7.5.4, "Attribute Encodings" +has a brief discussion of "constant" +which says there are 6 forms of constants. +It is incorrect in that it fails to mention (or count) +the block forms, which are clearly allowed by +section 4.1 "Data Object Entries" (see entry number 9 in +the numbered list, on constants). +.H 2 "DW_OP_bregx" +The description of DW_OP_bregx in 2.4.3.2 (Register Based +Addressing) is slightly misleading, in that it +lists the offset first. +As section 7.7.1 (Location Expression) +makes clear, in the encoding the register number +comes first. +.H 1 "MIPS attributes" +.H 2 "DW_AT_MIPS_fde" +This extension to Dwarf appears only on subprogram TAGs and has as +its value the offset, in the .debug_frame section, of the fde which +describes the frame of this function. It is an optimization of +sorts to have this present. + +.H 2 "DW_CFA_MIPS_advance_loc8 0x1d" +This obvious extension to dwarf line tables enables encoding of 8 byte +advance_loc values (for cases when such must be relocatable, +and thus must be full length). Applicable only to 64-bit objects. + +.H 2 "DW_TAG_MIPS_loop 0x4081" +For future use. Not currently emitted. +Places to be emitted and attributes that this might own +not finalized. + +.H 2 "DW_AT_MIPS_loop_begin 0x2002" +For future use. Not currently emitted. +Attribute form and content not finalized. + +.H 2 "DW_AT_MIPS_tail_loop_begin 0x2003" +For future use. Not currently emitted. +Attribute form and content not finalized. + +.H 2 "DW_AT_MIPS_epilog_begin 0x2004" +For future use. Not currently emitted. +Attribute form and content not finalized. + +.H 2 "DW_AT_MIPS_loop_unroll_factor 0x2005" +For future use. Not currently emitted. +Attribute form and content not finalized. + +.H 2 "DW_AT_MIPS_software_pipeline_depth 0x2006" +For future use. Not currently emitted. +Attribute form and content not finalized. +.H 2 "DW_AT_MIPS_linkage_name 0x2007" +The rules for mangling C++ names are not part of the +C++ standard and are different for different versions +of C++. With this extension, the compiler emits +both the DW_AT_name for things with mangled names +(recall that DW_AT_name is NOT the mangled form) +and also emits DW_AT_MIPS_linkage_name whose value +is the mangled name. +.P +This makes looking for the mangled name in other linker +information straightforward. +It also is passed (by the debugger) to the +libmangle routines to generate names to present to the +debugger user. +.H 2 "DW_AT_MIPS_stride 0x2008" +F90 allows assumed shape arguments and pointers to describe +non-contiguous memory. A (runtime) descriptor contains address, +bounds and stride information - rank and element size is known +during compilation. The extent in each dimension is given by the +bounds in a DW_TAG_subrange_type, but the stride cannot be +represented in conventional dwarf. DW_AT_MIPS_stride was added as +an attribute of a DW_TAG_subrange_type to describe the +location of the stride. +Used in the MIPSpro 7.2 (7.2.1 etc) compilers. +.P +If the stride is constant (ie: can be inferred from the type in the +usual manner) DW_AT_MIPS_stride is absent. +.P +If DW_AT_MIPS_stride is present, the attribute contains a reference +to a DIE which describes the location holding the stride, and the +DW_AT_stride_size field of DW_TAG_array_type is ignored if +present. The value of the stride is the number of +4 byte words between +elements along that axis. +.P +This applies to +.nf +a) Intrinsic types whose size is greater + or equal to 4bytes ie: real*4,integer*8 + complex etc, but not character types. + +b) Derived types (ie: structs) of any size, + unless all components are of type character. +.fi + +.H 2 "DW_AT_MIPS_abstract_name 0x2009" +This attribute only appears in a DA_TAG_inlined_subroutine DIE. +The value of this attribute is a string. +When IPA inlines a routine and the abstract origin is +in another compilation unit, there is a problem with putting +in a reference, since the ordering and timing of the +creation of references is unpredicatable with reference to +the DIE and compilation unit the reference refers to. +.P +Since there may be NO ordering of the compilation units that +allows a correct reference to be done without some kind of patching, +and since even getting the information from one place to another +is a problem, the compiler simply passes the problem on to the debugger. +.P +The debugger must match the DW_AT_MIPS_abstract_name +in the concrete +inlined instance DIE +with the DW_AT_MIPS_abstract_name +in the abstract inlined subroutine DIE. +.P +A dwarf-consumer-centric view of this and other inline +issues could be expressed as follows: +.nf +If DW_TAG_subprogram + If has DW_AT_inline is abstract instance root + If has DW_AT_abstract_origin, is out-of-line instance + of function (need abstract origin for some data) + (abstract root in same CU (conceptually anywhere + a ref can reach, but reaching outside of CU is + a problem for ipa: see DW_AT_MIPS_abstract_name)) + If has DW_AT_MIPS_abstract_name is abstract instance + root( must have DW_AT_inline) and this name is used to + match with the abstract root + +If DW_TAG_inline_subroutine + Is concrete inlined subprogram instance. + If has DW_AT_abstract_origin, it is a CU-local inline. + If it has DW_AT_MIPS_abstract_name it is an + inline whose abstract root is in another file (CU). +.fi + +.H 2 "DW_AT_MIPS_clone_origin 0x200a" +This attribute appears only in a cloned subroutine. +The procedure is cloned from the same compilation unit. +The value of this attribute is a reference to +the original routine in this compilation unit. +.P +The 'original' routine means the routine which has all the +original code. The cloned routines will always have +been 'specialized' by IPA. +A routine with DW_AT_MIPS_clone_origin +will also have the DW_CC_nocall value of the DW_AT_calling_convention +attribute. + +.H 2 "DW_AT_MIPS_has_inlines 0x200b" +This attribute may appear in a DW_TAG_subprogram DIE. +If present and it has the value True, then the subprogram +has inlined functions somewhere in the body. +.P +By default, at startup, the debugger may not look for +inlined functions in scopes inside the outer function. +.P +This is a hint to the debugger to look for the inlined functions +so the debugger can set breakpoints on these in case the user +requests 'stop in foo' and foo is inlined. +.H 2 "DW_AT_MIPS_stride_byte 0x200c" +Created for f90 pointer and assumed shape +arrays. +Used in the MIPSpro 7.2 (7.2.1 etc) compilers. +A variant of DW_AT_MIPS_stride. +This stride is interpreted as a byte count. +Used for integer*1 and character arrays +and arrays of derived type +whose components are all character. +.H 2 "DW_AT_MIPS_stride_elem 0x200d" +Created for f90 pointer and assumed shape +arrays. +Used in the MIPSpro 7.2 (7.2.1 etc) compilers. +A variant of DW_AT_MIPS_stride. +This stride is interpreted as a byte-pair (2 byte) count. +Used for integer*2 arrays. +.H 2 "DW_AT_MIPS_ptr_dopetype 0x200e" +See following. +.H 2 "DW_AT_MIPS_allocatable_dopetype 0x200f" +See following. +.H 2 "DW_AT_MIPS_assumed_shape_dopetype 0x2010" +DW_AT_MIPS_assumed_shape_dopetype, DW_AT_MIPS_allocatable_dopetype, +and DW_AT_MIPS_ptr_dopetype have an attribute value +which is a reference to a Fortran 90 Dope Vector. +These attributes are introduced in MIPSpro7.3. +They only apply to f90 arrays (where they are +needed to describe arrays never properly described +before in debug information). +C, C++, f77, and most f90 arrays continue to be described +in standard dwarf. +.P +The distinction between these three attributes is the f90 syntax +distinction: keywords 'pointer' and 'allocatable' with the absence +of these keywords on an assumed shape array being the third case. +.P +A "Dope Vector" is a struct (C struct) which describes +a dynamically-allocatable array. +In objects with full debugging the C struct will be +in the dwarf information (of the f90 object, represented like C). +A debugger will use the link to find the main struct DopeVector +and will use that information to decode the dope vector. +At the outer allocatable/assumed-shape/pointer +the DW_AT_location points at the dope vector (so debugger +calculations use that as a base). +.H 2 "Overview of debugger use of dope vectors" +Fundamentally, we build two distinct +representations of the arrays and pointers. +One, in dwarf, represents the statically-representable +information (the types and +variable/type-names, without type size information). +The other, using dope vectors in memory, represents +the run-time data of sizes. +A debugger must process the two representations +in parallel (and merge them) to deal with user expressions in +a debugger. +.H 2 "Example f90 code for use in explanation" +[Note +We want dwarf output with *exactly* +this little (arbitrary) example. +Not yet available. +end Note] +Consider the following code. +.nf + type array_ptr + real :: myvar + real, dimension (:), pointer :: ap + end type array_ptr + + type (array_ptr), allocatable, dimension (:) :: arrays + + allocate (arrays(20)) + do i = 1,20 + allocate (arrays(i)%ap(i)) + end do +.fi +arrays is an allocatable array (1 dimension) whose size is +not known at compile time (it has +a Dope Vector). At run time, the +allocate statement creats 20 array_ptr dope vectors +and marks the base arrays dopevector as allocated. +The myvar variable is just there to add complexity to +the example :-) +.nf +In the loop, arrays(1)%ap(1) + is allocated as a single element array of reals. +In the loop, arrays(2)%ap(2) + is allocated as an array of two reals. +... +In the loop, arrays(20)%ap(20) + is allocated as an array of twenty reals. +.fi +.H 2 "the problem with standard dwarf and this example" +.sp +In dwarf, there is no way to find the array bounds of arrays(3)%ap, +for example, (which are 1:3 in f90 syntax) +since any location expression in an ap array lower bound +attribute cannot involve the 3 (the 3 is known at debug time and +does not appear in the running binary, so no way for the +location expression to get to it). +And of course the 3 must actually index across the array of +dope vectors in 'arrays' in our implementation, but that is less of +a problem than the problem with the '3'. +.sp +Plus dwarf has no way to find the 'allocated' flag in the +dope vector (so the debugger can know when the allocate is done +for a particular arrays(j)%ap). +.sp +Consequently, the calculation of array bounds and indices +for these dynamically created f90 arrays +is now pushed of into the debugger, which must know the +field names and usages of the dope vector C structure and +use the field offsets etc to find data arrays. +C, C++, f77, and most f90 arrays continue to be described +in standard dwarf. +At the outer allocatable/assumed-shape/pointer +the DW_AT_location points at the dope vector (so debugger +calculations use that as a base). +.P +It would have been nice to design a dwarf extension +to handle the above problems, but +the methods considered to date were not +any more consistent with standard dwarf than +this dope vector centric approach: essentially just +as much work in the debugger appeared necessary either way. +A better (more dwarf-ish) +design would be welcome information. + +.H 2 "A simplified sketch of the dwarf information" +[Note: +Needs to be written. +end Note] + +.H 2 "A simplified sketch of the dope vector information" +[Note: +This one is simplified. +Details left out that should be here. Amplify. +end Note] +This is an overly simplified version of a dope vector, +presented as an initial hint. +Full details presented later. +.nf +struct simplified{ + void *base; // pointer to the data this describes + long el_len; + int assoc:1 + int ptr_alloc:1 + int num_dims:3; + struct dims_s { + long lb; + long ext; + long str_m; + } dims[7]; +}; +.fi +Only 'num_dims' elements of dims[] are actually used. + +.H 2 "The dwarf information" + +Here is dwarf information from the compiler for +the example above, as printed by dwarfdump(1) +.nf +[Note: +The following may not be the test. +Having field names with '.' in the name is +not such a good idea, as it conflicts with the +use of '.' in dbx extended naming. +Something else, like _$, would be much easier +to work with in dbx (customers won't care about this, +for the most part, +but folks working on dbx will, and in those +rare circumstances when a customer cares, +the '.' will be a real problem in dbx.). +Note that to print something about .base., in dbx one +would have to do + whatis `.base.` +where that is the grave accent, or back-quote I am using. +With extended naming one do + whatis `.dope.`.`.base.` +which is hard to type and hard to read. +end Note] + +<2>< 388> DW_TAG_array_type + DW_AT_name .base. + DW_AT_type <815> + DW_AT_declaration yes(1) +<3>< 401> DW_TAG_subrange_type + DW_AT_lower_bound 0 + DW_AT_upper_bound 0 +<2>< 405> DW_TAG_pointer_type + DW_AT_type <388> + DW_AT_byte_size 4 + DW_AT_address_class 0 +<2>< 412> DW_TAG_structure_type + DW_AT_name .flds. + DW_AT_byte_size 28 +<3>< 421> DW_TAG_member + DW_AT_name el_len + DW_AT_type <815> + DW_AT_data_member_location DW_OP_consts 0 +<3>< 436> DW_TAG_member + DW_AT_name assoc + DW_AT_type <841> + DW_AT_byte_size 0 + DW_AT_bit_offset 0 + DW_AT_bit_size 1 + DW_AT_data_member_location DW_OP_consts 4 +<3>< 453> DW_TAG_member + DW_AT_name ptr_alloc + DW_AT_type <841> + DW_AT_byte_size 0 + DW_AT_bit_offset 1 + DW_AT_bit_size 1 + DW_AT_data_member_location DW_OP_consts 4 +<3>< 474> DW_TAG_member + DW_AT_name p_or_a + DW_AT_type <841> + DW_AT_byte_size 0 + DW_AT_bit_offset 2 + DW_AT_bit_size 2 + DW_AT_data_member_location DW_OP_consts 4 +<3>< 492> DW_TAG_member + DW_AT_name a_contig + DW_AT_type <841> + DW_AT_byte_size 0 + DW_AT_bit_offset 4 + DW_AT_bit_size 1 + DW_AT_data_member_location DW_OP_consts 4 +<3>< 532> DW_TAG_member + DW_AT_name num_dims + DW_AT_type <841> + DW_AT_byte_size 0 + DW_AT_bit_offset 29 + DW_AT_bit_size 3 + DW_AT_data_member_location DW_OP_consts 8 +<3>< 572> DW_TAG_member + DW_AT_name type_code + DW_AT_type <841> + DW_AT_byte_size 0 + DW_AT_bit_offset 0 + DW_AT_bit_size 32 + DW_AT_data_member_location DW_OP_consts 16 +<3>< 593> DW_TAG_member + DW_AT_name orig_base + DW_AT_type <841> + DW_AT_data_member_location DW_OP_consts 20 +<3>< 611> DW_TAG_member + DW_AT_name orig_size + DW_AT_type <815> + DW_AT_data_member_location DW_OP_consts 24 +<2>< 630> DW_TAG_structure_type + DW_AT_name .dope_bnd. + DW_AT_byte_size 12 +<3>< 643> DW_TAG_member + DW_AT_name lb + DW_AT_type <815> + DW_AT_data_member_location DW_OP_consts 0 +<3>< 654> DW_TAG_member + DW_AT_name ext + DW_AT_type <815> + DW_AT_data_member_location DW_OP_consts 4 +<3>< 666> DW_TAG_member + DW_AT_name str_m + DW_AT_type <815> + DW_AT_data_member_location DW_OP_consts 8 +<2>< 681> DW_TAG_array_type + DW_AT_name .dims. + DW_AT_type <630> + DW_AT_declaration yes(1) +<3>< 694> DW_TAG_subrange_type + DW_AT_lower_bound 0 + DW_AT_upper_bound 0 +<2>< 698> DW_TAG_structure_type + DW_AT_name .dope. + DW_AT_byte_size 44 +<3>< 707> DW_TAG_member + DW_AT_name base + DW_AT_type <405> + DW_AT_data_member_location DW_OP_consts 0 +<3>< 720> DW_TAG_member + DW_AT_name .flds + DW_AT_type <412> + DW_AT_data_member_location DW_OP_consts 4 +<3>< 734> DW_TAG_member + DW_AT_name .dims. + DW_AT_type <681> + DW_AT_data_member_location DW_OP_consts 32 +<2>< 750> DW_TAG_variable + DW_AT_type <815> + DW_AT_location DW_OP_fbreg -32 + DW_AT_artificial yes(1) +<2>< 759> DW_TAG_variable + DW_AT_type <815> + DW_AT_location DW_OP_fbreg -28 + DW_AT_artificial yes(1) +<2>< 768> DW_TAG_variable + DW_AT_type <815> + DW_AT_location DW_OP_fbreg -24 + DW_AT_artificial yes(1) +<2>< 777> DW_TAG_array_type + DW_AT_type <815> + DW_AT_declaration yes(1) +<3>< 783> DW_TAG_subrange_type + DW_AT_lower_bound <750> + DW_AT_count <759> + DW_AT_MIPS_stride <768> +<2>< 797> DW_TAG_variable + DW_AT_decl_file 1 + DW_AT_decl_line 1 + DW_AT_name ARRAY + DW_AT_type <698> + DW_AT_location DW_OP_fbreg -64 DW_OP_deref +<1>< 815> DW_TAG_base_type + DW_AT_name INTEGER_4 + DW_AT_encoding DW_ATE_signed + DW_AT_byte_size 4 +<1>< 828> DW_TAG_base_type + DW_AT_name INTEGER_8 + DW_AT_encoding DW_ATE_signed + DW_AT_byte_size 8 +<1>< 841> DW_TAG_base_type + DW_AT_name INTEGER*4 + DW_AT_encoding DW_ATE_unsigned + DW_AT_byte_size 4 +<1>< 854> DW_TAG_base_type + DW_AT_name INTEGER*8 + DW_AT_encoding DW_ATE_unsigned + DW_AT_byte_size 8 + +.fi +.H 2 "The dope vector structure details" +A dope vector is the following C struct, "dopevec.h". +Not all the fields are of use to a debugger. +It may be that not all fields will show up +in the f90 dwarf (since not all are of interest to debuggers). +.nf +[Note: +Need details on the use of each field. +And need to know which are really 32 bits and which +are 32 or 64. +end Note] +The following +struct +is a representation of all the dope vector fields. +It suppresses irrelevant detail and may not +exactly match the layout in memory (a debugger must +examine the dwarf to find the fields, not +compile this structure into the debugger!). +.nf +struct .dope. { + void *base; // pointer to data + struct .flds. { + long el_len; // length of element in bytes? + unsigned int assoc:1; //means? + unsigned int ptr_alloc:1; //means? + unsigned int p_or_a:2; //means? + unsigned int a_contig:1; // means? + unsigned int num_dims: 3; // 0 thru 7 + unsigned int type_code:32; //values? + unsigned int orig_base; //void *? means? + long orig_size; // means? + } .flds; + + struct .dope_bnd. { + long lb ; // lower bound + long ext ; // means? + long str_m; // means? + } .dims[7]; +} +.fi + +.H 2 "DW_AT_MIPS_assumed_size 0x2011" +This flag was invented to deal with f90 arrays. +For example: + +.nf + pointer (rptr, axx(1)) + pointer (iptr, ita(*)) + rptr = malloc (100*8) + iptr = malloc (100*4) +.fi + +This flag attribute has the value 'yes' (true, on) if and only if +the size is unbounded, as iptr is. +Both may show an explicit upper bound of 1 in the dwarf, +but this flag notifies the debugger that there is explicitly +no user-provided size. + +So if a user asks for a printout of the rptr allocated +array, the default will be of a single entry (as +there is a user slice bound in the source). +In contrast, there is no explicit upper bound on the iptr +(ita) array so the default slice will use the current bound +(a value calculated from the malloc size, see the dope vector). + +Given explicit requests, more of rptr(axx) can me shown +than the default. + +.H 1 "Line information and Source Position" +DWARF does not define the meaning of the term 'source statement'. +Nor does it define any way to find the first user-written +executable code in a function. +.P +It does define that a source statement has a file name, +a line number, and a column position (see Sec 6.2, Line Number +Information of the Dwarf Version 2 document). +We will call those 3 source coordinates a 'source position' +in this document. We'll try not to accidentally call the +source position a 'line number' since that is ambiguous +as to what it means. + +.H 2 "Definition of Statement" +.P +A function prolog is a statement. +.P +A C, C++, Pascal, or Fortran statement is a statement. +.P +Each initialized local variable in C,C++ is a statement +in that its initialization generates a source position. +This means that + x =3, y=4; +is two statements. +.P +For C, C++: +The 3 parts a,b,c in for(a;b;c) {d;} are individual statements. +The condition portion of a while() and do {} while() is +a statement. (of course d; can be any number of statements) +.P +For Fortran, the controlling expression of a DO loop is a statement. +Is a 'continue' statement in Fortran a DWARF statement? +.P +Each function return, whether user coded or generated by the +compiler, is a statement. This is so one can step over (in +a debugger) the final user-coded statement +(exclusive of the return statement if any) in a function +wile not leaving the function scope. +.P + +.H 2 "Finding The First User Code in a Function" + +.nf +Consider: +int func(int a) +{ /* source position 1 */ + float b = a; /* source position 2 */ + int x; + x = b + 2; /* source position 3 */ +} /* source position 4 */ +.fi +.P +The DIE for a function gives the address range of the function, +including function prolog(s) and epilog(s) +.P +Since there is no scope block for the outer user scope of a +function (and thus no beginning address range for the outer +user scope: the DWARF committee explicitly rejected the idea +of having a user scope block) +it is necessary to use the source position information to find +the first user-executable statement. +.P +This means that the user code for a function must be presumed +to begin at the code location of the second source position in +the function address range. +.P +If a function has exactly one source position, the function +presumably consists solely of a return. +.P +If a function has exactly two source positions, the function +may consist of a function prolog and a return or a single user +statement and a return (there may be no prolog code needed in a +leaf function). In this case, there is no way to be sure which +is the first source position of user code, so the rule is to +presume that the first address is user code. +.P +If a function consists of 3 or more source positions, one +should assume that the first source position is function prolog and +the second is the first user executable code. + +.H 2 "Using debug_frame Information to find first user statement" +In addition to the line information, the debug_frame information +can be +useful in determining the first user source line. +.P +Given that a function has more than 1 source position, +Find the code location of the second source position, then +examine the debug_frame information to determine if the Canonical +Frame Address (cfa) is updated before the second source position +code location. +If the cfa is updated, then one can be pretty sure that the +code for the first source position is function prolog code. +.P +Similarly, if the cfa is restored in the code for +a source position, the source position is likely to +represent a function exit block. + +.H 2 "Debugger Use Of Source Position" +Command line debuggers, such as dbx and gdb, will ordinarily +want to consider multiple statements on one line to be a single +statement: doing otherwise is distressing to users since it +causes a 'step' command to appear to have no effect. +.P +An exception for command line debuggers is in determining the +first user statement: as detailed above, there one wants to +consider the full source position and will want to consider +the function return a separate statement. It is difficult to +make the function return a separate statement 'step' reliably +however if a function is coded all on one line or if the last +line of user code before the return is on the same line as the +return. +.P +A graphical debugger has none of these problems if it simply +highlights the portion of the line being executed. In that +case, stepping will appear natural even stepping within a +line. +.H 1 "Known Bugs" +Up through at least MIPSpro7.2.1 +the compiler has been emitting form DW_FORM_DATA1,2, or 4 +for DW_AT_const_value in DW_TAG_enumerator. +And dwarfdump and debuggers have read this with dwarf_formudata() +or form_sdata() and gotten some values incorrect. +For example, a value of 128 was printed by debuggers as a negative value. +Since dwarfdump and the compilers were not written to use the +value the same way, their output differed. +For negative enumerator values the compiler has been emitting 32bit values +in a DW_FORM_DATA4. +The compiler should probably be emitting a DW_FORM_sdata for +enumerator values. +And consumers of enumerator values should then call form_sdata(). +However, right now, debuggers should call form_udata() and only if +it fails, call form_sdata(). +Anything else will break backward compatibility with +the objects produced earlier. +.SK +.S +.TC 1 1 4 +.CS diff --git a/libdwarf/mips_extensions.pdf b/libdwarf/mips_extensions.pdf Binary files differnew file mode 100644 index 0000000..4bab49e --- /dev/null +++ b/libdwarf/mips_extensions.pdf diff --git a/libdwarf/pro_alloc.c b/libdwarf/pro_alloc.c new file mode 100644 index 0000000..840aad8 --- /dev/null +++ b/libdwarf/pro_alloc.c @@ -0,0 +1,188 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "pro_incl.h" +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif /* HAVE_STDLIB_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#include <malloc.h> + +/* When each block is allocated, there is a two-word structure + allocated at the beginning so the block can go on a list. + The address returned is the address *after* the two pointers + at the start. But this allows us to be given a pointer to + a generic block, and go backwards to find the list-node. Then + we can remove this block from it's list without the need to search + through a linked list in order to remove the node. It also allows + us to 'delete' a memory block without needing the dbg structure. + We still need the dbg structure on allocation so that we know which + linked list to add the block to. + + Only the allocation of the dbg structure itself cannot use + _dwarf_p_get_alloc. + That structure should be set up by hand, and the two list pointers + should be initialized to point at the node itself. That initializes + the doubly linked list. */ + +#define LIST_TO_BLOCK(lst) ((void*) (((char *)lst) + sizeof(memory_list_t))) +#define BLOCK_TO_LIST(blk) ((memory_list_t*) (((char*)blk) - sizeof(memory_list_t))) + + +/* + dbg should be NULL only when allocating dbg itself. In that + case we initialize it to an empty circular doubly-linked list. +*/ + +Dwarf_Ptr +_dwarf_p_get_alloc(Dwarf_P_Debug dbg, Dwarf_Unsigned size) +{ + void *sp; + memory_list_t *lp = NULL; + memory_list_t *dbglp = NULL; + memory_list_t *nextblock = NULL; + + /* alloc control struct and data block together for performance reasons */ + lp = (memory_list_t *) malloc(size + sizeof(memory_list_t)); + if (lp == NULL) { + /* should throw an error */ + return NULL; + } + + /* point to 'size' bytes just beyond lp struct */ + sp = LIST_TO_BLOCK(lp); + memset(sp, 0, size); + + if (dbg == NULL) { + lp->next = lp->prev = lp; + } else { + /* I always have to draw a picture to understand this part. */ + + dbglp = BLOCK_TO_LIST(dbg); + nextblock = dbglp->next; + + /* Insert between dbglp and nextblock */ + dbglp->next = lp; + lp->prev = dbglp; + lp->next = nextblock; + nextblock->prev = lp; + } + + return sp; +} + +/* + This routine is only here in case a caller of an older version of the + library is calling this for some reason. + We will clean up any stray blocks when the session is closed. + No need to remove this block. In theory the user might be + depending on the fact that we used to just 'free' this. + In theory they might also be + passing a block that they got from libdwarf. So we don't know if we + should try to remove this block from our global list. Safest just to + do nothing at this point. + + !!! + This function is deprecated! Don't call it inside libdwarf or outside of it. + !!! +*/ + +void +dwarf_p_dealloc(Dwarf_Small * ptr) +{ + return; +} + +/* + The dbg structure is not needed here anymore. +*/ + +void +_dwarf_p_dealloc(Dwarf_P_Debug dbg, Dwarf_Small * ptr) /* ARGSUSED */ +{ + memory_list_t *lp; + lp = BLOCK_TO_LIST(ptr); + + /* + Remove from a doubly linked, circular list. + Read carefully, use a white board if necessary. + If this is an empty list, the following statements are no-ops, and + will write to the same memory location they read from. + This should only happen when we deallocate the dbg structure itself. + */ + + lp->prev->next = lp->next; + lp->next->prev = lp->prev; + + free((void*)lp); +} + + +/* + This routine deallocates all the nodes on the dbg list, + and then deallocates the dbg structure itself. +*/ + +void +_dwarf_p_dealloc_all(Dwarf_P_Debug dbg) +{ + memory_list_t *dbglp; + + if (dbg == NULL) { + /* should throw an error */ + return; + } + + dbglp = BLOCK_TO_LIST(dbg); + while (dbglp->next != dbglp) { + _dwarf_p_dealloc(dbg, LIST_TO_BLOCK(dbglp->next)); + } + if (dbglp->next != dbglp || + dbglp->prev != dbglp) { + + /* should throw error */ + /* For some reason we couldn't free all the blocks? */ + return; + } + _dwarf_p_dealloc(NULL, (void*)dbg); +} + diff --git a/libdwarf/pro_alloc.h b/libdwarf/pro_alloc.h new file mode 100644 index 0000000..b4da653 --- /dev/null +++ b/libdwarf/pro_alloc.h @@ -0,0 +1,42 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +Dwarf_Ptr _dwarf_p_get_alloc(Dwarf_P_Debug, Dwarf_Unsigned); + +void _dwarf_p_dealloc(Dwarf_P_Debug dbg, Dwarf_Small * ptr); + +void _dwarf_p_dealloc_all(Dwarf_P_Debug dbg); diff --git a/libdwarf/pro_arange.c b/libdwarf/pro_arange.c new file mode 100644 index 0000000..3270b37 --- /dev/null +++ b/libdwarf/pro_arange.c @@ -0,0 +1,321 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#endif +#include "pro_incl.h" +#include "pro_arange.h" +#include "pro_section.h" +#include "pro_reloc.h" + + + +/* This function adds another address range + to the list of address ranges for the + given Dwarf_P_Debug. It returns 0 on error, + and 1 otherwise. */ +Dwarf_Unsigned +dwarf_add_arange(Dwarf_P_Debug dbg, + Dwarf_Addr begin_address, + Dwarf_Unsigned length, + Dwarf_Signed symbol_index, Dwarf_Error * error) +{ + return dwarf_add_arange_b(dbg, begin_address, length, symbol_index, + /* end_symbol_index */ 0, + /* offset_from_end_sym */ 0, + error); +} + +/* This function adds another address range + to the list of address ranges for the + given Dwarf_P_Debug. It returns 0 on error, + and 1 otherwise. */ +Dwarf_Unsigned +dwarf_add_arange_b(Dwarf_P_Debug dbg, + Dwarf_Addr begin_address, + Dwarf_Unsigned length, + Dwarf_Unsigned symbol_index, + Dwarf_Unsigned end_symbol_index, + Dwarf_Addr offset_from_end_sym, Dwarf_Error * error) +{ + Dwarf_P_Arange arange; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (0); + } + + arange = (Dwarf_P_Arange) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Arange_s)); + if (arange == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + + arange->ag_begin_address = begin_address; + arange->ag_length = length; + arange->ag_symbol_index = symbol_index; + arange->ag_end_symbol_index = end_symbol_index; + arange->ag_end_symbol_offset = offset_from_end_sym; + + if (dbg->de_arange == NULL) + dbg->de_arange = dbg->de_last_arange = arange; + else { + dbg->de_last_arange->ag_next = arange; + dbg->de_last_arange = arange; + } + dbg->de_arange_count++; + + return (1); +} + + +int +_dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + /* Total num of bytes in .debug_aranges section. */ + Dwarf_Unsigned arange_num_bytes = 0; + + /* Adjustment to align the start of the actual address ranges on a + boundary aligned with twice the address size. */ + Dwarf_Small remainder = 0; + + /* Total number of bytes excluding the length field. */ + Dwarf_Unsigned adjusted_length = 0; + + /* Points to first byte of .debug_aranges buffer. */ + Dwarf_Small *arange = 0; + + /* Fills in the .debug_aranges buffer. */ + Dwarf_Small *arange_ptr = 0; + + /* Scans the list of address ranges provided by user. */ + Dwarf_P_Arange given_arange = 0; + + /* Used to fill in 0. */ + const Dwarf_Signed big_zero = 0; + + int extension_word_size = dbg->de_64bit_extension ? 4 : 0; + int uword_size = dbg->de_offset_size; + int upointer_size = dbg->de_pointer_size; + int res = 0; + + + /* ***** BEGIN CODE ***** */ + + /* Size of the .debug_aranges section header. */ + arange_num_bytes = extension_word_size + + uword_size + /* Size of length field. */ + sizeof(Dwarf_Half) + /* Size of version field. */ + uword_size + /* Size of .debug_info offset. */ + sizeof(Dwarf_Small) + /* Size of address size field. */ + sizeof(Dwarf_Small); /* Size of segment size field. */ + + /* Adjust the size so that the set of aranges begins on a boundary + that aligned with twice the address size. This is a Libdwarf + requirement. */ + remainder = arange_num_bytes % (2 * upointer_size); + if (remainder != 0) + arange_num_bytes += (2 * upointer_size) - remainder; + + + /* Add the bytes for the actual address ranges. */ + arange_num_bytes += upointer_size * 2 * (dbg->de_arange_count + 1); + + GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_ARANGES], + arange, (unsigned long) arange_num_bytes, error); + arange_ptr = arange; + if (arange == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + if (extension_word_size) { + Dwarf_Word x = DISTINGUISHED_VALUE; + + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &x, + sizeof(x), extension_word_size); + arange_ptr += extension_word_size; + } + + /* Write the total length of .debug_aranges section. */ + adjusted_length = arange_num_bytes - uword_size + - extension_word_size; + { + Dwarf_Unsigned du = adjusted_length; + + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &du, sizeof(du), uword_size); + arange_ptr += uword_size; + } + + /* Write the version as 2 bytes. */ + { + Dwarf_Half verstamp = CURRENT_VERSION_STAMP; + + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &verstamp, + sizeof(verstamp), sizeof(Dwarf_Half)); + arange_ptr += sizeof(Dwarf_Half); + } + + + /* Write the .debug_info offset. This is always 0. */ + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &big_zero, + sizeof(big_zero), uword_size); + arange_ptr += uword_size; + + { + unsigned long count = dbg->de_arange_count + 1; + int res = 0; + + if (dbg->de_reloc_pair) { + count = (3 * dbg->de_arange_count) + 1; + } + /* The following is a small optimization: not needed for + correctness */ + res = _dwarf_pro_pre_alloc_n_reloc_slots(dbg, + DEBUG_ARANGES, count); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + } + + /* reloc for .debug_info */ + res = dbg->de_reloc_name(dbg, + DEBUG_ARANGES, + extension_word_size + + uword_size + sizeof(Dwarf_Half), + dbg->de_sect_name_idx[DEBUG_INFO], + dwarf_drt_data_reloc, uword_size); + + /* Write the size of addresses. */ + *arange_ptr = dbg->de_pointer_size; + arange_ptr++; + + /* Write the size of segment addresses. This is zero for MIPS + architectures. */ + *arange_ptr = 0; + arange_ptr++; + + /* Skip over the padding to align the start of the actual address + ranges to twice the address size. */ + if (remainder != 0) + arange_ptr += (2 * upointer_size) - remainder; + + + + + + /* The arange address, length are pointer-size fields of the target + machine. */ + for (given_arange = dbg->de_arange; given_arange != NULL; + given_arange = given_arange->ag_next) { + + /* Write relocation record for beginning of address range. */ + res = dbg->de_reloc_name(dbg, DEBUG_ARANGES, + arange_ptr - arange, /* r_offset */ + (long) given_arange->ag_symbol_index, + dwarf_drt_data_reloc, upointer_size); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + + /* Copy beginning address of range. */ + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &given_arange->ag_begin_address, + sizeof(given_arange->ag_begin_address), + upointer_size); + arange_ptr += upointer_size; + + if (dbg->de_reloc_pair && + given_arange->ag_end_symbol_index != 0 && + given_arange->ag_length == 0) { + /* symbolic reloc, need reloc for length What if we really + know the length? If so, should use the other part of + 'if'. */ + Dwarf_Unsigned val; + + res = dbg->de_reloc_pair(dbg, DEBUG_ARANGES, + arange_ptr - arange, /* r_offset */ + given_arange->ag_symbol_index, + given_arange->ag_end_symbol_index, + dwarf_drt_first_of_length_pair, + upointer_size); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + + /* arange pre-calc so assem text can do .word end - begin + + val (gets val from stream) */ + val = given_arange->ag_end_symbol_offset - + given_arange->ag_begin_address; + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &val, + sizeof(val), upointer_size); + arange_ptr += upointer_size; + + } else { + /* plain old length to copy, no relocation at all */ + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &given_arange->ag_length, + sizeof(given_arange->ag_length), + upointer_size); + arange_ptr += upointer_size; + } + } + + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &big_zero, + sizeof(big_zero), upointer_size); + + arange_ptr += upointer_size; + WRITE_UNALIGNED(dbg, (void *) arange_ptr, + (const void *) &big_zero, + sizeof(big_zero), upointer_size); + return (int) dbg->de_n_debug_sect; +} diff --git a/libdwarf/pro_arange.h b/libdwarf/pro_arange.h new file mode 100644 index 0000000..ff5db98 --- /dev/null +++ b/libdwarf/pro_arange.h @@ -0,0 +1,60 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +/* + If ag_end_symbol_index is zero, + ag_length must be known and non-zero. + + Deals with length being known costant or fr + assembler output, not known. +*/ + +struct Dwarf_P_Arange_s { + Dwarf_Addr ag_begin_address; /* known address or for + symbolic assem output, + offset of symbol */ + Dwarf_Addr ag_length; /* zero or address or offset */ + Dwarf_Unsigned ag_symbol_index; + + Dwarf_P_Arange ag_next; + + Dwarf_Unsigned ag_end_symbol_index; /* zero or index/id of end +symbol */ + Dwarf_Addr ag_end_symbol_offset; /* known address or for + symbolic assem output, + offset of end symbol */ + +}; diff --git a/libdwarf/pro_die.c b/libdwarf/pro_die.c new file mode 100644 index 0000000..cc22050 --- /dev/null +++ b/libdwarf/pro_die.c @@ -0,0 +1,439 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#include "pro_incl.h" +#include "pro_die.h" + +#ifndef R_MIPS_NONE +#define R_MIPS_NONE 0 +#endif + +/* adds an attribute to a die */ +void _dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr); + +/* This function creates a new die. + tag: tag of the new die to be created + parent,child,left,right: specify neighbors of the new die. Only + one of these may be non-null */ +Dwarf_P_Die +dwarf_new_die(Dwarf_P_Debug dbg, + Dwarf_Tag tag, + Dwarf_P_Die parent, + Dwarf_P_Die child, + Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error) +{ + Dwarf_P_Die ret_die = 0; + + Dwarf_P_Die new_die = (Dwarf_P_Die) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Die_s)); + if (new_die == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_ALLOC, + (Dwarf_P_Die) DW_DLV_BADADDR); + } + new_die->di_parent = NULL; + new_die->di_left = NULL; + new_die->di_right = NULL; + new_die->di_child = NULL; + new_die->di_last_child = NULL; + new_die->di_tag = tag; + new_die->di_dbg = dbg; + new_die->di_marker = 0; + ret_die = + dwarf_die_link(new_die, parent, child, left, right, error); + return ret_die; +} + +/* This function links up a die to specified neighbors + parent,child,left,right: specify neighbors of the new die. Only + one of these may be non-null */ +Dwarf_P_Die +dwarf_die_link(Dwarf_P_Die new_die, + Dwarf_P_Die parent, + Dwarf_P_Die child, + Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error) +{ + /* Count the # of non null neighbors. */ + int n_nulls = 0; + + if (parent != NULL) { + n_nulls++; + if (new_die->di_parent != NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_LINK_LOOP, + (Dwarf_P_Die) DW_DLV_BADADDR); + } + new_die->di_parent = parent; + if (parent->di_child) { + + /* di_last_child identifies the last sibling, the + die we want to attach new_die to. */ + /* ASSERT: if di_child is set so is di_last_child. */ + Dwarf_P_Die former_lastchild = parent->di_last_child; + parent->di_last_child = new_die; + /* Attach to the new die to end of the sibling list. */ + former_lastchild->di_right = new_die; + new_die->di_left = former_lastchild; + } else { + parent->di_child = new_die; + parent->di_last_child = new_die; + } + } + if (child != NULL) { + n_nulls++; + new_die->di_child = child; + new_die->di_last_child = child; + if (child->di_parent) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS, + (Dwarf_P_Die) DW_DLV_BADADDR); + } else { + child->di_parent = new_die; + } + } + if (left != NULL) { + n_nulls++; + new_die->di_left = left; + if (left->di_right) { + /* There's already a right sibling of left, + insert the new die in the list. */ + new_die->di_right = left->di_right; + left->di_right->di_left = new_die; + } + left->di_right = new_die; + if (new_die->di_parent) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS, + (Dwarf_P_Die) DW_DLV_BADADDR); + } else { + new_die->di_parent = left->di_parent; + } + } + if (right != NULL) { + n_nulls++; + new_die->di_right = right; + if (right->di_left) { + /* There is already a left sibling of the right die, + insert the new die in the list. */ + new_die->di_left = right->di_left; + right->di_left->di_right = new_die; + } + right->di_left = new_die; + if (new_die->di_parent) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS, + (Dwarf_P_Die) DW_DLV_BADADDR); + } else { + new_die->di_parent = right->di_parent; + } + } + if (n_nulls > 1) { + /* Multiple neighbors! error! */ + DWARF_P_DBG_ERROR(NULL, DW_DLE_EXTRA_NEIGHBORS, + (Dwarf_P_Die) DW_DLV_BADADDR); + } + return new_die; + +} + +Dwarf_Unsigned +dwarf_add_die_marker(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + Dwarf_Unsigned marker, + Dwarf_Error * error) +{ + if (die == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT); + } + die->di_marker = marker; + return 0; +} + + +Dwarf_Unsigned +dwarf_get_die_marker(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + Dwarf_Unsigned * marker, + Dwarf_Error * error) +{ + if (die == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT); + } + *marker = die->di_marker; + return 0; +} + + +/*---------------------------------------------------------------------------- + This function adds a die to dbg struct. It should be called using + the root of all the dies. +-----------------------------------------------------------------------------*/ +Dwarf_Unsigned +dwarf_add_die_to_debug(Dwarf_P_Debug dbg, + Dwarf_P_Die first_die, Dwarf_Error * error) +{ + if (first_die == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT); + } + if (first_die->di_tag != DW_TAG_compile_unit) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_WRONG_TAG, DW_DLV_NOCOUNT); + } + dbg->de_dies = first_die; + return 0; +} + +int +_dwarf_pro_add_AT_stmt_list(Dwarf_P_Debug dbg, + Dwarf_P_Die first_die, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + int uwordb_size = dbg->de_offset_size; + + /* Add AT_stmt_list attribute */ + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, DW_DLV_NOCOUNT); + } + + new_attr->ar_attribute = DW_AT_stmt_list; + new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form; + new_attr->ar_rel_type = dbg->de_offset_reloc; + + new_attr->ar_nbytes = uwordb_size; + new_attr->ar_next = NULL; + new_attr->ar_reloc_len = uwordb_size; + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(dbg, uwordb_size); + if (new_attr->ar_data == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT); + } + { + Dwarf_Unsigned du = 0; + + WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data, + (const void *) &du, sizeof(du), uwordb_size); + } + + _dwarf_pro_add_at_to_die(first_die, new_attr); + return 0; +} + +/*----------------------------------------------------------------------------- + Add AT_name attribute to die +------------------------------------------------------------------------------*/ +Dwarf_P_Attribute +dwarf_add_AT_name(Dwarf_P_Die die, char *name, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + + if (die == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, + (Dwarf_P_Attribute) DW_DLV_BADADDR); + } + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(die->di_dbg,sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, + (Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + /* fill in the information */ + new_attr->ar_attribute = DW_AT_name; + /* assume that form is string, no debug_str yet */ + new_attr->ar_attribute_form = DW_FORM_string; + new_attr->ar_nbytes = strlen(name) + 1; + new_attr->ar_next = NULL; + new_attr->ar_reloc_len = 0; + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(die->di_dbg, strlen(name)+1); + if (new_attr->ar_data == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC, + (Dwarf_P_Attribute) DW_DLV_BADADDR); + } + strcpy(new_attr->ar_data, name); + + new_attr->ar_rel_type = R_MIPS_NONE; + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(die, new_attr); + return new_attr; +} + + +/*----------------------------------------------------------------------------- + Add AT_comp_dir attribute to die +------------------------------------------------------------------------------*/ +Dwarf_P_Attribute +dwarf_add_AT_comp_dir(Dwarf_P_Die ownerdie, + char *current_working_directory, + Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + + if (ownerdie == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, + (Dwarf_P_Attribute) DW_DLV_BADADDR); + } + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(ownerdie->di_dbg, + sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, + (Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + /* fill in the information */ + new_attr->ar_attribute = DW_AT_comp_dir; + /* assume that form is string, no debug_str yet */ + new_attr->ar_attribute_form = DW_FORM_string; + new_attr->ar_nbytes = strlen(current_working_directory) + 1; + new_attr->ar_next = NULL; + new_attr->ar_reloc_len = 0; + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(ownerdie->di_dbg, + strlen(current_working_directory)+1); + if (new_attr->ar_data == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC, + (Dwarf_P_Attribute) DW_DLV_BADADDR); + } + strcpy(new_attr->ar_data, current_working_directory); + + new_attr->ar_rel_type = R_MIPS_NONE; + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + +int +_dwarf_pro_add_AT_fde(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + Dwarf_Unsigned offset, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + int uwordb_size = dbg->de_offset_size; + + if (die == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1); + } + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1); + } + + /* fill in the information */ + new_attr->ar_attribute = DW_AT_MIPS_fde; + new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;; + new_attr->ar_rel_type = dbg->de_offset_reloc; + new_attr->ar_nbytes = uwordb_size; + new_attr->ar_next = NULL; + new_attr->ar_reloc_len = uwordb_size; + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(dbg, uwordb_size); + if (new_attr->ar_data == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT); + } + { + Dwarf_Unsigned du = offset; + + WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data, + (const void *) &du, sizeof(du), uwordb_size); + } + + _dwarf_pro_add_at_to_die(die, new_attr); + + return 0; +} + +int +_dwarf_pro_add_AT_macro_info(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + Dwarf_Unsigned offset, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + int uwordb_size = dbg->de_offset_size; + + if (die == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1); + } + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1); + } + + /* fill in the information */ + new_attr->ar_attribute = DW_AT_macro_info; + new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form; + new_attr->ar_rel_type = dbg->de_offset_reloc; + + new_attr->ar_nbytes = uwordb_size; + new_attr->ar_next = NULL; + new_attr->ar_reloc_len = uwordb_size; + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(dbg, uwordb_size); + if (new_attr->ar_data == NULL) { + DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT); + } + { + Dwarf_Unsigned du = offset; + + WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data, + (const void *) &du, sizeof(du), uwordb_size); + } + + _dwarf_pro_add_at_to_die(die, new_attr); + + return 0; +} + + +void +_dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr) +{ + if (die->di_last_attr) { + die->di_last_attr->ar_next = attr; + die->di_last_attr = attr; + die->di_n_attr++; + } else { + die->di_n_attr = 1; + die->di_attrs = die->di_last_attr = attr; + } +} diff --git a/libdwarf/pro_die.h b/libdwarf/pro_die.h new file mode 100644 index 0000000..01924a9 --- /dev/null +++ b/libdwarf/pro_die.h @@ -0,0 +1,68 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +/* + This struct holds the abbreviation table, before they are written + on disk. Holds a linked list of abbreviations, each consisting of + a bitmap for attributes and a bitmap for forms +*/ +typedef struct Dwarf_P_Abbrev_s *Dwarf_P_Abbrev; + +struct Dwarf_P_Abbrev_s { + Dwarf_Unsigned abb_idx; /* index of abbreviation */ + Dwarf_Tag abb_tag; /* tag of die */ + Dwarf_Ubyte abb_children; /* if children are present */ + Dwarf_ufixed *abb_attrs; /* holds names of attrs */ + Dwarf_ufixed *abb_forms; /* forms of attributes */ + int abb_n_attr; /* num of attrs = # of forms */ + Dwarf_P_Abbrev abb_next; +}; + +/* used in pro_section.c */ + +int _dwarf_pro_add_AT_fde(Dwarf_P_Debug dbg, Dwarf_P_Die die, + Dwarf_Unsigned offset, Dwarf_Error * error); + +int _dwarf_pro_add_AT_stmt_list(Dwarf_P_Debug dbg, + Dwarf_P_Die first_die, + Dwarf_Error * error); + +int _dwarf_pro_add_AT_macro_info(Dwarf_P_Debug dbg, + Dwarf_P_Die first_die, + Dwarf_Unsigned offset, + Dwarf_Error * error); diff --git a/libdwarf/pro_encode_nm.c b/libdwarf/pro_encode_nm.c new file mode 100644 index 0000000..1b89781 --- /dev/null +++ b/libdwarf/pro_encode_nm.c @@ -0,0 +1,119 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <string.h> +#include "pro_incl.h" + +#define MORE_BYTES 0x80 +#define DATA_MASK 0x7f +#define DIGIT_WIDTH 7 +#define SIGN_BIT 0x40 + + +/* Encode val as a leb128. This encodes it as an unsigned + number. */ +/* Return DW_DLV_ERROR or DW_DLV_OK. + space to write leb number is provided by caller, with caller + passing length. + number of bytes used returned thru nbytes arg */ +int +_dwarf_pro_encode_leb128_nm(Dwarf_Unsigned val, int *nbytes, + char *space, int splen) +{ + char *a; + char *end = space + splen; + + a = space; + do { + unsigned char uc; + + if (a >= end) { + return DW_DLV_ERROR; + } + uc = val & DATA_MASK; + val >>= DIGIT_WIDTH; + if (val != 0) { + uc |= MORE_BYTES; + } + *a = uc; + a++; + } while (val); + *nbytes = a - space; + return DW_DLV_OK; +} + +/* return DW_DLV_ERROR or DW_DLV_OK. +** space to write leb number is provided by caller, with caller +** passing length. +** number of bytes used returned thru nbytes arg +** encodes a signed number. +*/ +int +_dwarf_pro_encode_signed_leb128_nm(Dwarf_Signed value, int *nbytes, + char *space, int splen) +{ + char *str; + Dwarf_Signed sign = -(value < 0); + int more = 1; + char *end = space + splen; + + str = space; + + do { + unsigned char byte = value & DATA_MASK; + + value >>= DIGIT_WIDTH; + + if (str >= end) { + return DW_DLV_ERROR; + } + /* Remaining chunks would just contain the sign bit, and this chunk + has already captured at least one sign bit. */ + if (value == sign && ((byte & SIGN_BIT) == (sign & SIGN_BIT))) { + more = 0; + } else { + byte |= MORE_BYTES; + } + *str = byte; + str++; + } while (more); + *nbytes = str - space; + return DW_DLV_OK; +} diff --git a/libdwarf/pro_encode_nm.h b/libdwarf/pro_encode_nm.h new file mode 100644 index 0000000..6e42838 --- /dev/null +++ b/libdwarf/pro_encode_nm.h @@ -0,0 +1,48 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +/* Bytes needed to encode a number. + Not a tight bound, just a reasonable bound. +*/ +#define ENCODE_SPACE_NEEDED (2*sizeof(Dwarf_Unsigned)) + + +int _dwarf_pro_encode_leb128_nm(Dwarf_Unsigned val, int *nbytes, + char *space, int splen); + +int _dwarf_pro_encode_signed_leb128_nm(Dwarf_Signed value, int *nbytes, + char *space, int splen); diff --git a/libdwarf/pro_error.c b/libdwarf/pro_error.c new file mode 100644 index 0000000..d9a599b --- /dev/null +++ b/libdwarf/pro_error.c @@ -0,0 +1,107 @@ +/* + + Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#ifdef HAVE_ELF_H +#include <elf.h> +#endif + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <stdlib.h> +#include "pro_incl.h" + +extern char *_dwarf_errmsgs[]; + +/* + This function performs error handling as described in the + libdwarf consumer document section 3. Dbg is the Dwarf_P_debug + structure being processed. Error is a pointer to the pointer + to the error descriptor that will be returned. Errval is an + error code listed in dwarf_error.h. + + The error number may be retrieved from the Dwarf_Error + by calling dwarf_errno(). + The error string implied by the error number may be retrieved + from the Dwarf_Error by calling dwarf_errmsg(). +*/ +void +_dwarf_p_error(Dwarf_P_Debug dbg, + Dwarf_Error * error, Dwarf_Word errval) +{ + Dwarf_Error errptr; + + if (errval > DW_DLE_LAST) { + /* We do not expect to ever see such an error number, + DW_DLE_LO_USER is not used. */ + /* The 'standard' typedef for Dwarf_Word is "unsigned long". */ + fprintf(stderr,"ERROR VALUE: %lu - %s\n", + (unsigned long) errval, "this error value is unknown to libdwarf."); + } + /* Allow NULL dbg on entry, since sometimes that can happen and we + want to report the upper-level error, not this one. */ + if (error != NULL) { + errptr = (Dwarf_Error) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_Error_s)); + if (errptr == NULL) { + fprintf(stderr, + "Could not allocate Dwarf_Error structure\n"); + abort(); + } + errptr->er_errval = (Dwarf_Sword) errval; + *error = errptr; + return; + } + + if (dbg != NULL && dbg->de_errhand != NULL) { + errptr = (Dwarf_Error) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_Error_s)); + if (errptr == NULL) { + fprintf(stderr, + "Could not allocate Dwarf_Error structure\n"); + abort(); + } + errptr->er_errval = (Dwarf_Sword) errval; + dbg->de_errhand(errptr, dbg->de_errarg); + return; + } + + abort(); +} diff --git a/libdwarf/pro_error.h b/libdwarf/pro_error.h new file mode 100644 index 0000000..fb255f5 --- /dev/null +++ b/libdwarf/pro_error.h @@ -0,0 +1,52 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +/* Handle error passing in the name of the Dwarf_P_Debug + User must supply {} around the macro. + Putting the {} here leads to macro uses that don't look like C. + The error argument to dwarf_error is hard coded here as 'error' +*/ +#define DWARF_P_DBG_ERROR(dbg,errval,retval) \ + _dwarf_p_error(dbg,error,errval); return(retval); + +struct Dwarf_Error_s { + Dwarf_Sword er_errval; +}; + +void _dwarf_p_error(Dwarf_P_Debug dbg, Dwarf_Error * error, + Dwarf_Word errval); diff --git a/libdwarf/pro_expr.c b/libdwarf/pro_expr.c new file mode 100644 index 0000000..21526c5 --- /dev/null +++ b/libdwarf/pro_expr.c @@ -0,0 +1,585 @@ +/* + Copyright (C) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2011 David Anderson. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#include "pro_incl.h" +#include "pro_expr.h" + +/* + This function creates a new expression + struct that can be used to build up a + location expression. +*/ +Dwarf_P_Expr +dwarf_new_expr(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + Dwarf_P_Expr ret_expr; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (NULL); + } + + ret_expr = (Dwarf_P_Expr) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Expr_s)); + if (ret_expr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (NULL); + } + + ret_expr->ex_dbg = dbg; + + return (ret_expr); +} + + +Dwarf_Unsigned +dwarf_add_expr_gen(Dwarf_P_Expr expr, + Dwarf_Small opcode, + Dwarf_Unsigned val1, + Dwarf_Unsigned val2, Dwarf_Error * error) +{ + /* 2* since used to concatenate 2 leb's below */ + char encode_buffer[2 * ENCODE_SPACE_NEEDED]; + + char encode_buffer2[ENCODE_SPACE_NEEDED]; + int res = 0; + Dwarf_P_Debug dbg = expr->ex_dbg; + + /* Give the buffer where the operands are first going to be + assembled the largest alignment. */ + Dwarf_Unsigned operand_buffer[10]; + + /* Size of the byte stream buffer that needs to be memcpy-ed. */ + int operand_size = 0; + + /* Points to the byte stream for the first operand, and finally to + the buffer that is memcp-ed into the Dwarf_P_Expr_s struct. */ + Dwarf_Small *operand = 0; + + /* Size of the byte stream for second operand. */ + int operand2_size = 0; + + /* Points to next byte to be written in Dwarf_P_Expr_s struct. */ + Dwarf_Small *next_byte_ptr = 0; + + /* Offset past the last byte written into Dwarf_P_Expr_s. */ + int next_byte_offset = 0; + + /* ***** BEGIN CODE ***** */ + + if (expr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL); + return (DW_DLV_NOCOUNT); + } + + if (expr->ex_dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_NOCOUNT); + } + + operand = NULL; + operand_size = 0; + + switch (opcode) { + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + res = _dwarf_pro_encode_signed_leb128_nm(val1, + &operand_size, encode_buffer, sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + break; + + case DW_OP_regx: + res = _dwarf_pro_encode_leb128_nm(val1, &operand_size, + encode_buffer, sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + break; + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + break; + + case DW_OP_addr: + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE); + return (DW_DLV_NOCOUNT); + + case DW_OP_const1u: + case DW_OP_const1s: + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 1); + operand_size = 1; + break; + + case DW_OP_const2u: + case DW_OP_const2s: + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 2); + operand_size = 2; + break; + + case DW_OP_const4u: + case DW_OP_const4s: + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 4); + operand_size = 4; + break; + + case DW_OP_const8u: + case DW_OP_const8s: + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 8); + operand_size = 8; + break; + + case DW_OP_constu: + res = _dwarf_pro_encode_leb128_nm(val1, + &operand_size, encode_buffer, sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + break; + + case DW_OP_consts: + res = _dwarf_pro_encode_signed_leb128_nm(val1, + &operand_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + break; + + case DW_OP_fbreg: + res = _dwarf_pro_encode_signed_leb128_nm(val1, + &operand_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + break; + + case DW_OP_bregx: + res = _dwarf_pro_encode_leb128_nm(val1, &operand_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + /* put this one directly into 'operand' at tail of prev value */ + res = _dwarf_pro_encode_signed_leb128_nm(val2, &operand2_size, + ((char *) operand) + + operand_size, + sizeof(encode_buffer2)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand_size += operand2_size; + + case DW_OP_dup: + case DW_OP_drop: + break; + + case DW_OP_pick: + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, (const void *) &val1, + sizeof(val1), 1); + operand_size = 1; + break; + + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_deref: + case DW_OP_xderef: + break; + + case DW_OP_deref_size: + case DW_OP_xderef_size: + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, (const void *) &val1, + sizeof(val1), 1); + operand_size = 1; + break; + + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + break; + + case DW_OP_plus_uconst: + res = _dwarf_pro_encode_leb128_nm(val1, &operand_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + break; + + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + break; + + case DW_OP_le: + case DW_OP_ge: + case DW_OP_eq: + case DW_OP_lt: + case DW_OP_gt: + case DW_OP_ne: + break; + + case DW_OP_skip: + case DW_OP_bra: + /* FIX: unhandled! OP_bra, OP_skip! */ + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE); + return (DW_DLV_NOCOUNT); + + case DW_OP_piece: + res = _dwarf_pro_encode_leb128_nm(val1, &operand_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + break; + + case DW_OP_nop: + break; + case DW_OP_push_object_address: /* DWARF3 */ + break; + case DW_OP_call2: /* DWARF3 */ + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 2); + operand_size = 2; + break; + + case DW_OP_call4: /* DWARF3 */ + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 4); + operand_size = 4; + break; + + case DW_OP_call_ref: /* DWARF3 */ + operand = (Dwarf_Small *) & operand_buffer[0]; + WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), + dbg->de_offset_size); + operand_size = dbg->de_offset_size; + break; + case DW_OP_form_tls_address: /* DWARF3f */ + break; + case DW_OP_call_frame_cfa: /* DWARF3f */ + break; + case DW_OP_bit_piece: /* DWARF3f */ + res = _dwarf_pro_encode_leb128_nm(val1, &operand_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand = (Dwarf_Small *) encode_buffer; + /* put this one directly into 'operand' at tail of prev value */ + res = _dwarf_pro_encode_leb128_nm(val2, &operand2_size, + ((char *) operand) + + operand_size, + sizeof(encode_buffer2)); + if (res != DW_DLV_OK) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + operand_size += operand2_size; + + + default: + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE); + return (DW_DLV_NOCOUNT); + } + + next_byte_offset = expr->ex_next_byte_offset + operand_size + 1; + + if (next_byte_offset > MAXIMUM_LOC_EXPR_LENGTH) { + _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + + next_byte_ptr = + &(expr->ex_byte_stream[0]) + expr->ex_next_byte_offset; + + *next_byte_ptr = opcode; + next_byte_ptr++; + memcpy(next_byte_ptr, operand, operand_size); + + expr->ex_next_byte_offset = next_byte_offset; + return (next_byte_offset); +} + +Dwarf_Unsigned +dwarf_add_expr_addr_b(Dwarf_P_Expr expr, + Dwarf_Unsigned addr, + Dwarf_Unsigned sym_index, Dwarf_Error * error) +{ + Dwarf_P_Debug dbg; + Dwarf_Small *next_byte_ptr; + Dwarf_Unsigned next_byte_offset; + int upointer_size; + + if (expr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL); + return (DW_DLV_NOCOUNT); + } + + dbg = expr->ex_dbg; + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_NOCOUNT); + } + + upointer_size = dbg->de_pointer_size; + next_byte_offset = expr->ex_next_byte_offset + upointer_size + 1; + if (next_byte_offset > MAXIMUM_LOC_EXPR_LENGTH) { + _dwarf_p_error(dbg, error, DW_DLE_EXPR_LENGTH_BAD); + return (DW_DLV_NOCOUNT); + } + + next_byte_ptr = + &(expr->ex_byte_stream[0]) + expr->ex_next_byte_offset; + + *next_byte_ptr = DW_OP_addr; + next_byte_ptr++; + WRITE_UNALIGNED(dbg, next_byte_ptr, (const void *) &addr, + sizeof(addr), upointer_size); + + if (expr->ex_reloc_offset != 0) { + _dwarf_p_error(dbg, error, DW_DLE_MULTIPLE_RELOC_IN_EXPR); + return (DW_DLV_NOCOUNT); + } + + expr->ex_reloc_sym_index = sym_index; + expr->ex_reloc_offset = expr->ex_next_byte_offset + 1; + + expr->ex_next_byte_offset = next_byte_offset; + return (next_byte_offset); +} + +Dwarf_Unsigned +dwarf_add_expr_addr(Dwarf_P_Expr expr, + Dwarf_Unsigned addr, + Dwarf_Signed sym_index, Dwarf_Error * error) +{ + return + dwarf_add_expr_addr_b(expr, addr, (Dwarf_Unsigned) sym_index, + error); +} + + +Dwarf_Unsigned +dwarf_expr_current_offset(Dwarf_P_Expr expr, Dwarf_Error * error) +{ + if (expr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL); + return (DW_DLV_NOCOUNT); + } + + if (expr->ex_dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_NOCOUNT); + } + + return (expr->ex_next_byte_offset); +} + +void +dwarf_expr_reset(Dwarf_P_Expr expr, Dwarf_Error * error) +{ + if (expr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL); + return; + } + expr->ex_next_byte_offset=0; +} + + +Dwarf_Addr +dwarf_expr_into_block(Dwarf_P_Expr expr, + Dwarf_Unsigned * length, Dwarf_Error * error) +{ + if (expr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL); + return (DW_DLV_BADADDR); + } + + if (expr->ex_dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_BADADDR); + } + + if (length != NULL) + *length = expr->ex_next_byte_offset; + /* The following cast from pointer to integer is ok as long as + Dwarf_Addr is at least as large as a pointer. Which is a + requirement of libdwarf so must be satisfied (some compilers + emit a warning about the following line). */ + return ((Dwarf_Addr) & (expr->ex_byte_stream[0])); +} diff --git a/libdwarf/pro_expr.h b/libdwarf/pro_expr.h new file mode 100644 index 0000000..202f2d3 --- /dev/null +++ b/libdwarf/pro_expr.h @@ -0,0 +1,45 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +#define MAXIMUM_LOC_EXPR_LENGTH 20 + +struct Dwarf_P_Expr_s { + Dwarf_Small ex_byte_stream[MAXIMUM_LOC_EXPR_LENGTH]; + Dwarf_P_Debug ex_dbg; + Dwarf_Unsigned ex_next_byte_offset; + Dwarf_Unsigned ex_reloc_sym_index; + Dwarf_Unsigned ex_reloc_offset; +}; diff --git a/libdwarf/pro_finish.c b/libdwarf/pro_finish.c new file mode 100644 index 0000000..43b0f29 --- /dev/null +++ b/libdwarf/pro_finish.c @@ -0,0 +1,56 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2011 David Anderson. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include "pro_incl.h" + +/* This routine deallocates all memory, and does some + finishing up */ +/*ARGSUSED*/ Dwarf_Unsigned +dwarf_producer_finish(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_NOCOUNT); + } + + /* this frees all blocks, then frees dbg. */ + _dwarf_p_dealloc_all(dbg); + return 0; +} diff --git a/libdwarf/pro_forms.c b/libdwarf/pro_forms.c new file mode 100644 index 0000000..ee1b98f --- /dev/null +++ b/libdwarf/pro_forms.c @@ -0,0 +1,1161 @@ +/* + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. 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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include "pro_incl.h" +#include "pro_expr.h" + +#ifndef R_MIPS_NONE +#define R_MIPS_NONE 0 +#endif + + +/* Indicates no relocation needed. */ +#define NO_ELF_SYM_INDEX 0 + + +/* Adds an attribute to a die */ +extern void _dwarf_pro_add_at_to_die(Dwarf_P_Die die, + Dwarf_P_Attribute attr); + +/* This function adds an attribute whose value is + a target address to the given die. The attribute + is given the name provided by attr. The address + is given in pc_value. */ + +static Dwarf_P_Attribute +local_add_AT_address(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Signed form, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error * error); + +/* old interface */ +Dwarf_P_Attribute +dwarf_add_AT_targ_address(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Signed sym_index, Dwarf_Error * error) +{ + return + dwarf_add_AT_targ_address_b(dbg, + ownerdie, + attr, + pc_value, + (Dwarf_Unsigned) sym_index, error); +} + +/* New interface, replacing dwarf_add_AT_targ_address. + Essentially just makes sym_index a Dwarf_Unsigned + so for symbolic relocations it can be a full address. */ +Dwarf_P_Attribute +dwarf_add_AT_targ_address_b(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error * error) +{ + switch (attr) { + case DW_AT_low_pc: + case DW_AT_high_pc: + + /* added to support location lists */ + /* no way to check that this is a loclist-style address though */ + case DW_AT_location: + case DW_AT_string_length: + case DW_AT_return_addr: + case DW_AT_frame_base: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: + case DW_AT_const_value: /* Gcc can generate this as address. */ + case DW_AT_entry_pc: + break; + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } + + return local_add_AT_address(dbg, ownerdie, attr, DW_FORM_addr, + pc_value, sym_index, error); +} + +Dwarf_P_Attribute +dwarf_add_AT_ref_address(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error * error) +{ + switch (attr) { + case DW_AT_type: + case DW_AT_import: + break; + + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } + + return local_add_AT_address(dbg, ownerdie, attr, DW_FORM_ref_addr, + pc_value, sym_index, error); +} + + +/* Make sure attribute types are checked before entering here. */ +static Dwarf_P_Attribute +local_add_AT_address(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Signed form, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + int upointer_size = dbg->de_pointer_size; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + /* attribute types have already been checked */ + /* switch (attr) { ... } */ + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = form; + new_attr->ar_nbytes = upointer_size; + new_attr->ar_rel_symidx = sym_index; + new_attr->ar_reloc_len = upointer_size; + new_attr->ar_next = 0; + if (sym_index != NO_ELF_SYM_INDEX) + new_attr->ar_rel_type = dbg->de_ptr_reloc; + else + new_attr->ar_rel_type = R_MIPS_NONE; + + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(dbg, upointer_size); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + WRITE_UNALIGNED(dbg, new_attr->ar_data, + (const void *) &pc_value, + sizeof(pc_value), upointer_size); + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + +/* Functions to compress and uncompress data from normal + arrays of integral types into arrays of LEB128 numbers. + Extend these functions as needed to handle wider input + variety. Return values should be freed with _dwarf_p_dealloc + after they aren't needed any more. */ + +/* return value points to an array of LEB number */ + +void * +dwarf_compress_integer_block( + Dwarf_P_Debug dbg, + Dwarf_Bool unit_is_signed, + Dwarf_Small unit_length_in_bits, + void* input_block, + Dwarf_Unsigned input_length_in_units, + Dwarf_Unsigned* output_length_in_bytes_ptr, + Dwarf_Error* error +) +{ + Dwarf_Unsigned output_length_in_bytes = 0; + char * output_block = 0; + char encode_buffer[ENCODE_SPACE_NEEDED]; + int i = 0; + char * ptr = 0; + int remain = 0; + int result = 0; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return((void *)DW_DLV_BADADDR); + } + + if (unit_is_signed == false || + unit_length_in_bits != 32 || + input_block == NULL || + input_length_in_units == 0 || + output_length_in_bytes_ptr == NULL) { + + _dwarf_p_error(NULL, error, DW_DLE_BADBITC); + return ((void *) DW_DLV_BADADDR); + } + + /* At this point we assume the format is: signed 32 bit */ + + /* First compress everything to find the total size. */ + + output_length_in_bytes = 0; + for (i=0; i<input_length_in_units; i++) { + int unit_encoded_size; + Dwarf_sfixed unit; /* this is fixed at signed-32-bits */ + + unit = ((Dwarf_sfixed*)input_block)[i]; + + result = _dwarf_pro_encode_signed_leb128_nm(unit, &unit_encoded_size, + encode_buffer,sizeof(encode_buffer)); + if (result != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + output_length_in_bytes += unit_encoded_size; + } + + + /* Then alloc */ + + output_block = (void *) + _dwarf_p_get_alloc(dbg, output_length_in_bytes); + if (output_block == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((void*)DW_DLV_BADADDR); + } + + /* Then compress again and copy into new buffer */ + + ptr = output_block; + remain = output_length_in_bytes; + for (i=0; i<input_length_in_units; i++) { + int unit_encoded_size; + Dwarf_sfixed unit; /* this is fixed at signed-32-bits */ + + unit = ((Dwarf_sfixed*)input_block)[i]; + + result = _dwarf_pro_encode_signed_leb128_nm(unit, &unit_encoded_size, + ptr, remain); + if (result != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + remain -= unit_encoded_size; + ptr += unit_encoded_size; + } + + if (remain != 0) { + _dwarf_p_dealloc(dbg, (unsigned char *)output_block); + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + *output_length_in_bytes_ptr = output_length_in_bytes; + return (void*) output_block; + +} + +void +dwarf_dealloc_compressed_block(Dwarf_P_Debug dbg, void * space) +{ + _dwarf_p_dealloc(dbg, space); +} + +/* This is very similar to targ_address but results in a different FORM */ +/* dbg->de_ar_data_attribute_form is data4 or data8 + and dwarf4 changes the definition for such on DW_AT_high_pc. + DWARF 3: the FORM here has no defined meaning for dwarf3. + DWARF 4: the FORM here means that for DW_AT_high_pc the value + is not a high address but is instead an offset + from a (separate) DW_AT_low_pc. + The intent for DWARF4 is that this is not a relocated + address at all. Instead a simple offset. + But this should NOT be called for a simple non-relocated offset. + So do not call this with an attr of DW_AT_high_pc. + Use dwarf_add_AT_unsigned_const() (for example) instead of + dwarf_add_AT_dataref when the value is a simple offset . */ +Dwarf_P_Attribute +dwarf_add_AT_dataref( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned pc_value, + Dwarf_Unsigned sym_index, + Dwarf_Error * error) +{ + /* TODO: Add checking here */ + return local_add_AT_address(dbg, ownerdie, attr, + dbg->de_ar_data_attribute_form, + pc_value, + sym_index, + error); +} + + + +Dwarf_P_Attribute +dwarf_add_AT_block( + Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Small *block_data, + Dwarf_Unsigned block_size, + Dwarf_Error *error +) +{ + Dwarf_P_Attribute new_attr = 0; + int result = 0; + char encode_buffer[ENCODE_SPACE_NEEDED]; + int len_size = 0; + char * attrdata = 0; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + /* I don't mess with block1, block2, block4, not worth the effort */ + + /* So, encode the length into LEB128 */ + result = _dwarf_pro_encode_leb128_nm(block_size, &len_size, + encode_buffer,sizeof(encode_buffer)); + if (result != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + /* Allocate the new attribute */ + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + /* Fill in the attribute */ + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = DW_FORM_block; + new_attr->ar_nbytes = len_size + block_size; + new_attr->ar_next = 0; + + new_attr->ar_data = attrdata = (char *) + _dwarf_p_get_alloc(dbg, len_size + block_size); + if (new_attr->ar_data == NULL) { + /* free the block we got earlier */ + _dwarf_p_dealloc(dbg, (unsigned char *) new_attr); + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + /* write length and data to attribute data buffer */ + memcpy(attrdata, encode_buffer, len_size); + attrdata += len_size; + memcpy(attrdata, block_data, block_size); + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + + return new_attr; +} + + +/* + This function adds attributes whose value + is an unsigned constant. It determines the + size of the value field from the value of + the constant. +*/ +Dwarf_P_Attribute +dwarf_add_AT_unsigned_const(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Unsigned value, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Small size = 0; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + 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_encoding: + case DW_AT_identifier_case: + case DW_AT_MIPS_loop_unroll_factor: + case DW_AT_MIPS_software_pipeline_depth: + break; + + case DW_AT_decl_column: + case DW_AT_decl_file: + case DW_AT_decl_line: + case DW_AT_const_value: + case DW_AT_start_scope: + case DW_AT_stride_size: + case DW_AT_count: + case DW_AT_associated: + case DW_AT_allocated: + case DW_AT_upper_bound: + case DW_AT_lower_bound: + case DW_AT_call_file: + case DW_AT_call_line: + break; + + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } + + /* Compute the number of bytes needed to hold constant. */ + if (value <= UCHAR_MAX) { + attr_form = DW_FORM_data1; + size = 1; + } else if (value <= USHRT_MAX) { + attr_form = DW_FORM_data2; + size = 2; + } else if (value <= UINT_MAX) { + attr_form = DW_FORM_data4; + size = 4; + } else { + attr_form = DW_FORM_data8; + size = 8; + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = attr_form; + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_reloc_len = 0; /* irrelevant: unused with R_MIPS_NONE */ + new_attr->ar_nbytes = size; + new_attr->ar_next = 0; + + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(dbg, size); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + WRITE_UNALIGNED(dbg, new_attr->ar_data, + (const void *) &value, sizeof(value), size); + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +/* This function adds attributes whose value + is an signed constant. It determines the + size of the value field from the value of + the constant. */ +Dwarf_P_Attribute +dwarf_add_AT_signed_const(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Signed value, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Small size = 0; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + switch (attr) { + case DW_AT_lower_bound: + case DW_AT_upper_bound: + case DW_AT_const_value: + case DW_AT_bit_offset: + case DW_AT_bit_size: + case DW_AT_byte_size: + case DW_AT_count: + case DW_AT_byte_stride: + case DW_AT_bit_stride: + case DW_AT_allocated: + case DW_AT_associated: + break; + + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } + + /* Compute the number of bytes needed to hold constant. */ + if (value >= SCHAR_MIN && value <= SCHAR_MAX) { + attr_form = DW_FORM_data1; + size = 1; + } else if (value >= SHRT_MIN && value <= SHRT_MAX) { + attr_form = DW_FORM_data2; + size = 2; + } else if (value >= INT_MIN && value <= INT_MAX) { + attr_form = DW_FORM_data4; + size = 4; + } else { + attr_form = DW_FORM_data8; + size = 8; + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = attr_form; + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_reloc_len = 0; /* irrelevant: unused with R_MIPS_NONE */ + new_attr->ar_nbytes = size; + new_attr->ar_next = 0; + + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(dbg, size); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + WRITE_UNALIGNED(dbg, new_attr->ar_data, + (const void *) &value, sizeof(value), size); + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +/* This function adds attributes whose value + is a location expression. */ +Dwarf_P_Attribute +dwarf_add_AT_location_expr(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_P_Expr loc_expr, Dwarf_Error * error) +{ + char encode_buffer[ENCODE_SPACE_NEEDED]; + int res = 0; + Dwarf_P_Attribute new_attr = 0; + Dwarf_Half attr_form = 0; + char *len_str = 0; + int len_size = 0; + int block_size = 0; + char *block_dest_ptr = 0; + int do_len_as_int = 0; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (loc_expr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_EXPR_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (loc_expr->ex_dbg != dbg) { + _dwarf_p_error(dbg, error, DW_DLE_LOC_EXPR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + block_size = loc_expr->ex_next_byte_offset; + + switch (attr) { + case DW_AT_location: + case DW_AT_string_length: + case DW_AT_const_value: + case DW_AT_use_location: + case DW_AT_return_addr: + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_static_link: + case DW_AT_vtable_elem_location: + case DW_AT_lower_bound: + case DW_AT_upper_bound: + case DW_AT_count: + case DW_AT_associated: + case DW_AT_allocated: + case DW_AT_data_location: + case DW_AT_byte_stride: + case DW_AT_bit_stride: + case DW_AT_byte_size: + case DW_AT_bit_size: + break; + + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } + + /* Compute the number of bytes needed to hold constant. */ + if (block_size <= UCHAR_MAX) { + attr_form = DW_FORM_block1; + len_size = 1; + do_len_as_int = 1; + } else if (block_size <= USHRT_MAX) { + attr_form = DW_FORM_block2; + len_size = 2; + do_len_as_int = 1; + } else if (block_size <= UINT_MAX) { + attr_form = DW_FORM_block4; + len_size = 4; + do_len_as_int = 1; + } else { + attr_form = DW_FORM_block; + res = _dwarf_pro_encode_leb128_nm(block_size, &len_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + len_str = (char *) encode_buffer; + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = attr_form; + new_attr->ar_reloc_len = dbg->de_pointer_size; + if (loc_expr->ex_reloc_sym_index != NO_ELF_SYM_INDEX) { + new_attr->ar_rel_type = dbg->de_ptr_reloc; + } else { + new_attr->ar_rel_type = R_MIPS_NONE; + } + new_attr->ar_rel_symidx = loc_expr->ex_reloc_sym_index; + new_attr->ar_rel_offset = + (Dwarf_Word) loc_expr->ex_reloc_offset + len_size; + + new_attr->ar_nbytes = block_size + len_size; + + new_attr->ar_next = 0; + new_attr->ar_data = block_dest_ptr = + (char *) _dwarf_p_get_alloc(dbg, block_size + len_size); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (do_len_as_int) { + WRITE_UNALIGNED(dbg, block_dest_ptr, (const void *) &block_size, + sizeof(block_size), len_size); + } else { + /* Is uleb number form, DW_FORM_block. See above. */ + memcpy(block_dest_ptr, len_str, len_size); + } + block_dest_ptr += len_size; + memcpy(block_dest_ptr, &(loc_expr->ex_byte_stream[0]), block_size); + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +/* This function adds attributes of reference class. + The references here are local CU references, + not DW_FORM_ref_addr. + The offset field is 4 bytes for 32-bit objects, + and 8-bytes for 64-bit objects. Otherdie is the + that is referenced by ownerdie. + + For reference attributes, the ar_data and ar_nbytes + are not needed. Instead, the ar_ref_die points to + the other die, and its di_offset value is used as + the reference value. */ +Dwarf_P_Attribute +dwarf_add_AT_reference(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_P_Die otherdie, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (otherdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + switch (attr) { + case DW_AT_specification: + case DW_AT_discr: + case DW_AT_common_reference: + case DW_AT_import: + case DW_AT_containing_type: + case DW_AT_default_value: + case DW_AT_abstract_origin: + case DW_AT_friend: + case DW_AT_priority: + case DW_AT_type: + case DW_AT_lower_bound: + case DW_AT_upper_bound: + case DW_AT_count: + case DW_AT_associated: + case DW_AT_allocated: + case DW_AT_bit_offset: + case DW_AT_bit_size: + case DW_AT_byte_size: + case DW_AT_sibling: + case DW_AT_bit_stride: + case DW_AT_byte_stride: + case DW_AT_namelist_item: + break; + + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = dbg->de_ar_ref_attr_form; + new_attr->ar_nbytes = dbg->de_offset_size; + new_attr->ar_reloc_len = dbg->de_offset_size; + new_attr->ar_ref_die = otherdie; + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_next = 0; + + /* Add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +/* This function adds attributes of the flag class. */ +Dwarf_P_Attribute +dwarf_add_AT_flag(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, + Dwarf_Small flag, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr = 0; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + +#if 0 + switch (attr) { + case DW_AT_is_optional: + case DW_AT_artificial: + case DW_AT_declaration: + case DW_AT_external: + case DW_AT_prototyped: + case DW_AT_variable_parameter: + break; + + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } +#endif + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = DW_FORM_flag; + new_attr->ar_nbytes = 1; + new_attr->ar_reloc_len = 0; /* not used */ + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_next = 0; + + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(dbg, 1); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + memcpy(new_attr->ar_data, &flag, 1); + + /* Add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +/* This function adds values of attributes + belonging to the string class. */ +Dwarf_P_Attribute +dwarf_add_AT_string(Dwarf_P_Debug dbg, + Dwarf_P_Die ownerdie, + Dwarf_Half attr, char *string, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + if (ownerdie == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + switch (attr) { + case DW_AT_name: + case DW_AT_comp_dir: + case DW_AT_const_value: + case DW_AT_producer: + break; + + default: + if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) { + _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + break; + } + + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form = DW_FORM_string; + new_attr->ar_nbytes = strlen(string) + 1; + new_attr->ar_next = 0; + + new_attr->ar_data = + (char *) _dwarf_p_get_alloc(dbg, strlen(string)+1); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + strcpy(new_attr->ar_data, string); + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */ + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +Dwarf_P_Attribute +dwarf_add_AT_const_value_string(Dwarf_P_Die ownerdie, + char *string_value, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + + if (ownerdie == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = DW_AT_const_value; + new_attr->ar_attribute_form = DW_FORM_string; + new_attr->ar_nbytes = strlen(string_value) + 1; + new_attr->ar_next = 0; + + new_attr->ar_data = + (char *) _dwarf_p_get_alloc(ownerdie->di_dbg, strlen(string_value)+1); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + strcpy(new_attr->ar_data, string_value); + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */ + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +Dwarf_P_Attribute +dwarf_add_AT_producer(Dwarf_P_Die ownerdie, + char *producer_string, Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + + if (ownerdie == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = DW_AT_producer; + new_attr->ar_attribute_form = DW_FORM_string; + new_attr->ar_nbytes = strlen(producer_string) + 1; + new_attr->ar_next = 0; + + new_attr->ar_data = + (char *) _dwarf_p_get_alloc(ownerdie->di_dbg, strlen(producer_string)+1); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + strcpy(new_attr->ar_data, producer_string); + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */ + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +Dwarf_P_Attribute +dwarf_add_AT_const_value_signedint(Dwarf_P_Die ownerdie, + Dwarf_Signed signed_value, + Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr = 0; + int leb_size = 0; + char encode_buffer[ENCODE_SPACE_NEEDED]; + int res = 0; + + if (ownerdie == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = DW_AT_const_value; + new_attr->ar_attribute_form = DW_FORM_sdata; + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */ + new_attr->ar_next = 0; + + res = _dwarf_pro_encode_signed_leb128_nm(signed_value, &leb_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(ownerdie->di_dbg, leb_size); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + memcpy(new_attr->ar_data, encode_buffer, leb_size); + new_attr->ar_nbytes = leb_size; + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} + + +Dwarf_P_Attribute +dwarf_add_AT_const_value_unsignedint(Dwarf_P_Die ownerdie, + Dwarf_Unsigned unsigned_value, + Dwarf_Error * error) +{ + Dwarf_P_Attribute new_attr; + int leb_size; + char encode_buffer[ENCODE_SPACE_NEEDED]; + int res; + + if (ownerdie == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr = (Dwarf_P_Attribute) + _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s)); + if (new_attr == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + + new_attr->ar_attribute = DW_AT_const_value; + new_attr->ar_attribute_form = DW_FORM_udata; + new_attr->ar_rel_type = R_MIPS_NONE; + new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */ + new_attr->ar_next = 0; + + res = _dwarf_pro_encode_leb128_nm(unsigned_value, &leb_size, + encode_buffer, + sizeof(encode_buffer)); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + new_attr->ar_data = (char *) + _dwarf_p_get_alloc(ownerdie->di_dbg, leb_size); + if (new_attr->ar_data == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL); + return ((Dwarf_P_Attribute) DW_DLV_BADADDR); + } + memcpy(new_attr->ar_data, encode_buffer, leb_size); + new_attr->ar_nbytes = leb_size; + + /* add attribute to the die */ + _dwarf_pro_add_at_to_die(ownerdie, new_attr); + return new_attr; +} diff --git a/libdwarf/pro_frame.c b/libdwarf/pro_frame.c new file mode 100644 index 0000000..d43f292 --- /dev/null +++ b/libdwarf/pro_frame.c @@ -0,0 +1,582 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include "pro_incl.h" +#include "pro_frame.h" + +static void _dwarf_pro_add_to_fde(Dwarf_P_Fde fde, + Dwarf_P_Frame_Pgm inst); + +/* This function adds a cie struct to the debug pointer. Its in the + form of a linked list. + augmenter: string reps augmentation (implementation defined) + code_align: alignment of code + data_align: alignment of data + init_bytes: byts having initial instructions + init_n_bytes: number of bytes of initial instructions */ +Dwarf_Unsigned +dwarf_add_frame_cie(Dwarf_P_Debug dbg, + char *augmenter, + Dwarf_Small code_align, + Dwarf_Small data_align, + Dwarf_Small return_reg, + Dwarf_Ptr init_bytes, + Dwarf_Unsigned init_n_bytes, Dwarf_Error * error) +{ + Dwarf_P_Cie curcie; + + if (dbg->de_frame_cies == NULL) { + dbg->de_frame_cies = (Dwarf_P_Cie) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s)); + if (dbg->de_frame_cies == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT); + } + curcie = dbg->de_frame_cies; + dbg->de_n_cie = 1; + dbg->de_last_cie = curcie; + } else { + curcie = dbg->de_last_cie; + curcie->cie_next = (Dwarf_P_Cie) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s)); + if (curcie->cie_next == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT); + } + curcie = curcie->cie_next; + dbg->de_n_cie++; + dbg->de_last_cie = curcie; + } + curcie->cie_version = DW_CIE_VERSION; + curcie->cie_aug = augmenter; + curcie->cie_code_align = code_align; + curcie->cie_data_align = data_align; + curcie->cie_ret_reg = return_reg; + curcie->cie_inst = (char *) init_bytes; + curcie->cie_inst_bytes = (long) init_n_bytes; + curcie->cie_next = NULL; + return dbg->de_n_cie; +} + + +/* This functions adds a fde struct to the debug pointer. Its in the + form of a linked list. + die: subprogram/function die corresponding to this fde + cie: cie referred to by this fde, obtained from call to + add_frame_cie() routine. + virt_addr: beginning address + code_len: length of code reps by the fde */ +/*ARGSUSED*/ /* pretend all args used */ +Dwarf_Unsigned +dwarf_add_frame_fde(Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Unsigned virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned symidx, Dwarf_Error * error) +{ + return dwarf_add_frame_fde_b(dbg, fde, die, cie, virt_addr, + code_len, symidx, 0, 0, error); +} + +/*ARGSUSED10*/ +Dwarf_Unsigned +dwarf_add_frame_fde_b(Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Unsigned virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned symidx, + Dwarf_Unsigned symidx_of_end, + Dwarf_Addr offset_from_end_sym, + Dwarf_Error * error) +{ + Dwarf_P_Fde curfde; + + fde->fde_die = die; + fde->fde_cie = (long) cie; + fde->fde_initloc = virt_addr; + fde->fde_r_symidx = symidx; + fde->fde_addr_range = code_len; + fde->fde_offset_into_exception_tables = DW_DLX_NO_EH_OFFSET; + fde->fde_exception_table_symbol = 0; + fde->fde_end_symbol_offset = offset_from_end_sym; + fde->fde_end_symbol = symidx_of_end; + fde->fde_dbg = dbg; + + curfde = dbg->de_last_fde; + if (curfde == NULL) { + dbg->de_frame_fdes = fde; + dbg->de_last_fde = fde; + dbg->de_n_fde = 1; + } else { + curfde->fde_next = fde; + dbg->de_last_fde = fde; + dbg->de_n_fde++; + } + return dbg->de_n_fde; +} + +/* This function adds information to an fde. The fde is + linked into the linked list of fde's maintained in the Dwarf_P_Debug + structure. + dbg: The debug descriptor. + fde: The fde to be added. + die: subprogram/function die corresponding to this fde + cie: cie referred to by this fde, obtained from call to + add_frame_cie() routine. + virt_addr: beginning address + code_len: length of code reps by the fde + symidx: The symbol id of the symbol wrt to which relocation needs + to be performed for 'virt_addr'. + offset_into_exception_tables: The start of exception tables for + this function (indicated as an offset into the exception + tables). A value of -1 indicates that there is no exception + table entries associated with this function. + exception_table_symbol: The symbol id of the section for exception + tables wrt to which the offset_into_exception_tables will + be relocated. */ +Dwarf_Unsigned +dwarf_add_frame_info(Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Unsigned virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned symidx, + Dwarf_Signed offset_into_exception_tables, + Dwarf_Unsigned exception_table_symbol, + Dwarf_Error * error) +{ + + return dwarf_add_frame_info_b(dbg, fde, die, cie, virt_addr, + code_len, symidx, + /* end_symbol */ 0, + /* offset_from_end */ 0, + offset_into_exception_tables, + exception_table_symbol, error); + +} + +/*ARGSUSED*/ /* pretend all args used */ +Dwarf_Unsigned +dwarf_add_frame_info_b(Dwarf_P_Debug dbg, + Dwarf_P_Fde fde, + Dwarf_P_Die die, + Dwarf_Unsigned cie, + Dwarf_Unsigned virt_addr, + Dwarf_Unsigned code_len, + Dwarf_Unsigned symidx, + Dwarf_Unsigned end_symidx, + Dwarf_Unsigned offset_from_end_symbol, + Dwarf_Signed offset_into_exception_tables, + Dwarf_Unsigned exception_table_symbol, + Dwarf_Error * error) +{ + Dwarf_P_Fde curfde; + + fde->fde_die = die; + fde->fde_cie = (long) cie; + fde->fde_initloc = virt_addr; + fde->fde_r_symidx = symidx; + fde->fde_addr_range = code_len; + fde->fde_offset_into_exception_tables = + offset_into_exception_tables; + fde->fde_exception_table_symbol = exception_table_symbol; + fde->fde_end_symbol_offset = offset_from_end_symbol; + fde->fde_end_symbol = end_symidx; + fde->fde_dbg = dbg; + + curfde = dbg->de_last_fde; + if (curfde == NULL) { + dbg->de_frame_fdes = fde; + dbg->de_last_fde = fde; + dbg->de_n_fde = 1; + } else { + curfde->fde_next = fde; + dbg->de_last_fde = fde; + dbg->de_n_fde++; + } + return dbg->de_n_fde; +} + +/* This is an alternate to inserting frame instructions + one instruction at a time. But use either this + or instruction level, not both in one fde. */ +int +dwarf_insert_fde_inst_bytes(Dwarf_P_Debug dbg, + Dwarf_P_Fde fde,Dwarf_Unsigned len, Dwarf_Ptr ibytes, + Dwarf_Error *error) +{ + if( len == 0) { + return DW_DLV_OK; + } + if(fde->fde_block || fde->fde_inst) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DUPLICATE_INST_BLOCK, + (int)DW_DLV_BADADDR); + } + fde->fde_block = (Dwarf_Ptr)_dwarf_p_get_alloc(dbg, len); + memcpy(fde->fde_block,ibytes,len); + fde->fde_inst_block_size = len; + fde->fde_n_bytes += len; + return DW_DLV_OK; +} + + + +/* Create a new fde. */ +Dwarf_P_Fde +dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + Dwarf_P_Fde fde; + + fde = (Dwarf_P_Fde) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Fde_s)); + if (fde == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_FDE_ALLOC, + (Dwarf_P_Fde) DW_DLV_BADADDR); + } + fde->fde_uwordb_size = dbg->de_offset_size; + return fde; +} + + +/* Add a cfe_offset instruction to the fde passed in. */ +Dwarf_P_Fde +dwarf_fde_cfa_offset(Dwarf_P_Fde fde, + Dwarf_Unsigned reg, + Dwarf_Signed offset, Dwarf_Error * error) +{ + Dwarf_Ubyte opc, regno; + char *ptr = 0; + Dwarf_P_Frame_Pgm curinst; + int nbytes = 0; + int res = 0; + char buff1[ENCODE_SPACE_NEEDED]; + Dwarf_P_Debug dbg = fde->fde_dbg; + + curinst = (Dwarf_P_Frame_Pgm) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s)); + if (curinst == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_FPGM_ALLOC, + (Dwarf_P_Fde) DW_DLV_BADADDR); + } + opc = DW_CFA_offset; + regno = reg; + if (regno & 0xc0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_REGNO_OVFL, + (Dwarf_P_Fde) DW_DLV_BADADDR); + } + opc = opc | regno; /* lower 6 bits are register number */ + curinst->dfp_opcode = opc; + res = _dwarf_pro_encode_leb128_nm(offset, &nbytes, + buff1, sizeof(buff1)); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy(ptr, buff1, nbytes); + + curinst->dfp_args = ptr; + curinst->dfp_nbytes = nbytes; + curinst->dfp_next = NULL; + + _dwarf_pro_add_to_fde(fde, curinst); + return fde; +} + +/* Generic routine to add opcode to fde instructions. val1 and + val2 are parameters whose interpretation depends on the 'op'. + + This does not work properly for DW_DLC_SYMBOLIC_RELOCATIONS + for DW_CFA_set_loc or DW_DVA_advance_loc* 'op', as + these ops normally are addresses or (DW_CFA_set_loc) + or code lengths (DW_DVA_advance_loc*) and such must be + represented with relocations and symbol indices for + DW_DLC_SYMBOLIC_RELOCATIONS. + + This does not treat all DW_CFA instructions yet. + + For certain operations a val? value must be + signed (though passed in as unsigned here). + + Currently this does not check that the frame + version is 3(for dwarf3) or 4 (for dwarf4) + when applying operations that are only valid for + dwarf3 or dwarf4. */ +Dwarf_P_Fde +dwarf_add_fde_inst(Dwarf_P_Fde fde, + Dwarf_Small op, + Dwarf_Unsigned val1, + Dwarf_Unsigned val2, Dwarf_Error * error) +{ + Dwarf_P_Frame_Pgm curinst; + int nbytes, nbytes1, nbytes2; + Dwarf_Ubyte db; + Dwarf_Half dh; + Dwarf_Word dw; + Dwarf_Unsigned du; + char *ptr; + int res; + char buff1[ENCODE_SPACE_NEEDED]; + char buff2[ENCODE_SPACE_NEEDED]; + Dwarf_P_Debug dbg = fde->fde_dbg; + /* This is a hack telling the code when to transform + a value to a signed leb number. */ + int signed_second = 0; + int signed_first = 0; + + + nbytes = 0; + ptr = NULL; + curinst = (Dwarf_P_Frame_Pgm) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s)); + if (curinst == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_FPGM_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + + switch (op) { + + case DW_CFA_advance_loc: + if (val1 <= 0x3f) { + db = val1; + op |= db; + } + /* test not portable FIX */ + else if (val1 <= UCHAR_MAX) { + op = DW_CFA_advance_loc1; + db = val1; + ptr = (char *) _dwarf_p_get_alloc(dbg, 1); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy((void *) ptr, (const void *) &db, 1); + nbytes = 1; + } + /* test not portable FIX */ + else if (val1 <= USHRT_MAX) { + op = DW_CFA_advance_loc2; + dh = val1; + ptr = (char *) _dwarf_p_get_alloc(dbg, 2); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy((void *) ptr, (const void *) &dh, 2); + nbytes = 2; + } + /* test not portable FIX */ + else if (val1 <= ULONG_MAX) { + op = DW_CFA_advance_loc4; + dw = (Dwarf_Word) val1; + ptr = (char *) _dwarf_p_get_alloc(dbg, 4); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy((void *) ptr, (const void *) &dw, 4); + nbytes = 4; + } else { + op = DW_CFA_MIPS_advance_loc8; + du = val1; + ptr = + (char *) _dwarf_p_get_alloc(dbg, + sizeof(Dwarf_Unsigned)); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy((void *) ptr, (const void *) &du, 8); + nbytes = 8; + } + break; + + case DW_CFA_offset: + if (val1 <= MAX_6_BIT_VALUE) { + db = val1; + op |= db; + res = _dwarf_pro_encode_leb128_nm(val2, &nbytes, + buff1, sizeof(buff1)); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy(ptr, buff1, nbytes); + + } else { + op = DW_CFA_offset_extended; + goto two_leb; + } + break; + case DW_CFA_offset_extended_sf: /* DWARF3 */ + signed_second = 1; + goto two_leb; + case DW_CFA_offset_extended: + goto two_leb; + + case DW_CFA_undefined: + case DW_CFA_same_value: + goto one_leb; + + case DW_CFA_val_offset: + goto two_leb; + case DW_CFA_val_offset_sf: + signed_second = 1; + goto two_leb; + case DW_CFA_def_cfa_sf: + signed_second = 1; + goto two_leb; + case DW_CFA_register: + case DW_CFA_def_cfa: + two_leb: + res = _dwarf_pro_encode_leb128_nm(val1, &nbytes1, + buff1, sizeof(buff1)); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + if (!signed_second) { + res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2, + buff2, sizeof(buff2)); + } else { + Dwarf_Signed val2s = val2; + res = _dwarf_pro_encode_signed_leb128_nm(val2s, &nbytes2, + buff2, sizeof(buff2)); + } + + res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2, + buff2, sizeof(buff2)); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + + ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes1 + nbytes2); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy(ptr, buff1, nbytes1); + memcpy(ptr + nbytes1, buff2, nbytes2); + nbytes = nbytes1 + nbytes2; + break; + + case DW_CFA_def_cfa_offset_sf: /* DWARF3 */ + signed_first = 1; + goto one_leb; + case DW_CFA_def_cfa_register: + case DW_CFA_def_cfa_offset: + one_leb: + if(!signed_first) { + res = _dwarf_pro_encode_leb128_nm(val1, &nbytes, + buff1, sizeof(buff1)); + } else { + Dwarf_Signed val1s = val1; + res = _dwarf_pro_encode_signed_leb128_nm(val1s, &nbytes, + buff1, sizeof(buff1)); + } + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes); + if (ptr == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + memcpy(ptr, buff1, nbytes); + break; + case DW_CFA_def_cfa_expression: /* DWARF3 */ + /* FIXME: argument is dwarf expr, not handled yet. */ + case DW_CFA_expression: /* DWARF3 */ + /* First arg: ULEB reg num. 2nd arg dwarf expr in form block. + FIXME: not handled yet. */ + case DW_CFA_val_expression: /* DWARF3f */ + /* First arg: ULEB reg num. 2nd arg dwarf expr in form block. + FIXME: not handled yet. */ + default: + _dwarf_p_error(dbg, error, DW_DLE_DEBUGFRAME_ERROR); + return ((Dwarf_P_Fde) DW_DLV_BADADDR); + } + + curinst->dfp_opcode = op; + curinst->dfp_args = ptr; + curinst->dfp_nbytes = nbytes; + curinst->dfp_next = NULL; + + _dwarf_pro_add_to_fde(fde, curinst); + return fde; +} + + +/* Instructions are added to an fde in the form of a linked + list. This function manages the linked list. */ +void +_dwarf_pro_add_to_fde(Dwarf_P_Fde fde, Dwarf_P_Frame_Pgm curinst) +{ + if (fde->fde_last_inst) { + fde->fde_last_inst->dfp_next = curinst; + fde->fde_last_inst = curinst; + fde->fde_n_inst++; + fde->fde_n_bytes += + (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte)); + } else { + fde->fde_last_inst = curinst; + fde->fde_inst = curinst; + fde->fde_n_inst = 1; + fde->fde_n_bytes = + (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte)); + } +} diff --git a/libdwarf/pro_frame.h b/libdwarf/pro_frame.h new file mode 100644 index 0000000..883f084 --- /dev/null +++ b/libdwarf/pro_frame.h @@ -0,0 +1,129 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +/* + Largest register value that can be coded into + the opcode since there are only 6 bits in the + register field. +*/ +#define MAX_6_BIT_VALUE 0x3f + +/* This struct holds debug_frame instructions */ +typedef struct Dwarf_P_Frame_Pgm_s *Dwarf_P_Frame_Pgm; + +struct Dwarf_P_Frame_Pgm_s { + Dwarf_Ubyte dfp_opcode; /* opcode - includes reg # */ + char *dfp_args; /* operands */ + int dfp_nbytes; /* number of bytes in args */ +#if 0 + Dwarf_Unsigned dfp_sym_index; /* 0 unless reloc needed */ +#endif + Dwarf_P_Frame_Pgm dfp_next; +}; + + +/* + This struct has cie related information. Used to gather data + from user program, and later to transform to disk form +*/ +struct Dwarf_P_Cie_s { + Dwarf_Ubyte cie_version; + char *cie_aug; /* augmentation */ + Dwarf_Ubyte cie_code_align; /* alignment of code */ + Dwarf_Sbyte cie_data_align; + Dwarf_Ubyte cie_ret_reg; /* return register # */ + char *cie_inst; /* initial instruction */ + long cie_inst_bytes; + /* no of init_inst */ + Dwarf_P_Cie cie_next; +}; + + +/* producer fields */ +struct Dwarf_P_Fde_s { + Dwarf_Unsigned fde_unused1; + + /* function/subr die for this fde */ + Dwarf_P_Die fde_die; + + /* index to asso. cie */ + Dwarf_Word fde_cie; + + /* Address of first location of the code this frame applies to If + fde_end_symbol non-zero, this represents the offset from the + symbol indicated by fde_r_symidx */ + Dwarf_Addr fde_initloc; + + /* Relocation symbol for address of the code this frame applies to. */ + Dwarf_Unsigned fde_r_symidx; + + /* Bytes of instr for this fde, if known */ + Dwarf_Unsigned fde_addr_range; + + /* linked list of instructions we will put in fde. */ + Dwarf_P_Frame_Pgm fde_inst; + + /* number of instructions in fde */ + long fde_n_inst; + + /* number of bytes of inst in fde */ + long fde_n_bytes; + + /* offset into exception table for this function. */ + Dwarf_Signed fde_offset_into_exception_tables; + + /* The symbol for the exception table elf section. */ + Dwarf_Unsigned fde_exception_table_symbol; + + /* pointer to last inst */ + Dwarf_P_Frame_Pgm fde_last_inst; + + Dwarf_P_Fde fde_next; + + /* The symbol and offset of the end symbol. When fde_end_symbol is + non-zero we must represent the */ + Dwarf_Addr fde_end_symbol_offset; + Dwarf_Unsigned fde_end_symbol; + + int fde_uwordb_size; + Dwarf_P_Debug fde_dbg; + + /* If fde_block is non-null, then it is the set of instructions. + so we should use it rather than fde_inst. */ + Dwarf_Unsigned fde_inst_block_size; + void *fde_block; +}; diff --git a/libdwarf/pro_funcs.c b/libdwarf/pro_funcs.c new file mode 100644 index 0000000..2c6b114 --- /dev/null +++ b/libdwarf/pro_funcs.c @@ -0,0 +1,61 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#endif +#include "pro_incl.h" +#include "pro_section.h" + +/* This function adds another function name to the + list of function names for the given Dwarf_P_Debug. + It returns 0 on error, and 1 otherwise. */ +Dwarf_Unsigned +dwarf_add_funcname(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *function_name, Dwarf_Error * error) +{ + return + _dwarf_add_simple_name_entry(dbg, die, function_name, + dwarf_snk_funcname, error); + +} diff --git a/libdwarf/pro_incl.h b/libdwarf/pro_incl.h new file mode 100644 index 0000000..9052dba --- /dev/null +++ b/libdwarf/pro_incl.h @@ -0,0 +1,95 @@ +/* + + Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2010 David Anderson. All rights reserved. + Portions Copyright 2010 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + +#ifdef HAVE_ELF_H +#include <elf.h> +#elif defined(HAVE_LIBELF_H) +/* On one platform without elf.h this gets Elf32_Rel + type defined (a required type). */ +#include <libelf.h> +/* Consider the other known directory too */ +#elif defined(HAVE_LIBELF_LIBELF_H) +#include <libelf/libelf.h> +#endif + +#if defined(sun) +#include <sys/elf_SPARC.h> +#include <sys/elf_386.h> +#endif + +/* The target address is given: the place in the source integer + is to be determined. +*/ +#ifdef WORDS_BIGENDIAN +#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \ + { \ + dbg->de_copy_word(dest, \ + ((char *)source) +(srclength)-(len_out),\ + (len_out)) ; \ + } + + +#else /* LITTLE ENDIAN */ + +#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \ + { \ + dbg->de_copy_word( (dest) , \ + ((char *)source) , \ + (len_out)) ; \ + } +#endif + + +#if defined(sparc) && defined(sun) +#define REL32 Elf32_Rela +#define REL64 Elf64_Rela +#define REL_SEC_PREFIX ".rela" +#else +#define REL32 Elf32_Rel +#define REL64 Elf64_Rel +#define REL_SEC_PREFIX ".rel" +#endif + +#include "dwarf.h" +#include "libdwarf.h" + +#include "pro_opaque.h" +#include "pro_error.h" +#include "pro_util.h" +#include "pro_encode_nm.h" +#include "pro_alloc.h" diff --git a/libdwarf/pro_init.c b/libdwarf/pro_init.c new file mode 100644 index 0000000..d293136 --- /dev/null +++ b/libdwarf/pro_init.c @@ -0,0 +1,291 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2011 David Anderson, Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#include "pro_incl.h" +#include "pro_section.h" /* for MAGIC_SECT_NO */ +#include "pro_reloc_symbolic.h" +#include "pro_reloc_stream.h" + + +static void common_init(Dwarf_P_Debug dbg, Dwarf_Unsigned flags); + +void *_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len); + +/* This function sets up a new dwarf producing region. + flags: Indicates type of access method, one of DW_DLC* macros + func(): Used to create a new object file, a call back function + errhand(): Error Handler provided by user + errarg: Argument to errhand() + error: returned error value */ + /* We want the following to have an elf section number that matches + 'nothing' */ +static struct Dwarf_P_Section_Data_s init_sect = { + MAGIC_SECT_NO, 0, 0, 0, 0 +}; + +/* New June, 2011, this is the latest, most flexible + version. It adds (compared to *_b) the user_data + pointer which is passed back (unchanged) in + each callback call. */ +Dwarf_P_Debug +dwarf_producer_init_c(Dwarf_Unsigned flags, + Dwarf_Callback_Func_c func, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + void * user_data, + Dwarf_Error * error) +{ + Dwarf_P_Debug dbg; + dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL, + sizeof(struct Dwarf_P_Debug_s)); + if (dbg == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, + (Dwarf_P_Debug) DW_DLV_BADADDR); + } + memset((void *) dbg, 0, sizeof(struct Dwarf_P_Debug_s)); + /* For the time being */ + if (func == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC, + (Dwarf_P_Debug) DW_DLV_BADADDR); + } + dbg->de_callback_func_c = func; + dbg->de_errhand = errhand; + dbg->de_errarg = errarg; + dbg->de_user_data = user_data; + common_init(dbg, flags); + return dbg; + +} + + +Dwarf_P_Debug +dwarf_producer_init_b(Dwarf_Unsigned flags, + Dwarf_Callback_Func_b func, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, Dwarf_Error * error) +{ + Dwarf_P_Debug dbg; + dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL, + sizeof(struct Dwarf_P_Debug_s)); + if (dbg == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, + (Dwarf_P_Debug) DW_DLV_BADADDR); + } + memset((void *) dbg, 0, sizeof(struct Dwarf_P_Debug_s)); + /* For the time being */ + if (func == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC, + (Dwarf_P_Debug) DW_DLV_BADADDR); + } + dbg->de_callback_func_b = func; + dbg->de_errhand = errhand; + dbg->de_errarg = errarg; + dbg->de_user_data = 0; + common_init(dbg, flags); + return dbg; + +} + +Dwarf_P_Debug +dwarf_producer_init(Dwarf_Unsigned flags, + Dwarf_Callback_Func func, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, Dwarf_Error * error) +{ + Dwarf_P_Debug dbg = 0; + + dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL, + sizeof(struct Dwarf_P_Debug_s)); + if (dbg == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, + (Dwarf_P_Debug) DW_DLV_BADADDR); + } + memset((void *) dbg, 0, sizeof(struct Dwarf_P_Debug_s)); + /* For the time being */ + if (func == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC, + (Dwarf_P_Debug) DW_DLV_BADADDR); + } + dbg->de_callback_func = func; + dbg->de_errhand = errhand; + dbg->de_errarg = errarg; + dbg->de_user_data = 0; + common_init(dbg, flags); + return dbg; +} +static void +common_init(Dwarf_P_Debug dbg, Dwarf_Unsigned flags) +{ + unsigned int k = 0; + + dbg->de_version_magic_number = PRO_VERSION_MAGIC; + dbg->de_n_debug_sect = 0; + dbg->de_debug_sects = &init_sect; + dbg->de_current_active_section = &init_sect; + dbg->de_flags = flags; + _dwarf_init_default_line_header_vals(dbg); + + /* Now, with flags set, can use 64bit tests */ + + + +#if defined(HAVE_STRICT_DWARF2_32BIT_OFFSET) + /* This is cygnus 32bit offset, as specified in pure dwarf2 v2.0.0. + It is consistent with normal DWARF2/3 generation of always + generating 32 bit offsets. */ + dbg->de_64bit_extension = 0; + dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4); + dbg->de_offset_size = (IS_64BIT(dbg) ? 4 : 4); + dbg->de_ptr_reloc = + IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg); + /* non-MIPS, dwarf lengths and offsets are 32 bits even for 64bit + pointer environments. */ + /* Get_REL32_isa here supports 64-bit-pointer dwarf with pure + dwarf2 v2.0.0 32bit offsets, as emitted by cygnus tools. And + pure 32 bit offset dwarf for 32bit pointer apps. */ + + dbg->de_offset_reloc = Get_REL32_isa(dbg); +#elif defined(HAVE_SGI_IRIX_OFFSETS) + /* MIPS-SGI-IRIX 32 or 64, where offsets and lengths are both 64 bit for + 64bit pointer objects and both 32 bit for 32bit pointer objects. + And a dwarf-reader must check elf info to tell which applies. */ + dbg->de_64bit_extension = 0; + dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4); + dbg->de_offset_size = (IS_64BIT(dbg) ? 8 : 4); + dbg->de_ptr_reloc = + IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg); + dbg->de_offset_reloc = dbg->de_ptr_reloc; +#else /* HAVE_DWARF2_99_EXTENSION or default. */ + /* Revised 64 bit output, using distingushed values. Per 1999 + dwarf3. This allows run-time selection of offset size. */ + dbg->de_64bit_extension = (IS_64BIT(dbg) ? 1 : 0); + dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4); + if( flags & DW_DLC_OFFSET_SIZE_64 && (dbg->de_pointer_size == 8)) { + /* When it's 64 bit address, a 64bit offset is sensible. + Arguably a 32 bit address with 64 bit offset could be + sensible, but who would want that? */ + dbg->de_offset_size = 8; + dbg->de_64bit_extension = 1; + } else { + dbg->de_offset_size = 4; + dbg->de_64bit_extension = 0; + } + dbg->de_ptr_reloc = + IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg); + /* Non-MIPS, dwarf lengths and offsets are 32 bits even for 64bit + pointer environments. */ + /* Get_REL??_isa here supports 64bit-offset dwarf. For 64bit, we + emit the extension bytes. */ + + dbg->de_offset_reloc = IS_64BIT(dbg) ? Get_REL64_isa(dbg) + : Get_REL32_isa(dbg); +#endif /* HAVE_DWARF2_99_EXTENSION etc. */ + + dbg->de_exc_reloc = Get_REL_SEGREL_isa(dbg); + + dbg->de_is_64bit = IS_64BIT(dbg); + + + if (flags & DW_DLC_SYMBOLIC_RELOCATIONS) { + dbg->de_relocation_record_size = + sizeof(struct Dwarf_Relocation_Data_s); + } else { + +#if HAVE_ELF64_GETEHDR + dbg->de_relocation_record_size = + IS_64BIT(dbg)? sizeof(REL64) : sizeof(REL32); +#else + dbg->de_relocation_record_size = sizeof(REL32); +#endif + + } + + if (dbg->de_offset_size == 8) { + dbg->de_ar_data_attribute_form = DW_FORM_data8; + dbg->de_ar_ref_attr_form = DW_FORM_ref8; + } else { + dbg->de_ar_data_attribute_form = DW_FORM_data4; + dbg->de_ar_ref_attr_form = DW_FORM_ref4; + } + + if (flags & DW_DLC_SYMBOLIC_RELOCATIONS) { + dbg->de_reloc_name = _dwarf_pro_reloc_name_symbolic; + dbg->de_reloc_pair = _dwarf_pro_reloc_length_symbolic; + dbg->de_transform_relocs_to_disk = + _dwarf_symbolic_relocs_to_disk; + } else { + if (IS_64BIT(dbg)) { + dbg->de_reloc_name = _dwarf_pro_reloc_name_stream64; + } else { + dbg->de_reloc_name = _dwarf_pro_reloc_name_stream32; + } + dbg->de_reloc_pair = 0; + dbg->de_transform_relocs_to_disk = _dwarf_stream_relocs_to_disk; + } + for (k = 0; k < NUM_DEBUG_SECTIONS; ++k) { + + Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[k]; + + prel->pr_slots_per_block_to_alloc = DEFAULT_SLOTS_PER_BLOCK; + } + /* First assume host, target same endianness */ + dbg->de_same_endian = 1; + dbg->de_copy_word = memcpy; +#ifdef WORDS_BIGENDIAN + /* host is big endian, so what endian is target? */ + if (flags & DW_DLC_TARGET_LITTLEENDIAN) { + dbg->de_same_endian = 0; + dbg->de_copy_word = _dwarf_memcpy_swap_bytes; + } +#else /* little endian */ + /* host is little endian, so what endian is target? */ + if (flags & DW_DLC_TARGET_BIGENDIAN) { + dbg->de_same_endian = 0; + dbg->de_copy_word = _dwarf_memcpy_swap_bytes; + } +#endif /* !WORDS_BIGENDIAN */ + + + return; + +} diff --git a/libdwarf/pro_line.c b/libdwarf/pro_line.c new file mode 100644 index 0000000..5860f13 --- /dev/null +++ b/libdwarf/pro_line.c @@ -0,0 +1,384 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELF_H +#include <elf.h> +#endif +#include "pro_incl.h" +#include "pro_line.h" + +static +Dwarf_Unsigned _dwarf_pro_add_line_entry(Dwarf_P_Debug, + Dwarf_Unsigned file_index, + Dwarf_Addr code_address, + Dwarf_Unsigned symidx, + Dwarf_Unsigned line_no, + Dwarf_Signed col_no, + Dwarf_Bool is_stmt_begin, + Dwarf_Bool is_bb_begin, + Dwarf_Ubyte opc, + Dwarf_Bool isepilbeg, + Dwarf_Bool isprolend, + Dwarf_Unsigned isa, + Dwarf_Unsigned discriminator, + Dwarf_Error * error); + +/* Add a entry to the line information section + file_index: index of file in file entries, obtained from + add_file_entry() call. + + This function actually calls _dwarf_pro_add_line_entry(), with + an extra parameter, the opcode. Done so that interface calls + dwarf_lne_set_address() and dwarf_lne_end_sequence() can use + this internal routine. */ +Dwarf_Unsigned +dwarf_add_line_entry_b(Dwarf_P_Debug dbg, + Dwarf_Unsigned file_index, + Dwarf_Addr code_address, + Dwarf_Unsigned line_no, + Dwarf_Signed col_no, + Dwarf_Bool is_stmt_begin, + Dwarf_Bool is_bb_begin, + Dwarf_Bool isepilbeg, + Dwarf_Bool isprolend, + Dwarf_Unsigned isa, + Dwarf_Unsigned discriminator, + Dwarf_Error * error) +{ + Dwarf_Unsigned retval = 0; + Dwarf_Ubyte opc = 0; + Dwarf_Unsigned symidx = 0; + + retval = _dwarf_pro_add_line_entry(dbg, file_index, code_address, + symidx, + line_no, col_no, is_stmt_begin, + is_bb_begin, + opc, + isepilbeg,isprolend,isa,discriminator, error); + return retval; +} +Dwarf_Unsigned +dwarf_add_line_entry(Dwarf_P_Debug dbg, + Dwarf_Unsigned file_index, + Dwarf_Addr code_address, + Dwarf_Unsigned line_no, + Dwarf_Signed col_no, /* Wrong, should be unsigned. */ + Dwarf_Bool is_stmt_begin, + Dwarf_Bool is_bb_begin, Dwarf_Error * error) +{ + Dwarf_Unsigned retval = 0; + Dwarf_Ubyte opc = 0; + Dwarf_Unsigned symidx = 0; + Dwarf_Bool isepilbeg = 0; + Dwarf_Bool isprolend = 0; + Dwarf_Unsigned isa = 0; + Dwarf_Unsigned discriminator = 0; + + retval = _dwarf_pro_add_line_entry(dbg, file_index, code_address, + symidx, + line_no, col_no, is_stmt_begin, + is_bb_begin, + opc, + isepilbeg, isprolend, isa, discriminator, + error); + return retval; +} + +void +_dwarf_init_default_line_header_vals(Dwarf_P_Debug dbg) +{ + dbg->de_line_inits.pi_version = DW_LINE_VERSION2; + dbg->de_line_inits.pi_default_is_stmt = DEFAULT_IS_STMT; + dbg->de_line_inits.pi_minimum_instruction_length = MIN_INST_LENGTH; + dbg->de_line_inits.pi_maximum_operations_per_instruction = 1; + dbg->de_line_inits.pi_opcode_base = OPCODE_BASE; + dbg->de_line_inits.pi_line_base = LINE_BASE; + dbg->de_line_inits.pi_line_range = LINE_RANGE; +} + + +/* Ask to emit DW_LNE_set_address opcode explicitly. Used by be + to emit start of a new .text section, or to force a relocated + address into debug line information entry. */ +Dwarf_Unsigned +dwarf_lne_set_address(Dwarf_P_Debug dbg, + Dwarf_Addr offs, + Dwarf_Unsigned symidx, Dwarf_Error * error) +{ + Dwarf_Ubyte opc = 0; + Dwarf_Unsigned retval = 0; + Dwarf_Unsigned file_index = 0; + Dwarf_Unsigned line_no = 0; + Dwarf_Signed col_no = 0; + Dwarf_Bool is_stmt = 0; + Dwarf_Bool is_bb = 0; + Dwarf_Bool isepilbeg = 0; + Dwarf_Bool isprolend = 0; + Dwarf_Unsigned isa = 0; + Dwarf_Unsigned discriminator = 0; + + + opc = DW_LNE_set_address; + retval = + _dwarf_pro_add_line_entry(dbg, file_index, offs, + symidx, + line_no, col_no, is_stmt, + is_bb, + opc, + isepilbeg, isprolend, isa, discriminator, + error); + return retval; +} + +/* Ask to emit end_seqence opcode. Used normally at the end of a + compilation unit. Can also be used in the middle if there + are gaps in the region described by the code address. */ +Dwarf_Unsigned +dwarf_lne_end_sequence(Dwarf_P_Debug dbg, + Dwarf_Addr end_address, Dwarf_Error * error) +{ + Dwarf_Ubyte opc = 0; + Dwarf_Unsigned retval = 0; + Dwarf_Unsigned file_index = 0; + Dwarf_Unsigned symidx = 0; + Dwarf_Unsigned line_no = 0; + Dwarf_Bool is_stmt = 0; + Dwarf_Bool is_bb = 0; + Dwarf_Signed col_no = 0;/* Wrong, should be unsigned. */ + Dwarf_Bool isepilbeg = 0; + Dwarf_Bool isprolend = 0; + Dwarf_Unsigned isa = 0; + Dwarf_Unsigned discriminator = 0; + + opc = DW_LNE_end_sequence; + retval = + _dwarf_pro_add_line_entry(dbg, file_index, end_address, + symidx, + line_no, col_no, is_stmt, + is_bb, + opc, + isepilbeg, isprolend, isa, discriminator, + error); + return retval; +} + +/* Add an entry in the internal list of lines mantained by producer. + Opc indicates if an opcode needs to be generated, rather than just + an entry in the matrix. During opcodes generation time, these + opcodes will be used. */ +static Dwarf_Unsigned +_dwarf_pro_add_line_entry(Dwarf_P_Debug dbg, + Dwarf_Unsigned file_index, + Dwarf_Addr code_address, + Dwarf_Unsigned symidx, + Dwarf_Unsigned line_no, + Dwarf_Signed col_no, + Dwarf_Bool is_stmt_begin, + Dwarf_Bool is_bb_begin, + Dwarf_Ubyte opc, + Dwarf_Bool isepilbeg, + Dwarf_Bool isprolend, + Dwarf_Unsigned isa, + Dwarf_Unsigned discriminator, + Dwarf_Error * error) +{ + if (dbg->de_lines == NULL) { + dbg->de_lines = (Dwarf_P_Line) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s)); + if (dbg->de_lines == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_NOCOUNT); + } + dbg->de_last_line = dbg->de_lines; + _dwarf_pro_reg_init(dbg,dbg->de_lines); + + } else { + dbg->de_last_line->dpl_next = (Dwarf_P_Line) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s)); + if (dbg->de_last_line->dpl_next == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_NOCOUNT); + } + dbg->de_last_line = dbg->de_last_line->dpl_next; + _dwarf_pro_reg_init(dbg,dbg->de_last_line); + } + dbg->de_last_line->dpl_address = code_address; + dbg->de_last_line->dpl_file = (unsigned long) file_index; + dbg->de_last_line->dpl_line = (unsigned long) line_no; + dbg->de_last_line->dpl_column = (unsigned long) col_no; + dbg->de_last_line->dpl_is_stmt = is_stmt_begin; + dbg->de_last_line->dpl_basic_block = is_bb_begin; + dbg->de_last_line->dpl_opc = opc; + dbg->de_last_line->dpl_r_symidx = symidx; + dbg->de_last_line->dpl_prologue_end = isprolend; + dbg->de_last_line->dpl_epilogue_begin = isepilbeg; + dbg->de_last_line->dpl_isa = isa; + dbg->de_last_line->dpl_discriminator = discriminator; + return (0); +} + +/* Add a directory declaration to the debug_line section. Stored + in linked list. */ +Dwarf_Unsigned +dwarf_add_directory_decl(Dwarf_P_Debug dbg, + char *name, Dwarf_Error * error) +{ + if (dbg->de_inc_dirs == NULL) { + dbg->de_inc_dirs = (Dwarf_P_Inc_Dir) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Inc_Dir_s)); + if (dbg->de_inc_dirs == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC, DW_DLV_NOCOUNT); + } + dbg->de_last_inc_dir = dbg->de_inc_dirs; + dbg->de_n_inc_dirs = 1; + } else { + dbg->de_last_inc_dir->did_next = (Dwarf_P_Inc_Dir) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Inc_Dir_s)); + if (dbg->de_last_inc_dir->did_next == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC, DW_DLV_NOCOUNT); + } + dbg->de_last_inc_dir = dbg->de_last_inc_dir->did_next; + dbg->de_n_inc_dirs++; + } + dbg->de_last_inc_dir->did_name = + (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1); + if (dbg->de_last_inc_dir->did_name == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_STRING_ALLOC, DW_DLV_NOCOUNT); + } + strcpy(dbg->de_last_inc_dir->did_name, name); + dbg->de_last_inc_dir->did_next = NULL; + + return dbg->de_n_inc_dirs; +} + +/* Add a file entry declaration to the debug_line section. Stored + in linked list. The data is immediately encoded as leb128 + and stored in Dwarf_P_F_Entry_s struct. */ +Dwarf_Unsigned +dwarf_add_file_decl(Dwarf_P_Debug dbg, + char *name, + Dwarf_Unsigned dir_idx, + Dwarf_Unsigned time_mod, + Dwarf_Unsigned length, Dwarf_Error * error) +{ + Dwarf_P_F_Entry cur; + char *ptr = 0; + int nbytes_idx, nbytes_time, nbytes_len; + char buffidx[ENCODE_SPACE_NEEDED]; + char bufftime[ENCODE_SPACE_NEEDED]; + char bufflen[ENCODE_SPACE_NEEDED]; + int res = 0; + + if (dbg->de_file_entries == NULL) { + dbg->de_file_entries = (Dwarf_P_F_Entry) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s)); + if (dbg->de_file_entries == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC, + DW_DLV_NOCOUNT); + } + cur = dbg->de_file_entries; + dbg->de_last_file_entry = cur; + dbg->de_n_file_entries = 1; + } else { + cur = dbg->de_last_file_entry; + cur->dfe_next = (Dwarf_P_F_Entry) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s)); + if (cur->dfe_next == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC, + DW_DLV_NOCOUNT); + } + cur = cur->dfe_next; + dbg->de_last_file_entry = cur; + dbg->de_n_file_entries++; + } + cur->dfe_name = (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1); + if (cur->dfe_name == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT); + } + strcpy((char *) cur->dfe_name, name); + res = _dwarf_pro_encode_leb128_nm(dir_idx, &nbytes_idx, + buffidx, sizeof(buffidx)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT); + } + res = _dwarf_pro_encode_leb128_nm(time_mod, &nbytes_time, + bufftime, sizeof(bufftime)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT); + } + res = _dwarf_pro_encode_leb128_nm(length, &nbytes_len, + bufflen, sizeof(bufflen)); + cur->dfe_args = (char *) + _dwarf_p_get_alloc(dbg, nbytes_idx + nbytes_time + nbytes_len); + if (cur->dfe_args == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT); + } + ptr = cur->dfe_args; + memcpy((void *) ptr, buffidx, nbytes_idx); + ptr += nbytes_idx; + memcpy((void *) ptr, bufftime, nbytes_time); + ptr += nbytes_time; + memcpy((void *) ptr, bufflen, nbytes_len); + ptr += nbytes_len; + cur->dfe_nbytes = nbytes_idx + nbytes_time + nbytes_len; + cur->dfe_next = NULL; + + return dbg->de_n_file_entries; +} + + +/* Initialize a row of the matrix for line numbers, meaning + initialize the struct corresponding to it */ +void +_dwarf_pro_reg_init(Dwarf_P_Debug dbg, Dwarf_P_Line cur_line) +{ + cur_line->dpl_address = 0; + cur_line->dpl_file = 1; + cur_line->dpl_line = 1; + cur_line->dpl_column = 0; + cur_line->dpl_is_stmt = dbg->de_line_inits.pi_default_is_stmt; + cur_line->dpl_basic_block = false; + cur_line->dpl_next = NULL; + cur_line->dpl_prologue_end = 0; + cur_line->dpl_epilogue_begin = 0; + cur_line->dpl_isa = 0; + cur_line->dpl_discriminator = 0; + cur_line->dpl_opc = 0; +} diff --git a/libdwarf/pro_line.h b/libdwarf/pro_line.h new file mode 100644 index 0000000..dd2c4e6 --- /dev/null +++ b/libdwarf/pro_line.h @@ -0,0 +1,121 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. 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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +#define DW_LINE_VERSION2 2 +#define DW_LINE_VERSION3 3 +#define DW_LINE_VERSION4 4 + +#if defined(__i386) || defined(__x86_64) +#define MIN_INST_LENGTH 1 +#else +#define MIN_INST_LENGTH 4 +#endif +#define DEFAULT_IS_STMT false +/* line base and range are temporarily defines. + They need to be calculated later */ +#define LINE_BASE -1 +#define LINE_RANGE 4 + +#define OPCODE_BASE 10 /* DWARF2. 13 in DWARF3, DWARF4 */ +#define MAX_OPCODE 255 + + +/* This struct is used to hold entries in the include directories + part of statement prologue. */ +struct Dwarf_P_Inc_Dir_s { + char *did_name; /* name of directory */ + Dwarf_P_Inc_Dir did_next; +}; + + +/* This struct holds file entries for the statement prologue. + Defined in pro_line.h */ +struct Dwarf_P_F_Entry_s { + char *dfe_name; + char *dfe_args; /* has dir index, time of modification, + length in bytes. Encodes as leb128 */ + int dfe_nbytes; /* number of bytes in args */ + Dwarf_P_F_Entry dfe_next; +}; + + +/* + Struct holding line number information for each of the producer + line entries +*/ +struct Dwarf_P_Line_s { + /* code address */ + Dwarf_Addr dpl_address; + + /* file index, index into file entry */ + Dwarf_Word dpl_file; + + /* line number */ + Dwarf_Word dpl_line; + + /* column number */ + Dwarf_Word dpl_column; + + /* whether its a beginning of a stmt */ + Dwarf_Ubyte dpl_is_stmt; + + /* whether its a beginning of basic blk */ + Dwarf_Ubyte dpl_basic_block; + + /* used to store opcodes set_address, and end_seq */ + Dwarf_Ubyte dpl_opc; + + /* Used only for relocations. Has index of symbol relative to + which relocation has to be done (the S part in S + A) */ + Dwarf_Unsigned dpl_r_symidx; + + Dwarf_P_Line dpl_next; + + Dwarf_Ubyte dpl_prologue_end; /* DWARF3 */ + Dwarf_Ubyte dpl_epilogue_begin; /* DWARF3 */ + Dwarf_Unsigned dpl_isa; /* DWARF3 */ + Dwarf_Unsigned dpl_discriminator; /* DWARF4 */ + +}; + +/* + to initialize state machine registers, definition in + pro_line.c +*/ +void _dwarf_pro_reg_init(Dwarf_P_Debug dbg,Dwarf_P_Line); + +void _dwarf_init_default_line_header_vals(Dwarf_P_Debug dbg); diff --git a/libdwarf/pro_macinfo.c b/libdwarf/pro_macinfo.c new file mode 100644 index 0000000..7985262 --- /dev/null +++ b/libdwarf/pro_macinfo.c @@ -0,0 +1,468 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#include "pro_incl.h" +#include "pro_section.h" +#include "pro_macinfo.h" + +/* I don't much like the error strings this generates, since + like the rest of libdwarf they are simple strings with + no useful numbers in them. But that's not something I can + fix without more work than I have time for + right now. davea Nov 94. +*/ + +/* these are gross overestimates of the number of +** bytes needed to store a number in LEB form. +** Just estimates, and since blocks are reasonable size, +** the end-block waste is small. +** Of course the waste is NOT present on disk. +*/ + +#define COMMAND_LEN ENCODE_SPACE_NEEDED +#define LINE_LEN ENCODE_SPACE_NEEDED +#define BASE_MACINFO_MALLOC_LEN 2048 + +static int +libdwarf_compose_begin(Dwarf_P_Debug dbg, int code, + size_t maxlen, int *compose_error_type) +{ + unsigned char *nextchar; + struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo; + + if (curblk == 0) { + struct dw_macinfo_block_s *newb; + size_t len; + + /* initial allocation */ + size_t blen = BASE_MACINFO_MALLOC_LEN; + + if (blen < maxlen) { + blen = 2 * maxlen; + } + len = sizeof(struct dw_macinfo_block_s) + blen; + newb = + (struct dw_macinfo_block_s *) _dwarf_p_get_alloc(dbg, len); + if (!newb) { + *compose_error_type = DW_DLE_MACINFO_MALLOC_FAIL; + return DW_DLV_ERROR; + } + newb->mb_data = + (char *) newb + sizeof(struct dw_macinfo_block_s); + newb->mb_avail_len = blen; + newb->mb_used_len = 0; + newb->mb_macinfo_data_space_len = blen; + dbg->de_first_macinfo = newb; + dbg->de_current_macinfo = newb; + curblk = newb; + } else if (curblk->mb_avail_len < maxlen) { + struct dw_macinfo_block_s *newb; + size_t len; + + /* no space left in block: allocate a new block */ + size_t blen = + dbg->de_current_macinfo->mb_macinfo_data_space_len * 2; + if (blen < maxlen) { + blen = 2 * maxlen; + } + len = sizeof(struct dw_macinfo_block_s) + blen; + newb = + (struct dw_macinfo_block_s *) _dwarf_p_get_alloc(dbg, len); + if (!newb) { + *compose_error_type = DW_DLE_MACINFO_MALLOC_FAIL; + return DW_DLV_ERROR; + } + newb->mb_data = + (char *) newb + sizeof(struct dw_macinfo_block_s); + newb->mb_avail_len = blen; + newb->mb_used_len = 0; + newb->mb_macinfo_data_space_len = blen; + dbg->de_first_macinfo->mb_next = newb; + dbg->de_current_macinfo = newb; + curblk = newb; + } + /* now curblk has enough room */ + dbg->de_compose_avail = curblk->mb_avail_len; + dbg->de_compose_used_len = curblk->mb_used_len; + nextchar = + (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len); + *nextchar = code; + dbg->de_compose_avail--; + ++dbg->de_compose_used_len; + return DW_DLV_OK; +} + + + +static void +libdwarf_compose_add_string(Dwarf_P_Debug dbg, char *string, size_t len) +{ + struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo; + unsigned char *nextchar; + + nextchar = + (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len); + + len += 1; /* count the null terminator */ + + memcpy(nextchar, string, len); + dbg->de_compose_avail -= len; + dbg->de_compose_used_len += len; + return; + +} +static int +libdwarf_compose_add_line(Dwarf_P_Debug dbg, + Dwarf_Unsigned line, int *compose_error_type) +{ + struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo; + unsigned char *nextchar; + int res; + int nbytes; + + nextchar = + (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len); + + /* Put the created leb number directly into the macro buffer If + dbg->de_compose_avail is > INT_MAX this will not work as the + 'int' will look negative to _dwarf_pro_encode_leb128_nm! */ + + res = _dwarf_pro_encode_leb128_nm(line, &nbytes, + (char *) nextchar, + (int) dbg->de_compose_avail); + if (res != DW_DLV_OK) { + *compose_error_type = DW_DLE_MACINFO_INTERNAL_ERROR_SPACE; + return DW_DLV_ERROR; + } + + dbg->de_compose_avail -= nbytes; + dbg->de_compose_used_len += nbytes; + return DW_DLV_OK; +} + +/* This function actually 'commits' the space used by the + preceeding calls. */ +static int +libdwarf_compose_complete(Dwarf_P_Debug dbg, int *compose_error_type) +{ + struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo; + + if (dbg->de_compose_used_len > curblk->mb_macinfo_data_space_len) { + *compose_error_type = DW_DLE_MACINFO_INTERNAL_ERROR_SPACE; + return DW_DLV_ERROR; + } + curblk->mb_avail_len = dbg->de_compose_avail; + curblk->mb_used_len = dbg->de_compose_used_len; + return DW_DLV_OK; +} + + + +int +dwarf_def_macro(Dwarf_P_Debug dbg, + Dwarf_Unsigned line, + char *macname, char *macvalue, Dwarf_Error * error) +{ + size_t len; + size_t len2; + size_t length_est; + int res; + int compose_error_type; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + if (macname == 0) { + _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL); + return (DW_DLV_ERROR); + } + len = strlen(macname) + 1; + if (len == 0) { + _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY); + return (DW_DLV_ERROR); + } + if (macvalue) { + len2 = strlen(macvalue) + 1; + } else { + len2 = 0; + } + + /* 1 for space character we add */ + length_est = COMMAND_LEN + LINE_LEN + len + len2 + 1; + + res = libdwarf_compose_begin(dbg, DW_MACINFO_define, length_est, + &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + res = libdwarf_compose_add_line(dbg, line, &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + libdwarf_compose_add_string(dbg, macname, len); + libdwarf_compose_add_string(dbg, " ", 1); + if (macvalue) { + libdwarf_compose_add_string(dbg, " ", 1); + libdwarf_compose_add_string(dbg, macvalue, len2); + } + res = libdwarf_compose_complete(dbg, &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + return DW_DLV_OK; +} + +int +dwarf_undef_macro(Dwarf_P_Debug dbg, + Dwarf_Unsigned line, + char *macname, Dwarf_Error * error) +{ + + size_t len; + size_t length_est; + int res; + int compose_error_type; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + if (macname == 0) { + _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL); + return (DW_DLV_ERROR); + } + len = strlen(macname) + 1; + if (len == 0) { + _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY); + return (DW_DLV_ERROR); + } + length_est = COMMAND_LEN + LINE_LEN + len; + res = libdwarf_compose_begin(dbg, DW_MACINFO_undef, length_est, + &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + res = libdwarf_compose_add_line(dbg, line, &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + libdwarf_compose_add_string(dbg, macname, len); + res = libdwarf_compose_complete(dbg, &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + return DW_DLV_OK; +} + +int +dwarf_start_macro_file(Dwarf_P_Debug dbg, + Dwarf_Unsigned fileindex, + Dwarf_Unsigned linenumber, Dwarf_Error * error) +{ + size_t length_est; + int res; + int compose_error_type; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + length_est = COMMAND_LEN + LINE_LEN + LINE_LEN; + res = libdwarf_compose_begin(dbg, DW_MACINFO_start_file, length_est, + &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + res = libdwarf_compose_add_line(dbg, fileindex, + &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + res = libdwarf_compose_add_line(dbg, linenumber, + &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + return DW_DLV_OK; +} + +int +dwarf_end_macro_file(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + size_t length_est; + int res; + int compose_error_type; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + length_est = COMMAND_LEN; + res = libdwarf_compose_begin(dbg, DW_MACINFO_end_file, length_est, + &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + res = libdwarf_compose_complete(dbg, &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + return DW_DLV_OK; +} + +int +dwarf_vendor_ext(Dwarf_P_Debug dbg, + Dwarf_Unsigned constant, + char *string, Dwarf_Error * error) +{ + size_t len; + size_t length_est; + int res; + int compose_error_type; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + if (string == 0) { + _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL); + return (DW_DLV_ERROR); + } + len = strlen(string) + 1; + if (len == 0) { + _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY); + return (DW_DLV_ERROR); + } + length_est = COMMAND_LEN + LINE_LEN + len; + res = libdwarf_compose_begin(dbg, DW_MACINFO_vendor_ext, length_est, + &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + res = libdwarf_compose_add_line(dbg, constant, &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + libdwarf_compose_add_string(dbg, string, len); + libdwarf_compose_complete(dbg, &compose_error_type); + if (res != DW_DLV_OK) { + _dwarf_p_error(NULL, error, compose_error_type); + return (DW_DLV_ERROR); + } + return DW_DLV_OK; +} + + + +int +_dwarf_pro_transform_macro_info_to_disk(Dwarf_P_Debug dbg, + Dwarf_Error * error) +{ + /* Total num of bytes in .debug_macinfo section. */ + Dwarf_Unsigned mac_num_bytes; + + /* Points to first byte of .debug_macinfo buffer. */ + Dwarf_Small *macinfo; + + /* Fills in the .debug_macinfo buffer. */ + Dwarf_Small *macinfo_ptr; + + + /* Used to scan the section data buffers. */ + struct dw_macinfo_block_s *m_prev; + struct dw_macinfo_block_s *m_sect; + + + /* Get the size of the debug_macinfo data */ + mac_num_bytes = 0; + for (m_sect = dbg->de_first_macinfo; m_sect != NULL; + m_sect = m_sect->mb_next) { + mac_num_bytes += m_sect->mb_used_len; + } + /* The final entry has a type code of 0 to indicate It is final + for this CU Takes just 1 byte. */ + mac_num_bytes += 1; + + GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_MACINFO], + macinfo, (unsigned long) mac_num_bytes, error); + if (macinfo == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + + macinfo_ptr = macinfo; + m_prev = 0; + for (m_sect = dbg->de_first_macinfo; m_sect != NULL; + m_sect = m_sect->mb_next) { + memcpy(macinfo_ptr, m_sect->mb_data, m_sect->mb_used_len); + macinfo_ptr += m_sect->mb_used_len; + if (m_prev) { + _dwarf_p_dealloc(dbg, (Dwarf_Small *) m_prev); + m_prev = 0; + } + m_prev = m_sect; + } + *macinfo_ptr = 0; /* the type code of 0 as last entry */ + if (m_prev) { + _dwarf_p_dealloc(dbg, (Dwarf_Small *) m_prev); + m_prev = 0; + } + + dbg->de_first_macinfo = NULL; + dbg->de_current_macinfo = NULL; + + return (int) dbg->de_n_debug_sect; +} diff --git a/libdwarf/pro_macinfo.h b/libdwarf/pro_macinfo.h new file mode 100644 index 0000000..1b77b42 --- /dev/null +++ b/libdwarf/pro_macinfo.h @@ -0,0 +1,40 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +int _dwarf_pro_transform_macro_info_to_disk(Dwarf_P_Debug dbg, + Dwarf_Error * error); diff --git a/libdwarf/pro_opaque.h b/libdwarf/pro_opaque.h new file mode 100644 index 0000000..2b2f3dd --- /dev/null +++ b/libdwarf/pro_opaque.h @@ -0,0 +1,516 @@ +/* + + Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +#include <stddef.h> + +/* + Sgidefs included to define __uint32_t, + a guaranteed 4-byte quantity. +*/ +#include "libdwarfdefs.h" + +#define true 1 +#define false 0 + +/* to identify a cie */ +#define DW_CIE_ID ~(0x0) +#define DW_CIE_VERSION 1 + +/*Dwarf_Word is unsigned word usable for index, count in memory */ +/*Dwarf_Sword is signed word usable for index, count in memory */ +/* The are 32 or 64 bits depending if 64 bit longs or not, which +** fits the ILP32 and LP64 models +** These work equally well with ILP64. +*/ + +typedef unsigned long Dwarf_Word; +typedef long Dwarf_Sword; + + +typedef signed char Dwarf_Sbyte; +typedef unsigned char Dwarf_Ubyte; +typedef signed short Dwarf_Shalf; + +/* + On any change that makes libdwarf producer + incompatible, increment this number. + 1->2->3 ... */ +#define PRO_VERSION_MAGIC 0xdead1 + + +/* these 2 are fixed sizes which must not vary with the +** ILP32/LP64 model. These two stay at 32 bit. +*/ +typedef __uint32_t Dwarf_ufixed; +typedef __int32_t Dwarf_sfixed; + +/* + producer: + This struct is used to hold information about all + debug* sections. On creating a new section, section + names and indices are added to this struct + definition in pro_section.h */ +typedef struct Dwarf_P_Section_Data_s *Dwarf_P_Section_Data; + +/* + producer: + This struct is used to hold entries in the include directories + part of statement prologue. Definition in pro_line.h +*/ +typedef struct Dwarf_P_Inc_Dir_s *Dwarf_P_Inc_Dir; + +/* + producer: + This struct holds file entries for the statement prologue. + Defined in pro_line.h +*/ +typedef struct Dwarf_P_F_Entry_s *Dwarf_P_F_Entry; + +/* + producer: + This struct holds information for each cie. Defn in pro_frame.h +*/ +typedef struct Dwarf_P_Cie_s *Dwarf_P_Cie; + +/* + producer: + Struct to hold line number information, different from + Dwarf_Line opaque type. +*/ +typedef struct Dwarf_P_Line_s *Dwarf_P_Line; + +/* + producer: + Struct to hold information about address ranges. +*/ +typedef struct Dwarf_P_Simple_nameentry_s *Dwarf_P_Simple_nameentry; +typedef struct Dwarf_P_Simple_name_header_s *Dwarf_P_Simple_name_header; +typedef struct Dwarf_P_Arange_s *Dwarf_P_Arange; +typedef struct Dwarf_P_Per_Reloc_Sect_s *Dwarf_P_Per_Reloc_Sect; +typedef struct Dwarf_P_Per_Sect_String_Attrs_s *Dwarf_P_Per_Sect_String_Attrs; + +/* Defined to get at the elf section numbers and section name + indices in symtab for the dwarf sections + Must match .rel.* names in _dwarf_rel_section_names + exactly. +*/ +#define DEBUG_INFO 0 +#define DEBUG_LINE 1 +#define DEBUG_ABBREV 2 +#define DEBUG_FRAME 3 +#define DEBUG_ARANGES 4 +#define DEBUG_PUBNAMES 5 +#define DEBUG_STR 6 +#define DEBUG_FUNCNAMES 7 +#define DEBUG_TYPENAMES 8 +#define DEBUG_VARNAMES 9 +#define DEBUG_WEAKNAMES 10 +#define DEBUG_MACINFO 11 +#define DEBUG_LOC 12 +#define DEBUG_RANGES 13 +#define DEBUG_TYPES 14 + +/* Maximum number of debug_* sections not including the relocations */ +#define NUM_DEBUG_SECTIONS 15 + +/* Describes the data needed to generate line table header info + so we can vary the init at runtime. */ +struct Dwarf_P_Line_Inits_s { + unsigned pi_version; /* line table version number */ + unsigned pi_default_is_stmt; /* default value for is_stmt */ + + /* Size of the smallest instruction, in bytes. */ + unsigned pi_minimum_instruction_length; + + /* Make this >1 for VLIW machines. */ + unsigned pi_maximum_operations_per_instruction; + + /* Normally opcode_base is determined by pi_version, but we + allow manual setting here so we can generate data like + GNU with a DWARF3 opcode base in a DWARF2 section. + This determines how much of the header_opcode_lengths + table is emitted in the line table header */ + unsigned pi_opcode_base; + + int pi_line_base; /* For line table header. */ + int pi_line_range; /* For line table header. */ +}; + + +struct Dwarf_P_Die_s { + Dwarf_Unsigned di_offset; /* offset in debug info */ + char *di_abbrev; /* abbreviation */ + Dwarf_Word di_abbrev_nbytes; /* # of bytes in abbrev */ + Dwarf_Tag di_tag; + Dwarf_P_Die di_parent; /* parent of current die */ + Dwarf_P_Die di_child; /* first child */ + /* The last child field makes linking up children an O(1) operation, + See pro_die.c. */ + Dwarf_P_Die di_last_child; + Dwarf_P_Die di_left; /* left sibling */ + Dwarf_P_Die di_right; /* right sibling */ + Dwarf_P_Attribute di_attrs; /* list of attributes */ + Dwarf_P_Attribute di_last_attr; /* last attribute */ + int di_n_attr; /* number of attributes */ + Dwarf_P_Debug di_dbg; /* For memory management */ + Dwarf_Unsigned di_marker; /* used to attach symbols to dies */ +}; + + +/* producer fields */ +struct Dwarf_P_Attribute_s { + Dwarf_Half ar_attribute; /* Attribute Value. */ + Dwarf_Half ar_attribute_form; /* Attribute Form. */ + Dwarf_P_Die ar_ref_die; /* die pointer if form ref */ + char *ar_data; /* data, format given by form */ + Dwarf_Unsigned ar_nbytes; /* no. of bytes of data */ + Dwarf_Unsigned ar_rel_symidx; /* when attribute has a + relocatable value, holds + index of symbol in SYMTAB */ + Dwarf_Ubyte ar_rel_type; /* relocation type */ + Dwarf_Word ar_rel_offset; /* Offset of relocation within block */ + char ar_reloc_len; /* Number of bytes that relocation + applies to. 4 or 8. Unused and may + be 0 if if ar_rel_type is + R_MIPS_NONE */ + Dwarf_P_Attribute ar_next; +}; + +/* A block of .debug_macinfo data: this forms a series of blocks. +** Each macinfo input is compressed immediately and put into +** the current block if room, else a newblock allocated. +** The space allocation is such that the block and the macinfo +** data are one malloc block: free with a pointer to this and the +** mb_data is freed automatically. +** Like the struct hack, but legal ANSI C. +*/ +struct dw_macinfo_block_s { + struct dw_macinfo_block_s *mb_next; + unsigned long mb_avail_len; + unsigned long mb_used_len; + unsigned long mb_macinfo_data_space_len; + char *mb_data;/* original malloc ptr. */ +}; + +/* dwarf_sn_kind is for the array of similarly-treated + name -> cu ties +*/ +enum dwarf_sn_kind { dwarf_snk_pubname, dwarf_snk_funcname, + dwarf_snk_weakname, dwarf_snk_typename, + dwarf_snk_varname, + dwarf_snk_entrycount /* this one must be last */ +}; + + + +/* The calls to add a varname etc use a list of + these as the list. +*/ +struct Dwarf_P_Simple_nameentry_s { + Dwarf_P_Die sne_die; + char *sne_name; + int sne_name_len; + Dwarf_P_Simple_nameentry sne_next; +}; + +/* An array of these, each of which heads a list + of Dwarf_P_Simple_nameentry +*/ +struct Dwarf_P_Simple_name_header_s { + Dwarf_P_Simple_nameentry sn_head; + Dwarf_P_Simple_nameentry sn_tail; + Dwarf_Signed sn_count; + + /* Length that will be generated, not counting fixed header or + trailer */ + Dwarf_Signed sn_net_len; +}; +typedef int (*_dwarf_pro_reloc_name_func_ptr) (Dwarf_P_Debug dbg, + int sec_index, + Dwarf_Unsigned offset,/* r_offset */ + Dwarf_Unsigned symidx, + enum Dwarf_Rel_Type type, + int reltarget_length); + +typedef int (*_dwarf_pro_reloc_length_func_ptr) (Dwarf_P_Debug dbg, + int sec_index, Dwarf_Unsigned offset,/* r_offset */ + Dwarf_Unsigned start_symidx, + Dwarf_Unsigned end_symidx, + enum Dwarf_Rel_Type type, + int reltarget_length); +typedef int (*_dwarf_pro_transform_relocs_func_ptr) (Dwarf_P_Debug dbg, + Dwarf_Signed * + new_sec_count); + +/* + Each slot in a block of slots could be: + a binary stream relocation entry (32 or 64bit relocation data) + a SYMBOLIC relocation entry. + During creation sometimes we create multiple chained blocks, + but sometimes we create a single long block. + Before returning reloc data to caller, + we switch to a single, long-enough, + block. + + We make counters here Dwarf_Unsigned so that we + get sufficient alignment. Since we use space after + the struct (at malloc time) for user data which + must have Dwarf_Unsigned alignment, this + struct must have that alignment too. +*/ +struct Dwarf_P_Relocation_Block_s { + Dwarf_Unsigned rb_slots_in_block; /* slots in block, as created */ + Dwarf_Unsigned rb_next_slot_to_use; /* counter, start at 0. */ + struct Dwarf_P_Relocation_Block_s *rb_next; + char *rb_where_to_add_next; /* pointer to next slot (might be past + end, depending on + rb_next_slot_to_use) */ + char *rb_data; /* data area */ +}; + +/* One of these per potential relocation section + So one per actual dwarf section. + Left zeroed when not used (some sections have + no relocations). +*/ +struct Dwarf_P_Per_Reloc_Sect_s { + unsigned long pr_reloc_total_count; /* total number of entries + across all blocks */ + + unsigned long pr_slots_per_block_to_alloc; /* at Block alloc, this + is the default number of slots to use */ + + int pr_sect_num_of_reloc_sect; /* sect number returned by + de_callback_func() or de_callback_func_b() or_c() + call, this is the sect + number of the relocation section. */ + + /* singly-linked list. add at and ('last') with count of blocks */ + struct Dwarf_P_Relocation_Block_s *pr_first_block; + struct Dwarf_P_Relocation_Block_s *pr_last_block; + unsigned long pr_block_count; +}; + +#define DEFAULT_SLOTS_PER_BLOCK 3 + +typedef struct memory_list_s { + struct memory_list_s *prev; + struct memory_list_s *next; +} memory_list_t; + +struct Dwarf_P_Per_Sect_String_Attrs_s { + int sect_sa_section_number; + unsigned sect_sa_n_alloc; + unsigned sect_sa_n_used; + Dwarf_P_String_Attr sect_sa_list; +}; + +/* Fields used by producer */ +struct Dwarf_P_Debug_s { + /* Used to catch dso passing dbg to another DSO with incompatible + version of libdwarf See PRO_VERSION_MAGIC */ + int de_version_magic_number; + + Dwarf_Handler de_errhand; + /* de_user_data is provided so users can use it to readily tie + a callback to anything they desire. The contents are not + used by libdwarf except to pass the data as a callback + argument. New in June 2011. Available in + dwarf_pro_init_c() and its callback function. */ + void * de_user_data; + Dwarf_Ptr de_errarg; + + /* Call back function, used to create .debug* sections. Provided + By user. Only of these used per dbg. */ + Dwarf_Callback_Func de_callback_func; + Dwarf_Callback_Func_b de_callback_func_b; + Dwarf_Callback_Func_c de_callback_func_c; + + /* Flags from producer_init call */ + Dwarf_Unsigned de_flags; + + /* This holds information on debug section stream output, including + the stream data */ + Dwarf_P_Section_Data de_debug_sects; + + /* Pointer to the 'current active' section */ + Dwarf_P_Section_Data de_current_active_section; + + /* Number of debug data streams globs. */ + Dwarf_Word de_n_debug_sect; + + /* File entry information, null terminated singly-linked list */ + Dwarf_P_F_Entry de_file_entries; + Dwarf_P_F_Entry de_last_file_entry; + Dwarf_Unsigned de_n_file_entries; + + /* Has the directories used to search for source files */ + Dwarf_P_Inc_Dir de_inc_dirs; + Dwarf_P_Inc_Dir de_last_inc_dir; + Dwarf_Unsigned de_n_inc_dirs; + + /* Has all the line number info for the stmt program */ + Dwarf_P_Line de_lines; + Dwarf_P_Line de_last_line; + + /* List of cie's for the debug unit */ + Dwarf_P_Cie de_frame_cies; + Dwarf_P_Cie de_last_cie; + Dwarf_Unsigned de_n_cie; + + /* Singly-linked list of fde's for the debug unit */ + Dwarf_P_Fde de_frame_fdes; + Dwarf_P_Fde de_last_fde; + Dwarf_Unsigned de_n_fde; + + /* First die, leads to all others */ + Dwarf_P_Die de_dies; + + /* Pointer to list of strings */ + char *de_strings; + + /* Pointer to chain of aranges */ + Dwarf_P_Arange de_arange; + Dwarf_P_Arange de_last_arange; + Dwarf_Sword de_arange_count; + + /* macinfo controls. */ + /* first points to beginning of the list during creation */ + struct dw_macinfo_block_s *de_first_macinfo; + + /* current points to the current, unfilled, block */ + struct dw_macinfo_block_s *de_current_macinfo; + + /* Pointer to the first section, to support reset_section_bytes */ + Dwarf_P_Section_Data de_first_debug_sect; + + /* Handles pubnames, weaknames, etc. See dwarf_sn_kind in + pro_opaque.h */ + struct Dwarf_P_Simple_name_header_s + de_simple_name_headers[dwarf_snk_entrycount]; + + /* Relocation data. not all sections will actally have relocation + info, of course */ + struct Dwarf_P_Per_Reloc_Sect_s de_reloc_sect[NUM_DEBUG_SECTIONS]; + int de_reloc_next_to_return; /* iterator on reloc sections + (SYMBOLIC output) */ + + /* used in remembering sections */ + int de_elf_sects[NUM_DEBUG_SECTIONS]; /* elf sect number of + the section itself, DEBUG_LINE for example */ + + Dwarf_Unsigned de_sect_name_idx[NUM_DEBUG_SECTIONS]; /* section + name index or handle for the name of the symbol for + DEBUG_LINE for example */ + + int de_offset_reloc; /* offset reloc type, R_MIPS_32 for + example. Specific to the ABI being + produced. Relocates offset size + field */ + int de_exc_reloc; /* reloc type specific to exception + table relocs. */ + int de_ptr_reloc; /* standard reloc type, R_MIPS_32 for + example. Specific to the ABI being + produced. relocates pointer size + field */ + + unsigned char de_offset_size; /* section offset. Here to + avoid test of abi in macro + at run time MIPS -n32 4, + -64 8. */ + + unsigned char de_pointer_size; /* size of pointer in target. + Here to avoid test of abi in + macro at run time MIPS -n32 + 4, -64 is 8. */ + + unsigned char de_is_64bit; /* non-zero if is 64bit. Else 32 bit: + used for passing this info as a flag */ + unsigned char de_relocation_record_size; /* reloc record size + varies by ABI and + relocation-output + method (stream or + symbolic) */ + + unsigned char de_64bit_extension;/* non-zero if creating 64 bit + offsets using dwarf2-99 + extension proposal */ + + int de_ar_data_attribute_form; /* data8, data4 abi dependent */ + int de_ar_ref_attr_form; /* ref8 ref4 , abi dependent */ + + /* simple name relocations */ + _dwarf_pro_reloc_name_func_ptr de_reloc_name; + + /* relocations for a length, requiring a pair of symbols */ + _dwarf_pro_reloc_length_func_ptr de_reloc_pair; + + _dwarf_pro_transform_relocs_func_ptr de_transform_relocs_to_disk; + + /* following used for macro buffers */ + unsigned long de_compose_avail; + unsigned long de_compose_used_len; + + unsigned char de_same_endian; + void *(*de_copy_word) (void *, const void *, size_t); + + /* Add new fields at the END of this struct to preserve some hope + of sensible behavior on dbg passing between DSOs linked with + mismatched libdwarf producer versions. */ + + Dwarf_P_Marker de_markers; /* pointer to array of markers */ + unsigned de_marker_n_alloc; + unsigned de_marker_n_used; + int de_sect_sa_next_to_return; /* Iterator on sring attrib sects */ + /* String attributes data of each section. */ + struct Dwarf_P_Per_Sect_String_Attrs_s de_sect_string_attr[NUM_DEBUG_SECTIONS]; + /* Hold data needed to init new line output flexibly. */ + struct Dwarf_P_Line_Inits_s de_line_inits; +}; + +#define CURRENT_VERSION_STAMP 2 + +Dwarf_Unsigned _dwarf_add_simple_name_entry(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *entry_name, + enum dwarf_sn_kind + entrykind, + Dwarf_Error * error); + + +#define DISTINGUISHED_VALUE 0xffffffff /* 64bit extension flag */ diff --git a/libdwarf/pro_pubnames.c b/libdwarf/pro_pubnames.c new file mode 100644 index 0000000..4758652 --- /dev/null +++ b/libdwarf/pro_pubnames.c @@ -0,0 +1,62 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#endif +#include "pro_incl.h" +#include "pro_section.h" + + +/* This function adds another public name to the + list of public names for the given Dwarf_P_Debug. + It returns 0 on error, and 1 otherwise. */ + +Dwarf_Unsigned +dwarf_add_pubname(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *pubname_name, Dwarf_Error * error) +{ + return + _dwarf_add_simple_name_entry(dbg, die, pubname_name, + dwarf_snk_pubname, error); +} diff --git a/libdwarf/pro_reloc.c b/libdwarf/pro_reloc.c new file mode 100644 index 0000000..48c8065 --- /dev/null +++ b/libdwarf/pro_reloc.c @@ -0,0 +1,263 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2008-2011 David Anderson, Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +/*#include <elfaccess.h> */ +#include "pro_incl.h" + + +/*Do initial alloc of newslots slots. + Fails only if malloc fails. + + Supposed to be called before any relocs allocated. + Ignored if after any allocated. + + Part of an optimization, so that for a known 'newslots' + relocations count we can preallocate the right size block. + Called from just 2 places. + + returns DW_DLV_OK or DW_DLV_ERROR +*/ +int +_dwarf_pro_pre_alloc_n_reloc_slots(Dwarf_P_Debug dbg, + int rel_sec_index, + Dwarf_Unsigned newslots) +{ + unsigned long len = 0; + struct Dwarf_P_Relocation_Block_s *data = 0; + Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[rel_sec_index]; + unsigned long slots_in_blk = (unsigned long) newslots; + unsigned long rel_rec_size = dbg->de_relocation_record_size; + + if (prel->pr_first_block) + return DW_DLV_OK; /* do nothing */ + + len = sizeof(struct Dwarf_P_Relocation_Block_s) + + slots_in_blk * rel_rec_size; + + + data = (struct Dwarf_P_Relocation_Block_s *) + _dwarf_p_get_alloc(dbg, len); + if (!data) { + return DW_DLV_ERROR; + } + data->rb_slots_in_block = slots_in_blk; /* could use default + here, as fallback in case our origininal + estimate wrong. When we call this we + presumably know what we are doing, so + keep this count for now */ + data->rb_next_slot_to_use = 0; + data->rb_where_to_add_next = + ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s); + data->rb_data = data->rb_where_to_add_next; + + prel->pr_first_block = data; + prel->pr_last_block = data; + prel->pr_block_count = 1; + + + return DW_DLV_OK; +} + + +/*Do alloc of slots. + Fails only if malloc fails. + + Only allocator used. + + returns DW_DLV_OK or DW_DLV_ERROR +*/ +int +_dwarf_pro_alloc_reloc_slots(Dwarf_P_Debug dbg, int rel_sec_index) +{ + unsigned long len = 0; + struct Dwarf_P_Relocation_Block_s *data = 0; + Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[rel_sec_index]; + unsigned long slots_in_blk = prel->pr_slots_per_block_to_alloc; + unsigned long rel_rec_size = dbg->de_relocation_record_size; + + len = sizeof(struct Dwarf_P_Relocation_Block_s) + + slots_in_blk * rel_rec_size; + + data = (struct Dwarf_P_Relocation_Block_s *) + _dwarf_p_get_alloc(dbg, len); + if (!data) { + return DW_DLV_ERROR; + } + + if (prel->pr_first_block) { + prel->pr_last_block->rb_next = data; + prel->pr_last_block = data; + prel->pr_block_count += 1; + + } else { + + prel->pr_first_block = data; + prel->pr_last_block = data; + prel->pr_block_count = 1; + } + + data->rb_slots_in_block = slots_in_blk; + data->rb_next_slot_to_use = 0; + data->rb_where_to_add_next = + ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s); + data->rb_data = data->rb_where_to_add_next; + + return DW_DLV_OK; + +} + +/* Reserve a slot. return DW_DLV_OK if succeeds. + + Return DW_DLV_ERROR if fails (malloc error). + + Use the relrec_to_fill to pass back a pointer to + a slot space to use. */ +int +_dwarf_pro_reloc_get_a_slot(Dwarf_P_Debug dbg, + int base_sec_index, void **relrec_to_fill) +{ + struct Dwarf_P_Relocation_Block_s *data = 0; + Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[base_sec_index]; + unsigned long rel_rec_size = dbg->de_relocation_record_size; + + char *ret_addr = 0; + + data = prel->pr_last_block; + if ((data == 0) || + (data->rb_next_slot_to_use >= data->rb_slots_in_block)) { + int res; + + res = _dwarf_pro_alloc_reloc_slots(dbg, base_sec_index); + if (res != DW_DLV_OK) { + return res; + } + } + + data = prel->pr_last_block; + /* now we have an empty slot */ + ret_addr = data->rb_where_to_add_next; + + data->rb_where_to_add_next += rel_rec_size; + data->rb_next_slot_to_use += 1; + + prel->pr_reloc_total_count += 1; + + *relrec_to_fill = (void *) ret_addr; + + return DW_DLV_OK; + +} + +/* + On success returns count of + .rel.* sections that are symbolic + thru count_of_relocation_sections. + + On success, returns DW_DLV_OK. + + If this is not a 'symbolic' run, returns + DW_DLV_NO_ENTRY. + + No errors are possible. + + + + +*/ + +/*ARGSUSED*/ int +dwarf_get_relocation_info_count(Dwarf_P_Debug dbg, + Dwarf_Unsigned * + count_of_relocation_sections, + int *drd_buffer_version, + Dwarf_Error * error) +{ + if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) { + int i; + unsigned int count = 0; + + for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) { + if (dbg->de_reloc_sect[i].pr_reloc_total_count > 0) { + ++count; + } + } + *count_of_relocation_sections = (Dwarf_Unsigned) count; + *drd_buffer_version = DWARF_DRD_BUFFER_VERSION; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +int +dwarf_get_relocation_info(Dwarf_P_Debug dbg, + Dwarf_Signed * elf_section_index, + Dwarf_Signed * elf_section_index_link, + Dwarf_Unsigned * relocation_buffer_count, + Dwarf_Relocation_Data * reldata_buffer, + Dwarf_Error * error) +{ + int next = dbg->de_reloc_next_to_return; + + if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) { + int i; + + for (i = next; i < NUM_DEBUG_SECTIONS; ++i) { + Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[i]; + + if (prel->pr_reloc_total_count > 0) { + dbg->de_reloc_next_to_return = i + 1; + + + /* ASSERT: prel->.pr_block_count == 1 */ + + *elf_section_index = prel->pr_sect_num_of_reloc_sect; + *elf_section_index_link = dbg->de_elf_sects[i]; + *relocation_buffer_count = prel->pr_reloc_total_count; + *reldata_buffer = (Dwarf_Relocation_Data) + (prel->pr_first_block->rb_data); + return DW_DLV_OK; + } + } + DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, DW_DLV_ERROR); + } + return DW_DLV_NO_ENTRY; +} diff --git a/libdwarf/pro_reloc.h b/libdwarf/pro_reloc.h new file mode 100644 index 0000000..81954fc --- /dev/null +++ b/libdwarf/pro_reloc.h @@ -0,0 +1,47 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +int _dwarf_pro_pre_alloc_n_reloc_slots(Dwarf_P_Debug dbg, + int rel_sec_index, + Dwarf_Unsigned newslots); + +int _dwarf_pro_alloc_reloc_slots(Dwarf_P_Debug dbg, int rel_sec_index); + +int _dwarf_pro_reloc_get_a_slot(Dwarf_P_Debug dbg, + int base_sec_index, + void **relrec_to_fill); diff --git a/libdwarf/pro_reloc_stream.c b/libdwarf/pro_reloc_stream.c new file mode 100644 index 0000000..74d217b --- /dev/null +++ b/libdwarf/pro_reloc_stream.c @@ -0,0 +1,291 @@ +/* + + Copyright (C) 2000,2001,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2011 David Anderson, Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#else +/* Set r_info as defined by ELF generic ABI */ +#define Set_REL32_info(r,s,t) ((r).r_info = ELF32_R_INFO(s,t)) +#define Set_REL64_info(r,s,t) ((r).r_info = ELF64_R_INFO(s,t)) +#endif +#include "pro_incl.h" +#include "pro_section.h" +#include "pro_reloc.h" +#include "pro_reloc_stream.h" + +/* Return DW_DLV_ERROR on malloc error or reltarget_length error. + Return DW_DLV_OK otherwise */ +/*ARGSUSED*/ int +_dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset, /* r_offset of reloc */ + Dwarf_Unsigned symidx, + enum Dwarf_Rel_Type type, + int reltarget_length) +{ +#if HAVE_ELF64_GETEHDR + REL64 *elf64_reloc = 0; + void *relrec_to_fill = 0; + int res = 0; + int rel_type = 0; + + res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index, + &relrec_to_fill); + if (res != DW_DLV_OK) + return res; + + + if (type == dwarf_drt_data_reloc) { + if (reltarget_length == dbg->de_offset_size) { + rel_type = dbg->de_offset_reloc; + } else if (reltarget_length == dbg->de_pointer_size) { + rel_type = dbg->de_ptr_reloc; + } else { + return DW_DLV_ERROR; + } + } else if (type == dwarf_drt_segment_rel) { + rel_type = dbg->de_exc_reloc; + } else { + /* We are in trouble: improper use of stream relocations. + Someone else will diagnose */ + rel_type = 0; + } + + elf64_reloc = (REL64 *)relrec_to_fill; + elf64_reloc->r_offset = offset; + Set_REL64_info(*elf64_reloc, symidx, rel_type); + return DW_DLV_OK; +#else /* !HAVE_ELF64_GETEHDR */ + return DW_DLV_ERROR; +#endif /* #if HAVE_ELF64_GETEHDR */ +} + +/* Return DW_DLV_ERROR on malloc error or reltarget_length error. + Return DW_DLV_OK otherwise + a binary reloc: 32bit ABI */ int +_dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, int base_sec_index, + Dwarf_Unsigned offset, /* r_offset of reloc */ + Dwarf_Unsigned symidx, + enum Dwarf_Rel_Type type, + int reltarget_length) +{ + REL32 *elf32_reloc = 0; + void *relrec_to_fill = 0; + int res = 0; + int rel_type = 0; + + res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index, + &relrec_to_fill); + if (res != DW_DLV_OK) + return res; + if (type == dwarf_drt_data_reloc) { + if (reltarget_length == dbg->de_offset_size) { + rel_type = dbg->de_offset_reloc; + } else if (reltarget_length == dbg->de_pointer_size) { + rel_type = dbg->de_ptr_reloc; + } else { + return DW_DLV_ERROR; + } + } else if (type == dwarf_drt_segment_rel) { + rel_type = dbg->de_exc_reloc; + } else { + /* We are in trouble: improper use of stream relocations. + Someone else will diagnose */ + rel_type = 0; + } + + elf32_reloc = (REL32*)relrec_to_fill; + elf32_reloc->r_offset = (Elf32_Addr) offset; + Set_REL32_info(*elf32_reloc, (Dwarf_Word) symidx, rel_type); + return DW_DLV_OK; + + /* get a slot, fill in the slot entry */ +} + + + +/* Return DW_DLV_OK. + Never can really do anything: lengths cannot + be represented as end-start in a stream. */ +/*ARGSUSED*/ int +_dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset, /* r_offset of reloc */ + Dwarf_Unsigned start_symidx, + Dwarf_Unsigned end_symidx, + enum Dwarf_Rel_Type type, + int reltarget_length) +{ + /* get a slot, fill in the slot entry */ + return DW_DLV_OK; +} + + +/* Ensure each stream is a single buffer and + add that single buffer to the set of stream buffers. + + By creating a new buffer and copying if necessary. + + Free the input set of buffers if we consolidate. + Return -1 on error (malloc failure) + + Return DW_DLV_OK on success. Any other return indicates + malloc failed. */ +int +_dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg, + Dwarf_Signed * new_sec_count) +{ + unsigned long total_size = 0; + Dwarf_Small *data = 0; + int sec_index = 0; + unsigned long i = 0; + Dwarf_Error err = 0; + Dwarf_Error *error = &err; + + Dwarf_Signed sec_count = 0; + + Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0]; + + for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) { + unsigned long ct = p_reloc->pr_reloc_total_count; + unsigned len = 0; + struct Dwarf_P_Relocation_Block_s *p_blk = 0; + struct Dwarf_P_Relocation_Block_s *p_blk_last = 0; + Dwarf_P_Per_Reloc_Sect prb = 0; + + if (ct == 0) { + continue; + } + prb = &dbg->de_reloc_sect[i]; + len = dbg->de_relocation_record_size; + ++sec_count; + + total_size = ct * len; + sec_index = prb->pr_sect_num_of_reloc_sect; + if (sec_index == 0) { + /* Call de_callback_func or de_callback_func_b or _c, getting + section number of reloc section. */ + int rel_section_index = 0; + Dwarf_Unsigned name_idx = 0; + int int_name = 0; + int err = 0; + + if (dbg->de_callback_func_c) { + rel_section_index = + dbg->de_callback_func_c(_dwarf_rel_section_names[i], + /* size */ dbg->de_relocation_record_size, + /* type */ SHT_REL, + /* flags */ 0, + /* link to symtab, which we cannot + know */ 0, + /* info == link to sec rels apply to */ + dbg->de_elf_sects[i], + &name_idx, + dbg->de_user_data, + &err); + } else if (dbg->de_callback_func_b) { + rel_section_index = + dbg->de_callback_func_b(_dwarf_rel_section_names[i], + /* size */ dbg->de_relocation_record_size, + /* type */ SHT_REL, + /* flags */ 0, + /* link to symtab, which we cannot + know */ 0, + /* info == link to sec rels apply to */ + dbg->de_elf_sects[i], + &name_idx, &err); + } else { + rel_section_index = + dbg->de_callback_func(_dwarf_rel_section_names[i], + /* size */ dbg->de_relocation_record_size, + /* type */ SHT_REL, + /* flags */ 0, + /* link to symtab, which we cannot + know */ 0, + /* info == link to sec rels apply to */ + dbg->de_elf_sects[i], &int_name, &err); + name_idx = int_name; + } + if (rel_section_index == -1) { + { + _dwarf_p_error(dbg, error, DW_DLE_ELF_SECT_ERR); + return (DW_DLV_ERROR); + } + + } + prb->pr_sect_num_of_reloc_sect = rel_section_index; + sec_index = rel_section_index; + } + GET_CHUNK(dbg, sec_index, data, total_size, &err); + p_blk = p_reloc->pr_first_block; + + /* Following loop executes at least once. Effects the + consolidation to a single block or, if already a single + block, simply copies to the output buffer. And frees the + input block. The new block is in the de_debug_sects list. */ + while (p_blk) { + + unsigned long len = + p_blk->rb_where_to_add_next - p_blk->rb_data; + + memcpy(data, p_blk->rb_data, len); + + + data += len; + + p_blk_last = p_blk; + p_blk = p_blk->rb_next; + + _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last); + } + /* ASSERT: sum of len copied == total_size */ + + /* We have copied the input, now drop the pointers to it. For + debugging, leave the other data untouched. */ + p_reloc->pr_first_block = 0; + p_reloc->pr_last_block = 0; + } + + *new_sec_count = sec_count; + return DW_DLV_OK; +} diff --git a/libdwarf/pro_reloc_stream.h b/libdwarf/pro_reloc_stream.h new file mode 100644 index 0000000..22a3727 --- /dev/null +++ b/libdwarf/pro_reloc_stream.h @@ -0,0 +1,61 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +int _dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset,/* r_offset of reloc */ + Dwarf_Unsigned symidx, + enum Dwarf_Rel_Type, + int reltarget_length); +int _dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset,/* r_offset of reloc */ + Dwarf_Unsigned symidx, + enum Dwarf_Rel_Type, + int reltarget_length); + +int _dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset, /* r_offset of reloc */ + Dwarf_Unsigned start_symidx, + Dwarf_Unsigned end_symidx, + enum Dwarf_Rel_Type, + int reltarget_length); + +int _dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg, + Dwarf_Signed * new_sec_count); diff --git a/libdwarf/pro_reloc_symbolic.c b/libdwarf/pro_reloc_symbolic.c new file mode 100644 index 0000000..3db4505 --- /dev/null +++ b/libdwarf/pro_reloc_symbolic.c @@ -0,0 +1,279 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +/*#include <elfaccess.h> */ +#include "pro_incl.h" +#include "pro_section.h" +#include "pro_reloc.h" +#include "pro_reloc_symbolic.h" + +/* Return DW_DLV_ERROR on malloc error. + Return DW_DLV_OK otherwise */ + +int +_dwarf_pro_reloc_name_symbolic(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset, /* r_offset of reloc */ + Dwarf_Unsigned symidx, + enum Dwarf_Rel_Type type, + int reltarget_length) +{ + /* get a slot, fill in the slot entry */ + void *relrec_to_fill = 0; + int res = 0; + struct Dwarf_Relocation_Data_s *slotp; + + res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index, + &relrec_to_fill); + if (res != DW_DLV_OK) + return res; + slotp = (struct Dwarf_Relocation_Data_s *) relrec_to_fill; + slotp->drd_type = type; + slotp->drd_length = reltarget_length; + slotp->drd_offset = offset; + slotp->drd_symbol_index = symidx; + return DW_DLV_OK; +} + + + +/* Return DW_DLV_ERROR on malloc error. + Return DW_DLV_OK otherwise */ +int +_dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset, /* r_offset of reloc */ + Dwarf_Unsigned start_symidx, + Dwarf_Unsigned end_symidx, + enum Dwarf_Rel_Type type, + int reltarget_length) +{ + /* get a slot, fill in the slot entry */ + void *relrec_to_fill = 0; + int res = 0; + struct Dwarf_Relocation_Data_s *slotp1 = 0; + struct Dwarf_Relocation_Data_s *slotp2 = 0; + + res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index, + &relrec_to_fill); + if (res != DW_DLV_OK) + return res; + slotp1 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill; + res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index, + &relrec_to_fill); + if (res != DW_DLV_OK) + return res; + slotp2 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill; + + /* ASSERT: type == dwarf_drt_first_of_length_type_pair */ + slotp1->drd_type = type; + slotp1->drd_length = reltarget_length; + slotp1->drd_offset = offset; + slotp1->drd_symbol_index = start_symidx; + + slotp2->drd_type = dwarf_drt_second_of_length_pair; + slotp2->drd_length = reltarget_length; + slotp2->drd_offset = offset; + slotp2->drd_symbol_index = end_symidx; + return DW_DLV_OK; +} + +/* Reset whatever fields of Dwarf_P_Per_Reloc_Sect_s + we must to allow adding a fresh new single + block easily (block consolidation use only). */ +static void +_dwarf_reset_reloc_sect_info(struct Dwarf_P_Per_Reloc_Sect_s *pblk, + unsigned long ct) +{ + + + /* Do not zero pr_sect_num_of_reloc_sect */ + pblk->pr_reloc_total_count = 0; + pblk->pr_first_block = 0; + pblk->pr_last_block = 0; + pblk->pr_block_count = 0; + pblk->pr_slots_per_block_to_alloc = ct; +} + +/* Ensure each stream is a single buffer and + add that single buffer to the set of stream buffers. + + By creating a new buffer and copying if necessary. + (If > 1 block, reduce to 1 block) + + Free the input set of buffers if we consolidate. + + We pass back *new_sec_count as zero because we + are not creating normal sections for a .o, but + symbolic relocations, separately counted. + + Return -1 on error (malloc failure) + + Return DW_DLV_OK on success. Any other return indicates + malloc failed. */ +int +_dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg, + Dwarf_Signed * new_sec_count) +{ + /* unsigned long total_size =0; */ + Dwarf_Small *data = 0; + int sec_index = 0; + int res = 0; + unsigned long i = 0; + Dwarf_Error error = 0; + Dwarf_Signed sec_count = 0; + Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0]; + + for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) { + unsigned long ct = p_reloc->pr_reloc_total_count; + struct Dwarf_P_Relocation_Block_s *p_blk; + struct Dwarf_P_Relocation_Block_s *p_blk_last; + int err; + if (ct == 0) { + continue; + } + + /* len = dbg->de_relocation_record_size; */ + ++sec_count; + + /* total_size = ct *len; */ + sec_index = p_reloc->pr_sect_num_of_reloc_sect; + if (sec_index == 0) { + /* Call de_callback_func or de_callback_func_b, + getting section number of reloc section. */ + int rel_section_index = 0; + int int_name = 0; + Dwarf_Unsigned name_idx = 0; + + /* This is a bit of a fake, as we do not really have true + elf sections at all. Just the data such might contain. + But this lets the caller eventually link things + together: without this call we would not know what rel + data goes with what section when we are asked for the + real arrays. */ + + if (dbg->de_callback_func_c) { + rel_section_index = + dbg->de_callback_func_c(_dwarf_rel_section_names[i], + dbg->de_relocation_record_size, + /* type */ SHT_REL, + /* flags */ 0, + /* link to symtab, which we cannot + know */ SHN_UNDEF, + /* sec rels apply to */ + dbg->de_elf_sects[i], + &name_idx, + dbg->de_user_data,&err); + } else if (dbg->de_callback_func_b) { + rel_section_index = + dbg->de_callback_func_b(_dwarf_rel_section_names[i], + dbg->de_relocation_record_size, + /* type */ SHT_REL, + /* flags */ 0, + /* link to symtab, which we cannot + know */ SHN_UNDEF, + /* sec rels apply to */ + dbg->de_elf_sects[i], + &name_idx, &err); + } else { + rel_section_index = + dbg->de_callback_func(_dwarf_rel_section_names[i], + dbg->de_relocation_record_size, + /* type */ SHT_REL, + /* flags */ 0, + /* link to symtab, which we cannot + know */ SHN_UNDEF, + /* sec rels apply to, in elf, sh_info */ + dbg->de_elf_sects[i], &int_name, &err); + name_idx = int_name; + } + if (rel_section_index == -1) { + { + _dwarf_p_error(dbg, &error, DW_DLE_ELF_SECT_ERR); + return (DW_DLV_ERROR); + } + } + p_reloc->pr_sect_num_of_reloc_sect = rel_section_index; + sec_index = rel_section_index; + } + + p_blk = p_reloc->pr_first_block; + + if (p_reloc->pr_block_count > 1) { + struct Dwarf_P_Relocation_Block_s *new_blk; + + /* HACK , not normal interfaces, trashing p_reloc current + contents! */ + _dwarf_reset_reloc_sect_info(p_reloc, ct); + + /* Creating new single block for all 'ct' entries */ + res = _dwarf_pro_pre_alloc_n_reloc_slots(dbg, (int) i, ct); + if (res != DW_DLV_OK) { + return res; + } + new_blk = p_reloc->pr_first_block; + + data = (Dwarf_Small *) new_blk->rb_data; + + /* The following loop does the consolidation to a single + block and frees the input block(s). */ + do { + unsigned long len = + p_blk->rb_where_to_add_next - p_blk->rb_data; + memcpy(data, p_blk->rb_data, len); + data += len; + p_blk_last = p_blk; + p_blk = p_blk->rb_next; + _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last); + } while (p_blk); + /* ASSERT: sum of len copied == total_size */ + new_blk->rb_next_slot_to_use = ct; + new_blk->rb_where_to_add_next = (char *) data; + p_reloc->pr_reloc_total_count = ct; + + /* Have now created a single block, but no change in slots + used (pr_reloc_total_count) */ + } + } + *new_sec_count = 0; + return DW_DLV_OK; +} diff --git a/libdwarf/pro_reloc_symbolic.h b/libdwarf/pro_reloc_symbolic.h new file mode 100644 index 0000000..5c76cc3 --- /dev/null +++ b/libdwarf/pro_reloc_symbolic.h @@ -0,0 +1,54 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +int _dwarf_pro_reloc_name_symbolic(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset,/* r_offset of reloc */ + Dwarf_Unsigned symidx, + enum Dwarf_Rel_Type, + int reltarget_length); + +int +_dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg, + int base_sec_index, + Dwarf_Unsigned offset, /* r_offset of reloc */ + Dwarf_Unsigned start_symidx, + Dwarf_Unsigned end_symidx, + enum Dwarf_Rel_Type, + int reltarget_length); + +int _dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg, + Dwarf_Signed * new_sec_count); diff --git a/libdwarf/pro_section.c b/libdwarf/pro_section.c new file mode 100644 index 0000000..b975d6c --- /dev/null +++ b/libdwarf/pro_section.c @@ -0,0 +1,2263 @@ +/* + Copyright (C) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + Portions Copyright 2002-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ +/* + SGI has moved from the Crittenden Lane address. +*/ + + + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#endif +#include "pro_incl.h" +#include "pro_section.h" +#include "pro_line.h" +#include "pro_frame.h" +#include "pro_die.h" +#include "pro_macinfo.h" +#include "pro_types.h" + +#ifndef SHF_MIPS_NOSTRIP +/* if this is not defined, we probably don't need it: just use 0 */ +#define SHF_MIPS_NOSTRIP 0 +#endif +#ifndef R_MIPS_NONE +#define R_MIPS_NONE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* Must match up with pro_section.h defines of DEBUG_INFO etc +and sectnames (below). REL_SEC_PREFIX is either ".rel" or ".rela" +see pro_incl.h +*/ +char *_dwarf_rel_section_names[] = { + REL_SEC_PREFIX ".debug_info", + REL_SEC_PREFIX ".debug_line", + REL_SEC_PREFIX ".debug_abbrev", /* no relocations on this, really */ + REL_SEC_PREFIX ".debug_frame", + REL_SEC_PREFIX ".debug_aranges", + REL_SEC_PREFIX ".debug_pubnames", + REL_SEC_PREFIX ".debug_str", + REL_SEC_PREFIX ".debug_funcnames", /* sgi extension */ + REL_SEC_PREFIX ".debug_typenames", /* sgi extension */ + REL_SEC_PREFIX ".debug_varnames", /* sgi extension */ + REL_SEC_PREFIX ".debug_weaknames", /* sgi extension */ + REL_SEC_PREFIX ".debug_macinfo", + REL_SEC_PREFIX ".debug_loc", + REL_SEC_PREFIX ".debug_ranges", + REL_SEC_PREFIX ".debug_types" + +}; + +/* names of sections. Ensure that it matches the defines + in pro_section.h, in the same order + Must match also _dwarf_rel_section_names above +*/ +char *_dwarf_sectnames[] = { + ".debug_info", + ".debug_line", + ".debug_abbrev", + ".debug_frame", + ".debug_aranges", + ".debug_pubnames", + ".debug_str", + ".debug_funcnames", /* sgi extension */ + ".debug_typenames", /* sgi extension */ + ".debug_varnames", /* sgi extension */ + ".debug_weaknames", /* sgi extension */ + ".debug_macinfo", + ".debug_loc", + ".debug_ranges", + ".debug_types", +}; + + + + +static Dwarf_Ubyte std_opcode_len[] = { 0, /* DW_LNS_copy */ + 1, /* DW_LNS_advance_pc */ + 1, /* DW_LNS_advance_line */ + 1, /* DW_LNS_set_file */ + 1, /* DW_LNS_set_column */ + 0, /* DW_LNS_negate_stmt */ + 0, /* DW_LNS_set_basic_block */ + 0, /* DW_LNS_const_add_pc */ + 1, /* DW_LNS_fixed_advance_pc */ + /* The following for DWARF3 and DWARF4, though GNU + uses these in DWARF2 as well. */ + 0, /* DW_LNS_set_prologue_end */ + 0, /* DW_LNS_set_epilogue_begin */ + 1, /* DW_LNS_set_isa */ +}; + +/* struct to hold relocation entries. Its mantained as a linked + list of relocation structs, and will then be written at as a + whole into the relocation section. Whether its 32 bit or + 64 bit will be obtained from Dwarf_Debug pointer. +*/ + +typedef struct Dwarf_P_Rel_s *Dwarf_P_Rel; +struct Dwarf_P_Rel_s { + Dwarf_P_Rel dr_next; + void *dr_rel_datap; +}; +typedef struct Dwarf_P_Rel_Head_s *Dwarf_P_Rel_Head; +struct Dwarf_P_Rel_Head_s { + struct Dwarf_P_Rel_s *drh_head; + struct Dwarf_P_Rel_s *drh_tail; +}; + +static int _dwarf_pro_generate_debugline(Dwarf_P_Debug dbg, + Dwarf_Error * error); +static int _dwarf_pro_generate_debugframe(Dwarf_P_Debug dbg, + Dwarf_Error * error); +static int _dwarf_pro_generate_debuginfo(Dwarf_P_Debug dbg, + Dwarf_Error * error); +static Dwarf_P_Abbrev _dwarf_pro_getabbrev(Dwarf_P_Die, Dwarf_P_Abbrev); +static int _dwarf_pro_match_attr + (Dwarf_P_Attribute, Dwarf_P_Abbrev, int no_attr); + +/* these macros used as return value for below functions */ +#define OPC_INCS_ZERO -1 +#define OPC_OUT_OF_RANGE -2 +#define LINE_OUT_OF_RANGE -3 +static int _dwarf_pro_get_opc(Dwarf_P_Debug dbg,Dwarf_Unsigned addr_adv, int line_adv); + + +/* BEGIN_LEN_SIZE is the size of the 'length' field in total. + Which may be 4,8, or 12 bytes! + 4 is standard DWARF2. + 8 is non-standard MIPS-IRIX 64-bit. + 12 is standard DWARF3 for 64 bit offsets. + Used in various routines: local variable names + must match the names here. +*/ +#define BEGIN_LEN_SIZE (uwordb_size + extension_size) + +/* Return TRUE if we need the section, FALSE otherwise + + If any of the 'line-data-related' calls were made + including file or directory entries, + produce .debug_line . + +*/ +static int +dwarf_need_debug_line_section(Dwarf_P_Debug dbg) +{ + if (dbg->de_lines == NULL && dbg->de_file_entries == NULL + && dbg->de_inc_dirs == NULL) { + return FALSE; + } + return TRUE; +} + +/* Convert debug information to a format such that + it can be written on disk. + Called exactly once per execution. +*/ +Dwarf_Signed +dwarf_transform_to_disk_form(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + /* Section data in written out in a number of buffers. Each + _generate_*() function returns a cumulative count of buffers for + all the sections. get_section_bytes() returns pointers to these + buffers one at a time. */ + int nbufs = 0; + int sect = 0; + int err = 0; + Dwarf_Unsigned du = 0; + + if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_NOCOUNT); + } + + /* Create dwarf section headers */ + for (sect = 0; sect < NUM_DEBUG_SECTIONS; sect++) { + long flags = 0; + + switch (sect) { + + case DEBUG_INFO: + if (dbg->de_dies == NULL) { + continue; + } + break; + + case DEBUG_LINE: + if (dwarf_need_debug_line_section(dbg) == FALSE) { + continue; + } + break; + + case DEBUG_ABBREV: + if (dbg->de_dies == NULL) { + continue; + } + break; + + case DEBUG_FRAME: + if (dbg->de_frame_cies == NULL) { + continue; + } + flags = SHF_MIPS_NOSTRIP; + break; + + case DEBUG_ARANGES: + if (dbg->de_arange == NULL) { + continue; + } + break; + + case DEBUG_PUBNAMES: + if (dbg->de_simple_name_headers[dwarf_snk_pubname]. + sn_head == NULL) { + continue; + } + break; + + case DEBUG_STR: + if (dbg->de_strings == NULL) { + continue; + } + break; + + case DEBUG_FUNCNAMES: + if (dbg->de_simple_name_headers[dwarf_snk_funcname]. + sn_head == NULL) { + continue; + } + break; + + case DEBUG_TYPENAMES: + if (dbg->de_simple_name_headers[dwarf_snk_typename]. + sn_head == NULL) { + continue; + } + break; + + case DEBUG_VARNAMES: + if (dbg->de_simple_name_headers[dwarf_snk_varname]. + sn_head == NULL) { + continue; + } + break; + + case DEBUG_WEAKNAMES: + if (dbg->de_simple_name_headers[dwarf_snk_weakname]. + sn_head == NULL) { + continue; + } + break; + + case DEBUG_MACINFO: + if (dbg->de_first_macinfo == NULL) { + continue; + } + break; + case DEBUG_LOC: + /* Not handled yet. */ + continue; + case DEBUG_RANGES: + /* Not handled yet. */ + continue; + case DEBUG_TYPES: + /* Not handled yet. */ + continue; + default: + /* logic error: missing a case */ + DWARF_P_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR, DW_DLV_NOCOUNT); + } + { + int new_base_elf_sect = 0; + + if (dbg->de_callback_func_c) { + new_base_elf_sect = + dbg->de_callback_func_c(_dwarf_sectnames[sect], + /* rec size */ 1, + SECTION_TYPE, + flags, SHN_UNDEF, 0, &du, + dbg->de_user_data, &err); + } else if (dbg->de_callback_func_b) { + new_base_elf_sect = + dbg->de_callback_func_b(_dwarf_sectnames[sect], + /* rec size */ 1, + SECTION_TYPE, + flags, SHN_UNDEF, 0, &du, &err); + } else { + int name_idx = 0; + new_base_elf_sect = dbg->de_callback_func( + _dwarf_sectnames[sect], + dbg->de_relocation_record_size, + SECTION_TYPE, flags, + SHN_UNDEF, 0, + &name_idx, &err); + du = name_idx; + } + if (new_base_elf_sect == -1) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR, + DW_DLV_NOCOUNT); + } + dbg->de_elf_sects[sect] = new_base_elf_sect; + + dbg->de_sect_name_idx[sect] = du; + } + } + + nbufs = 0; + + /* Changing the order in which the sections are generated may cause + problems because of relocations. */ + + if (dwarf_need_debug_line_section(dbg) == TRUE) { + nbufs = _dwarf_pro_generate_debugline(dbg, error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGLINE_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_frame_cies) { + nbufs = _dwarf_pro_generate_debugframe(dbg, error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGFRAME_ERROR, + DW_DLV_NOCOUNT); + } + } + if (dbg->de_first_macinfo) { + nbufs = _dwarf_pro_transform_macro_info_to_disk(dbg, error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGMACINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_dies) { + nbufs = _dwarf_pro_generate_debuginfo(dbg, error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_arange) { + nbufs = _dwarf_transform_arange_to_disk(dbg, error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_simple_name_headers[dwarf_snk_pubname].sn_head) { + nbufs = _dwarf_transform_simplename_to_disk(dbg, + dwarf_snk_pubname, + DEBUG_PUBNAMES, + error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_simple_name_headers[dwarf_snk_funcname].sn_head) { + nbufs = _dwarf_transform_simplename_to_disk(dbg, + dwarf_snk_funcname, + DEBUG_FUNCNAMES, + error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_simple_name_headers[dwarf_snk_typename].sn_head) { + nbufs = _dwarf_transform_simplename_to_disk(dbg, + dwarf_snk_typename, + DEBUG_TYPENAMES, + error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_simple_name_headers[dwarf_snk_varname].sn_head) { + nbufs = _dwarf_transform_simplename_to_disk(dbg, + dwarf_snk_varname, + DEBUG_VARNAMES, + error); + + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + if (dbg->de_simple_name_headers[dwarf_snk_weakname].sn_head) { + nbufs = _dwarf_transform_simplename_to_disk(dbg, + dwarf_snk_weakname, DEBUG_WEAKNAMES, error); + if (nbufs < 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + } + + { + Dwarf_Signed new_secs = 0; + int res = 0; + + res = dbg->de_transform_relocs_to_disk(dbg, &new_secs); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR, + DW_DLV_NOCOUNT); + } + nbufs += new_secs; + } + return nbufs; +} + +static unsigned +write_fixed_size(Dwarf_Unsigned val, + Dwarf_P_Debug dbg, + int elfsectno, + Dwarf_Unsigned size, + Dwarf_Error* error) +{ + Dwarf_Ubyte db = val; + unsigned char *data = 0; + GET_CHUNK(dbg, elfsectno, data, size, error); + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &val, + sizeof(val), size); + return size; +} + +static unsigned +write_ubyte(unsigned val, + Dwarf_P_Debug dbg, + int elfsectno, + Dwarf_Error* error) +{ + Dwarf_Ubyte db = val; + unsigned char *data = 0; + unsigned len = sizeof(Dwarf_Ubyte); + GET_CHUNK(dbg, elfsectno, data, + len, error); + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), len); + return 1; +} +static unsigned +pretend_write_uval(Dwarf_Unsigned val, + Dwarf_P_Debug dbg, + int elfsectno, + Dwarf_Error* error) +{ + char buff1[ENCODE_SPACE_NEEDED]; + int nbytes = 0; + int res = _dwarf_pro_encode_leb128_nm(val, + &nbytes, buff1, + sizeof(buff1)); + return nbytes; +} + +static unsigned +write_sval(Dwarf_Signed val, + Dwarf_P_Debug dbg, + int elfsectno, + Dwarf_Error* error) +{ + char buff1[ENCODE_SPACE_NEEDED]; + unsigned char *data = 0; + int nbytes = 0; + int res = _dwarf_pro_encode_signed_leb128_nm(val, + &nbytes, buff1, + sizeof(buff1)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1); + } + GET_CHUNK(dbg, elfsectno, data, nbytes, error); + memcpy((void *) data, (const void *) buff1, nbytes); + return nbytes; +} + +static unsigned +write_uval(Dwarf_Unsigned val, + Dwarf_P_Debug dbg, + int elfsectno, + Dwarf_Error* error) +{ + char buff1[ENCODE_SPACE_NEEDED]; + unsigned char *data = 0; + int nbytes = 0; + int res = _dwarf_pro_encode_leb128_nm(val, + &nbytes, buff1, + sizeof(buff1)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1); + } + GET_CHUNK(dbg, elfsectno, data, nbytes, error); + memcpy((void *) data, (const void *) buff1, nbytes); + return nbytes; +} +static unsigned +write_opcode_uval(int opcode, + Dwarf_P_Debug dbg, + int elfsectno, + Dwarf_Unsigned val, + Dwarf_Error* error) +{ + unsigned totallen = write_ubyte(opcode,dbg,elfsectno,error); + totallen += write_uval(val,dbg,elfsectno,error); + return totallen; +} + +/* Generate debug_line section */ +static int +_dwarf_pro_generate_debugline(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + Dwarf_P_Inc_Dir curdir = 0; + Dwarf_P_F_Entry curentry = 0; + Dwarf_P_Line curline = 0; + Dwarf_P_Line prevline = 0; + + /* all data named cur* are used to loop thru linked lists */ + + int sum_bytes = 0; + int prolog_size = 0; + unsigned char *data = 0; /* holds disk form data */ + int elfsectno = 0; + unsigned char *start_line_sec = 0; /* pointer to the buffer at + section start */ + /* temps for memcpy */ + Dwarf_Unsigned du = 0; + Dwarf_Ubyte db = 0; + Dwarf_Half dh = 0; + int res = 0; + int uwordb_size = dbg->de_offset_size; + int extension_size = dbg->de_64bit_extension ? 4 : 0; + int upointer_size = dbg->de_pointer_size; + char buff1[ENCODE_SPACE_NEEDED]; + + + + sum_bytes = 0; + + elfsectno = dbg->de_elf_sects[DEBUG_LINE]; + + /* include directories */ + curdir = dbg->de_inc_dirs; + while (curdir) { + prolog_size += strlen(curdir->did_name) + 1; + curdir = curdir->did_next; + } + prolog_size++; /* last null following last directory + entry. */ + + /* file entries */ + curentry = dbg->de_file_entries; + while (curentry) { + prolog_size += + strlen(curentry->dfe_name) + 1 + curentry->dfe_nbytes; + curentry = curentry->dfe_next; + } + prolog_size++; /* last null byte */ + + + prolog_size += BEGIN_LEN_SIZE + sizeof_uhalf(dbg) + /* version # */ + uwordb_size + /* header length */ + sizeof_ubyte(dbg) + /* min_instr length */ + sizeof_ubyte(dbg) + /* default is_stmt */ + sizeof_ubyte(dbg) + /* linebase */ + sizeof_ubyte(dbg) + /* linerange */ + sizeof_ubyte(dbg); /* opcode base */ + + /* length of table specifying # of opnds */ + prolog_size += dbg->de_line_inits.pi_opcode_base-1; + if(dbg->de_line_inits.pi_version == DW_LINE_VERSION4) { + /* For maximum_operations_per_instruction. */ + prolog_size += sizeof_ubyte(dbg); + } + + GET_CHUNK(dbg, elfsectno, data, prolog_size, error); + start_line_sec = data; + + /* copy over the data */ + /* total_length */ + du = 0; + if (extension_size) { + Dwarf_Word x = DISTINGUISHED_VALUE; + + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &x, + sizeof(x), extension_size); + data += extension_size; + } + + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du, + sizeof(du), uwordb_size); + data += uwordb_size; + + dh = dbg->de_line_inits.pi_version; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &dh, + sizeof(dh), sizeof(Dwarf_Half)); + data += sizeof(Dwarf_Half); + + /* header length */ + du = prolog_size - (BEGIN_LEN_SIZE + sizeof(Dwarf_Half) + + uwordb_size); + { + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du, + sizeof(du), uwordb_size); + data += uwordb_size; + } + db = dbg->de_line_inits.pi_minimum_instruction_length; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + + if(dbg->de_line_inits.pi_version == DW_LINE_VERSION4) { + db = dbg->de_line_inits.pi_maximum_operations_per_instruction; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + } + + db = dbg->de_line_inits.pi_default_is_stmt; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + db = dbg->de_line_inits.pi_line_base; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + db = dbg->de_line_inits.pi_line_range; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + db = dbg->de_line_inits.pi_opcode_base; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + WRITE_UNALIGNED(dbg, (void *) data, (const void *) std_opcode_len, + dbg->de_line_inits.pi_opcode_base-1, + dbg->de_line_inits.pi_opcode_base-1); + data += dbg->de_line_inits.pi_opcode_base-1; + + /* copy over include directories */ + curdir = dbg->de_inc_dirs; + while (curdir) { + strcpy((char *) data, curdir->did_name); + data += strlen(curdir->did_name) + 1; + curdir = curdir->did_next; + } + *data = '\0'; /* last null */ + data++; + + /* copy file entries */ + curentry = dbg->de_file_entries; + while (curentry) { + strcpy((char *) data, curentry->dfe_name); + data += strlen(curentry->dfe_name) + 1; + /* copies of leb numbers, no endian issues */ + memcpy((void *) data, + (const void *) curentry->dfe_args, curentry->dfe_nbytes); + data += curentry->dfe_nbytes; + curentry = curentry->dfe_next; + } + *data = '\0'; + data++; + + sum_bytes += prolog_size; + + curline = dbg->de_lines; + prevline = (Dwarf_P_Line) + _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s)); + if (prevline == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, -1); + } + _dwarf_pro_reg_init(dbg,prevline); + /* generate opcodes for line numbers */ + while (curline) { + int nbytes; + char *arg; + int opc; + int no_lns_copy; /* if lns copy opcode doesnt need to be + generated, if special opcode or end + sequence */ + Dwarf_Unsigned addr_adv; + int line_adv; /* supposed to be a reasonably small + number, so the size should not be a + problem. ? */ + + no_lns_copy = 0; + if (curline->dpl_opc != 0) { + int inst_bytes; /* no of bytes in extended opcode */ + char *str; /* hold leb encoded inst_bytes */ + int str_nbytes; /* no of bytes in str */ + unsigned writelen = 0; + + switch (curline->dpl_opc) { + case DW_LNE_end_sequence: + /* Advance pc to end of text section. */ + addr_adv = curline->dpl_address - prevline->dpl_address; + if (addr_adv > 0) { + writelen = write_opcode_uval(DW_LNS_advance_pc,dbg, + elfsectno, + addr_adv/ + dbg->de_line_inits.pi_minimum_instruction_length, + error); + sum_bytes += writelen; + prevline->dpl_address = curline->dpl_address; + } + + /* first null byte */ + db = 0; + writelen = write_ubyte(db,dbg,elfsectno,error); + sum_bytes += writelen; + + /* write length of extended opcode */ + inst_bytes = sizeof(Dwarf_Ubyte); + writelen = write_uval(inst_bytes,dbg,elfsectno,error); + sum_bytes += writelen; + + /* write extended opcode */ + writelen = write_ubyte(DW_LNE_end_sequence,dbg,elfsectno,error); + sum_bytes += writelen; + + /* reset value to original values */ + _dwarf_pro_reg_init(dbg,prevline); + no_lns_copy = 1; + /* this is set only for end_sequence, so that a + dw_lns_copy is not generated */ + break; + + case DW_LNE_set_address: + + /* first null byte */ + db = 0; + writelen = write_ubyte(db,dbg,elfsectno,error); + sum_bytes += writelen; + + /* write length of extended opcode */ + inst_bytes = sizeof(Dwarf_Ubyte) + upointer_size; + writelen = write_uval(inst_bytes,dbg,elfsectno,error); + sum_bytes += writelen; + + /* write extended opcode */ + writelen = write_ubyte(DW_LNE_set_address,dbg,elfsectno,error); + sum_bytes += writelen; + + /* reloc for address */ + res = dbg->de_reloc_name(dbg, DEBUG_LINE, + sum_bytes, /* r_offset */ + curline->dpl_r_symidx, + dwarf_drt_data_reloc, + uwordb_size); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1); + } + + /* write offset (address) */ + du = curline->dpl_address; + writelen = write_fixed_size(du,dbg,elfsectno, + upointer_size,error); + sum_bytes += writelen; + prevline->dpl_address = curline->dpl_address; + no_lns_copy = 1; + break; + case DW_LNE_define_file: + /* Not supported, all add-file entries + are added via dbg -> de_file_entries, + which adds to the line table header. */ + no_lns_copy = 1; + break; + case DW_LNE_set_discriminator: {/* DWARF4 */ + unsigned val_len = 0; + /* first null byte */ + db = 0; + writelen = write_ubyte(db,dbg,elfsectno,error); + sum_bytes += writelen; + + /* Write len of opcode + value here. */ + val_len = pretend_write_uval(curline->dpl_discriminator, + dbg, elfsectno,error) + 1; + writelen = write_uval(val_len +1,dbg,elfsectno,error); + sum_bytes += writelen; + + /* Write opcode */ + writelen = write_ubyte(DW_LNE_set_discriminator, + dbg,elfsectno,error); + sum_bytes += writelen; + + /* Write the value itself. */ + writelen = write_uval(curline->dpl_discriminator, + dbg,elfsectno,error); + sum_bytes += writelen; + no_lns_copy = 1; + } + break; + } + } else { + unsigned writelen = 0; + if (dbg->de_line_inits.pi_opcode_base >12) { + /* We have the newer standard opcodes + DW_LNS_set_prologue_end, DW_LNS_set_epilogue_end, + DW_LNS_set_isa, we do not write them if not + in the table. DWARF3 and DWARF4 */ + /* Should we check if a change? These reset automatically + in the line processing/reading engine, + so I think no check of prevline is wanted. */ + if (curline->dpl_epilogue_begin) { + writelen = write_ubyte(DW_LNS_set_epilogue_begin,dbg, + elfsectno, error); + sum_bytes += writelen; + } + if (curline->dpl_prologue_end) { + writelen = write_ubyte(DW_LNS_set_prologue_end,dbg, + elfsectno, error); + sum_bytes += writelen; + } + if (curline->dpl_isa != prevline->dpl_isa) { + writelen = write_opcode_uval(DW_LNS_set_isa,dbg, + elfsectno, + curline->dpl_isa ,error); + sum_bytes += writelen; + } + } + if (curline->dpl_file != prevline->dpl_file) { + db = DW_LNS_set_file; + writelen = write_opcode_uval(db,dbg, + elfsectno, + curline->dpl_file ,error); + sum_bytes += writelen; + + prevline->dpl_file = curline->dpl_file; + } + if (curline->dpl_column != prevline->dpl_column) { + db = DW_LNS_set_column; + writelen = write_opcode_uval(db,dbg, + elfsectno, + curline->dpl_column ,error); + sum_bytes += writelen; + prevline->dpl_column = curline->dpl_column; + } + if (curline->dpl_is_stmt != prevline->dpl_is_stmt) { + writelen = write_ubyte(DW_LNS_negate_stmt,dbg,elfsectno,error); + sum_bytes += writelen; + prevline->dpl_is_stmt = curline->dpl_is_stmt; + } + if (curline->dpl_basic_block == true && + prevline->dpl_basic_block == false) { + writelen = write_ubyte(DW_LNS_set_basic_block,dbg, + elfsectno,error); + sum_bytes += writelen; + prevline->dpl_basic_block = curline->dpl_basic_block; + } + if(curline->dpl_discriminator) { + /* This is dwarf4, but because it is an extended op + not a standard op, + we allow it without testing version. + GNU seems to set this from time to time. */ + unsigned val_len = 0; + /* first null byte */ + db = 0; + writelen = write_ubyte(db,dbg,elfsectno,error); + sum_bytes += writelen; + + /* Write len of opcode + value here. */ + val_len = pretend_write_uval(curline->dpl_discriminator, + dbg, elfsectno,error) + 1; + writelen = write_uval(val_len +1,dbg,elfsectno,error); + sum_bytes += writelen; + + /* Write opcode */ + writelen = write_ubyte(DW_LNE_set_discriminator, + dbg,elfsectno,error); + sum_bytes += writelen; + + /* Write the value itself. */ + writelen = write_uval(curline->dpl_discriminator, + dbg,elfsectno,error); + sum_bytes += writelen; + } + + addr_adv = curline->dpl_address - prevline->dpl_address; + + line_adv = (int) (curline->dpl_line - prevline->dpl_line); + if ((addr_adv % MIN_INST_LENGTH) != 0) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_WRONG_ADDRESS, -1); + } + opc = _dwarf_pro_get_opc(dbg,addr_adv, line_adv); + if (opc > 0) { + /* Use special opcode. */ + no_lns_copy = 1; + writelen = write_ubyte(opc,dbg,elfsectno,error); + sum_bytes += writelen; + prevline->dpl_basic_block = false; + prevline->dpl_address = curline->dpl_address; + prevline->dpl_line = curline->dpl_line; + } else { + /* opc says use standard opcodes. */ + if (addr_adv > 0) { + db = DW_LNS_advance_pc; + writelen = write_opcode_uval(db,dbg, + elfsectno, + addr_adv/ + dbg->de_line_inits.pi_minimum_instruction_length, + error); + sum_bytes += writelen; + prevline->dpl_basic_block = false; + prevline->dpl_address = curline->dpl_address; + } + if (line_adv != 0) { + db = DW_LNS_advance_line; + writelen = write_ubyte(db,dbg, + elfsectno, + error); + sum_bytes += writelen; + writelen = write_sval(line_adv,dbg, + elfsectno, + error); + sum_bytes += writelen; + prevline->dpl_basic_block = false; + prevline->dpl_line = curline->dpl_line; + } + } + } /* ends else for opc <= 0 */ + if (no_lns_copy == 0) { /* if not a special or dw_lne_end_seq + generate a matrix line */ + unsigned writelen = 0; + writelen = write_ubyte(DW_LNS_copy,dbg,elfsectno,error); + sum_bytes += writelen; + prevline->dpl_basic_block = false; + } + curline = curline->dpl_next; + } + + /* write total length field */ + du = sum_bytes - BEGIN_LEN_SIZE; + { + start_line_sec += extension_size; + WRITE_UNALIGNED(dbg, (void *) start_line_sec, + (const void *) &du, sizeof(du), uwordb_size); + } + + return (int) dbg->de_n_debug_sect; +} + +/* + Generate debug_frame section */ +static int +_dwarf_pro_generate_debugframe(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + int elfsectno = 0; + int i = 0; + int firsttime = 1; + int pad = 0; /* Pad for padding to align cies and fdes */ + Dwarf_P_Cie curcie = 0; + Dwarf_P_Fde curfde = 0; + unsigned char *data = 0; + Dwarf_sfixed dsw = 0; + Dwarf_Unsigned du = 0; + Dwarf_Ubyte db = 0; + long *cie_offs = 0; /* Holds byte offsets for links to fde's */ + unsigned long cie_length = 0; + int cie_no = 0; + int uwordb_size = dbg->de_offset_size; + int extension_size = dbg->de_64bit_extension ? 4 : 0; + int upointer_size = dbg->de_pointer_size; + Dwarf_Unsigned cur_off = 0; /* current offset of written data, held + for relocation info */ + + elfsectno = dbg->de_elf_sects[DEBUG_FRAME]; + + curcie = dbg->de_frame_cies; + cie_length = 0; + cur_off = 0; + cie_offs = (long *) + _dwarf_p_get_alloc(dbg, sizeof(long) * dbg->de_n_cie); + if (cie_offs == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1); + } + /* Generate cie number as we go along. This writes + all CIEs first before any FDEs, which is rather + different from the order a compiler might like (which + might be each CIE followed by its FDEs then the next CIE, and + so on). */ + cie_no = 1; + while (curcie) { + char *code_al = 0; + int c_bytes = 0; + char *data_al = 0; + int d_bytes = 0; + int res = 0; + char buff1[ENCODE_SPACE_NEEDED]; + char buff2[ENCODE_SPACE_NEEDED]; + char buff3[ENCODE_SPACE_NEEDED]; + char *augmentation = 0; + char *augmented_al = 0; + long augmented_fields_length = 0; + int a_bytes = 0; + + res = _dwarf_pro_encode_leb128_nm(curcie->cie_code_align, + &c_bytes, + buff1, sizeof(buff1)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1); + } + /* Before April 1999, the following was using an unsigned + encode. That worked ok even though the decoder used the + correct signed leb read, but doing the encode correctly + (according to the dwarf spec) saves space in the output file + and is completely compatible. + + Note the actual stored amount on MIPS was 10 bytes (!) to + store the value -4. (hex)fc ffffffff ffffffff 01 The + libdwarf consumer consumed all 10 bytes too! + + old version res = + _dwarf_pro_encode_leb128_nm(curcie->cie_data_align, + + below is corrected signed version. */ + res = _dwarf_pro_encode_signed_leb128_nm(curcie->cie_data_align, + &d_bytes, + buff2, sizeof(buff2)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1); + } + code_al = buff1; + data_al = buff2; + + /* get the correct offset */ + if (firsttime) { + cie_offs[cie_no - 1] = 0; + firsttime = 0; + } else { + cie_offs[cie_no - 1] = cie_offs[cie_no - 2] + + (long) cie_length + BEGIN_LEN_SIZE; + } + cie_no++; + augmentation = curcie->cie_aug; + if (strcmp(augmentation, DW_CIE_AUGMENTER_STRING_V0) == 0) { + augmented_fields_length = 0; + res = _dwarf_pro_encode_leb128_nm(augmented_fields_length, + &a_bytes, buff3, + sizeof(buff3)); + augmented_al = buff3; + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1); + } + cie_length = uwordb_size + /* cie_id */ + sizeof(Dwarf_Ubyte) + /* cie version */ + strlen(curcie->cie_aug) + 1 + /* augmentation */ + c_bytes + /* code alignment factor */ + d_bytes + /* data alignment factor */ + sizeof(Dwarf_Ubyte) + /* return reg address */ + a_bytes + /* augmentation length */ + curcie->cie_inst_bytes; + } else { + cie_length = uwordb_size + /* cie_id */ + sizeof(Dwarf_Ubyte) + /* cie version */ + strlen(curcie->cie_aug) + 1 + /* augmentation */ + c_bytes + d_bytes + sizeof(Dwarf_Ubyte) + + /* return reg address */ curcie->cie_inst_bytes; + } + pad = (int) PADDING(cie_length, upointer_size); + cie_length += pad; + GET_CHUNK(dbg, elfsectno, data, cie_length + + BEGIN_LEN_SIZE, error); + if (extension_size) { + Dwarf_Unsigned x = DISTINGUISHED_VALUE; + + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &x, + sizeof(x), extension_size); + data += extension_size; + + } + du = cie_length; + /* total length of cie */ + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, sizeof(du), uwordb_size); + data += uwordb_size; + + /* cie-id is a special value. */ + du = DW_CIE_ID; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du, + sizeof(du), uwordb_size); + data += uwordb_size; + + db = curcie->cie_version; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + strcpy((char *) data, curcie->cie_aug); + data += strlen(curcie->cie_aug) + 1; + memcpy((void *) data, (const void *) code_al, c_bytes); + data += c_bytes; + memcpy((void *) data, (const void *) data_al, d_bytes); + data += d_bytes; + db = curcie->cie_ret_reg; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); + + if (strcmp(augmentation, DW_CIE_AUGMENTER_STRING_V0) == 0) { + memcpy((void *) data, (const void *) augmented_al, a_bytes); + data += a_bytes; + } + memcpy((void *) data, (const void *) curcie->cie_inst, + curcie->cie_inst_bytes); + data += curcie->cie_inst_bytes; + for (i = 0; i < pad; i++) { + *data = DW_CFA_nop; + data++; + } + curcie = curcie->cie_next; + } + /* calculate current offset */ + cur_off = cie_offs[cie_no - 2] + cie_length + BEGIN_LEN_SIZE; + + /* write out fde's */ + curfde = dbg->de_frame_fdes; + while (curfde) { + Dwarf_P_Frame_Pgm curinst = 0; + long fde_length = 0; + int pad = 0; + Dwarf_P_Cie cie_ptr = 0; + Dwarf_Word cie_index = 0; + Dwarf_Word index = 0; + int oet_length = 0; + int afl_length = 0; + int res = 0; + int v0_augmentation = 0; +#if 0 + unsigned char *fde_start_point = 0; +#endif + char afl_buff[ENCODE_SPACE_NEEDED]; + + /* Find the CIE associated with this fde. */ + cie_ptr = dbg->de_frame_cies; + cie_index = curfde->fde_cie; + index = 1; /* The cie_index of the first cie is 1, not 0. */ + while (cie_ptr && index < cie_index) { + cie_ptr = cie_ptr->cie_next; + index++; + } + if (cie_ptr == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_NULL, -1); + } + + if (strcmp(cie_ptr->cie_aug, DW_CIE_AUGMENTER_STRING_V0) == 0) { + v0_augmentation = 1; + oet_length = sizeof(Dwarf_sfixed); + /* encode the length of augmented fields. */ + res = _dwarf_pro_encode_leb128_nm(oet_length, + &afl_length, afl_buff, + sizeof(afl_buff)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1); + } + + fde_length = curfde->fde_n_bytes + + BEGIN_LEN_SIZE + /* cie pointer */ + upointer_size + /* initial loc */ + upointer_size + /* address range */ + afl_length + /* augmented field length */ + oet_length; /* exception_table offset */ + } else { + fde_length = curfde->fde_n_bytes + BEGIN_LEN_SIZE + /* cie + pointer */ + upointer_size + /* initial loc */ + upointer_size; /* address range */ + } + + + if (curfde->fde_die) { + /* IRIX/MIPS extension: + Using fde offset, generate DW_AT_MIPS_fde attribute for the + die corresponding to this fde. */ + if(_dwarf_pro_add_AT_fde(dbg, curfde->fde_die, cur_off, + error) < 0) { + return -1; + } + } + + /* store relocation for cie pointer */ + res = dbg->de_reloc_name(dbg, DEBUG_FRAME, cur_off + + BEGIN_LEN_SIZE /* r_offset */, + dbg->de_sect_name_idx[DEBUG_FRAME], + dwarf_drt_data_reloc, uwordb_size); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1); + } + + /* store relocation information for initial location */ + res = dbg->de_reloc_name(dbg, DEBUG_FRAME, + cur_off + BEGIN_LEN_SIZE + + upointer_size /* r_offset */, + curfde->fde_r_symidx, + dwarf_drt_data_reloc, upointer_size); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1); + } + /* Store the relocation information for the + offset_into_exception_info field, if the offset is valid (0 + is a valid offset). */ + if (v0_augmentation && + curfde->fde_offset_into_exception_tables >= 0) { + + res = dbg->de_reloc_name(dbg, DEBUG_FRAME, + /* r_offset, where in cie this field starts */ + cur_off + BEGIN_LEN_SIZE + + uwordb_size + 2 * upointer_size + + afl_length, + curfde->fde_exception_table_symbol, + dwarf_drt_segment_rel, + sizeof(Dwarf_sfixed)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1); + } + } + + /* adjust for padding */ + pad = (int) PADDING(fde_length, upointer_size); + fde_length += pad; + + + /* write out fde */ + GET_CHUNK(dbg, elfsectno, data, fde_length + BEGIN_LEN_SIZE, + error); +#if 0 + fde_start_point = data; +#endif + du = fde_length; + { + if (extension_size) { + Dwarf_Word x = DISTINGUISHED_VALUE; + + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &x, + sizeof(x), extension_size); + data += extension_size; + } + /* length */ + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, + sizeof(du), uwordb_size); + data += uwordb_size; + + /* offset to cie */ + du = cie_offs[curfde->fde_cie - 1]; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, + sizeof(du), uwordb_size); + data += uwordb_size; + + du = curfde->fde_initloc; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, + sizeof(du), upointer_size); + data += upointer_size; + + if (dbg->de_reloc_pair && + curfde->fde_end_symbol != 0 && + curfde->fde_addr_range == 0) { + /* symbolic reloc, need reloc for length What if we + really know the length? If so, should use the other + part of 'if'. */ + Dwarf_Unsigned val; + + res = dbg->de_reloc_pair(dbg, + /* DEBUG_ARANGES, */ DEBUG_FRAME, + cur_off + 2 * uwordb_size + upointer_size, + /* r_offset */ curfde->fde_r_symidx, + curfde->fde_end_symbol, + dwarf_drt_first_of_length_pair, + upointer_size); + if (res != DW_DLV_OK) { + { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + } + + /* arrange pre-calc so assem text can do .word end - + begin + val (gets val from stream) */ + val = curfde->fde_end_symbol_offset - + curfde->fde_initloc; + WRITE_UNALIGNED(dbg, data, + (const void *) &val, + sizeof(val), upointer_size); + data += upointer_size; + } else { + + du = curfde->fde_addr_range; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, + sizeof(du), upointer_size); + data += upointer_size; + } + } + + if (v0_augmentation) { + /* write the encoded augmented field length. */ + memcpy((void *) data, (const void *) afl_buff, afl_length); + data += afl_length; + /* write the offset_into_exception_tables field. */ + dsw = + (Dwarf_sfixed) curfde->fde_offset_into_exception_tables; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &dsw, + sizeof(dsw), sizeof(Dwarf_sfixed)); + data += sizeof(Dwarf_sfixed); + } + + curinst = curfde->fde_inst; + if(curfde->fde_block) { + unsigned long size = curfde->fde_inst_block_size; + memcpy((void *) data, (const void *) curfde->fde_block, size); + data += size; + } else { + while (curinst) { + db = curinst->dfp_opcode; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + data += sizeof(Dwarf_Ubyte); +#if 0 + if (curinst->dfp_sym_index) { + int res = dbg->de_reloc_name(dbg, + DEBUG_FRAME, + /* r_offset = */ + (data - fde_start_point) + cur_off + uwordb_size, + curinst->dfp_sym_index, + dwarf_drt_data_reloc, + upointer_size); + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + } +#endif + memcpy((void *) data, + (const void *) curinst->dfp_args, + curinst->dfp_nbytes); + data += curinst->dfp_nbytes; + curinst = curinst->dfp_next; + } + } + /* padding */ + for (i = 0; i < pad; i++) { + *data = DW_CFA_nop; + data++; + } + cur_off += fde_length + uwordb_size; + curfde = curfde->fde_next; + } + + + return (int) dbg->de_n_debug_sect; +} + +/* + These functions remember all the markers we see along + with the right offset in the .debug_info section so that + we can dump them all back to the user with the section info. +*/ + +static int +marker_init(Dwarf_P_Debug dbg, + unsigned count) +{ + dbg->de_marker_n_alloc = count; + dbg->de_markers = NULL; + if (count > 0) { + dbg->de_markers = _dwarf_p_get_alloc(dbg, + sizeof(struct Dwarf_P_Marker_s) * dbg->de_marker_n_alloc); + if (dbg->de_markers == NULL) { + dbg->de_marker_n_alloc = 0; + return -1; + } + } + return 0; +} + +static int +marker_add(Dwarf_P_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Unsigned marker) +{ + if (dbg->de_marker_n_alloc >= (dbg->de_marker_n_used + 1)) { + unsigned n = dbg->de_marker_n_used++; + dbg->de_markers[n].ma_offset = offset; + dbg->de_markers[n].ma_marker = marker; + return 0; + } + + return -1; +} + +Dwarf_Signed +dwarf_get_die_markers(Dwarf_P_Debug dbg, + Dwarf_P_Marker * marker_list, /* pointer to a pointer */ + Dwarf_Unsigned * marker_count, + Dwarf_Error * error) +{ + if (marker_list == NULL || marker_count == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_BADADDR); + } + if (dbg->de_marker_n_used != dbg->de_marker_n_alloc) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_MAF, DW_DLV_BADADDR); + } + + *marker_list = dbg->de_markers; + *marker_count = dbg->de_marker_n_used; + return DW_DLV_OK; +} + +/* These functions provide the offsets of DW_FORM_string + attributes in the section section_index. These information + will enable a producer app that is generating assembly + text output to easily emit those attributes in ascii form + without having to decode the byte stream. */ +static int +string_attr_init (Dwarf_P_Debug dbg, + Dwarf_Signed section_index, + unsigned count) +{ + Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[section_index]; + + sect_sa->sect_sa_n_alloc = count; + sect_sa->sect_sa_list = NULL; + if (count > 0) { + sect_sa->sect_sa_section_number = section_index; + sect_sa->sect_sa_list = _dwarf_p_get_alloc(dbg, + sizeof(struct Dwarf_P_String_Attr_s) * sect_sa->sect_sa_n_alloc); + if (sect_sa->sect_sa_list == NULL) { + sect_sa->sect_sa_n_alloc = 0; + return -1; + } + } + return 0; +} + +static int +string_attr_add (Dwarf_P_Debug dbg, + Dwarf_Signed section_index, + Dwarf_Unsigned offset, + Dwarf_P_Attribute attr) +{ + Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[section_index]; + if (sect_sa->sect_sa_n_alloc >= (sect_sa->sect_sa_n_used + 1)) { + unsigned n = sect_sa->sect_sa_n_used++; + sect_sa->sect_sa_list[n].sa_offset = offset; + sect_sa->sect_sa_list[n].sa_nbytes = attr->ar_nbytes; + return 0; + } + + return -1; +} + +int +dwarf_get_string_attributes_count(Dwarf_P_Debug dbg, + Dwarf_Unsigned * + count_of_sa_sections, + int *drd_buffer_version, + Dwarf_Error *error) +{ + int i = 0; + unsigned int count = 0; + + for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) { + if (dbg->de_sect_string_attr[i].sect_sa_n_used > 0) { + ++count; + } + } + *count_of_sa_sections = (Dwarf_Unsigned) count; + *drd_buffer_version = DWARF_DRD_BUFFER_VERSION; + + return DW_DLV_OK; +} + +int +dwarf_get_string_attributes_info(Dwarf_P_Debug dbg, + Dwarf_Signed *elf_section_index, + Dwarf_Unsigned *sect_sa_buffer_count, + Dwarf_P_String_Attr *sect_sa_buffer, + Dwarf_Error *error) +{ + int i = 0; + int next = dbg->de_sect_sa_next_to_return; + + for (i = next; i < NUM_DEBUG_SECTIONS; ++i) { + Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[i]; + if (sect_sa->sect_sa_n_used > 0) { + dbg->de_sect_sa_next_to_return = i + 1; + *elf_section_index = sect_sa->sect_sa_section_number; + *sect_sa_buffer_count = sect_sa->sect_sa_n_used; + *sect_sa_buffer = sect_sa->sect_sa_list; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + + + +/* Generate debug_info and debug_abbrev sections */ + +static int +_dwarf_pro_generate_debuginfo(Dwarf_P_Debug dbg, Dwarf_Error * error) +{ + int elfsectno_of_debug_info = 0; + int abbrevsectno = 0; + unsigned char *data = 0; + int cu_header_size = 0; + Dwarf_P_Abbrev curabbrev = 0; + Dwarf_P_Abbrev abbrev_head = 0; + Dwarf_P_Abbrev abbrev_tail = 0; + Dwarf_P_Die curdie = 0; + Dwarf_P_Die first_child = 0; + Dwarf_Word dw = 0; + Dwarf_Unsigned du = 0; + Dwarf_Half dh = 0; + Dwarf_Ubyte db = 0; + Dwarf_Half version = 0; /* Need 2 byte quantity. */ + Dwarf_Unsigned die_off = 0; /* Offset of die in debug_info. */ + int n_abbrevs = 0; + int res = 0; + unsigned marker_count = 0; + unsigned string_attr_count = 0; + unsigned string_attr_offset = 0; + + Dwarf_Small *start_info_sec = 0; + + int uwordb_size = dbg->de_offset_size; + int extension_size = dbg->de_64bit_extension ? 4 : 0; + + abbrev_head = abbrev_tail = NULL; + elfsectno_of_debug_info = dbg->de_elf_sects[DEBUG_INFO]; + + /* write cu header */ + cu_header_size = BEGIN_LEN_SIZE + + sizeof(Dwarf_Half) + /* version stamp */ + uwordb_size + /* offset into abbrev table */ + sizeof(Dwarf_Ubyte); /* size of target address */ + GET_CHUNK(dbg, elfsectno_of_debug_info, data, cu_header_size, + error); + start_info_sec = data; + if (extension_size) { + du = DISTINGUISHED_VALUE; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, sizeof(du), extension_size); + data += extension_size; + } + du = 0; /* length of debug_info, not counting + this field itself (unknown at this point). */ + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, sizeof(du), uwordb_size); + data += uwordb_size; + + version = CURRENT_VERSION_STAMP; + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &version, + sizeof(version), sizeof(Dwarf_Half)); + data += sizeof(Dwarf_Half); + + du = 0;/* offset into abbrev table, not yet known. */ + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, sizeof(du), uwordb_size); + data += uwordb_size; + + + db = dbg->de_pointer_size; + + WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db, + sizeof(db), 1); + + /* We have filled the chunk we got with GET_CHUNK. At this point we + no longer dare use "data" or "start_info_sec" as a pointer any + longer except to refer to that first small chunk for the cu + header. */ + + curdie = dbg->de_dies; + + /* Create AT_macro_info if appropriate */ + if (dbg->de_first_macinfo != NULL) { + if (_dwarf_pro_add_AT_macro_info(dbg, curdie, 0, error) < 0) + return -1; + } + + /* Create AT_stmt_list attribute if necessary */ + if (dwarf_need_debug_line_section(dbg) == TRUE) + if (_dwarf_pro_add_AT_stmt_list(dbg, curdie, error) < 0) + return -1; + + die_off = cu_header_size; + + /* Relocation for abbrev offset in cu header store relocation + record in linked list */ + res = dbg->de_reloc_name(dbg, DEBUG_INFO, BEGIN_LEN_SIZE + + sizeof(Dwarf_Half), + /* r_offset */ + dbg->de_sect_name_idx[DEBUG_ABBREV], + dwarf_drt_data_reloc, uwordb_size); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1); + } + + /* Pass 0: only top level dies, add at_sibling attribute to those + dies with children */ + first_child = curdie->di_child; + while (first_child && first_child->di_right) { + if (first_child->di_child) + dwarf_add_AT_reference(dbg, + first_child, + DW_AT_sibling, + first_child->di_right, error); + first_child = first_child->di_right; + } + + /* Pass 1: create abbrev info, get die offsets, calc relocations */ + marker_count = 0; + string_attr_count = 0; + while (curdie != NULL) { + int nbytes = 0; + Dwarf_P_Attribute curattr; + Dwarf_P_Attribute new_first_attr; + Dwarf_P_Attribute new_last_attr; + char *space = 0; + int res = 0; + char buff1[ENCODE_SPACE_NEEDED]; + int i = 0; + + curdie->di_offset = die_off; + + if (curdie->di_marker != 0) + marker_count++; + + curabbrev = _dwarf_pro_getabbrev(curdie, abbrev_head); + if (curabbrev == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1); + } + if (abbrev_head == NULL) { + n_abbrevs = 1; + curabbrev->abb_idx = n_abbrevs; + abbrev_tail = abbrev_head = curabbrev; + } else { + /* check if its a new abbreviation, if yes, add to tail */ + if (curabbrev->abb_idx == 0) { + n_abbrevs++; + curabbrev->abb_idx = n_abbrevs; + abbrev_tail->abb_next = curabbrev; + abbrev_tail = curabbrev; + } + } + res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_idx, + &nbytes, + buff1, sizeof(buff1)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1); + } + space = _dwarf_p_get_alloc(dbg, nbytes); + if (space == NULL) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1); + } + memcpy(space, buff1, nbytes); + curdie->di_abbrev = space; + curdie->di_abbrev_nbytes = nbytes; + die_off += nbytes; + + /* Resorting the attributes!! */ + new_first_attr = new_last_attr = NULL; + curattr = curdie->di_attrs; + for (i = 0; i < (int)curabbrev->abb_n_attr; i++) { + Dwarf_P_Attribute ca; + Dwarf_P_Attribute cl; + + /* The following should always find an attribute! */ + for (ca = cl = curattr; + ca && curabbrev->abb_attrs[i] != ca->ar_attribute; + cl = ca, ca = ca->ar_next) + { + } + + if (!ca) { + DWARF_P_DBG_ERROR(dbg,DW_DLE_ABBREV_ALLOC, -1); + } + + /* Remove the attribute from the old list. */ + if (ca == curattr) { + curattr = ca->ar_next; + } else { + cl->ar_next = ca->ar_next; + } + + ca->ar_next = NULL; + + /* Add the attribute to the new list. */ + if (new_first_attr == NULL) { + new_first_attr = new_last_attr = ca; + } else { + new_last_attr->ar_next = ca; + new_last_attr = ca; + } + } + + curdie->di_attrs = new_first_attr; + + curattr = curdie->di_attrs; + + while (curattr) { + if (curattr->ar_rel_type != R_MIPS_NONE) { + switch (curattr->ar_attribute) { + case DW_AT_stmt_list: + curattr->ar_rel_symidx = + dbg->de_sect_name_idx[DEBUG_LINE]; + break; + case DW_AT_MIPS_fde: + curattr->ar_rel_symidx = + dbg->de_sect_name_idx[DEBUG_FRAME]; + break; + case DW_AT_macro_info: + curattr->ar_rel_symidx = + dbg->de_sect_name_idx[DEBUG_MACINFO]; + break; + default: + break; + } + res = dbg->de_reloc_name(dbg, DEBUG_INFO, + die_off + curattr->ar_rel_offset,/* r_offset */ + curattr->ar_rel_symidx, + dwarf_drt_data_reloc, + curattr->ar_reloc_len); + + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1); + } + + } + if (curattr->ar_attribute_form == DW_FORM_string) { + string_attr_count++; + } + die_off += curattr->ar_nbytes; + curattr = curattr->ar_next; + } + + /* depth first search */ + if (curdie->di_child) + curdie = curdie->di_child; + else { + while (curdie != NULL && curdie->di_right == NULL) { + curdie = curdie->di_parent; + die_off++; /* since we are writing a null die at + the end of each sibling chain */ + } + if (curdie != NULL) + curdie = curdie->di_right; + } + + } /* end while (curdie != NULL) */ + + res = marker_init(dbg, marker_count); + if (res == -1) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1); + } + res = string_attr_init(dbg, DEBUG_INFO, string_attr_count); + if (res == -1) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1); + } + + /* Pass 2: Write out the die information Here 'data' is a + temporary, one block for each GET_CHUNK. 'data' is overused. */ + curdie = dbg->de_dies; + while (curdie != NULL) { + Dwarf_P_Attribute curattr; + + if (curdie->di_marker != 0) { + res = marker_add(dbg, curdie->di_offset, curdie->di_marker); + if (res == -1) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1); + } + } + + /* Index to abbreviation table */ + GET_CHUNK(dbg, elfsectno_of_debug_info, + data, curdie->di_abbrev_nbytes, error); + + memcpy((void *) data, + (const void *) curdie->di_abbrev, + curdie->di_abbrev_nbytes); + + /* Attribute values - need to fill in all form attributes */ + curattr = curdie->di_attrs; + string_attr_offset = curdie->di_offset + curdie->di_abbrev_nbytes; + + while (curattr) { + GET_CHUNK(dbg, elfsectno_of_debug_info, data, + (unsigned long) curattr->ar_nbytes, error); + switch (curattr->ar_attribute_form) { + case DW_FORM_ref1: + { + if (curattr->ar_ref_die->di_offset > + (unsigned) 0xff) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1); + } + db = curattr->ar_ref_die->di_offset; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &db, + sizeof(db), sizeof(Dwarf_Ubyte)); + break; + } + case DW_FORM_ref2: + { + if (curattr->ar_ref_die->di_offset > + (unsigned) 0xffff) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1); + } + dh = curattr->ar_ref_die->di_offset; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &dh, + sizeof(dh), sizeof(Dwarf_Half)); + break; + } + case DW_FORM_ref_addr: + { + /* curattr->ar_ref_die == NULL! + + ref_addr doesn't take a CU-offset. + This is different than other refs. + This value will be set by the user of the + producer library using a relocation. + No need to set a value here. */ +#if 0 + du = curattr->ar_ref_die->di_offset; + { + /* ref to offset of die */ + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, + sizeof(du), uwordb_size); + } +#endif + break; + + } + case DW_FORM_ref4: + { + if (curattr->ar_ref_die->di_offset > + (unsigned) 0xffffffff) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1); + } + dw = (Dwarf_Word) curattr->ar_ref_die->di_offset; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &dw, + sizeof(dw), sizeof(Dwarf_ufixed)); + break; + } + case DW_FORM_ref8: + du = curattr->ar_ref_die->di_offset; + WRITE_UNALIGNED(dbg, (void *) data, + (const void *) &du, + sizeof(du), sizeof(Dwarf_Unsigned)); + break; + case DW_FORM_ref_udata: + { /* unsigned leb128 offset */ + + int nbytes; + char buff1[ENCODE_SPACE_NEEDED]; + + res = + _dwarf_pro_encode_leb128_nm(curattr-> + ar_ref_die-> + di_offset, &nbytes, + buff1, + sizeof(buff1)); + if (res != DW_DLV_OK) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1); + } + + memcpy(data, buff1, nbytes); + break; + } + default: + memcpy((void *) data, + (const void *) curattr->ar_data, + curattr->ar_nbytes); + break; + } + if (curattr->ar_attribute_form == DW_FORM_string) { + string_attr_add(dbg, DEBUG_INFO, string_attr_offset, curattr); + } + string_attr_offset += curattr->ar_nbytes; + curattr = curattr->ar_next; + } + + /* depth first search */ + if (curdie->di_child) + curdie = curdie->di_child; + else { + while (curdie != NULL && curdie->di_right == NULL) { + GET_CHUNK(dbg, elfsectno_of_debug_info, data, 1, error); + *data = '\0'; + curdie = curdie->di_parent; + } + if (curdie != NULL) + curdie = curdie->di_right; + } + } /* end while (curdir != NULL) */ + + /* Write out debug_info size */ + /* Do not include length field or extension bytes */ + du = die_off - BEGIN_LEN_SIZE; + WRITE_UNALIGNED(dbg, (void *) (start_info_sec + extension_size), + (const void *) &du, sizeof(du), uwordb_size); + + + data = 0; /* Emphasise not usable now */ + + /* Write out debug_abbrev section */ + abbrevsectno = dbg->de_elf_sects[DEBUG_ABBREV]; + + curabbrev = abbrev_head; + while (curabbrev) { + char *val; + int nbytes; + int idx; + int res; + char buff1[ENCODE_SPACE_NEEDED]; + + write_uval(curabbrev->abb_idx,dbg,abbrevsectno,error); + write_uval(curabbrev->abb_tag,dbg,abbrevsectno,error); + + db = curabbrev->abb_children; + write_ubyte(db,dbg,abbrevsectno,error); + + /* add attributes and forms */ + for (idx = 0; idx < curabbrev->abb_n_attr; idx++) { + write_uval(curabbrev->abb_attrs[idx], + dbg,abbrevsectno,error); + + write_uval(curabbrev->abb_forms[idx], + dbg,abbrevsectno,error); + } + /* Two zeros, for last entry, see dwarf2 sec 7.5.3 */ + GET_CHUNK(dbg, abbrevsectno, data, 2, error); + *data = 0; + data++; + *data = 0; + + curabbrev = curabbrev->abb_next; + } + + /* one zero, for end of cu, see dwarf2 sec 7.5.3 */ + GET_CHUNK(dbg, abbrevsectno, data, 1, error); + *data = 0; + return (int) dbg->de_n_debug_sect; +} + + +/* Get a buffer of section data. + section_idx is the elf-section number that this data applies to. + length shows length of returned data */ + +/*ARGSUSED*/ /* pretend all args used */ +Dwarf_Ptr +dwarf_get_section_bytes(Dwarf_P_Debug dbg, + Dwarf_Signed dwarf_section, + Dwarf_Signed * section_idx, + Dwarf_Unsigned * length, Dwarf_Error * error) +{ + Dwarf_Ptr buf = 0; + + if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) { + DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, NULL); + } + + if (dbg->de_debug_sects == 0) { + /* no more data !! */ + return NULL; + } + if (dbg->de_debug_sects->ds_elf_sect_no == MAGIC_SECT_NO) { + /* no data ever entered !! */ + return NULL; + } + *section_idx = dbg->de_debug_sects->ds_elf_sect_no; + *length = dbg->de_debug_sects->ds_nbytes; + + buf = (Dwarf_Ptr *) dbg->de_debug_sects->ds_data; + + dbg->de_debug_sects = dbg->de_debug_sects->ds_next; + + /* We may want to call the section stuff more than once: see + dwarf_reset_section_bytes() do not do: dbg->de_n_debug_sect--; */ + + return buf; +} + +/* No errors possible. */ +void +dwarf_reset_section_bytes(Dwarf_P_Debug dbg) +{ + dbg->de_debug_sects = dbg->de_first_debug_sect; + /* No need to reset; commented out decrement. dbg->de_n_debug_sect + = ???; */ + dbg->de_reloc_next_to_return = 0; + dbg->de_sect_sa_next_to_return = 0; +} + +/* Storage handler. Gets either a new chunk of memory, or + a pointer in existing memory, from the linked list attached + to dbg at de_debug_sects, depending on size of nbytes + + Assume dbg not null, checked in top level routine + + Returns a pointer to the allocated buffer space for the + lib to fill in, predincrements next-to-use count so the + space requested is already counted 'used' + when this returns (ie, reserved). + +*/ +Dwarf_Small * +_dwarf_pro_buffer(Dwarf_P_Debug dbg, + int elfsectno, unsigned long nbytes) +{ + Dwarf_P_Section_Data cursect = 0; + + cursect = dbg->de_current_active_section; + /* By using MAGIC_SECT_NO we allow the following MAGIC_SECT_NO must + not match any legit section number. test to have just two + clauses (no NULL pointer test) See dwarf_producer_init(). */ + if ((cursect->ds_elf_sect_no != elfsectno) || + ((cursect->ds_nbytes + nbytes) > cursect->ds_orig_alloc) + ) { + + /* Either the elf section has changed or there is not enough + space in the current section. + + Create a new Dwarf_P_Section_Data_s for the chunk. and have + space 'on the end' for the buffer itself so we just do one + malloc (not two). */ + unsigned long space = nbytes; + + if (nbytes < CHUNK_SIZE) + space = CHUNK_SIZE; + + cursect = (Dwarf_P_Section_Data) + _dwarf_p_get_alloc(dbg, + sizeof(struct Dwarf_P_Section_Data_s) + + space); + if (cursect == NULL) { + return (NULL); + } + + /* _dwarf_p_get_alloc zeroes the space... */ + + cursect->ds_data = (char *) cursect + + sizeof(struct Dwarf_P_Section_Data_s); + cursect->ds_orig_alloc = space; + cursect->ds_elf_sect_no = elfsectno; + cursect->ds_nbytes = nbytes; /* reserve this number of bytes + of space for caller to fill in */ + /* Now link on the end of the list, and mark this one as the + current one */ + + if (dbg->de_debug_sects->ds_elf_sect_no == MAGIC_SECT_NO) { + /* The only entry is the special one for 'no entry' so + delete that phony one while adding this initial real + one. */ + dbg->de_debug_sects = cursect; + dbg->de_current_active_section = cursect; + dbg->de_first_debug_sect = cursect; + } else { + dbg->de_current_active_section->ds_next = cursect; + dbg->de_current_active_section = cursect; + } + dbg->de_n_debug_sect++; + + return ((Dwarf_Small *) cursect->ds_data); + } + + /* There is enough space in the current buffer */ + { + Dwarf_Small *space_for_caller = (Dwarf_Small *) + (cursect->ds_data + cursect->ds_nbytes); + + cursect->ds_nbytes += nbytes; + return space_for_caller; + } +} + + +/* Given address advance and line advance, it gives + either special opcode, or a number < 0 */ +static int +_dwarf_pro_get_opc(Dwarf_P_Debug dbg,Dwarf_Unsigned addr_adv, int line_adv) +{ + int line_base = dbg->de_line_inits.pi_line_base; + int line_range = dbg->de_line_inits.pi_line_range; + Dwarf_Unsigned factored_adv = 0; + + factored_adv = addr_adv / dbg->de_line_inits.pi_minimum_instruction_length; + if (line_adv == 0 && factored_adv == 0) { + return OPC_INCS_ZERO; + } + if (line_adv >= line_base && line_adv < line_base + line_range) { + int opc = (line_adv - line_base) + (factored_adv * line_range) + + dbg->de_line_inits.pi_opcode_base; + if (opc > 255) { + return OPC_OUT_OF_RANGE; + } + return opc; + } + return LINE_OUT_OF_RANGE; +} + +/* Handles abbreviations. It takes a die, searches through + current list of abbreviations for matching one. If it + finds one, it returns a pointer to it, and if it doesnt, + it returns a new one. Upto the user of this function to + link it up to the abbreviation head. If its a new one, + abb_idx has 0. */ +static Dwarf_P_Abbrev +_dwarf_pro_getabbrev(Dwarf_P_Die die, Dwarf_P_Abbrev head) +{ + Dwarf_P_Abbrev curabbrev; + Dwarf_P_Attribute curattr; + int res1; + int nattrs; + int match; + Dwarf_ufixed *forms = 0; + Dwarf_ufixed *attrs = 0; + + curabbrev = head; + while (curabbrev) { + if ((die->di_tag == curabbrev->abb_tag) && + ((die->di_child != NULL && + curabbrev->abb_children == DW_CHILDREN_yes) || + (die->di_child == NULL && + curabbrev->abb_children == DW_CHILDREN_no)) && + (die->di_n_attr == curabbrev->abb_n_attr)) { + + /* There is a chance of a match. */ + curattr = die->di_attrs; + match = 1; /* Assume match found. */ + while (match && curattr) { + res1 = _dwarf_pro_match_attr(curattr, + curabbrev, + (int) curabbrev-> + abb_n_attr); + if (res1 == 0) { + match = 0; + } + curattr = curattr->ar_next; + } + if (match == 1) { + return curabbrev; + } + } + curabbrev = curabbrev->abb_next; + } + + /* no match, create new abbreviation */ + if (die->di_n_attr != 0) { + forms = (Dwarf_ufixed *) + _dwarf_p_get_alloc(die->di_dbg, + sizeof(Dwarf_ufixed) * die->di_n_attr); + if (forms == NULL) { + return NULL; + } + attrs = (Dwarf_ufixed *) + _dwarf_p_get_alloc(die->di_dbg, + sizeof(Dwarf_ufixed) * die->di_n_attr); + if (attrs == NULL) + return NULL; + } + nattrs = 0; + curattr = die->di_attrs; + while (curattr) { + attrs[nattrs] = curattr->ar_attribute; + forms[nattrs] = curattr->ar_attribute_form; + nattrs++; + curattr = curattr->ar_next; + } + + curabbrev = (Dwarf_P_Abbrev) + _dwarf_p_get_alloc(die->di_dbg, sizeof(struct Dwarf_P_Abbrev_s)); + if (curabbrev == NULL) { + return NULL; + } + + if (die->di_child == NULL) { + curabbrev->abb_children = DW_CHILDREN_no; + } else { + curabbrev->abb_children = DW_CHILDREN_yes; + } + curabbrev->abb_tag = die->di_tag; + curabbrev->abb_attrs = attrs; + curabbrev->abb_forms = forms; + curabbrev->abb_n_attr = die->di_n_attr; + curabbrev->abb_idx = 0; + curabbrev->abb_next = NULL; + + return curabbrev; +} + +/* Tries to see if given attribute and form combination + exists in the given abbreviation */ +static int +_dwarf_pro_match_attr(Dwarf_P_Attribute attr, + Dwarf_P_Abbrev abbrev, int no_attr) +{ + int i; + int found = 0; + + for (i = 0; i < no_attr; i++) { + if (attr->ar_attribute == abbrev->abb_attrs[i] && + attr->ar_attribute_form == abbrev->abb_forms[i]) { + found = 1; + break; + } + } + return found; +} diff --git a/libdwarf/pro_section.h b/libdwarf/pro_section.h new file mode 100644 index 0000000..d6e1627 --- /dev/null +++ b/libdwarf/pro_section.h @@ -0,0 +1,109 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + + +/* relocation section names */ +extern char *_dwarf_rel_section_names[]; + +/* section names */ +extern char *_dwarf_sectnames[]; + +/* struct to hold relocation entries. Its mantained as a linked + list of relocation structs, and will then be written at as a + whole into the relocation section. Whether its 32 bit or + 64 bit will be obtained from Dwarf_Debug pointer. */ + + + + + +/* struct stores a chunk of data pertaining to a section */ +struct Dwarf_P_Section_Data_s { + int ds_elf_sect_no; /* elf section number */ + char *ds_data; /* data contained in section */ + unsigned long ds_nbytes; /* bytes of data used so far */ + unsigned long ds_orig_alloc; /* bytes allocated originally */ + Dwarf_P_Section_Data ds_next; /* next on the list */ +}; + +/* Used to allow a dummy initial struct (which we + drop before it gets used + This must not match any legitimate 'section' number. +*/ +#define MAGIC_SECT_NO -3 + +/* Size of chunk of data allocated in one alloc + Not clear if this is the best size. + Used to be just 4096 for user data, the section data struct + was a separate malloc. +*/ +#define CHUNK_SIZE (4096 - sizeof (struct Dwarf_P_Section_Data_s)) + +/* + chunk alloc routine - + if chunk->ds_data is nil, it will alloc CHUNK_SIZE bytes, + and return pointer to the beginning. If chunk is not nil, + it will see if there's enoungh space for nbytes in current + chunk, if not, add new chunk to linked list, and return + a char * pointer to it. Return null if unsuccessful. +*/ +Dwarf_Small *_dwarf_pro_buffer(Dwarf_P_Debug dbg, int sectno, + unsigned long nbytes); + +#define GET_CHUNK(dbg,sectno,ptr,nbytes,error) \ +{ \ + (ptr) = _dwarf_pro_buffer((dbg),(sectno),(nbytes)); \ + if ((ptr) == NULL) { \ + DWARF_P_DBG_ERROR(dbg,DW_DLE_CHUNK_ALLOC,-1); \ + } \ +} + + + +int + _dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg, + Dwarf_Error * error); + +/* These are for creating ELF section type codes. +*/ +#if defined(linux) || defined(__BEOS__) || !defined(SHT_MIPS_DWARF) +/* Intel's SoftSdv accepts only this */ +#define SECTION_TYPE SHT_PROGBITS +#else +#define SECTION_TYPE SHT_MIPS_DWARF +#endif diff --git a/libdwarf/pro_types.c b/libdwarf/pro_types.c new file mode 100644 index 0000000..ad14164 --- /dev/null +++ b/libdwarf/pro_types.c @@ -0,0 +1,284 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#endif +#include "pro_incl.h" +#include "pro_section.h" + + +/* + This function adds another type name to the + list of type names for the given Dwarf_P_Debug. + It returns 0 on error, and 1 otherwise. +*/ +Dwarf_Unsigned +dwarf_add_typename(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *type_name, Dwarf_Error * error) +{ + return + _dwarf_add_simple_name_entry(dbg, die, type_name, + dwarf_snk_typename, error); +} + +/* + The following is the generic 'add a simple name entry' + for any of the simple name sections. + + See enum dwarf_sn_kind in pro_opaque.h + +*/ +Dwarf_Unsigned +_dwarf_add_simple_name_entry(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *entry_name, + enum dwarf_sn_kind entrykind, + Dwarf_Error * error) +{ + Dwarf_P_Simple_nameentry nameentry; + Dwarf_P_Simple_name_header hdr; + char *name; + int uword_size; + + if (dbg == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL); + return (0); + } + + if (die == NULL) { + _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL); + return (0); + } + + + nameentry = (Dwarf_P_Simple_nameentry) + _dwarf_p_get_alloc(dbg, + sizeof(struct Dwarf_P_Simple_nameentry_s)); + if (nameentry == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + + name = _dwarf_p_get_alloc(dbg, strlen(entry_name) + 1); + if (name == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + strcpy(name, entry_name); + + nameentry->sne_die = die; + nameentry->sne_name = name; + nameentry->sne_name_len = strlen(name); + uword_size = dbg->de_offset_size; + + hdr = &dbg->de_simple_name_headers[entrykind]; + if (hdr->sn_head == NULL) + hdr->sn_head = hdr->sn_tail = nameentry; + else { + hdr->sn_tail->sne_next = nameentry; + hdr->sn_tail = nameentry; + } + hdr->sn_count++; + hdr->sn_net_len += uword_size + nameentry->sne_name_len + 1; + + return (1); +} + + + +/* + _dwarf_transform_simplename_to_disk writes + ".rel.debug_pubnames", + ".rel.debug_funcnames", sgi extension + ".rel.debug_typenames", sgi extension + ".rel.debug_varnames", sgi extension + ".rel.debug_weaknames", sgi extension + to disk. + section_index indexes one of those sections. + entrykind is one of those 'kind's. */ +int +_dwarf_transform_simplename_to_disk(Dwarf_P_Debug dbg, + enum dwarf_sn_kind entrykind, + int section_index, /* in de_elf_sects etc */ + Dwarf_Error * error) +{ + + + /* Used to fill in 0. */ + const Dwarf_Signed big_zero = 0; + + /* Used to scan the section data buffers. */ + Dwarf_P_Section_Data debug_sect; + + Dwarf_Signed debug_info_size; + + Dwarf_P_Simple_nameentry nameentry_original; + Dwarf_P_Simple_nameentry nameentry; + Dwarf_Small *stream_bytes; + Dwarf_Small *cur_stream_bytes_ptr; + Dwarf_Unsigned stream_bytes_count; + Dwarf_Unsigned adjusted_length; /* count excluding length field */ + + + int uword_size = dbg->de_offset_size; + int extension_size = dbg->de_64bit_extension ? 4 : 0; + + Dwarf_P_Simple_name_header hdr; + + + /* ***** BEGIN CODE ***** */ + + debug_info_size = 0; + for (debug_sect = dbg->de_debug_sects; debug_sect != NULL; + debug_sect = debug_sect->ds_next) { + /* We want the size of the .debug_info section for this CU + because the dwarf spec requires us to output it below so we + look for it specifically. */ + if (debug_sect->ds_elf_sect_no == dbg->de_elf_sects[DEBUG_INFO]) { + debug_info_size += debug_sect->ds_nbytes; + } + } + + hdr = &dbg->de_simple_name_headers[entrykind]; + /* Size of the .debug_typenames (or similar) section header. */ + stream_bytes_count = extension_size + uword_size + /* Size of + length field. */ + sizeof(Dwarf_Half) + /* Size of version field. */ + uword_size + /* Size of .debug_info offset. */ + uword_size; /* Size of .debug_names. */ + + + + nameentry_original = hdr->sn_head; + nameentry = nameentry_original; + /* add in the content size */ + stream_bytes_count += hdr->sn_net_len; + + /* Size of the last 0 offset. */ + stream_bytes_count += uword_size; + + /* Now we know how long the entire section is */ + GET_CHUNK(dbg, dbg->de_elf_sects[section_index], + stream_bytes, (unsigned long) stream_bytes_count, error); + if (stream_bytes == NULL) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + cur_stream_bytes_ptr = stream_bytes; + + if (extension_size) { + Dwarf_Unsigned x = DISTINGUISHED_VALUE; + + WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr, + (const void *) &x, sizeof(x), extension_size); + cur_stream_bytes_ptr += extension_size; + + } + /* Write the adjusted length of .debug_*names section. */ + adjusted_length = stream_bytes_count - uword_size - extension_size; + WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr, + (const void *) &adjusted_length, + sizeof(adjusted_length), uword_size); + cur_stream_bytes_ptr += uword_size; + + /* Write the version as 2 bytes. */ + { + Dwarf_Half verstamp = CURRENT_VERSION_STAMP; + + WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr, + (const void *) &verstamp, + sizeof(verstamp), sizeof(Dwarf_Half)); + cur_stream_bytes_ptr += sizeof(Dwarf_Half); + } + + /* Write the offset of the compile-unit. */ + WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr, + (const void *) &big_zero, + sizeof(big_zero), uword_size); + cur_stream_bytes_ptr += uword_size; + + /* now create the relocation for the compile_unit offset */ + { + int res = dbg->de_reloc_name(dbg, + section_index, + extension_size + uword_size + + sizeof(Dwarf_Half) /* r_offset */ , + /* debug_info section name symbol */ + dbg->de_sect_name_idx[DEBUG_INFO], + dwarf_drt_data_reloc, + uword_size); + + if (res != DW_DLV_OK) { + _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (0); + } + } + + /* Write the size of .debug_info section. */ + WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr, + (const void *) &debug_info_size, + sizeof(debug_info_size), uword_size); + cur_stream_bytes_ptr += uword_size; + + + for (nameentry = nameentry_original; + nameentry != NULL; nameentry = nameentry->sne_next) { + + /* Copy offset of die from start of compile-unit. */ + WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr, + (const void *) &nameentry->sne_die->di_offset, + sizeof(nameentry->sne_die->di_offset), + uword_size); + cur_stream_bytes_ptr += uword_size; + + /* Copy the type name. */ + strcpy((char *) cur_stream_bytes_ptr, nameentry->sne_name); + cur_stream_bytes_ptr += nameentry->sne_name_len + 1; + } + + WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr, + (const void *) &big_zero, + sizeof(big_zero), uword_size); + return (int) dbg->de_n_debug_sect; +} diff --git a/libdwarf/pro_types.h b/libdwarf/pro_types.h new file mode 100644 index 0000000..03d3549 --- /dev/null +++ b/libdwarf/pro_types.h @@ -0,0 +1,43 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + +/* pro_types.h */ + + +int _dwarf_transform_simplename_to_disk(Dwarf_P_Debug dbg, + enum dwarf_sn_kind entrykind, + int section_index,/* in de_elf_sects etc */ + Dwarf_Error * error); diff --git a/libdwarf/pro_util.h b/libdwarf/pro_util.h new file mode 100644 index 0000000..6a8e8e1 --- /dev/null +++ b/libdwarf/pro_util.h @@ -0,0 +1,146 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002-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.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + + +#define IS_64BIT(dbg) ((dbg)->de_flags & DW_DLC_SIZE_64 ? 1 : 0) +#define ISA_IA64(dbg) ((dbg)->de_flags & DW_DLC_ISA_IA64 ? 1 : 0) + +/* definition of sizes of types, given target machine */ +#define sizeof_sbyte(dbg) sizeof(Dwarf_Sbyte) +#define sizeof_ubyte(dbg) sizeof(Dwarf_Ubyte) +#define sizeof_uhalf(dbg) sizeof(Dwarf_Half) +/* certain sizes not defined here, but set in dbg record. + See pro_init.c +*/ + +/* Computes amount of padding necessary to align n to a k-boundary. */ +/* Important: Assumes n, k both GREATER than zero. */ +#define PADDING(n, k) ( (k)-1 - ((n)-1)%(k) ) + +/* The following defines are only important for users of the +** producer part of libdwarf, and such should have these +** defined correctly (as necessary) +** by the #include <elf.h> done in pro_incl.h +** before the #include "pro_util.h". +** For others producer macros do not matter so 0 is a usable value, and +** zero values let compilation succeed on more non-MIPS architectures. +** A better approach would be welcome. +*/ +/* R_MIPS* are #define so #ifndef works */ +/* R_IA_64* are not necessarily #define (might be enum) so #ifndef + is useless, we use the configure script generating + HAVE_R_IA_64_DIR32LSB and HAVE_R_IA64_DIR32LSB. +*/ +#ifndef R_MIPS_64 +#define R_MIPS_64 0 +#endif +#ifndef R_MIPS_32 +#define R_MIPS_32 0 +#endif +#ifndef R_MIPS_SCN_DISP +#define R_MIPS_SCN_DISP 0 +#endif + +/* R_IA_64_DIR32LSB came before the now-standard R_IA64_DIR32LSB + (etc) was defined. This now deals with either form, + preferring the new form if available. */ +#ifdef HAVE_R_IA64_DIR32LSB +#define DWARF_PRO_R_IA64_DIR32LSB R_IA64_DIR32LSB +#define DWARF_PRO_R_IA64_DIR64LSB R_IA64_DIR64LSB +#define DWARF_PRO_R_IA64_SEGREL64LSB R_IA64_SEGREL64LSB +#define DWARF_PRO_R_IA64_SEGREL32LSB R_IA64_SEGREL32LSB +#endif +#if defined(HAVE_R_IA_64_DIR32LSB) && !defined(HAVE_R_IA64_DIR32LSB) +#define DWARF_PRO_R_IA64_DIR32LSB R_IA_64_DIR32LSB +#define DWARF_PRO_R_IA64_DIR64LSB R_IA_64_DIR64LSB +#define DWARF_PRO_R_IA64_SEGREL64LSB R_IA_64_SEGREL64LSB +#define DWARF_PRO_R_IA64_SEGREL32LSB R_IA_64_SEGREL32LSB +#endif +#if !defined(HAVE_R_IA_64_DIR32LSB) && !defined(HAVE_R_IA64_DIR32LSB) +#define DWARF_PRO_R_IA64_DIR32LSB 0 +#define DWARF_PRO_R_IA64_DIR64LSB 0 +#define DWARF_PRO_R_IA64_SEGREL64LSB 0 +#define DWARF_PRO_R_IA64_SEGREL32LSB 0 +#endif + +/* The default "I don't know" value can't be zero. + Because that's the sentinel value that means "no relocation". + In order to use this library in 'symbolic relocation mode we + don't care if this value is the right relocation value, + only that it's non-NULL. So at the end, we define it + to something sensible. */ + + + +#if defined(sun) +#if defined(sparc) +#define Get_REL64_isa(dbg) (R_SPARC_UA64) +#define Get_REL32_isa(dbg) (R_SPARC_UA32) +#define Get_REL_SEGREL_isa(dbg) (R_SPARC_NONE) /* I don't know! */ +#else /* i386 */ +#define Get_REL64_isa(dbg) (R_386_32) /* Any non-zero value is ok */ +#define Get_REL32_isa(dbg) (R_386_32) +#define Get_REL_SEGREL_isa(dbg) (R_386_NONE) /* I don't know! */ +#endif /* sparc || i386 */ +#else /* !sun */ +#ifdef HAVE_SYS_IA64_ELF_H +#define Get_REL64_isa(dbg) (ISA_IA64(dbg) ? \ + DWARF_PRO_R_IA64_DIR64LSB : R_MIPS_64) +#define Get_REL32_isa(dbg) (ISA_IA64(dbg) ? \ + DWARF_PRO_R_IA64_DIR32LSB : R_MIPS_32) + + +/* ia64 uses 32bit dwarf offsets for sections */ +#define Get_REL_SEGREL_isa(dbg) (ISA_IA64(dbg) ? \ + DWARF_PRO_R_IA64_SEGREL32LSB : R_MIPS_SCN_DISP) +#else /* HAVE_SYS_IA64_ELF_H */ + +#if !defined(linux) && !defined(__BEOS__) +#define Get_REL64_isa(dbg) (R_MIPS_64) +#define Get_REL32_isa(dbg) (R_MIPS_32) +#define Get_REL_SEGREL_isa(dbg) (R_MIPS_SCN_DISP) +#else +#define Get_REL64_isa(dbg) (1) +#define Get_REL32_isa(dbg) (1) /* these are used on linux */ +#define Get_REL_SEGREL_isa(dbg) (1) /* non zero values, see comments above */ +#endif + +#endif /* HAVE_SYS_IA64_ELF_H */ +#endif /* !sun */ + + diff --git a/libdwarf/pro_vars.c b/libdwarf/pro_vars.c new file mode 100644 index 0000000..b2e42f9 --- /dev/null +++ b/libdwarf/pro_vars.c @@ -0,0 +1,63 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#endif +#include "pro_incl.h" +#include "pro_section.h" + +/* + This function adds another variable name to the + list of variable names for the given Dwarf_P_Debug. + It returns 0 on error, and 1 otherwise. +*/ +Dwarf_Unsigned +dwarf_add_varname(Dwarf_P_Debug dbg, + Dwarf_P_Die die, char *var_name, Dwarf_Error * error) +{ + return + _dwarf_add_simple_name_entry(dbg, die, var_name, + dwarf_snk_varname, error); + + +} diff --git a/libdwarf/pro_weaks.c b/libdwarf/pro_weaks.c new file mode 100644 index 0000000..2e3de72 --- /dev/null +++ b/libdwarf/pro_weaks.c @@ -0,0 +1,62 @@ +/* + + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + 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 + +*/ + + + +#include "config.h" +#include "libdwarfdefs.h" +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ELFACCESS_H +#include <elfaccess.h> +#endif +#include "pro_incl.h" +#include "pro_section.h" + +/* + This function adds another weak name to the + list of weak names for the given Dwarf_P_Debug. + It returns 0 on error, and 1 otherwise. +*/ +Dwarf_Unsigned +dwarf_add_weakname(Dwarf_P_Debug dbg, + Dwarf_P_Die die, + char *weak_name, Dwarf_Error * error) +{ + return + _dwarf_add_simple_name_entry(dbg, die, weak_name, + dwarf_snk_weakname, error); +} |