diff options
Diffstat (limited to 'libdwarf')
128 files changed, 66034 insertions, 0 deletions
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); +} |