diff options
Diffstat (limited to 'libdw')
96 files changed, 9028 insertions, 0 deletions
diff --git a/libdw/.cvsignore b/libdw/.cvsignore new file mode 100644 index 00000000..70845e08 --- /dev/null +++ b/libdw/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libdw/ChangeLog b/libdw/ChangeLog new file mode 100644 index 00000000..28c582ad --- /dev/null +++ b/libdw/ChangeLog @@ -0,0 +1,512 @@ +2005-07-23 Ulrich Drepper <drepper@redhat.com> + + * dwarf_error.c: Add internal alias for dwarf_errno. + * libdwP.h: Declare __dwarf_errno_internal. + * dwarf_getloclist.c: Use INTDEF for dwarf_errno. + + * dwarf_error.c [USE_TLS]: Actually use __thread in definition of + global_error. + +2005-06-01 Roland McGrath <roland@redhat.com> + + * dwarf_getaranges.c (dwarf_getaranges): Sort result array. + * dwarf_getarange_addr.c (dwarf_getarange_addr): Use binary search. + +2005-06-08 Roland McGrath <roland@redhat.com> + + * memory-access.h (get_uleb128_step, get_uleb128): Remove casts. + (get_sleb128_step, get_sleb128): Likewise. + * dwarf_getattrs.c (dwarf_getattrs): Add consts. + * dwarf_getloclist.c (getloclist): Likewise. + * dwarf_formblock.c (dwarf_formblock): Likewise. + * dwarf_getsrclines.c (dwarf_getsrclines): Likewise. + * dwarf_getabbrevattr.c (dwarf_getabbrevattr): Likewise. + * dwarf_formref.c (dwarf_formref): Likewise. + * dwarf_formsdata.c (dwarf_formsdata): Likewise. + * dwarf_formudata.c (dwarf_formudata): Likewise. + * dwarf_haschildren.c (dwarf_haschildren): Likewise. + * dwarf_child.c (__libdw_find_attr, __libdw_find_attr): Likewise. + * dwarf_tag.c (dwarf_tag): Likewise. + * dwarf_getabbrev.c (__libdw_getabbrev): Likewise. + * memory-access.c (__libdw_get_uleb128, __libdw_get_sleb128): Likewise. + * libdw_form.c (__libdw_form_val_len): Likewise. + * libdwP.h: Update decl. + +2005-06-04 Roland McGrath <roland@redhat.com> + + * memory-access.h (get_uleb128_rest_return): New macro. + [! IS_LIBDW] (__libdw_get_uleb128): New static, defined using it. + (get_sleb128_rest_return): New macro. + [! IS_LIBDW] (__libdw_get_sleb128): New static, defined using it. + * memory-access.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + (DEFS): Add -DIS_LIBDW. + +2005-05-31 Roland McGrath <roland@redhat.com> + + * dwarf_formref_die.c (dwarf_formref_die): Add CU header offset to + formref offset. + +2005-05-30 Roland McGrath <roland@redhat.com> + + * dwarf_getloclist.c (dwarf_addrloclists): Use DW_AT_entry_pc for base + address if DW_AT_low_pc is missing. Not to spec, but GCC generates it. + + * dwarf_getloclist.c (dwarf_addrloclists): Don't sign-extend 4-byte + BEGIN value. Instead, match base address entries separately for + 32/64 size cases. + +2005-05-28 Roland McGrath <roland@redhat.com> + + * dwarf_getloclist.c (dwarf_addrloclists): Fix decoding to advance + past location expression contents. + +2005-05-23 Roland McGrath <roland@redhat.com> + + * dwarf_getsrclines.c: Comment typo fix. + + * dwarf_haspc.c (dwarf_haspc): Fix CU DIE address calculation. + * dwarf_getloclist.c (dwarf_addrloclists): Likewise. + +2005-05-22 Ulrich Drepper <drepper@redhat.com> + + * libdwP.h: Only use INTDECL for alias prototypes. + +2005-05-19 Roland McGrath <roland@redhat.com> + + * dwarf_getloclist.c (attr_ok): Permit DW_AT_static_link too. + + * dwarf_getscopevar.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.h: Declare dwarf_getscopevar. + + * dwarf_getsrcfiles.c: Add INTDEF. + * dwarf_haschildren.c: Likewise. + * libdwP.h (dwarf_getsrcfiles, dwarf_haschildren): Add INTDECL. + + * dwarf_getscopes.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.h: Declare dwarf_getscopes. + * libdw.map: Add it. + +2005-05-18 Roland McGrath <roland@redhat.com> + + * libdwP.h (IDX_debug_ranges): New enum constant. + * dwarf_begin_elf.c (dwarf_scnnames): Add it for ".debug_ranges". + * libdwP.h (DWARF_E_NO_DEBUG_RANGES): New enum constant. + * dwarf_error.c (errmsgs): Add it. + * dwarf_haspc.c: New file. + * libdw.h: Declare dwarf_haspc. + * libdw.map: Add it. + * libdwP.h: Add INTDECL. + + * dwarf_attr_integrate.c: New file. + * dwarf_hasattr_integrate.c: New file. + * Makefile.am (libdw_a_SOURCES): Add them. + * libdw.h: Declare dwarf_attr_integrate, dwarf_hasattr_integrate. + * libdw.map: Add them. + + * dwarf_hasattr.c: Add INTDEF. + * libdwP.h: Add INTDECL for it. + + * dwarf_formref_die.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.h (dwarf_formref_die): Declare it. + * libdwP.h (dwarf_formref_die): Add INTDECL. + * libdw.map: Add it. + + * dwarf_getloclist.c (attr_ok, getloclist): New functions, broken out + of ... + (dwarf_getloclist): ... here. Call them. + (dwarf_addrloclists): New function. + * libdw.h: Declare it. + * libdw.map: Add it. + + * dwarf_getmacros.c (dwarf_getmacros): Don't bail at + DW_MACINFO_end_file. Recognize type 0 as terminator. + +2005-05-05 Roland McGrath <roland@redhat.com> + + * dwarf_getsrc_die.c (dwarf_getsrc_die): Use binary search. + + * dwarf_getsrclines.c (dwarf_getsrclines): Sort result array, since + the line program does not produce all entries in ascending order. + +2005-04-25 Ulrich Drepper <drepper@redhat.com> + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Handle multiple + occurences (e.g., inlines) better. + +2005-04-24 Ulrich Drepper <drepper@redhat.com> + + * libdw.h (DWARF_END_ABBREV): Define. + * dwarf_getabbrev.c (__libdw_getabbrev): Return DWARF_END_ABBREV if + end is reached. + * dwarf_offabbrev.c (dwarf_offabbrev): Return -1 on error, 1 if end + of records reached. + * dwarf_tag.c (__libdw_findabbrev): Also recognize DWARF_END_ABBREV + as error of __libdw_getabbrev. + +2005-04-04 Ulrich Drepper <drepper@redhat.com> + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Minor optimization. + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Always pass number of + results back to caller. + +2005-04-04 Roland McGrath <roland@redhat.com> + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Use size_t for CUHL. + + * dwarf_func_line.c (__libdw_func_intval): Use internal_function in + defn. + +2005-04-04 Ulrich Drepper <drepper@redhat.com> + + * dwarf_getsrc_file.c (dwarf_getsrc_file): Use INTUSE. + + * dwarf_getsrc_file.c: New file. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getsrc_file.c. + * libdw.h: Declare dwarf_getsrc_file. + * libdw.map: Add dwarf_getsrc_file. + +2005-04-02 Ulrich Drepper <drepper@redhat.com> + + * dwarf_func_entrypc.c: New file. + * dwarf_func_col.c: New file. + * dwarf_func_line.c: New file. + * dwarf_func_file.c: New file. + * libdw.h: Add prototypes for new functions. + * libdw.map: Add dwarf_func_entrypc, dwarf_func_col, dwarf_func_line, + dwarf_func_file. + * Makefile.am (libdw_a_SOURCES): Add dwarf_func_entrypc.c, + dwarf_func_col.c, dwarf_func_line.c, dwarf_func_file.c. + * libdwP.h (struct Dwarf_Func_s): Add cudie element. + Declare __libdw_func_intval and __dwarf_formsdata_internal. + * dwarf_getfuncs.c: Also fill in cudie in Dwarf_Func object. + * dwarf_formsdata.c: Use INTUSE and INTDEF to avoid PLTs. + + * dwarf.h: Add some DWARF3 definitions. + +2005-04-01 Ulrich Drepper <drepper@redhat.com> + + * dwarf_getfuncs.c: New file. + * dwarf_func_highpc.c: New file. + * dwarf_func_lowpc.c: New file. + * dwarf_func_name.c: New file. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getfuncs.c, + dwarf_func_highpc.c, dwarf_func_lowpc.c, and dwarf_func_name.c. + * libdw.map: Add dwarf_getfuncs, dwarf_func_highpc, dwarf_func_lowpc, + and dwarf_func_name. + * libdw.h: Add prototypes for new functions. + * dwarf_child.c: Use INTUSE and INTDEF to avoid PLTs. + * dwarf_siblingof.c: Likewise. + * dwarf_dieoffset.c: Likewise. + * dwarf_highpc.c: Likewise. + * dwarf_lowpc.c: Likewise. + * libdwP.h: Add prototypes for internal functions. + Define Dwarf_Func_s structure. + +2005-03-29 Ulrich Drepper <drepper@redhat.com> + + * libdw.h: Add padding in Dwarf_die. + + * dwarf_arrayorder.c: Use INTUSE and INTDEF to avoid PLTs. + * dwarf_attr.c: Likewise. + * dwarf_begin.c: Likewise. + * dwarf_begin_elf.c: Likewise. + * dwarf_bitoffset.c: Likewise. + * dwarf_bitsize.c: Likewise. + * dwarf_bytesize.c: Likewise. + * dwarf_diename.c: Likewise. + * dwarf_formaddr.c: Likewise. + * dwarf_formblock.c: Likewise. + * dwarf_formref.c: Likewise. + * dwarf_formstring.c: Likewise. + * dwarf_formudata.c: Likewise. + * dwarf_getarange_addr.c: Likewise. + * dwarf_getarangeinfo.c: Likewise. + * dwarf_getaranges.c: Likewise. + * dwarf_getloclist.c: Likewise. + * dwarf_getmacros.c: Likewise. + * dwarf_getsrc_die.c: Likewise. + * dwarf_getsrcfiles.c: Likewise. + * dwarf_getsrclines.c: Likewise. + * dwarf_highpc.c: Likewise. + * dwarf_lowpc.c: Likewise. + * dwarf_nextcu.c: Likewise. + * dwarf_offdie.c: Likewise. + * dwarf_siblingof.c: Likewise. + * dwarf_srclang.c: Likewise. + * dwarf_tag.c: Likewise. + * libdw_findcu.c: Likewise. + * libdwP.h: Add prototypes for internal functions. + + * dwarf_addrdie.c: New file. + * dwarf_macro_opcode.c: New file. + * dwarf_macro_param1.c: New file. + * dwarf_macro_param2.c: New file. + * libdw.h: Add declarations. Move Dwarf_Macro definition to libdwP.h. + * libdwP.h: Remove Dwarf_Macro definition. + * Makefile.am (libdw_a_SOURCES): Add dwarf_addrdie.c, + dwarf_macro_opcode.c, dwarf_macro_param1.c, and dwarf_macro_param2.c. + * libdw.map: Add entries for new functions. + +2005-03-21 Ulrich Drepper <drepper@redhat.com> + + * libdw.h: Handle broken gcc < 4. + +2005-02-15 Ulrich Drepper <drepper@redhat.com> + + * Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2. + + * dwarf_begin_elf.c: Fix warnings. + * dwarf_dieoffset.c: Likewise. + * dwarf_end.c: Likewise. + * dwarf_error.c: Likewise. + * dwarf_getpubnames.c: Likewise. + + * libdwP.h: Add new error values. + * dwarf_error.c: Support new error values. + * dwarf_getpubnames.c: Check parameter value. + +2005-02-05 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: Check for text relocations in constructed DSO. + + * Makefile.am [MUDFLAP] (AM_CFLAGS): Add -fmudflap. + +2005-02-04 Ulrich Drepper <drepper@redhat.com> + + * dwarf_siblingof.c (dwarf_siblingof): Add some buffer boundary + checks to not read over buffer boundaries for ill-formed DWARF data. + +2004-09-25 Ulrich Drepper <drepper@redhat.com> + + * dwarf_child.c: Make compile with gcc 4.0. + * dwarf_error.c: Likewise. + * dwarf_formblock.c: Likewise. + * dwarf_getabbrev.c: Likewise. + * dwarf_getattrs.c: Likewise. + * dwarf_getsrclines.c: Likewise. + * dwarf_tag.c: Likewise. + * libdw_form.c: Likewise. + +2004-01-20 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: Support building with mudflap. + + * dwarf_getloclist.c: Fix warnings gcc 3.4 spits out. + * dwarf_getsrclines.c: Likewise. + * dwarf_memory-access.h: Likewise. + +2004-01-19 Ulrich Drepper <drepper@redhat.com> + + * dwarf_getsrcfiles.c: Third parameter can be NULL. + + * libdw.h: Define Dwarf_macro. Declare dwarf_getmacros. + Third parameter of dwarf_getsrcfiles can be NULL. + + * libdw.map: Add dwarf_getmacros. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getmacros. + * dwarf_getmacros.c: New file. + +2004-01-18 Ulrich Drepper <drepper@redhat.com> + + * libdw.h: Second parameter of dwarf_getaranges can be NULL. + + * dwarf_nextcu.c: Return -1 if dwarf parameter is NULL. + + * dwarf_getsrclines.c: + Use read_2ubyte_unaligned_inc instead of _inc-less variant. + + * dwarf_getaranges.c: Allow naranges parameter to be NULL. + + * libdwP.h (_): Use elfutils domain. + + * dwarf_getsrclines.c (dwarf_getsrclines): Add more branch prediction. + + * dwarf_getsrclines.c: Fix typo in comment. + +2004-01-17 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: Support building with mudflap. + +2004-01-16 Ulrich Drepper <drepper@redhat.com> + + * memory-access.h: Add lots of const in case a pointer passed is const. + + * dwarf_formflag.c: New file. + * dwarf_getattrs.c: New file. + * dwarf_error.c: Add new error value. + * libdw.h: Add prototypes for new functions. Adjust prototype for + dwarf_getpubnames. + * libdw.map: Add new functions. + * dwarf_getpubnames.c: Change type of return value and fourth parameter + to ptrdiff_t. + * libdwP.h: Add new error value. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getattrs.c and + dwarf_formflag.c. + + * dwarf_getpubnames.c (dwarf_getpubnames): Just fail if dbg is NULL. + +2004-01-12 Ulrich Drepper <drepper@redhat.com> + + * dwarf_getarange_addr.c: New file + * dwarf_getarangeinfo.c: New file. + * dwarf_getaranges.c: New file. + * dwarf_onerange.c: New file. + * libdw.h: Declare new functions. Define Dwarf_Arange and + Dwarf_Aranges. + * libdw.map: Add new functions. + * libdwP.h: Add new errors. Add aranges member to struct Dwarf. + Define Dwarf_Aranges_s and Dwarf_Arange_s. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getaranges.c, + dwarf_onearange.c, dwarf_getarangeinfo.c, dwarf_getarange_addr.c. + * dwarf_error.c: Add new message. + +2004-01-11 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am (libdw_a_SOURCES): Add dwarf_lineaddr.c, dwarf_linecol.c, + dwarf_linebeginstatement.c, dwarf_lineendsequence.c, dwarf_lineblock.c, + dwarf_lineprologueend.c, dwarf_lineepiloguebegin.c, dwarf_onesrcline.c. + * dwarf_error.c: Add another message. + * dwarf_getsrc_die.c: Adjust for Dwarf_Files and Dwarf_Lines + introduction. + * dwarf_filesrc.c: Likewise. + * dwarf_getsrcfiles.c: Likewise. + * dwarf_getsrclines.c: Likewise. + * dwarf_lineaddr.c: New file. + * dwarf_linebeginstatement.c: New file. + * dwarf_lineblock.c: New file. + * dwarf_linecol.c: New file. + * dwarf_lineendsequence.c: New file. + * dwarf_lineepiloguebegin.c: New file. + * dwarf_lineno.c: New file. + * dwarf_lineprologueend.c: New file. + * dwarf_onesrcline.c: New file. + * dwarf_lineno.c: Change interface to store result in object pointed + to by second parameter. + * libdw.h: Add prototypes for new functions. Change dwarf_lineno + prototype. Define Dwarf_Files and Dwarf_Lines. + * libdw.map: Add new functions. + * libdwP.h: Define Dwarf_Files_s and Dwarf_Lines_s. + * libdw_findcu.c: Don't initialize nlines field. + + * dwarf_siblingof: Little optimization. + + * dwarf_begin.c: Remember that the ELF descriptor must be closed. + * dwarf_end.c: Close ELF descriptor if free_elf is set. + * libdwP.h (struct Dwarf): Add free_elf field. + + * Makefile.am (libdw_a_SOURCES): Add dwarf_getstring.c and + dwarf_offabbrev.c. + * dwarf_getstring.c: New file. + * dwarf_offabbrev.c: New file. + * libdw.map: Add dwarf_getstring and dwarf_offabbrev. + * dwarf_getabbrev.c (__libdw_getabbrev): Add new dbg and result + parameters. Don't allocate memory if not necessary and don't lookup + previous results if no CU given. + (dwarf_getabbrev): Adjust call to __libdw_getabbrev. + * dwarf_tag.c: Adjust call to __libdw_getabbrev. + * libdw.h: Declare dwarf_offabbrev and dwarf_getstring. + * libdwP.h: Change prototype for __libdw_getabbrev. + + * dwarf_getabbrevattr.c: Add offsetp parameter. Fill in before + returning if this is wanted. + +2004-01-09 Ulrich Drepper <drepper@redhat.com> + + * dwarf_nextcu.c: Add new parameter offset_sizep. Initialize it + with offset_size value. + * libdw.h: Adjust dwarf_nextcu prototype. + * libdwP.h (struct Dwarf_CU): Add offset_size member. + * libdw_findcu.c: Adjust dwarf_nextcu call. Initialize offset_size + member of new CU struct. + * dwarf_formstring.c: Depend on offset_size not address_size for + DW_FORM_strp handling. + * dwarf_form.c: Likewise for DW_FORM_strp and DW_FORM_ref_addr. + + * dwarf_tag.c (__libdw_findabbrev): Return correct value for + failing lookup. + (dwarf_tag): Correctly recognize failed lookup. + + * dwarf_end.c (cu_free): Call tdestroy for locs member. Use new + function noop_free. + * dwarf_error.c: Add message for DWARF_E_NO_BLOCK. + * dwarf_formblock.c: New file. + * dwarf_getloclist.c: Rewrite to handle a single block. + * libdw.h: Define Dwarf_Block. Rename Dwarf_Loc members. Remove + Dwarf_Locdesc definition. Declare dwarf_formblock. Remove + dwarf_getloclistent declaration. + * libdw.map: Add dwarf_formblock, remove dwarf_getloclistent. + * libdwP.h: Define struct loc_s and DWARF_E_NO_BLOCK. + Add locs member to struct Dwarf_CU. + * libdw_fundcu.c: Initialize locs member of new CU. + * Makefile.am (libdw_a_SOURCES): Add dwarf_formblock.c. + Remove dwarf_getloclistent.c. + +2004-01-07 Ulrich Drepper <drepper@redhat.com> + + * libdw.h: Use __nonnull__ attribute only for gcc >= 3.3. + * libdwP.h: Likewise. + + * dwarf_getloclist.c: New file. + * dwarf_getloclistent.c: New file. + * libdw.h: Define Dwarf_Loc and Dwarf_Locdesc. + Declare dwarf_getloclistent and dwarf_getloclist. + * libdw.map: Add dwarf_getloclistent and dwarf_getloclist. + * libdwP.h: Define DWARF_E_NO_LOCLIST. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getloclistent.c and + dwarf_getloclist.c. + + * dwarf_error.c: More error messages. + +2004-01-06 Ulrich Drepper <drepper@redhat.com> + + * dwarf_getsrclines.c: Remove debugging support. + + * dwarf_getsrcfiles.c: New file. + * dwarf_filesrc.c: New file. + * libdw.h: Declare these functions. Define Dwarf_File. + * libdwP.c: Adjust Dwarf_File_s definition. + * libdw.map: Add these functions. + * Makefile.am (libdw_a_SOURCES): Add dwarf_getsrcfiles.c and + dwarf_filesrc.c. + * dwarf_getsrclines.c: Initialize cu->files. + +2004-01-05 Ulrich Drepper <drepper@redhat.com> + + * libdw.h: Add more nonnull function attributes. + + * dwarf_begin_elf.c (dwarf_begin_elf): Don't initialize mem_tail->next. + * dwarf_end.c (cu_free): New function. + (dwarf_end): Also free CU tree. Correct freeing of memory blocks. + * dwarf_error.c (errmsgs): Add new messages. + * dwarf_getsrc_die.c: New file. + * dwarf_getsrclines.c: New file. + * dwarf_lineno.c: New file. + * dwarf_linesrc.c: New file. + * dwarf_nextcu.c (dwarf_nextcu): Use read_*byte_unaligned_inc + instead of the *_inc-less variants. + * libdw.h: Define Dwarf_Line. Add some function attributes. Declare + dwarf_getsrclines, dwarf_getsrc_die, dwarf_lineno, and dwarf_linesrc. + * libdw.map: Add dwarf_getsrclines, dwarf_getsrc_die, dwarf_lineno, + and dwarf_linesrc. + * libdwP.h: Add more error codes. + (struct Dwarf): Remove mem_tail.next member. + (Dwarf_File): Define type. + (struct Dwarf_Line_s): Define type. + (struct Dwarf_CU): Add lines and nlines members. + (libdw_alloc): Define local variable _tail and use it. + Add some function attributes. + * libdw_alloc.c (__libdw_allocate): Don't initialize next member. + * libdw_findcu.c (__libdw_findcu): Initialize lines and nlines members. + * memory-access.h: Add unlikely for the endian conversion paths. + * Makefile.am (AM_CFLAGS): Add -std parameter. + (libdw_a_SOURCES): Add dwarf_getsrclines, dwarf_getsrc_die, + dwarf_lineno, and dwarf_linesrc. + +2003-08-11 Ulrich Drepper <drepper@redhat.com> + + * Moved to CVS archive. diff --git a/libdw/Makefile.am b/libdw/Makefile.am new file mode 100644 index 00000000..17be31dd --- /dev/null +++ b/libdw/Makefile.am @@ -0,0 +1,108 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. +## +## This program is Open Source software; you can redistribute it and/or +## modify it under the terms of the Open Software License version 1.0 as +## published by the Open Source Initiative. +## +## You should have received a copy of the Open Software License along +## with this program; if not, you may obtain a copy of the Open Software +## License version 1.0 from http://www.opensource.org/licenses/osl.php or +## by writing the Open Source Initiative c/o Lawrence Rosen, Esq., +## 3001 King Ranch Road, Ukiah, CA 95482. +## +DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DIS_LIBDW +if MUDFLAP +AM_CFLAGS = -fmudflap +else +AM_CFLAGS = +endif +AM_CFLAGS += -Wall -Werror -Wshadow -Wunused -Wformat=2 -Wextra -std=gnu99 +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/../libelf -I.. -I$(srcdir)/../lib +VERSION = 1 + +lib_LIBRARIES = libdw.a +if !MUDFLAP +noinst_LIBRARIES = libdw_pic.a +noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so) +endif + +include_HEADERS = dwarf.h +euincludedir = ${includedir}/elfutils +euinclude_HEADERS = libdw.h + +libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ + dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \ + dwarf_error.c dwarf_nextcu.c dwarf_diename.c dwarf_offdie.c \ + dwarf_attr.c dwarf_formstring.c dwarf_abbrev_hash.c \ + dwarf_attr_integrate.c dwarf_hasattr_integrate.c \ + dwarf_child.c dwarf_haschildren.c dwarf_formaddr.c \ + dwarf_formudata.c dwarf_formsdata.c dwarf_lowpc.c \ + dwarf_haspc.c dwarf_highpc.c \ + dwarf_formref.c dwarf_formref_die.c dwarf_siblingof.c \ + dwarf_dieoffset.c dwarf_cuoffset.c dwarf_hasattr.c \ + dwarf_hasform.c dwarf_whatform.c dwarf_whatattr.c \ + dwarf_bytesize.c dwarf_arrayorder.c dwarf_bitsize.c \ + dwarf_bitoffset.c dwarf_srclang.c dwarf_getabbrevtag.c \ + dwarf_getabbrevcode.c dwarf_abbrevhaschildren.c \ + dwarf_getattrcnt.c dwarf_getabbrevattr.c \ + dwarf_getsrclines.c dwarf_getsrc_die.c \ + dwarf_getscopes.c dwarf_getscopevar.c \ + dwarf_linesrc.c dwarf_lineno.c dwarf_lineaddr.c \ + dwarf_linecol.c dwarf_linebeginstatement.c \ + dwarf_lineendsequence.c dwarf_lineblock.c \ + dwarf_lineprologueend.c dwarf_lineepiloguebegin.c \ + dwarf_onesrcline.c dwarf_formblock.c \ + dwarf_getsrcfiles.c dwarf_filesrc.c \ + dwarf_getloclist.c dwarf_getstring.c dwarf_offabbrev.c \ + dwarf_getaranges.c dwarf_onearange.c dwarf_getarangeinfo.c \ + dwarf_getarange_addr.c dwarf_getattrs.c dwarf_formflag.c \ + dwarf_getmacros.c dwarf_macro_opcode.c dwarf_macro_param1.c \ + dwarf_macro_param2.c dwarf_addrdie.c \ + dwarf_getfuncs.c dwarf_func_name.c dwarf_func_lowpc.c \ + dwarf_func_highpc.c dwarf_func_entrypc.c dwarf_func_file.c \ + dwarf_func_line.c dwarf_func_col.c dwarf_getsrc_file.c \ + libdw_findcu.c libdw_form.c libdw_alloc.c memory-access.c + + +if !MUDFLAP +libdw_pic_a_SOURCES = +am_libdw_pic_a_OBJECTS = $(libdw_a_SOURCES:.c=.os) + +libdw_so_SOURCES = +libdw.so: libdw_pic.a $(srcdir)/libdw.map + $(CC) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \ + -Wl,--version-script,$(srcdir)/libdw.map,--no-undefined \ + -Wl,--soname,$@.$(VERSION),-z,defs \ + ../libelf/libelf.so + if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi + ln -fs $@ $@.$(VERSION) + + +%.os: %.c %.o + if $(COMPILE) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \ + -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \ + then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \ + rm -f "$(DEPDIR)/$*.Tpo"; \ + else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ + fi + +install: install-am libdw.so + $(mkinstalldirs) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libdw.so $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so + ln -fs libdw-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdw.so.$(VERSION) + ln -fs libdw.so.$(VERSION) $(DESTDIR)$(libdir)/libdw.so + +uninstall: uninstall-am + rm -f $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so + rm -f $(DESTDIR)$(libdir)/libdw.so.$(VERSION) + rm -f $(DESTDIR)$(libdir)/libdw.so + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils +endif + +noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h + +EXTRA_DIST = libdw.map + +CLEANFILES = $(am_libdw_pic_a_OBJECTS) diff --git a/libdw/dwarf.h b/libdw/dwarf.h new file mode 100644 index 00000000..ce011aac --- /dev/null +++ b/libdw/dwarf.h @@ -0,0 +1,581 @@ +/* This file defines standard DWARF types, structures, and macros. + Copyright (C) 2000, 2002, 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _DWARF_H +#define _DWARF_H 1 + +/* DWARF tags. */ +enum + { + 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, + 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_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + DW_TAG_mutable_type = 0x3e, + DW_TAG_lo_user = 0x4080, + DW_TAG_MIPS_loop = 0x4081, + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + DW_TAG_hi_user = 0xffff + }; + + +/* Children determination encodings. */ +enum + { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1 + }; + + +/* DWARF attributes encodings. */ +enum + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + DW_AT_description = 0x5a, + DW_AT_lo_user = 0x2000, + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_hi_user = 0x3fff + }; + + +/* DWARF form encodings. */ +enum + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 + }; + + +/* DWARF location operation encodings. */ +enum + { + DW_OP_addr = 0x03, /* Constant address. */ + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ + DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ + DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ + DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ + DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ + DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ + DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ + DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ + DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ + DW_OP_consts = 0x11, /* Signed LEB128 constant. */ + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, /* 1-byte stack index. */ + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, /* Signed 2-byte constant. */ + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ + DW_OP_lit0 = 0x30, /* Literal 0. */ + DW_OP_lit1 = 0x31, /* Literal 1. */ + DW_OP_lit2 = 0x32, /* Literal 2. */ + DW_OP_lit3 = 0x33, /* Literal 3. */ + DW_OP_lit4 = 0x34, /* Literal 4. */ + DW_OP_lit5 = 0x35, /* Literal 5. */ + DW_OP_lit6 = 0x36, /* Literal 6. */ + DW_OP_lit7 = 0x37, /* Literal 7. */ + DW_OP_lit8 = 0x38, /* Literal 8. */ + DW_OP_lit9 = 0x39, /* Literal 9. */ + DW_OP_lit10 = 0x3a, /* Literal 10. */ + DW_OP_lit11 = 0x3b, /* Literal 11. */ + DW_OP_lit12 = 0x3c, /* Literal 12. */ + DW_OP_lit13 = 0x3d, /* Literal 13. */ + DW_OP_lit14 = 0x3e, /* Literal 14. */ + DW_OP_lit15 = 0x3f, /* Literal 15. */ + DW_OP_lit16 = 0x40, /* Literal 16. */ + DW_OP_lit17 = 0x41, /* Literal 17. */ + DW_OP_lit18 = 0x42, /* Literal 18. */ + DW_OP_lit19 = 0x43, /* Literal 19. */ + DW_OP_lit20 = 0x44, /* Literal 20. */ + DW_OP_lit21 = 0x45, /* Literal 21. */ + DW_OP_lit22 = 0x46, /* Literal 22. */ + DW_OP_lit23 = 0x47, /* Literal 23. */ + DW_OP_lit24 = 0x48, /* Literal 24. */ + DW_OP_lit25 = 0x49, /* Literal 25. */ + DW_OP_lit26 = 0x4a, /* Literal 26. */ + DW_OP_lit27 = 0x4b, /* Literal 27. */ + DW_OP_lit28 = 0x4c, /* Literal 28. */ + DW_OP_lit29 = 0x4d, /* Literal 29. */ + DW_OP_lit30 = 0x4e, /* Literal 30. */ + DW_OP_lit31 = 0x4f, /* Literal 31. */ + DW_OP_reg0 = 0x50, /* Register 0. */ + DW_OP_reg1 = 0x51, /* Register 1. */ + DW_OP_reg2 = 0x52, /* Register 2. */ + DW_OP_reg3 = 0x53, /* Register 3. */ + DW_OP_reg4 = 0x54, /* Register 4. */ + DW_OP_reg5 = 0x55, /* Register 5. */ + DW_OP_reg6 = 0x56, /* Register 6. */ + DW_OP_reg7 = 0x57, /* Register 7. */ + DW_OP_reg8 = 0x58, /* Register 8. */ + DW_OP_reg9 = 0x59, /* Register 9. */ + DW_OP_reg10 = 0x5a, /* Register 10. */ + DW_OP_reg11 = 0x5b, /* Register 11. */ + DW_OP_reg12 = 0x5c, /* Register 12. */ + DW_OP_reg13 = 0x5d, /* Register 13. */ + DW_OP_reg14 = 0x5e, /* Register 14. */ + DW_OP_reg15 = 0x5f, /* Register 15. */ + DW_OP_reg16 = 0x60, /* Register 16. */ + DW_OP_reg17 = 0x61, /* Register 17. */ + DW_OP_reg18 = 0x62, /* Register 18. */ + DW_OP_reg19 = 0x63, /* Register 19. */ + DW_OP_reg20 = 0x64, /* Register 20. */ + DW_OP_reg21 = 0x65, /* Register 21. */ + DW_OP_reg22 = 0x66, /* Register 22. */ + DW_OP_reg23 = 0x67, /* Register 24. */ + DW_OP_reg24 = 0x68, /* Register 24. */ + DW_OP_reg25 = 0x69, /* Register 25. */ + DW_OP_reg26 = 0x6a, /* Register 26. */ + DW_OP_reg27 = 0x6b, /* Register 27. */ + DW_OP_reg28 = 0x6c, /* Register 28. */ + DW_OP_reg29 = 0x6d, /* Register 29. */ + DW_OP_reg30 = 0x6e, /* Register 30. */ + DW_OP_reg31 = 0x6f, /* Register 31. */ + DW_OP_breg0 = 0x70, /* Base register 0. */ + DW_OP_breg1 = 0x71, /* Base register 1. */ + DW_OP_breg2 = 0x72, /* Base register 2. */ + DW_OP_breg3 = 0x73, /* Base register 3. */ + DW_OP_breg4 = 0x74, /* Base register 4. */ + DW_OP_breg5 = 0x75, /* Base register 5. */ + DW_OP_breg6 = 0x76, /* Base register 6. */ + DW_OP_breg7 = 0x77, /* Base register 7. */ + DW_OP_breg8 = 0x78, /* Base register 8. */ + DW_OP_breg9 = 0x79, /* Base register 9. */ + DW_OP_breg10 = 0x7a, /* Base register 10. */ + DW_OP_breg11 = 0x7b, /* Base register 11. */ + DW_OP_breg12 = 0x7c, /* Base register 12. */ + DW_OP_breg13 = 0x7d, /* Base register 13. */ + DW_OP_breg14 = 0x7e, /* Base register 14. */ + DW_OP_breg15 = 0x7f, /* Base register 15. */ + DW_OP_breg16 = 0x80, /* Base register 16. */ + DW_OP_breg17 = 0x81, /* Base register 17. */ + DW_OP_breg18 = 0x82, /* Base register 18. */ + DW_OP_breg19 = 0x83, /* Base register 19. */ + DW_OP_breg20 = 0x84, /* Base register 20. */ + DW_OP_breg21 = 0x85, /* Base register 21. */ + DW_OP_breg22 = 0x86, /* Base register 22. */ + DW_OP_breg23 = 0x87, /* Base register 23. */ + DW_OP_breg24 = 0x88, /* Base register 24. */ + DW_OP_breg25 = 0x89, /* Base register 25. */ + DW_OP_breg26 = 0x8a, /* Base register 26. */ + DW_OP_breg27 = 0x8b, /* Base register 27. */ + DW_OP_breg28 = 0x8c, /* Base register 28. */ + DW_OP_breg29 = 0x8d, /* Base register 29. */ + DW_OP_breg30 = 0x8e, /* Base register 30. */ + DW_OP_breg31 = 0x8f, /* Base register 31. */ + DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ + DW_OP_fbreg = 0x91, /* Signed LEB128 register. */ + DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ + DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ + DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ + DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ + DW_OP_hi_user = 0xff /* Implementation-defined range end. */ + }; + + +/* DWARF base type encodings. */ +enum + { + DW_ATE_void = 0x0, + 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_imaginary_float = 0x9, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; + + +/* DWARF accessibility encodings. */ +enum + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + + +/* DWARF visibility encodings. */ +enum + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + + +/* DWARF virtuality encodings. */ +enum + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + + +/* DWARF language encodings. */ +enum + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Java = 0x000b, + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + DW_LANG_PL1 = 0x000f, + DW_LANG_lo_user = 0x8000, + DW_LANG_Mips_Assembler = 0x8001, + DW_LANG_hi_user = 0xffff + }; + + +/* DWARF identifier case encodings. */ +enum + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + + +/* DWARF calling conventions encodings. */ +enum + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; + + +/* DWARF inline encodings. */ +enum + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + + +/* DWARF ordering encodings. */ +enum + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + + +/* DWARF discriminant descriptor encodings. */ +enum + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + + +/* DWARF standard opcode encodings. */ +enum + { + 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, + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilog_begin = 11, + DW_LNS_set_isa = 12 + }; + + +/* DWARF extended opcide encodings. */ +enum + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + + DW_LNE_lo_user = 128, + DW_LNE_hi_user = 255 + }; + + +/* DWARF macinfo type encodings. */ +enum + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + + +/* DWARF call frame instruction encodings. */ +enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_extended = 0, + + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_low_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_high_user = 0x3f + }; + + +/* DWARF XXX. */ +#define DW_ADDR_none 0 + +#endif /* dwarf.h */ diff --git a/libdw/dwarf_abbrev_hash.c b/libdw/dwarf_abbrev_hash.c new file mode 100644 index 00000000..009e757f --- /dev/null +++ b/libdw/dwarf_abbrev_hash.c @@ -0,0 +1,29 @@ +/* Implementation of hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define NO_UNDEF +#include "libdwP.h" + +#define next_prime __libdwarf_next_prime +extern size_t next_prime (size_t) attribute_hidden; + +#include <dynamicsizehash.c> + +#undef next_prime +#define next_prime attribute_hidden __libdwarf_next_prime +#include "../lib/next_prime.c" diff --git a/libdw/dwarf_abbrev_hash.h b/libdw/dwarf_abbrev_hash.h new file mode 100644 index 00000000..ef3cc48b --- /dev/null +++ b/libdw/dwarf_abbrev_hash.h @@ -0,0 +1,24 @@ +/* Hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _DWARF_ABBREV_HASH_H +#define _DWARF_ABBREV_HASH_H 1 + +#define NAME Dwarf_Abbrev_Hash +#define TYPE Dwarf_Abbrev * +#define COMPARE(a, b) (0) + +#include <dynamicsizehash.h> + +#endif /* dwarf_abbrev_hash.h */ diff --git a/libdw/dwarf_abbrevhaschildren.c b/libdw/dwarf_abbrevhaschildren.c new file mode 100644 index 00000000..2261b2f3 --- /dev/null +++ b/libdw/dwarf_abbrevhaschildren.c @@ -0,0 +1,29 @@ +/* Return true if abbreviation is children flag set. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_abbrevhaschildren (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? -1 : abbrev->has_children; +} diff --git a/libdw/dwarf_addrdie.c b/libdw/dwarf_addrdie.c new file mode 100644 index 00000000..c3fd4661 --- /dev/null +++ b/libdw/dwarf_addrdie.c @@ -0,0 +1,39 @@ +/* Return CU DIE containing given address. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Die * +dwarf_addrdie (dbg, addr, result) + Dwarf *dbg; + Dwarf_Addr addr; + Dwarf_Die *result; +{ + Dwarf_Aranges *aranges; + size_t naranges; + Dwarf_Off off; + + if (INTUSE(dwarf_getaranges) (dbg, &aranges, &naranges) != 0 + || INTUSE(dwarf_getarangeinfo) (INTUSE(dwarf_getarange_addr) (aranges, + addr), + NULL, NULL, &off) != 0) + return NULL; + + return INTUSE(dwarf_offdie) (dbg, off, result); +} diff --git a/libdw/dwarf_arrayorder.c b/libdw/dwarf_arrayorder.c new file mode 100644 index 00000000..a1ea09fa --- /dev/null +++ b/libdw/dwarf_arrayorder.c @@ -0,0 +1,33 @@ +/* Return array order attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_arrayorder (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_ordering, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_attr.c b/libdw/dwarf_attr.c new file mode 100644 index 00000000..8ebbb8f5 --- /dev/null +++ b/libdw/dwarf_attr.c @@ -0,0 +1,40 @@ +/* Return specific DWARF attribute of a DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Attribute * +dwarf_attr (die, search_name, result) + Dwarf_Die *die; + unsigned int search_name; + Dwarf_Attribute *result; +{ + if (die == NULL) + return NULL; + + /* Search for the attribute with the given name. */ + result->valp = __libdw_find_attr (die, search_name, &result->code, + &result->form); + /* Always fill in the CU information. */ + result->cu = die->cu; + + return result->code == search_name ? result : NULL; +} +INTDEF(dwarf_attr) diff --git a/libdw/dwarf_attr_integrate.c b/libdw/dwarf_attr_integrate.c new file mode 100644 index 00000000..4b27296a --- /dev/null +++ b/libdw/dwarf_attr_integrate.c @@ -0,0 +1,43 @@ +/* Return specific DWARF attribute of a DIE, integrating DW_AT_abstract_origin. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + +Dwarf_Attribute * +dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name, + Dwarf_Attribute *result) +{ + Dwarf_Die die_mem; + + do + { + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, search_name, result); + if (attr != NULL) + return attr; + + attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, result); + if (attr == NULL) + break; + + die = INTUSE(dwarf_formref_die) (attr, &die_mem); + } + while (die != NULL); + + return NULL; +} +INTDEF (dwarf_attr_integrate) diff --git a/libdw/dwarf_begin.c b/libdw/dwarf_begin.c new file mode 100644 index 00000000..70a1b07d --- /dev/null +++ b/libdw/dwarf_begin.c @@ -0,0 +1,85 @@ +/* Create descriptor from file descriptor for processing file. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <stddef.h> +#include <sys/stat.h> + +#include <libdwP.h> + + +Dwarf * +dwarf_begin (fd, cmd) + int fd; + Dwarf_Cmd cmd; +{ + Elf *elf; + Elf_Cmd elfcmd; + Dwarf *result = NULL; + + switch (cmd) + { + case DWARF_C_READ: + elfcmd = ELF_C_READ_MMAP; + break; + case DWARF_C_WRITE: + elfcmd = ELF_C_WRITE; + break; + case DWARF_C_RDWR: + elfcmd = ELF_C_RDWR; + break; + default: + /* No valid mode. */ + __libdw_seterrno (DWARF_E_INVALID_CMD); + return NULL; + } + + /* We have to call `elf_version' here since the user might have not + done it or initialized libelf with a different version. This + would break libdwarf since we are using the ELF data structures + in a certain way. */ + elf_version (EV_CURRENT); + + /* Get an ELF descriptor. */ + elf = elf_begin (fd, elfcmd, NULL); + if (elf == NULL) + { + /* Test why the `elf_begin" call failed. */ + struct stat64 st; + + if (fstat64 (fd, &st) == 0 && ! S_ISREG (st.st_mode)) + __libdw_seterrno (DWARF_E_NO_REGFILE); + else if (errno == EBADF) + __libdw_seterrno (DWARF_E_INVALID_FILE); + else + __libdw_seterrno (DWARF_E_IO_ERROR); + } + else + { + /* Do the real work now that we have an ELF descriptor. */ + result = INTUSE(dwarf_begin_elf) (elf, cmd, NULL); + + /* If this failed, free the resources. */ + if (result == NULL) + elf_end (elf); + else + result->free_elf = true; + } + + return result; +} diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c new file mode 100644 index 00000000..427ffc39 --- /dev/null +++ b/libdw/dwarf_begin_elf.c @@ -0,0 +1,252 @@ +/* Create descriptor from ELF descriptor for processing file. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "libdwP.h" + + +/* Section names. */ +static const char dwarf_scnnames[IDX_last][17] = +{ + [IDX_debug_info] = ".debug_info", + [IDX_debug_abbrev] = ".debug_abbrev", + [IDX_debug_aranges] = ".debug_aranges", + [IDX_debug_line] = ".debug_line", + [IDX_debug_frame] = ".debug_frame", + [IDX_eh_frame] = ".eh_frame", + [IDX_debug_loc] = ".debug_loc", + [IDX_debug_pubnames] = ".debug_pubnames", + [IDX_debug_str] = ".debug_str", + [IDX_debug_funcnames] = ".debug_funcnames", + [IDX_debug_typenames] = ".debug_typenames", + [IDX_debug_varnames] = ".debug_varnames", + [IDX_debug_weaknames] = ".debug_weaknames", + [IDX_debug_macinfo] = ".debug_macinfo", + [IDX_debug_ranges] = ".debug_ranges" +}; +#define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) + + +static void +check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + /* Get the section header data. */ + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + /* This should never happen. If it does something is + wrong in the libelf library. */ + abort (); + + + /* Make sure the section is part of a section group only iff we + really need it. If we are looking for the global (= non-section + group debug info) we have to ignore all the info in section + groups. If we are looking into a section group we cannot look at + a section which isn't part of the section group. */ + if (! inscngrp && (shdr->sh_flags & SHF_GROUP) != 0) + /* Ignore the section. */ + return; + + + /* We recognize the DWARF section by their names. This is not very + safe and stable but the best we can do. */ + const char *scnname = elf_strptr (result->elf, ehdr->e_shstrndx, + shdr->sh_name); + if (scnname == NULL) + { + /* The section name must be valid. Otherwise is the ELF file + invalid. */ + __libdw_seterrno (DWARF_E_INVALID_ELF); + free (result); + return; + } + + + /* Recognize the various sections. Most names start with .debug_. */ + size_t cnt; + for (cnt = 0; cnt < ndwarf_scnnames; ++cnt) + if (strcmp (scnname, dwarf_scnnames[cnt]) == 0) + { + /* Found it. Remember where the data is. */ + if (unlikely (result->sectiondata[cnt] != NULL)) + /* A section appears twice. That's bad. We ignore the section. */ + break; + + /* Get the section data. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL && data->d_size != 0) + /* Yep, there is actually data available. */ + result->sectiondata[cnt] = data; + + break; + } +} + + +/* Check whether all the necessary DWARF information is available. */ +static Dwarf * +valid_p (Dwarf *result) +{ + /* We looked at all the sections. Now determine whether all the + sections with debugging information we need are there. + + XXX Which sections are absolutely necessary? Add tests if + necessary. For now we require only .debug_info. Hopefully this + is correct. */ + if (unlikely (result->sectiondata[IDX_debug_info] == NULL)) + { + __libdw_seterrno (DWARF_E_NO_DWARF); + result = NULL; + } + + return result; +} + + +static Dwarf * +global_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr) +{ + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn (elf, scn)) != NULL) + check_section (result, ehdr, scn, false); + + return valid_p (result); +} + + +static Dwarf * +scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp) +{ + /* SCNGRP is the section descriptor for a section group which might + contain debug sections. */ + Elf_Data *data = elf_getdata (scngrp, NULL); + if (data == NULL) + { + /* We cannot read the section content. Fail! */ + free (result); + return NULL; + } + + /* The content of the section is a number of 32-bit words which + represent section indices. The first word is a flag word. */ + Elf32_Word *scnidx = (Elf32_Word *) data->d_buf; + size_t cnt; + for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt) + { + Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); + if (scn == NULL) + { + /* A section group refers to a non-existing section. Should + never happen. */ + __libdw_seterrno (DWARF_E_INVALID_ELF); + free (result); + return NULL; + } + + check_section (result, ehdr, scn, true); + } + + return valid_p (result); +} + + +Dwarf * +dwarf_begin_elf (elf, cmd, scngrp) + Elf *elf; + Dwarf_Cmd cmd; + Elf_Scn *scngrp; +{ + GElf_Ehdr *ehdr; + GElf_Ehdr ehdr_mem; + + /* Get the ELF header of the file. We need various pieces of + information from it. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + if (elf_kind (elf) != ELF_K_ELF) + __libdw_seterrno (DWARF_E_NOELF); + else + __libdw_seterrno (DWARF_E_GETEHDR_ERROR); + + return NULL; + } + + + /* Default memory allocation size. */ + size_t mem_default_size = sysconf (_SC_PAGESIZE) - 4 * sizeof (void *); + + /* Allocate the data structure. */ + Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size); + if (result == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + /* Fill in some values. */ + if ((BYTE_ORDER == LITTLE_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (BYTE_ORDER == BIG_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + result->other_byte_order = true; + + result->elf = elf; + + /* Initialize the memory handling. */ + result->mem_default_size = mem_default_size; + result->oom_handler = __libdw_oom; + result->mem_tail = (struct libdw_memblock *) (result + 1); + result->mem_tail->size = (result->mem_default_size + - offsetof (struct libdw_memblock, mem)); + result->mem_tail->remaining = result->mem_tail->size; + result->mem_tail->prev = NULL; + + + if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR) + { + /* If the caller provides a section group we get the DWARF + sections only from this setion group. Otherwise we search + for the first section with the required name. Further + sections with the name are ignored. The DWARF specification + does not really say this is allowed. */ + if (scngrp == NULL) + return global_read (result, elf, ehdr); + else + return scngrp_read (result, elf, ehdr, scngrp); + } + else if (cmd == DWARF_C_WRITE) + { + __libdw_seterrno (DWARF_E_UNIMPL); + free (result); + return NULL; + } + + __libdw_seterrno (DWARF_E_INVALID_CMD); + free (result); + return NULL; +} +INTDEF(dwarf_begin_elf) diff --git a/libdw/dwarf_bitoffset.c b/libdw/dwarf_bitoffset.c new file mode 100644 index 00000000..52ab1759 --- /dev/null +++ b/libdw/dwarf_bitoffset.c @@ -0,0 +1,33 @@ +/* Return bit offset attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_bitoffset (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_bit_offset, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_bitsize.c b/libdw/dwarf_bitsize.c new file mode 100644 index 00000000..c67b4ccf --- /dev/null +++ b/libdw/dwarf_bitsize.c @@ -0,0 +1,33 @@ +/* Return bit size attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_bitsize (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_bit_size, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_bytesize.c b/libdw/dwarf_bytesize.c new file mode 100644 index 00000000..3e0b05a8 --- /dev/null +++ b/libdw/dwarf_bytesize.c @@ -0,0 +1,33 @@ +/* Return byte size attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_bytesize (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_byte_size, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c new file mode 100644 index 00000000..8dbe9179 --- /dev/null +++ b/libdw/dwarf_child.c @@ -0,0 +1,159 @@ +/* Return vhild of current DIE. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <string.h> + +/* Some arbitrary value not conflicting with any existing code. */ +#define INVALID 0xffffe444 + + +unsigned char * +internal_function_def +__libdw_find_attr (Dwarf_Die *die, unsigned int search_name, + unsigned int *codep, unsigned int *formp) +{ + Dwarf *dbg = die->cu->dbg; + const unsigned char *readp = (unsigned char *) die->addr; + + /* First we have to get the abbreviation code so that we can decode + the data in the DIE. */ + unsigned int abbrev_code; + get_uleb128 (abbrev_code, readp); + + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = die->abbrev; + if (abbrevp == NULL) + { + abbrevp = __libdw_findabbrev (die->cu, abbrev_code); + die->abbrev = abbrevp ?: (Dwarf_Abbrev *) -1l; + } + if (unlikely (die->abbrev == (Dwarf_Abbrev *) -1l)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Search the name attribute. */ + unsigned char *const endp + = ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size); + + const unsigned char *attrp = die->abbrev->attrp; + while (1) + { + /* Are we still in bounds? This test needs to be refined. */ + if (unlikely (attrp + 1 >= endp)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Get attribute name and form. + + XXX We don't check whether this reads beyond the end of the + section. */ + unsigned int attr_name; + get_uleb128 (attr_name, attrp); + unsigned int attr_form; + get_uleb128 (attr_form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (attr_name == search_name && search_name != INVALID) + { + if (codep != NULL) + *codep = attr_name; + if (formp != NULL) + *formp = attr_form; + + return (unsigned char *) readp; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len = __libdw_form_val_len (dbg, die->cu, attr_form, readp); + + if (unlikely (len == (size_t) -1l)) + { + readp = NULL; + break; + } + + // XXX We need better boundary checks. + readp += len; + } + } + + // XXX Do we need other values? + if (codep != NULL) + *codep = INVALID; + if (formp != NULL) + *formp = INVALID; + + return (unsigned char *) readp; +} + + +int +dwarf_child (die, result) + Dwarf_Die *die; + Dwarf_Die *result; +{ + /* Ignore previous errors. */ + if (die == NULL) + return -1; + + /* Skip past the last attribute. */ + void *addr = NULL; + + /* If we already know there are no children do not search. */ + if (die->abbrev != (Dwarf_Abbrev *) -1 + && (die->abbrev == NULL || die->abbrev->has_children)) + addr = __libdw_find_attr (die, INVALID, NULL, NULL); + if (die->abbrev == (Dwarf_Abbrev *) -1l) + return -1; + + /* Make sure the DIE really has children. */ + if (! die->abbrev->has_children) + /* There cannot be any children. */ + return 1; + + if (addr == NULL) + return -1; + + /* RESULT can be the same as DIE. So preserve what we need. */ + struct Dwarf_CU *cu = die->cu; + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + /* We have the address. */ + result->addr = addr; + + /* Same CU as the parent. */ + result->cu = cu; + + return 0; +} +INTDEF(dwarf_child) diff --git a/libdw/dwarf_cuoffset.c b/libdw/dwarf_cuoffset.c new file mode 100644 index 00000000..f3adfa83 --- /dev/null +++ b/libdw/dwarf_cuoffset.c @@ -0,0 +1,32 @@ +/* Return offset of DIE in CU. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Off +dwarf_cuoffset (die) + Dwarf_Die *die; +{ + return (die == NULL + ? (Dwarf_Off) -1l + : (die->addr + - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf + - die->cu->start)); +} diff --git a/libdw/dwarf_diename.c b/libdw/dwarf_diename.c new file mode 100644 index 00000000..41d763c5 --- /dev/null +++ b/libdw/dwarf_diename.c @@ -0,0 +1,31 @@ +/* Return string in name attribute of DIE. + Copyright (C) 2002, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +const char * +dwarf_diename (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (die, DW_AT_name, + &attr_mem)); +} diff --git a/libdw/dwarf_dieoffset.c b/libdw/dwarf_dieoffset.c new file mode 100644 index 00000000..e678a404 --- /dev/null +++ b/libdw/dwarf_dieoffset.c @@ -0,0 +1,32 @@ +/* Return offset of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Off +dwarf_dieoffset (die) + Dwarf_Die *die; +{ + return (die == NULL + ? ~0ul + : (Dwarf_Off) (die->addr + - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf)); +} +INTDEF(dwarf_dieoffset) diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c new file mode 100644 index 00000000..935bd3d2 --- /dev/null +++ b/libdw/dwarf_end.c @@ -0,0 +1,75 @@ +/* Release debugging handling context. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <search.h> +#include <stdlib.h> + +#include "libdwP.h" + + + +static void +noop_free (void *arg __attribute__ ((unused))) +{ +} + + +static void +cu_free (void *arg) +{ + struct Dwarf_CU *p = (struct Dwarf_CU *) arg; + + Dwarf_Abbrev_Hash_free (&p->abbrev_hash); + + tdestroy (p->locs, noop_free); +} + + +int +dwarf_end (dwarf) + Dwarf *dwarf; +{ + if (dwarf != NULL) + { + /* The search tree for the CUs. NB: the CU data itself is + allocated separately, but the abbreviation hash tables need + to be handled. */ + tdestroy (dwarf->cu_tree, cu_free); + + struct libdw_memblock *memp = dwarf->mem_tail; + /* The first block is allocated together with the Dwarf object. */ + while (memp->prev != NULL) + { + struct libdw_memblock *prevp = memp->prev; + free (memp); + memp = prevp; + } + + /* Free the pubnames helper structure. */ + free (dwarf->pubnames_sets); + + /* Free the ELF descriptor if necessary. */ + if (dwarf->free_elf) + elf_end (dwarf->elf); + + /* Free the context descriptor. */ + free (dwarf); + } + + return 0; +} diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c new file mode 100644 index 00000000..85d928c9 --- /dev/null +++ b/libdw/dwarf_error.c @@ -0,0 +1,180 @@ +/* Retrieve ELF descriptor used for DWARF access. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stddef.h> + +#include "libdwP.h" + + +#ifdef USE_TLS +/* The error number. */ +static __thread int global_error; +#else +/* This is the key for the thread specific memory. */ +static tls_key_t key; + +/* The error number. Used in non-threaded programs. */ +static int global_error; +static bool threaded; +/* We need to initialize the thread-specific data. */ +once_define (static, once); + +/* The initialization and destruction functions. */ +static void init (void); +static void free_key_mem (void *mem); +#endif /* TLS */ + + +int +dwarf_errno (void) +{ + int result; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + { + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + result = (intptr_t) getspecific (key); + + setspecific (key, (void *) (intptr_t) DWARF_E_NOERROR); + return result; + } +#endif /* TLS */ + + result = global_error; + global_error = DWARF_E_NOERROR; + return result; +} +INTDEF(dwarf_errno) + + +/* XXX For now we use string pointers. Once the table stablelizes + make it more DSO-friendly. */ +static const char *errmsgs[] = + { + [DWARF_E_NOERROR] = N_("no error"), + [DWARF_E_UNKNOWN_ERROR] = N_("unknown error"), + [DWARF_E_INVALID_ACCESS] = N_("invalid access"), + [DWARF_E_NO_REGFILE] = N_("no regular file"), + [DWARF_E_IO_ERROR] = N_("I/O error"), + [DWARF_E_INVALID_ELF] = N_("invalid ELF file"), + [DWARF_E_NO_DWARF] = N_("no DWARF information"), + [DWARF_E_NOELF] = N_("no ELF file"), + [DWARF_E_GETEHDR_ERROR] = N_("cannot get ELF header"), + [DWARF_E_NOMEM] = N_("out of memory"), + [DWARF_E_UNIMPL] = N_("not implemented"), + [DWARF_E_INVALID_CMD] = N_("invalid command"), + [DWARF_E_INVALID_VERSION] = N_("invalid version"), + [DWARF_E_INVALID_FILE] = N_("invalid file"), + [DWARF_E_NO_ENTRY] = N_("no entries found"), + [DWARF_E_INVALID_DWARF] = N_("invalid DWARF"), + [DWARF_E_NO_STRING] = N_("no string data"), + [DWARF_E_NO_ADDR] = N_("no address value"), + [DWARF_E_NO_CONSTANT] = N_("no constant value"), + [DWARF_E_NO_REFERENCE] = N_("no reference value"), + [DWARF_E_INVALID_REFERENCE] = N_("invalid reference value"), + [DWARF_E_NO_DEBUG_LINE] = N_(".debug_line section missing"), + [DWARF_E_INVALID_DEBUG_LINE] = N_("invalid .debug_line section"), + [DWARF_E_TOO_BIG] = N_("debug information too big"), + [DWARF_E_VERSION] = N_("invalid DWARF version"), + [DWARF_E_INVALID_DIR_IDX] = N_("invalid directory index"), + [DWARF_E_ADDR_OUTOFRANGE] = N_("address out of range"), + [DWARF_E_NO_LOCLIST] = N_("no location list value"), + [DWARF_E_NO_BLOCK] = N_("no block data"), + [DWARF_E_INVALID_LINE_IDX] = N_("invalid line index"), + [DWARF_E_INVALID_ARANGE_IDX] = N_("invalid address range index"), + [DWARF_E_NO_MATCH] = N_("no matching address range"), + [DWARF_E_NO_FLAG] = N_("no flag value"), + [DWARF_E_INVALID_OFFSET] = N_("invalid offset"), + [DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"), + }; +#define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0])) + + +void +__libdw_seterrno (value) + int value; +{ +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if (threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + setspecific (key, (void *) (intptr_t) value); +#endif /* TLS */ + + global_error = (value >= 0 && value < (int) nerrmsgs + ? value : DWARF_E_UNKNOWN_ERROR); +} + + +const char * +dwarf_errmsg (error) + int error; +{ + int last_error; + +#ifndef USE_TLS + /* If we have not yet initialized the buffer do it now. */ + once_execute (once, init); + + if ((error == 0 || error == -1) && threaded) + /* We do not allocate memory for the data. It is only a word. + We can store it in place of the pointer. */ + last_error = (intptr_t) getspecific (key); + else +#endif /* TLS */ + last_error = global_error; + + if (error == 0) + return last_error != 0 ? _(errmsgs[last_error]) : NULL; + else if (error < -1 || error >= (int) nerrmsgs) + return _(errmsgs[DWARF_E_UNKNOWN_ERROR]); + + return _(errmsgs[error == -1 ? last_error : error]); +} + + +#ifndef USE_TLS +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem __attribute__ ((unused))) +{ + setspecific (key, NULL); +} + + +/* Initialize the key for the global variable. */ +static void +init (void) +{ + // XXX Screw you, gcc4, the unused function attribute does not work. + __asm ("" :: "r" (free_key_mem)); + + if (key_create (&key, free_key_mem) == 0) + /* Creating the key succeeded. */ + threaded = true; +} +#endif /* TLS */ diff --git a/libdw/dwarf_filesrc.c b/libdw/dwarf_filesrc.c new file mode 100644 index 00000000..770c004b --- /dev/null +++ b/libdw/dwarf_filesrc.c @@ -0,0 +1,36 @@ +/* Find source file information. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +const char * +dwarf_filesrc (Dwarf_Files *file, size_t idx, Dwarf_Word *mtime, + Dwarf_Word *length) +{ + if (file == NULL || idx >= file->nfiles) + return NULL; + + if (mtime != NULL) + *mtime = file->info[idx].mtime; + + if (length != NULL) + *length = file->info[idx].length; + + return file->info[idx].name; +} diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c new file mode 100644 index 00000000..168eb89a --- /dev/null +++ b/libdw/dwarf_formaddr.c @@ -0,0 +1,44 @@ +/* Return address represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formaddr (attr, return_addr) + Dwarf_Attribute *attr; + Dwarf_Addr *return_addr; +{ + if (attr == NULL) + return -1; + + if (unlikely (attr->form != DW_FORM_addr)) + { + __libdw_seterrno (DWARF_E_NO_ADDR); + return -1; + } + + if (attr->cu->address_size == 8) + *return_addr = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + else + *return_addr = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + + return 0; +} +INTDEF(dwarf_formaddr) diff --git a/libdw/dwarf_formblock.c b/libdw/dwarf_formblock.c new file mode 100644 index 00000000..30c2ac93 --- /dev/null +++ b/libdw/dwarf_formblock.c @@ -0,0 +1,72 @@ +/* Return block represented by attribute. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formblock (attr, return_block) + Dwarf_Attribute *attr; + Dwarf_Block *return_block; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_block1: + return_block->length = *(uint8_t *) attr->valp; + return_block->data = attr->valp + 1; + break; + + case DW_FORM_block2: + return_block->length = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + return_block->data = attr->valp + 2; + break; + + case DW_FORM_block4: + return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + return_block->data = attr->valp + 4; + break; + + case DW_FORM_block: + datap = attr->valp; + get_uleb128 (return_block->length, datap); + return_block->data = (unsigned char *) datap; + break; + + default: + __libdw_seterrno (DWARF_E_NO_BLOCK); + return -1; + } + + if (return_block->data + return_block->length + > ((unsigned char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + attr->cu->dbg->sectiondata[IDX_debug_info]->d_size)) + { + /* Block does not fit. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + return 0; +} +INTDEF(dwarf_formblock) diff --git a/libdw/dwarf_formflag.c b/libdw/dwarf_formflag.c new file mode 100644 index 00000000..ac344019 --- /dev/null +++ b/libdw/dwarf_formflag.c @@ -0,0 +1,40 @@ +/* Return flag represented by attribute. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formflag (attr, return_bool) + Dwarf_Attribute *attr; + bool *return_bool; +{ + if (attr == NULL) + return -1; + + if (unlikely (attr->form != DW_FORM_flag)) + { + __libdw_seterrno (DWARF_E_NO_FLAG); + return -1; + } + + *return_bool = *attr->valp != 0; + + return 0; +} diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c new file mode 100644 index 00000000..ea569905 --- /dev/null +++ b/libdw/dwarf_formref.c @@ -0,0 +1,67 @@ +/* Return reference offset represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formref (attr, return_offset) + Dwarf_Attribute *attr; + Dwarf_Off *return_offset; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_ref1: + *return_offset = *attr->valp; + break; + + case DW_FORM_ref2: + *return_offset = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref4: + *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref8: + *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref_udata: + datap = attr->valp; + get_uleb128 (*return_offset, datap); + break; + + case DW_FORM_ref_addr: + __libdw_seterrno (DWARF_E_INVALID_REFERENCE); + return -1; + + default: + __libdw_seterrno (DWARF_E_NO_REFERENCE); + return -1; + } + + return 0; +} +INTDEF(dwarf_formref) diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c new file mode 100644 index 00000000..7f5b4f97 --- /dev/null +++ b/libdw/dwarf_formref_die.c @@ -0,0 +1,28 @@ +/* Look up the DIE in a reference-form attribute. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + +Dwarf_Die * +dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem) +{ + Dwarf_Off offset; + return (unlikely (INTUSE(dwarf_formref) (attr, &offset) != 0) ? NULL + : INTUSE(dwarf_offdie) (attr->cu->dbg, attr->cu->start + offset, + die_mem)); +} +INTDEF (dwarf_formref_die) diff --git a/libdw/dwarf_formsdata.c b/libdw/dwarf_formsdata.c new file mode 100644 index 00000000..a5b6b88a --- /dev/null +++ b/libdw/dwarf_formsdata.c @@ -0,0 +1,68 @@ +/* Return signed constant represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formsdata (attr, return_sval) + Dwarf_Attribute *attr; + Dwarf_Sword *return_sval; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_data1: + *return_sval = *attr->valp; + break; + + case DW_FORM_data2: + *return_sval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + *return_sval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data8: + *return_sval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_sdata: + datap = attr->valp; + get_sleb128 (*return_sval, datap); + break; + + case DW_FORM_udata: + datap = attr->valp; + get_uleb128 (*return_sval, datap); + break; + + default: + __libdw_seterrno (DWARF_E_NO_CONSTANT); + return -1; + } + + return 0; +} +INTDEF(dwarf_formsdata) diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c new file mode 100644 index 00000000..eac1cc05 --- /dev/null +++ b/libdw/dwarf_formstring.c @@ -0,0 +1,58 @@ +/* Return string associated with given attribute. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +const char * +dwarf_formstring (attrp) + Dwarf_Attribute *attrp; +{ + /* Ignore earlier errors. */ + if (attrp == NULL) + return NULL; + + /* We found it. Now determine where the string is stored. */ + if (attrp->form == DW_FORM_string) + /* A simple inlined string. */ + return (const char *) attrp->valp; + + Dwarf *dbg = attrp->cu->dbg; + + if (unlikely (attrp->form != DW_FORM_strp) + || dbg->sectiondata[IDX_debug_str] == NULL) + { + invalid_error: + __libdw_seterrno (DWARF_E_NO_STRING); + return NULL; + } + + uint64_t off; + // XXX We need better boundary checks. + if (attrp->cu->offset_size == 8) + off = read_8ubyte_unaligned (dbg, attrp->valp); + else + off = read_4ubyte_unaligned (dbg, attrp->valp); + + if (off >= dbg->sectiondata[IDX_debug_str]->d_size) + goto invalid_error; + + return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off; +} +INTDEF(dwarf_formstring) diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c new file mode 100644 index 00000000..67985621 --- /dev/null +++ b/libdw/dwarf_formudata.c @@ -0,0 +1,68 @@ +/* Return unsigned constant represented by attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formudata (attr, return_uval) + Dwarf_Attribute *attr; + Dwarf_Word *return_uval; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap; + + switch (attr->form) + { + case DW_FORM_data1: + *return_uval = *attr->valp; + break; + + case DW_FORM_data2: + *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + *return_uval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data8: + *return_uval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_sdata: + datap = attr->valp; + get_sleb128 (*return_uval, datap); + break; + + case DW_FORM_udata: + datap = attr->valp; + get_uleb128 (*return_uval, datap); + break; + + default: + __libdw_seterrno (DWARF_E_NO_CONSTANT); + return -1; + } + + return 0; +} +INTDEF(dwarf_formudata) diff --git a/libdw/dwarf_func_col.c b/libdw/dwarf_func_col.c new file mode 100644 index 00000000..feda1435 --- /dev/null +++ b/libdw/dwarf_func_col.c @@ -0,0 +1,27 @@ +/* Get line number of beginning of given function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_func_col (Dwarf_Func *func, int *colp) +{ + return __libdw_func_intval (func, colp, DW_AT_decl_column); +} diff --git a/libdw/dwarf_func_entrypc.c b/libdw/dwarf_func_entrypc.c new file mode 100644 index 00000000..6b5103e0 --- /dev/null +++ b/libdw/dwarf_func_entrypc.c @@ -0,0 +1,33 @@ +/* Get entry address of function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_func_entrypc (Dwarf_Func *func, Dwarf_Addr *return_addr) +{ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (func->die, DW_AT_entry_pc, + &attr_mem); + if (attr != NULL) + return INTUSE(dwarf_formaddr) (attr, return_addr); + + return INTUSE(dwarf_lowpc) (func->die, return_addr); +} diff --git a/libdw/dwarf_func_file.c b/libdw/dwarf_func_file.c new file mode 100644 index 00000000..d5302df0 --- /dev/null +++ b/libdw/dwarf_func_file.c @@ -0,0 +1,72 @@ +/* Return file name containing definition of the given function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +const char * +dwarf_func_file (Dwarf_Func *func) +{ + Dwarf_Attribute attr_mem; + Dwarf_Sword idx = 0; + Dwarf_Die *die = func->die; + + if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr) (die, DW_AT_decl_file, + &attr_mem), &idx) != 0) + return NULL; + + /* Zero means no source file information available. */ + if (idx == 0) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + return NULL; + } + + /* Get the array of source files for the CU. */ + struct Dwarf_CU *cu = die->cu; + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + + /* Let the more generic function do the work. It'll create more + data but that will be needed in an real program anyway. */ + (void) INTUSE(dwarf_getsrclines) (func->cudie, &lines, &nlines); + assert (cu->lines != NULL); + } + + if (cu->lines == (void *) -1l) + { + /* If the file index is not zero, there must be file information + available. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + assert (cu->files != NULL && cu->files != (void *) -1l); + + if (idx >= cu->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + return cu->files->info[idx].name; +} diff --git a/libdw/dwarf_func_highpc.c b/libdw/dwarf_func_highpc.c new file mode 100644 index 00000000..c5d2eec3 --- /dev/null +++ b/libdw/dwarf_func_highpc.c @@ -0,0 +1,26 @@ +/* Get end address of function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_func_highpc (Dwarf_Func *func, Dwarf_Addr *return_addr) +{ + return INTUSE(dwarf_highpc) (func->die, return_addr); +} diff --git a/libdw/dwarf_func_line.c b/libdw/dwarf_func_line.c new file mode 100644 index 00000000..6259b9f1 --- /dev/null +++ b/libdw/dwarf_func_line.c @@ -0,0 +1,47 @@ +/* Get line number of beginning of given function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include <limits.h> +#include "libdwP.h" + + +int +dwarf_func_line (Dwarf_Func *func, int *linep) +{ + return __libdw_func_intval (func, linep, DW_AT_decl_line); +} + + +int internal_function +__libdw_func_intval (Dwarf_Func *func, int *linep, int attval) +{ + Dwarf_Attribute attr_mem; + Dwarf_Sword line; + + int res = INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr) (func->die, attval, + &attr_mem), &line); + if (res == 0) + { + assert (line >= 0 && line <= INT_MAX); + *linep = line; + } + + return res; +} diff --git a/libdw/dwarf_func_lowpc.c b/libdw/dwarf_func_lowpc.c new file mode 100644 index 00000000..d364e6c6 --- /dev/null +++ b/libdw/dwarf_func_lowpc.c @@ -0,0 +1,26 @@ +/* Get start address of function. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_func_lowpc (Dwarf_Func *func, Dwarf_Addr *return_addr) +{ + return INTUSE(dwarf_lowpc) (func->die, return_addr); +} diff --git a/libdw/dwarf_func_name.c b/libdw/dwarf_func_name.c new file mode 100644 index 00000000..4151c359 --- /dev/null +++ b/libdw/dwarf_func_name.c @@ -0,0 +1,30 @@ +/* Get function name. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +const char * +dwarf_func_name (Dwarf_Func *func) +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (func->die, DW_AT_name, + &attr_mem)); +} diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c new file mode 100644 index 00000000..a6968a83 --- /dev/null +++ b/libdw/dwarf_getabbrev.c @@ -0,0 +1,127 @@ +/* Get abbreviation at given offset. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Abbrev * +internal_function_def +__libdw_getabbrev (dbg, cu, offset, lengthp, result) + Dwarf *dbg; + struct Dwarf_CU *cu; + Dwarf_Off offset; + size_t *lengthp; + Dwarf_Abbrev *result; +{ + /* Don't fail if there is not .debug_abbrev section. */ + if (dbg->sectiondata[IDX_debug_abbrev] == NULL) + return NULL; + + const unsigned char *abbrevp + = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset; + if (*abbrevp == '\0') + /* We are past the last entry. */ + return DWARF_END_ABBREV; + + /* 7.5.3 Abbreviations Tables + + [...] Each declaration begins with an unsigned LEB128 number + representing the abbreviation code itself. [...] The + abbreviation code is followed by another unsigned LEB128 + number that encodes the entry's tag. [...] + + [...] Following the tag encoding is a 1-byte value that + determines whether a debugging information entry using this + abbreviation has child entries or not. [...] + + [...] Finally, the child encoding is followed by a series of + attribute specifications. Each attribute specification + consists of two parts. The first part is an unsigned LEB128 + number representing the attribute's name. The second part is + an unsigned LEB128 number representing the attribute's form. */ + const unsigned char *start_abbrevp = abbrevp; + unsigned int code; + get_uleb128 (code, abbrevp); + + /* Check whether this code is already in the hash table. */ + bool foundit = false; + Dwarf_Abbrev *abb = NULL; + if (cu == NULL + || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL) + { + if (result == NULL) + abb = libdw_typed_alloc (dbg, Dwarf_Abbrev); + else + abb = result; + } + else + { + foundit = true; + + assert (abb->offset == offset); + + /* If the caller doesn't need the length we are done. */ + if (lengthp == NULL) + goto out; + } + + /* If there is already a value in the hash table we are going to + overwrite its content. This must not be a problem, since the + content better be the same. */ + abb->code = code; + get_uleb128 (abb->tag, abbrevp); + abb->has_children = *abbrevp++ == DW_CHILDREN_yes; + abb->attrp = (unsigned char *) abbrevp; + abb->offset = offset; + + /* Skip over all the attributes and count them while doing so. */ + abb->attrcnt = 0; + unsigned int attrname; + unsigned int attrform; + do + { + get_uleb128 (attrname, abbrevp); + get_uleb128 (attrform, abbrevp); + } + while (attrname != 0 && attrform != 0 && ++abb->attrcnt); + + /* Return the length to the caller if she asked for it. */ + if (lengthp != NULL) + *lengthp = abbrevp - start_abbrevp; + + /* Add the entry to the hash table. */ + if (cu != NULL && ! foundit) + (void) Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb); + + out: + return abb; +} + + +Dwarf_Abbrev * +dwarf_getabbrev (die, offset, lengthp) + Dwarf_Die *die; + Dwarf_Off offset; + size_t *lengthp; +{ + return __libdw_getabbrev (die->cu->dbg, die->cu, + die->cu->orig_abbrev_offset + offset, lengthp, + NULL); +} diff --git a/libdw/dwarf_getabbrevattr.c b/libdw/dwarf_getabbrevattr.c new file mode 100644 index 00000000..8cdf6a3d --- /dev/null +++ b/libdw/dwarf_getabbrevattr.c @@ -0,0 +1,64 @@ +/* Get specific attribute of abbreviation. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_getabbrevattr (abbrev, idx, namep, formp, offsetp) + Dwarf_Abbrev *abbrev; + size_t idx; + unsigned int *namep; + unsigned int *formp; + Dwarf_Off *offsetp; +{ + if (abbrev == NULL) + return -1; + + size_t cnt = 0; + const unsigned char *attrp = abbrev->attrp; + const unsigned char *start_attrp; + unsigned int name; + unsigned int form; + + do + { + start_attrp = attrp; + + /* Attribute code and form are encoded as ULEB128 values. */ + get_uleb128 (name, attrp); + get_uleb128 (form, attrp); + + /* If both values are zero the index is out of range. */ + if (name == 0 && form == 0) + return -1; + } + while (cnt++ < idx); + + /* Store the result if requested. */ + if (namep != NULL) + *namep = name; + if (formp != NULL) + *formp = form; + if (offsetp != NULL) + *offsetp = (start_attrp - abbrev->attrp) + abbrev->offset; + + return 0; +} diff --git a/libdw/dwarf_getabbrevcode.c b/libdw/dwarf_getabbrevcode.c new file mode 100644 index 00000000..ef3dac46 --- /dev/null +++ b/libdw/dwarf_getabbrevcode.c @@ -0,0 +1,29 @@ +/* Get abbreviation code. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_getabbrevcode (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? 0 : abbrev->code; +} diff --git a/libdw/dwarf_getabbrevtag.c b/libdw/dwarf_getabbrevtag.c new file mode 100644 index 00000000..4707fdd1 --- /dev/null +++ b/libdw/dwarf_getabbrevtag.c @@ -0,0 +1,29 @@ +/* Get abbreviation tag. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_getabbrevtag (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? 0 : abbrev->tag; +} diff --git a/libdw/dwarf_getarange_addr.c b/libdw/dwarf_getarange_addr.c new file mode 100644 index 00000000..2d0408e4 --- /dev/null +++ b/libdw/dwarf_getarange_addr.c @@ -0,0 +1,47 @@ +/* Get address range which includes given address. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libdwP.h> + + +Dwarf_Arange * +dwarf_getarange_addr (aranges, addr) + Dwarf_Aranges *aranges; + Dwarf_Addr addr; +{ + if (aranges == NULL) + return NULL; + + /* The ranges are sorted by address, so we can use binary search. */ + size_t l = 0, u = aranges->naranges; + while (l < u) + { + size_t idx = (l + u) / 2; + if (addr < aranges->info[idx].addr) + u = idx; + else if (addr > aranges->info[idx].addr + && addr - aranges->info[idx].addr >= aranges->info[idx].length) + l = idx + 1; + else + return &aranges->info[idx]; + } + + __libdw_seterrno (DWARF_E_NO_MATCH); + return NULL; +} +INTDEF(dwarf_getarange_addr) diff --git a/libdw/dwarf_getarangeinfo.c b/libdw/dwarf_getarangeinfo.c new file mode 100644 index 00000000..eb1f539d --- /dev/null +++ b/libdw/dwarf_getarangeinfo.c @@ -0,0 +1,38 @@ +/* Return list address ranges. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libdwP.h> + + +int +dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp, + Dwarf_Word *lengthp, Dwarf_Off *offsetp) +{ + if (arange == NULL) + return -1; + + if (addrp != NULL) + *addrp = arange->addr; + if (lengthp != NULL) + *lengthp = arange->length; + if (offsetp != NULL) + *offsetp = arange->offset; + + return 0; +} +INTDEF(dwarf_getarangeinfo) diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c new file mode 100644 index 00000000..f7cf050f --- /dev/null +++ b/libdw/dwarf_getaranges.c @@ -0,0 +1,212 @@ +/* Return list address ranges. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <assert.h> +#include "libdwP.h" + + +struct arangelist +{ + Dwarf_Arange arange; + struct arangelist *next; +}; + +/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */ +static int +compare_aranges (const void *a, const void *b) +{ + Dwarf_Arange *const *p1 = a, *const *p2 = b; + Dwarf_Arange *l1 = *p1, *l2 = *p2; + return l1->addr - l2->addr; +} + +int +dwarf_getaranges (dbg, aranges, naranges) + Dwarf *dbg; + Dwarf_Aranges **aranges; + size_t *naranges; +{ + if (dbg == NULL) + return -1; + + if (dbg->aranges != NULL) + { + *aranges = dbg->aranges; + if (naranges != NULL) + *naranges = dbg->aranges->naranges; + return 0; + } + + if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL) + return -1; + + struct arangelist *arangelist = NULL; + unsigned int narangelist = 0; + + const char *readp + = (const char *) dbg->sectiondata[IDX_debug_aranges]->d_buf; + const char *readendp = readp + dbg->sectiondata[IDX_debug_aranges]->d_size; + + while (readp < readendp) + { + const char *hdrstart = readp; + + /* Each entry starts with a header: + + 1. A 4-byte or 12-byte length containing the length of the + set of entries for this compilation unit, not including the + length field itself. [...] + + 2. A 2-byte version identifier containing the value 2 for + DWARF Version 2.1. + + 3. A 4-byte or 8-byte offset into the .debug_info section. [...] + + 4. A 1-byte unsigned integer containing the size in bytes of + an address (or the offset portion of an address for segmented + addressing) on the target system. + + 5. A 1-byte unsigned integer containing the size in bytes of + a segment descriptor on the target system. */ + Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp); + unsigned int length_bytes = 4; + if (length == 0xffffffff) + { + length = read_8ubyte_unaligned_inc (dbg, readp); + length_bytes = 8; + } + + unsigned int version = read_2ubyte_unaligned_inc (dbg, readp); + if (version != 2) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + Dwarf_Word offset; + if (length_bytes == 4) + offset = read_4ubyte_unaligned_inc (dbg, readp); + else + offset = read_8ubyte_unaligned_inc (dbg, readp); + + unsigned int address_size = *readp++; + if (address_size != 4 && address_size != 8) + goto invalid; + + /* Ignore the segment size value. */ + // XXX Really? + (void) *readp++; + + /* Round the address to the next multiple of 2*address_size. */ + readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size))) + % (2 * address_size)); + + while (1) + { + Dwarf_Word range_address; + Dwarf_Word range_length; + + if (address_size == 4) + { + range_address = read_4ubyte_unaligned_inc (dbg, readp); + range_length = read_4ubyte_unaligned_inc (dbg, readp); + } + else + { + range_address = read_8ubyte_unaligned_inc (dbg, readp); + range_length = read_8ubyte_unaligned_inc (dbg, readp); + } + + /* Two zero values mark the end. */ + if (range_address == 0 && range_length == 0) + break; + + struct arangelist *new_arange = + (struct arangelist *) alloca (sizeof (struct arangelist)); + + new_arange->arange.addr = range_address; + new_arange->arange.length = range_length; + + /* We store the actual CU DIE offset, not the CU header offset. */ + const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf + + offset); + unsigned int offset_size; + if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff) + offset_size = 8; + else + offset_size = 4; + new_arange->arange.offset = offset + 3 * offset_size - 4 + 3; + + new_arange->next = arangelist; + arangelist = new_arange; + ++narangelist; + } + } + + if (narangelist == 0) + { + if (naranges != NULL) + *naranges = 0; + *aranges = NULL; + return 0; + } + + /* Allocate the array for the result. */ + void *buf = libdw_alloc (dbg, Dwarf_Aranges, + sizeof (Dwarf_Aranges) + + narangelist * sizeof (Dwarf_Arange), 1); + + /* First use the buffer for the pointers, and sort the entries. + We'll write the pointers in the end of the buffer, and then + copy into the buffer from the beginning so the overlap works. */ + assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *)); + Dwarf_Arange **sortaranges = (buf + sizeof (Dwarf_Aranges) + + ((sizeof (Dwarf_Arange) + - sizeof (Dwarf_Arange *)) * narangelist)); + + /* The list is in LIFO order and usually they come in clumps with + ascending addresses. So fill from the back to probably start with + runs already in order before we sort. */ + unsigned int i = narangelist; + while (i-- > 0) + { + sortaranges[i] = &arangelist->arange; + arangelist = arangelist->next; + } + assert (arangelist == NULL); + + /* Sort by ascending address. */ + qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges); + + /* Now that they are sorted, put them in the final array. + The buffers overlap, so we've clobbered the early elements + of SORTARANGES by the time we're reading the later ones. */ + *aranges = buf; + (*aranges)->dbg = dbg; + (*aranges)->naranges = narangelist; + dbg->aranges = *aranges; + if (naranges != NULL) + *naranges = narangelist; + for (i = 0; i < narangelist; ++i) + (*aranges)->info[i] = *sortaranges[i]; + + return 0; +} +INTDEF(dwarf_getaranges) diff --git a/libdw/dwarf_getattrcnt.c b/libdw/dwarf_getattrcnt.c new file mode 100644 index 00000000..0758e030 --- /dev/null +++ b/libdw/dwarf_getattrcnt.c @@ -0,0 +1,33 @@ +/* Get number of attributes of abbreviation. + Copyright (C) 2003, 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_getattrcnt (abbrev, attrcntp) + Dwarf_Abbrev *abbrev; + size_t *attrcntp; +{ + if (abbrev == NULL) + return -1; + + *attrcntp = abbrev->attrcnt; + + return 0; +} diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c new file mode 100644 index 00000000..8e6326d7 --- /dev/null +++ b/libdw/dwarf_getattrs.c @@ -0,0 +1,94 @@ +/* Get attributes of the DIE. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +ptrdiff_t +dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *), + void *arg, ptrdiff_t offset) +{ + if (die == NULL) + return -1l; + + const unsigned char *die_addr = die->addr; + + /* Get the abbreviation code. */ + unsigned int u128; + get_uleb128 (u128, die_addr); + + if (die->abbrev == NULL) + /* Find the abbreviation. */ + die->abbrev = __libdw_findabbrev (die->cu, u128); + + if (die->abbrev == (Dwarf_Abbrev *) -1l) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1l; + } + + /* This is where the attributes start. */ + const unsigned char *attrp = die->abbrev->attrp + offset; + + /* Go over the list of attributes. */ + Dwarf *dbg = die->cu->dbg; + while (1) + { + /* Are we still in bounds? */ + if (unlikely (attrp + >= ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size))) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Get attribute name and form. */ + Dwarf_Attribute attr; + // XXX Fix bound checks + get_uleb128 (attr.code, attrp); + get_uleb128 (attr.form, attrp); + + /* We can stop if we found the attribute with value zero. */ + if (attr.code == 0 && attr.form == 0) + return 0; + + /* Fill in the rest. */ + attr.valp = (unsigned char *) die_addr; + attr.cu = die->cu; + + /* Now call the callback function. */ + if (callback (&attr, arg) != DWARF_CB_OK) + return attrp - die->abbrev->attrp; + + /* Skip over the rest of this attribute (if there is any). */ + if (attr.form != 0) + { + size_t len = __libdw_form_val_len (dbg, die->cu, attr.form, + die_addr); + + if (unlikely (len == (size_t) -1l)) + /* Something wrong with the file. */ + return -1l; + + // XXX We need better boundary checks. + die_addr += len; + } + } + /* NOTREACHED */ +} diff --git a/libdw/dwarf_getelf.c b/libdw/dwarf_getelf.c new file mode 100644 index 00000000..1e2a06aa --- /dev/null +++ b/libdw/dwarf_getelf.c @@ -0,0 +1,33 @@ +/* Retrieve ELF descriptor used for DWARF access. + Copyright (C) 2002, 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stddef.h> + +#include "libdwP.h" + + +Elf * +dwarf_get_elf (dwarf) + Dwarf *dwarf; +{ + if (dwarf == NULL) + /* Some error occurred before. */ + return NULL; + + return dwarf->elf; +} diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c new file mode 100644 index 00000000..149f1860 --- /dev/null +++ b/libdw/dwarf_getfuncs.c @@ -0,0 +1,63 @@ +/* Get function information. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +ptrdiff_t +dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Func *, void *), + void *arg, ptrdiff_t offset) +{ + if (unlikely (cudie == NULL + || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) + return -1; + + Dwarf_Die die_mem; + Dwarf_Die *die; + + int res; + if (offset == 0) + res = INTUSE(dwarf_child) (cudie, &die_mem); + else + { + die = INTUSE(dwarf_offdie) (cudie->cu->dbg, offset, &die_mem); + res = INTUSE(dwarf_siblingof) (die, &die_mem); + } + die = res != 0 ? NULL : &die_mem; + + while (die != NULL) + { + if (INTUSE(dwarf_tag) (die) == DW_TAG_subprogram) + { + Dwarf_Func fct; + + fct.die = die; + fct.cudie = cudie; + + if (callback (&fct, arg) != DWARF_CB_OK) + return INTUSE(dwarf_dieoffset) (die); + } + + if (INTUSE(dwarf_siblingof) (die, &die_mem) != 0) + break; + } + + /* That's all. */ + return 0; +} diff --git a/libdw/dwarf_getloclist.c b/libdw/dwarf_getloclist.c new file mode 100644 index 00000000..ab7c3869 --- /dev/null +++ b/libdw/dwarf_getloclist.c @@ -0,0 +1,454 @@ +/* Return location expression list. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include <search.h> +#include <stdlib.h> + +#include <libdwP.h> + + +static bool +attr_ok (Dwarf_Attribute *attr) +{ + if (attr == NULL) + return false; + + /* Must be one of the attributes listed below. */ + switch (attr->code) + { + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_string_length: + case DW_AT_use_location: + case DW_AT_frame_base: + case DW_AT_return_addr: + case DW_AT_static_link: + break; + + default: + __libdw_seterrno (DWARF_E_NO_LOCLIST); + return false; + } + + return true; +} + + +struct loclist +{ + uint8_t atom; + Dwarf_Word number; + Dwarf_Word number2; + Dwarf_Word offset; + struct loclist *next; +}; + + +static int +loc_compare (const void *p1, const void *p2) +{ + const struct loc_s *l1 = (const struct loc_s *) p1; + const struct loc_s *l2 = (const struct loc_s *) p2; + + if ((uintptr_t) l1->addr < (uintptr_t) l2->addr) + return -1; + if ((uintptr_t) l1->addr > (uintptr_t) l2->addr) + return 1; + + return 0; +} + +static int +getloclist (struct Dwarf_CU *cu, const Dwarf_Block *block, + Dwarf_Loc **llbuf, size_t *listlen) +{ + Dwarf *dbg = cu->dbg; + + /* Check whether we already looked at this list. */ + struct loc_s fake = { .addr = block->data }; + struct loc_s **found = tfind (&fake, &cu->locs, loc_compare); + if (found != NULL) + { + /* We already saw it. */ + *llbuf = (*found)->loc; + *listlen = (*found)->nloc; + + return 0; + } + + const unsigned char *data = block->data; + const unsigned char *const end_data = data + block->length; + + struct loclist *loclist = NULL; + unsigned int n = 0; + /* Decode the opcodes. It is possible in some situations to have a + block of size zero. */ + while (data < end_data) + { + struct loclist *newloc; + newloc = (struct loclist *) alloca (sizeof (struct loclist)); + newloc->number = 0; + newloc->number2 = 0; + newloc->offset = data - block->data; + newloc->next = loclist; + loclist = newloc; + ++n; + + switch ((newloc->atom = *data++)) + { + case DW_OP_addr: + /* Address, depends on address size of CU. */ + if (cu->address_size == 4) + { + if (unlikely (data + 4 > end_data)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + newloc->number = read_4ubyte_unaligned_inc (dbg, data); + } + else + { + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8ubyte_unaligned_inc (dbg, data); + } + break; + + case DW_OP_deref: + case DW_OP_dup: + case DW_OP_drop: + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_xderef: + 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: + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + case DW_OP_eq: + case DW_OP_ge: + case DW_OP_gt: + case DW_OP_le: + case DW_OP_lt: + case DW_OP_ne: + case DW_OP_lit0 ... DW_OP_lit31: + case DW_OP_reg0 ... DW_OP_reg31: + case DW_OP_nop: + case DW_OP_push_object_address: + case DW_OP_call_ref: + /* No operand. */ + break; + + case DW_OP_const1u: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + if (unlikely (data >= end_data)) + goto invalid; + + newloc->number = *data++; + break; + + case DW_OP_const1s: + if (unlikely (data >= end_data)) + goto invalid; + + newloc->number = *((int8_t *) data); + ++data; + break; + + case DW_OP_const2u: + if (unlikely (data + 2 > end_data)) + goto invalid; + + newloc->number = read_2ubyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const2s: + case DW_OP_skip: + case DW_OP_bra: + case DW_OP_call2: + if (unlikely (data + 2 > end_data)) + goto invalid; + + newloc->number = read_2sbyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const4u: + if (unlikely (data + 4 > end_data)) + goto invalid; + + newloc->number = read_4ubyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const4s: + case DW_OP_call4: + if (unlikely (data + 4 > end_data)) + goto invalid; + + newloc->number = read_4sbyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const8u: + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8ubyte_unaligned_inc (dbg, data); + break; + + case DW_OP_const8s: + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8sbyte_unaligned_inc (dbg, data); + break; + + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + /* XXX Check size. */ + get_uleb128 (newloc->number, data); + break; + + case DW_OP_consts: + case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_fbreg: + /* XXX Check size. */ + get_sleb128 (newloc->number, data); + break; + + case DW_OP_bregx: + /* XXX Check size. */ + get_uleb128 (newloc->number, data); + get_sleb128 (newloc->number2, data); + break; + + default: + goto invalid; + } + } + + if (unlikely (n == 0)) + { + /* This is not allowed. + + XXX Is it? */ + goto invalid; + } + + /* Allocate the array. */ + Dwarf_Loc *result = libdw_alloc (dbg, Dwarf_Loc, sizeof (Dwarf_Loc), n); + + /* Store the result. */ + *llbuf = result; + *listlen = n; + + do + { + /* We populate the array from the back since the list is + backwards. */ + --n; + result[n].atom = loclist->atom; + result[n].number = loclist->number; + result[n].number2 = loclist->number2; + result[n].offset = loclist->offset; + + loclist = loclist->next; + } + while (n > 0); + + /* Insert a record in the search tree so that we can find it again + later. */ + struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), + 1); + newp->addr = block->data; + newp->loc = result; + newp->nloc = *listlen; + (void) tsearch (newp, &cu->locs, loc_compare); + + /* We did it. */ + return 0; +} + +int +dwarf_getloclist (attr, llbuf, listlen) + Dwarf_Attribute *attr; + Dwarf_Loc **llbuf; + size_t *listlen; +{ + if (! attr_ok (attr)) + return -1; + + /* If it has a block form, it's a single location expression. */ + Dwarf_Block block; + if (INTUSE(dwarf_formblock) (attr, &block) != 0) + return -1; + + return getloclist (attr->cu, &block, llbuf, listlen); +} + +int +dwarf_addrloclists (attr, address, llbufs, listlens, maxlocs) + Dwarf_Attribute *attr; + Dwarf_Addr address; + Dwarf_Loc **llbufs; + size_t *listlens; + size_t maxlocs; +{ + if (! attr_ok (attr)) + return -1; + + if (llbufs == NULL) + maxlocs = SIZE_MAX; + + /* If it has a block form, it's a single location expression. */ + Dwarf_Block block; + if (INTUSE(dwarf_formblock) (attr, &block) == 0) + { + if (maxlocs == 0) + return 0; + if (llbufs != NULL && + getloclist (attr->cu, &block, &llbufs[0], &listlens[0]) != 0) + return -1; + return listlens[0] == 0 ? 0 : 1; + } + + int error = INTUSE(dwarf_errno) (); + if (error != DWARF_E_NO_BLOCK) + { + __libdw_seterrno (error); + return -1; + } + + /* Must have the form data4 or data8 which act as an offset. */ + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (attr, &offset) != 0) + return -1; + + const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc]; + if (d == NULL) + { + __libdw_seterrno (DWARF_E_NO_LOCLIST); + return -1; + } + + /* Fetch the CU's base address. */ + Dwarf_Addr base; + Dwarf_Die cudie = + { + .cu = attr->cu, + .addr = ((char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + attr->cu->start + 3 * attr->cu->offset_size - 4 + 3), + }; + + + /* Find the base address of the compilation unit. It will + normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, + the base address could be overridden by DW_AT_entry_pc. It's + been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc + for compilation units with discontinuous ranges. */ + Dwarf_Attribute attr_mem; + if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0 + && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, DW_AT_entry_pc, + &attr_mem), + &base) != 0) + return -1; + + unsigned char *readp = d->d_buf + offset; + size_t got = 0; + while (got < maxlocs) + { + if ((unsigned char *) d->d_buf + d->d_size - readp + < attr->cu->address_size * 2) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + Dwarf_Addr begin; + Dwarf_Addr end; + if (attr->cu->address_size == 8) + { + begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + + if (begin == (Elf64_Addr) -1l) /* Base address entry. */ + { + base = end; + continue; + } + } + else + { + begin = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); + end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); + + if (begin == (Elf32_Addr) -1) /* Base address entry. */ + { + base = end; + continue; + } + } + + if (begin == 0 && end == 0) /* End of list entry. */ + break; + + if ((unsigned char *) d->d_buf + d->d_size - readp < 2) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* We have a location expression. */ + block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp); + block.data = readp; + if ((unsigned char *) d->d_buf + d->d_size - readp + < (ptrdiff_t) block.length) + goto invalid; + readp += block.length; + + if (address >= base + begin && address < base + end) + { + /* This one matches the address. */ + if (llbufs != NULL && getloclist (attr->cu, &block, + &llbufs[got], &listlens[got]) != 0) + return -1; + ++got; + } + } + + return got; +} diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c new file mode 100644 index 00000000..d3678c99 --- /dev/null +++ b/libdw/dwarf_getmacros.c @@ -0,0 +1,119 @@ +/* Get macro information. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include <string.h> + +#include <libdwP.h> + + +ptrdiff_t +dwarf_getmacros (die, callback, arg, offset) + Dwarf_Die *die; + int (*callback) (Dwarf_Macro *, void *); + void *arg; + ptrdiff_t offset; +{ + /* Get the appropriate attribute. */ + Dwarf_Attribute attr; + if (INTUSE(dwarf_attr) (die, DW_AT_macro_info, &attr) == NULL) + return -1; + + /* Offset into the .debug_macinfo section. */ + Dwarf_Word macoff; + if (INTUSE(dwarf_formudata) (&attr, &macoff) != 0) + return -1; + + const unsigned char *readp + = die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_buf + offset; + const unsigned char *readendp + = readp + die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_size; + + if (readp == readendp) + return 0; + + if (*readp != DW_MACINFO_start_file) + goto invalid; + + while (readp < readendp) + { + unsigned int opcode = *readp++; + unsigned int u128; + unsigned int u128_2 = 0; + const char *str = NULL; + const unsigned char *endp; + + switch (opcode) + { + case DW_MACINFO_define: + case DW_MACINFO_undef: + case DW_MACINFO_vendor_ext: + /* For the first two opcodes the parameters are + line, string + For the latter + number, string. + We can treat these cases together. */ + get_uleb128 (u128, readp); + + endp = memchr (readp, '\0', readendp - readp); + if (endp == NULL) + goto invalid; + + str = (char *) readp; + readp = endp + 1; + break; + + case DW_MACINFO_start_file: + /* The two parameters are line and file index. */ + get_uleb128 (u128, readp); + get_uleb128 (u128_2, readp); + break; + + case DW_MACINFO_end_file: + /* No parameters for this one. */ + u128 = 0; + break; + + case 0: + /* Nothing more to do. */ + return 0; + + default: + goto invalid; + } + + Dwarf_Macro mac; + mac.opcode = opcode; + mac.param1 = u128; + if (str == NULL) + mac.param2.u = u128_2; + else + mac.param2.s = str; + + if (callback (&mac, arg) != DWARF_CB_OK) + return (readp + - ((unsigned char *) die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_buf + + offset)); + } + + /* If we come here the termination of the data for the CU is not + present. */ + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; +} diff --git a/libdw/dwarf_getpubnames.c b/libdw/dwarf_getpubnames.c new file mode 100644 index 00000000..5700cd77 --- /dev/null +++ b/libdw/dwarf_getpubnames.c @@ -0,0 +1,213 @@ +/* Get public symbol information. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +#include <libdwP.h> + + +static int +get_offsets (Dwarf *dbg) +{ + size_t allocated = 0; + size_t cnt = 0; + struct pubnames_s *mem = NULL; + const size_t entsize = sizeof (struct pubnames_s); + unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf; + unsigned char *readp = startp; + unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size; + + while (readp + 14 < endp) + { + /* If necessary, allocate more entries. */ + if (cnt >= allocated) + { + allocated = MAX (10, 2 * allocated); + struct pubnames_s *newmem + = (struct pubnames_s *) realloc (mem, allocated * entsize); + if (newmem == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + err_return: + free (mem); + return -1; + } + + mem = newmem; + } + + /* Read the set header. */ + int len_bytes = 4; + Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp); + if (len == 0xffffffff) + { + len = read_8ubyte_unaligned_inc (dbg, readp); + len_bytes = 8; + } + + /* Now we know the offset of the first offset/name pair. */ + mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp; + mem[cnt].address_len = len_bytes; + if (mem[cnt].set_start >= dbg->sectiondata[IDX_debug_pubnames]->d_size) + /* Something wrong, the first entry is beyond the end of + the section. */ + break; + + /* Read the version. It better be two for now. */ + uint16_t version = read_2ubyte_unaligned (dbg, readp); + if (version != 2) + { + __libdw_seterrno (DWARF_E_INVALID_VERSION); + goto err_return; + } + + /* Get the CU offset. */ + if (len_bytes == 4) + mem[cnt].cu_offset = read_4ubyte_unaligned (dbg, readp + 2); + else + mem[cnt].cu_offset = read_8ubyte_unaligned (dbg, readp + 2); + + /* Determine the size of the CU header. */ + assert (dbg->sectiondata[IDX_debug_info] != NULL); + assert (dbg->sectiondata[IDX_debug_info]->d_buf != NULL); + assert (mem[cnt].cu_offset + 3 + < dbg->sectiondata[IDX_debug_info]->d_size); + unsigned char *infop + = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf + + mem[cnt].cu_offset); + if (read_4ubyte_unaligned_noncvt (infop) == 0xffffffff) + mem[cnt].cu_header_size = 23; + else + mem[cnt].cu_header_size = 11; + + ++cnt; + + /* Advance to the next set. */ + readp += len; + } + + if (mem == NULL) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + return -1; + } + + dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize); + dbg->pubnames_nsets = cnt; + + return 0; +} + + +ptrdiff_t +dwarf_getpubnames (dbg, callback, arg, offset) + Dwarf *dbg; + int (*callback) (Dwarf *, Dwarf_Global *, void *); + void *arg; + ptrdiff_t offset; +{ + if (dbg == NULL) + return -1l; + + if (offset < 0) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return -1l; + } + + /* Make sure it is a valid offset. */ + if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL + || ((size_t) offset + >= dbg->sectiondata[IDX_debug_pubnames]->d_size))) + /* No (more) entry. */ + return 0; + + /* If necessary read the set information. */ + if (dbg->pubnames_nsets == 0 && get_offsets (dbg) != 0) + return -1l; + + /* Find the place where to start. */ + size_t cnt; + if (offset == 0) + { + cnt = 0; + offset = dbg->pubnames_sets[0].set_start; + } + else + { + for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt) + if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start) + { + assert ((Dwarf_Off) offset + < dbg->pubnames_sets[cnt + 1].set_start); + break; + } + assert (cnt + 1 < dbg->pubnames_nsets); + } + + unsigned char *startp + = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; + unsigned char *readp = startp + offset; + while (1) + { + Dwarf_Global gl; + + gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset + + dbg->pubnames_sets[cnt].cu_header_size); + + while (1) + { + /* READP points to the next offset/name pair. */ + if (dbg->pubnames_sets[cnt].address_len == 4) + gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp); + else + gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp); + + /* If the offset is zero we reached the end of the set. */ + if (gl.die_offset == 0) + break; + + /* Add the CU offset. */ + gl.die_offset += dbg->pubnames_sets[cnt].cu_offset; + + gl.name = (char *) readp; + readp = (unsigned char *) rawmemchr (gl.name, '\0') + 1; + + /* We found name and DIE offset. Report it. */ + if (callback (dbg, &gl, arg) != DWARF_CB_OK) + { + /* The user wants us to stop. Return the offset of the + next entry. */ + return readp - startp; + } + } + + if (++cnt == dbg->pubnames_nsets) + /* This was the last set. */ + break; + + startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; + readp = startp + dbg->pubnames_sets[cnt].set_start; + } + + /* We are done. No more entries. */ + return 0; +} diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c new file mode 100644 index 00000000..21d6f20a --- /dev/null +++ b/libdw/dwarf_getscopes.c @@ -0,0 +1,334 @@ +/* Return scope DIEs containing PC address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include "libdwP.h" +#include <dwarf.h> + + +enum die_class { ignore, match, match_inline, walk, imported }; + +static enum die_class +classify_die (Dwarf_Die *die) +{ + switch (INTUSE(dwarf_tag) (die)) + { + /* DIEs with addresses we can try to match. */ + case DW_TAG_compile_unit: + case DW_TAG_module: + case DW_TAG_lexical_block: + case DW_TAG_with_stmt: + case DW_TAG_catch_block: + case DW_TAG_try_block: + case DW_TAG_entry_point: + return match; + case DW_TAG_inlined_subroutine: + return match_inline; + case DW_TAG_subprogram: + /* This might be a concrete out-of-line instance of an inline, in + which case it is not guaranteed to be owned by the right scope and + we will search for its origin as for DW_TAG_inlined_subroutine. */ + return (INTUSE(dwarf_hasattr) (die, DW_AT_abstract_origin) + ? match_inline : match); + + /* DIEs without addresses that can own DIEs with addresses. */ + case DW_TAG_namespace: + return walk; + + /* Special indirection required. */ + case DW_TAG_imported_unit: + return imported; + + /* Other DIEs we have no reason to descend. */ + default: + break; + } + return ignore; +} + +/* DIE contains PC. Find its child that contains PC. Returns -1 for + errors, 0 for no matches. On success, *SCOPES gets the malloc'd array + of containing scopes. A positive return value is the number of those + scopes. A return value < -1 is -1 - number of those scopes, when the + outermost scope is a concrete instance of an inline subroutine. */ +static int +find_pc (unsigned int depth, Dwarf_Die *die, Dwarf_Addr pc, Dwarf_Die **scopes) +{ + Dwarf_Die child; + if (INTUSE(dwarf_child) (die, &child) != 0) + return -1; + + /* Recurse on this DIE to search within its children. + Return nonzero if this gets an error or a final result. */ + inline int search_child (void) + { + int n = find_pc (depth + 1, &child, pc, scopes); + if (n > 0) + /* That stored the N innermost scopes. Now store ours. */ + (*scopes)[n++] = child; + return n; + } + + /* Check each of our child DIEs. */ + enum die_class got = ignore; + do + { + enum die_class child_class = classify_die (&child); + switch (child_class) + { + case match: + case match_inline: + if (INTUSE(dwarf_haspc) (&child, pc) > 0) + break; + continue; + + case walk: + if (INTUSE(dwarf_haschildren) (&child)) + got = walk; + continue; + + case imported: + got = walk; + continue; + + default: + case ignore: + continue; + } + + /* We get here only when the PC has matched. */ + got = child_class; + break; + } + while (INTUSE(dwarf_siblingof) (&child, &child) == 0); + + switch (got) + { + case match: + case match_inline: + /* We have a DIE that matched the PC. */ + if (INTUSE(dwarf_haschildren) (&child)) + { + /* Recurse on this DIE to narrow within its children. + Return now if this gets an error or a final result. */ + int result = search_child (); + if (result < 0 || (got == match && result > 0)) + return result; + if (result > 0) /* got == match_inline */ + /* We have a winner, but CHILD is a concrete inline instance + so DIE and its containing scopes do not actually apply. + DIE is the scope that inlined the function. Our root + caller must find the abstract scope that defines us. */ + return -1 - result; + } + + /* This DIE has no children containing the PC, so this is it. */ + *scopes = malloc (depth * sizeof (*scopes)[0]); + if (*scopes == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + (*scopes)[0] = child; + return got == match ? 1 : -2; + + case walk: + /* We don't have anything matching the PC, but we have some things + we might descend to find one. Recurse on each of those. */ + if (INTUSE(dwarf_child) (die, &child) != 0) + return -1; + do + switch (classify_die (&child)) + { + case walk: + if (INTUSE(dwarf_haschildren) (&child)) + { + /* Recurse on this DIE to look for the PC within its children. + Return now if this gets an error or a final result. */ + int result = search_child (); + if (result != 0) + return result; + } + break; + + case imported: + { + /* This imports another compilation unit to appear + as part of this one, inside the current scope. + Recurse to search the referenced unit, but without + recording it as an inner scoping level. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import, + &attr_mem); + if (INTUSE(dwarf_formref_die) (attr, &child) != NULL) + { + int result = find_pc (depth, &child, pc, scopes); + if (result != 0) + return result; + } + } + break; + + default: + break; + } + while (INTUSE(dwarf_siblingof) (&child, &child) == 0); + break; + + default: + case ignore: + /* Nothing to see here. */ + break; + } + + /* No matches. */ + return 0; +} + + +/* OWNER owns OWNED. Find intermediate scopes. *SCOPES was allocated by + find_pc and has SKIP elements. We realloc it, append more containing + scopes, and return 1 + the number appended. Returns -1 on errors, + or 0 when OWNED was not found within OWNER. */ +static int +find_die (unsigned int depth, Dwarf_Die *owner, Dwarf_Die *owned, + Dwarf_Die **scopes, unsigned int skip) +{ + Dwarf_Die child; + if (INTUSE(dwarf_child) (owner, &child) != 0) + return -1; + + do + { + if (child.addr == owned->addr) + /* This is the one. OWNER is the innermost owner. */ + return 1; + + /* Unfortunately we cannot short-circuit the dead-end paths just by + checking the physical layout to see if OWNED falls within CHILD. + If it doesn't, there may still be a DW_TAG_imported_unit that + refers to its true owner indirectly. */ + + switch (classify_die (&child)) + { + case match: + case match_inline: + case walk: + if (INTUSE(dwarf_haschildren) (&child)) + { + /* Recurse on this DIE to look for OWNED within its children. + Return now if this gets an error or a final result. */ + int n = find_die (depth + 1, &child, owned, scopes, skip); + if (n < 0) + return n; + if (n > 1) + { + /* We have a winner. CHILD owns the owner of OWNED. */ + (*scopes)[skip + n - 1] = child; + return n + 1; + } + if (n > 0) /* n == 1 */ + { + /* CHILD is the direct owner of OWNED. */ + Dwarf_Die *nscopes = realloc (*scopes, + (skip + depth) + * sizeof nscopes[0]); + if (nscopes == NULL) + { + free (*scopes); + *scopes = NULL; + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + nscopes[skip] = child; + *scopes = nscopes; + return 2; + } + } + break; + + case imported: + { + /* This is imports another compilation unit to appear + as part of this one, inside the current scope. + Recurse to search the referenced unit, but without + recording it as an inner scoping level. */ + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child, DW_AT_import, + &attr_mem); + if (INTUSE(dwarf_formref_die) (attr, &child) != NULL) + { + int result = find_die (depth, &child, owner, scopes, skip); + if (result != 0) + return result; + } + } + break; + + default: + break; + } + } + while (INTUSE(dwarf_siblingof) (&child, &child) == 0); + + return 0; +} + + +int +dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes) +{ + if (cudie == NULL) + return -1; + + int n = find_pc (1, cudie, pc, scopes); + if (likely (n >= -1)) + /* We have an error or a final result. */ + return n; + + /* We have the scopes out to one that is a concrete instance of an + inlined subroutine (usually DW_TAG_inlined_subroutine, but can + be DW_TAG_subprogram for a concrete out-of-line instance). + Now we must find the lexical scopes that contain the + corresponding abstract inline subroutine definition. */ + + n = -n - 1; + + Dwarf_Attribute attr_mem; + Dwarf_Die die_mem; + Dwarf_Die *origin = INTUSE(dwarf_formref_die) + (INTUSE(dwarf_attr) (&(*scopes)[n - 1], DW_AT_abstract_origin, &attr_mem), + &die_mem); + if (unlikely (origin == NULL)) + goto invalid; + + int result = find_die (0, cudie, origin, scopes, n); + if (likely (result > 0)) + return n + result - 1; + + if (result == 0) /* No match, shouldn't happen. */ + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + } + + free (*scopes); + *scopes = NULL; + return -1; +} diff --git a/libdw/dwarf_getscopevar.c b/libdw/dwarf_getscopevar.c new file mode 100644 index 00000000..3ceb292d --- /dev/null +++ b/libdw/dwarf_getscopevar.c @@ -0,0 +1,147 @@ +/* Find a named variable or parameter within given scopes. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdbool.h> +#include <string.h> +#include "libdwP.h" +#include <dwarf.h> + + +/* Find the containing CU's files. */ +static int +getfiles (Dwarf_Die *die, Dwarf_Files **files) +{ + Dwarf_Die cudie = + { + .cu = die->cu, + .addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + 3 * die->cu->offset_size - 4 + 3), + }; + return INTUSE(dwarf_getsrcfiles) (&cudie, files, NULL); +} + +/* Fetch an attribute that should have a constant integer form. */ +static int +getattr (Dwarf_Die *die, int search_name, Dwarf_Word *value) +{ + Dwarf_Attribute attr_mem; + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, search_name, + &attr_mem), value); +} + +/* Search SCOPES[0..NSCOPES-1] for a variable called NAME. + Ignore the first SKIP_SHADOWS scopes that match the name. + If MATCH_FILE is not null, accept only declaration in that source file; + if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration + at that line and column. + + If successful, fill in *RESULT with the DIE of the variable found, + and return N where SCOPES[N] is the scope defining the variable. + Return -1 for errors or -2 for no matching variable found. */ + +int +dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, + const char *name, int skip_shadows, + const char *match_file, int match_lineno, int match_linecol, + Dwarf_Die *result) +{ + /* Match against the given file name. */ + size_t match_file_len = match_file == NULL ? 0 : strlen (match_file); + bool lastfile_matches = false; + const char *lastfile = NULL; + inline bool file_matches (Dwarf_Files *files, size_t idx) + { + if (idx >= files->nfiles) + return false; + + const char *file = files->info[idx].name; + if (file != lastfile) + { + size_t len = strlen (file); + lastfile_matches = (len >= match_file_len + && !memcmp (match_file, file, match_file_len) + && (len == match_file_len + || file[len - match_file_len - 1] == '/')); + } + return lastfile_matches; + } + + /* Start with the innermost scope and move out. */ + for (int out = 0; out < nscopes; ++out) + if (INTUSE(dwarf_haschildren) (&scopes[out])) + { + if (INTUSE(dwarf_child) (&scopes[out], result) != 0) + return -1; + do + { + switch (INTUSE(dwarf_tag) (result)) + { + case DW_TAG_variable: + case DW_TAG_formal_parameter: + break; + + default: + continue; + } + + /* Only get here for a variable or parameter. Check the name. */ + Dwarf_Attribute attr_mem; + const char *diename = INTUSE(dwarf_formstring) + (INTUSE(dwarf_attr_integrate) (result, DW_AT_name, &attr_mem)); + if (diename != NULL && !strcmp (name, diename)) + { + /* We have a matching name. */ + + if (skip_shadows > 0) + { + /* Punt this scope for the one it shadows. */ + --skip_shadows; + break; + } + + if (match_file != NULL) + { + /* Check its decl_file. */ + + Dwarf_Word i; + Dwarf_Files *files; + if (getattr (result, DW_AT_decl_file, &i) != 0 + || getfiles (&scopes[out], &files) != 0) + break; + + if (!file_matches (files, i)) + break; + + if (match_lineno > 0 + && (getattr (result, DW_AT_decl_line, &i) != 0 + || (int) i != match_lineno)) + break; + if (match_linecol > 0 + && (getattr (result, DW_AT_decl_column, &i) != 0 + || (int) i != match_linecol)) + break; + } + + /* We have a winner! */ + return out; + } + } + while (INTUSE(dwarf_siblingof) (result, result) == 0); + } + + return -2; +} diff --git a/libdw/dwarf_getsrc_die.c b/libdw/dwarf_getsrc_die.c new file mode 100644 index 00000000..e3ce4f2a --- /dev/null +++ b/libdw/dwarf_getsrc_die.c @@ -0,0 +1,58 @@ +/* Find line information for address. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <assert.h> + + +Dwarf_Line * +dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr) +{ + Dwarf_Lines *lines; + size_t nlines; + + if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) + return NULL; + + /* The lines are sorted by address, so we can use binary search. */ + size_t l = 0, u = nlines; + while (l < u) + { + size_t idx = (l + u) / 2; + if (addr < lines->info[idx].addr) + u = idx; + else if (addr > lines->info[idx].addr) + l = idx + 1; + else + return &lines->info[idx]; + } + + if (nlines > 0) + assert (lines->info[nlines - 1].end_sequence); + + /* If none were equal, the closest one below is what we want. We + never want the last one, because it's the end-sequence marker + with an address at the high bound of the CU's code. If the debug + information is faulty and no end-sequence marker is present, we + still ignore it. */ + if (u > 0 && u < nlines && addr > lines->info[u - 1].addr) + return &lines->info[u - 1]; + + __libdw_seterrno (DWARF_E_ADDR_OUTOFRANGE); + return NULL; +} diff --git a/libdw/dwarf_getsrc_file.c b/libdw/dwarf_getsrc_file.c new file mode 100644 index 00000000..a10581d4 --- /dev/null +++ b/libdw/dwarf_getsrc_file.c @@ -0,0 +1,158 @@ +/* Find line information for given file/line/column triple. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +#include "libdwP.h" + + +int +dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, + Dwarf_Line ***srcsp, size_t *nsrcs) +{ + if (dbg == NULL) + return -1; + + bool is_basename = strchr (fname, '/') == NULL; + + size_t max_match = *nsrcs ?: ~0u; + size_t act_match = *nsrcs; + size_t cur_match = 0; + Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp; + + Dwarf_Off off = 0; + size_t cuhl; + Dwarf_Off noff; + + while (INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0) + { + Dwarf_Die cudie_mem; + Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem); + if (cudie == NULL) + continue; + + /* Get the line number information for this file. */ + Dwarf_Lines *lines; + size_t nlines; + if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) + return -1; + + /* Search through all the line number records for a matching + file and line/column number. If any of the numbers is zero, + no match is performed. */ + unsigned int lastfile = UINT_MAX; + bool lastmatch = false; + for (size_t cnt = 0; cnt < nlines; ++cnt) + { + Dwarf_Line *line = &lines->info[cnt]; + + if (lastfile != line->file) + { + lastfile = line->file; + if (lastfile >= line->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Match the name with the name the user provided. */ + const char *fname2 = line->files->info[lastfile].name; + if (is_basename) + lastmatch = strcmp (basename (fname2), fname) == 0; + else + lastmatch = strcmp (fname2, fname) == 0; + } + if (!lastmatch) + continue; + + /* See whether line and possibly column match. */ + if (lineno != 0 + && (lineno > line->line + || (column != 0 && column > line->column))) + /* Cannot match. */ + continue; + + /* Determine whether this is the best match so far. */ + size_t inner; + for (inner = 0; inner < cur_match; ++inner) + if (match[inner]->files == line->files + && match[inner]->file == line->file) + break; + if (inner < cur_match + && (match[inner]->line != line->line + || match[inner]->line != lineno + || (column != 0 + && (match[inner]->column != line->column + || match[inner]->column != column)))) + { + /* We know about this file already. If this is a better + match for the line number, use it. */ + if (match[inner]->line >= line->line + && (match[inner]->line != line->line + || match[inner]->column >= line->column)) + /* Use the new line. Otherwise the old one. */ + match[inner] = line; + continue; + } + + if (cur_match < max_match) + { + if (cur_match == act_match) + { + /* Enlarge the array for the results. */ + act_match += 10; + Dwarf_Line **newp = realloc (match, + act_match + * sizeof (Dwarf_Line *)); + if (newp == NULL) + { + free (match); + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + match = newp; + } + + match[cur_match++] = line; + } + } + + /* If we managed to find as many matches as the user requested + already, there is no need to go on to the next CU. */ + if (cur_match == max_match) + break; + + off = noff; + } + + if (cur_match > 0) + { + assert (*nsrcs == 0 || *srcsp == match); + + *nsrcs = cur_match; + *srcsp = match; + + return 0; + } + + __libdw_seterrno (DWARF_E_NO_MATCH); + return -1; +} diff --git a/libdw/dwarf_getsrcfiles.c b/libdw/dwarf_getsrcfiles.c new file mode 100644 index 00000000..6472bf44 --- /dev/null +++ b/libdw/dwarf_getsrcfiles.c @@ -0,0 +1,60 @@ +/* Return source file information of CU. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles) +{ + if (unlikely (cudie == NULL + || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) + return -1; + + int res = -1; + + /* Get the information if it is not already known. */ + struct Dwarf_CU *const cu = cudie->cu; + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + + /* Let the more generic function do the work. It'll create more + data but that will be needed in an real program anyway. */ + res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines); + } + else if (cu->files != (void *) -1l) + /* We already have the information. */ + res = 0; + + if (likely (res == 0)) + { + assert (cu->files != NULL && cu->files != (void *) -1l); + *files = cu->files; + if (nfiles != NULL) + *nfiles = cu->files->nfiles; + } + + // XXX Eventually: unlocking here. + + return res; +} +INTDEF (dwarf_getsrcfiles) diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c new file mode 100644 index 00000000..37e14aee --- /dev/null +++ b/libdw/dwarf_getsrclines.c @@ -0,0 +1,652 @@ +/* Return line number information of CU. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include "dwarf.h" +#include "libdwP.h" + + +struct filelist +{ + Dwarf_Fileinfo info; + struct filelist *next; +}; + +struct linelist +{ + Dwarf_Line line; + struct linelist *next; +}; + + +/* Compare by Dwarf_Line.addr, given pointers into an array of pointers. */ +static int +compare_lines (const void *a, const void *b) +{ + Dwarf_Line *const *p1 = a; + Dwarf_Line *const *p2 = b; + + return (*p1)->addr - (*p2)->addr; +} + + +/* Adds a new line to the matrix. We cannot define a function because + we want to use alloca. */ +#define NEW_LINE(end_seq) \ + do { \ + /* Add the new line. */ \ + new_line = (struct linelist *) alloca (sizeof (struct linelist)); \ + \ + /* Set the line information. */ \ + new_line->line.addr = address; \ + new_line->line.file = file; \ + new_line->line.line = line; \ + new_line->line.column = column; \ + new_line->line.is_stmt = is_stmt; \ + new_line->line.basic_block = basic_block; \ + new_line->line.end_sequence = end_seq; \ + new_line->line.prologue_end = prologue_end; \ + new_line->line.epilogue_begin = epilogue_begin; \ + \ + new_line->next = linelist; \ + linelist = new_line; \ + ++nlinelist; \ + } while (0) + + +int +dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) +{ + if (unlikely (cudie == NULL + || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) + return -1; + + int res = -1; + + /* Get the information if it is not already known. */ + struct Dwarf_CU *const cu = cudie->cu; + if (cu->lines == NULL) + { + /* Failsafe mode: no data found. */ + cu->lines = (void *) -1l; + cu->files = (void *) -1l; + + /* The die must have a statement list associated. */ + Dwarf_Attribute stmt_list_mem; + Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, + &stmt_list_mem); + + /* Get the offset into the .debug_line section. NB: this call + also checks whether the previous dwarf_attr call failed. */ + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (stmt_list, &offset) != 0) + goto out; + + Dwarf *dbg = cu->dbg; + if (dbg->sectiondata[IDX_debug_line] == NULL) + { + __libdw_seterrno (DWARF_E_NO_DEBUG_LINE); + goto out; + } + const uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset; + const uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf + + dbg->sectiondata[IDX_debug_line]->d_size); + + /* Get the compilation directory. */ + Dwarf_Attribute compdir_attr_mem; + Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie, + DW_AT_comp_dir, + &compdir_attr_mem); + const char *comp_dir = INTUSE(dwarf_formstring) (compdir_attr); + + if (unlikely (linep + 4 > lineendp)) + { + invalid_data: + __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); + goto out; + } + Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); + unsigned int length = 4; + if (unlikely (unit_length == 0xffffffff)) + { + if (unlikely (linep + 8 > lineendp)) + goto invalid_data; + unit_length = read_8ubyte_unaligned_inc (dbg, linep); + length = 8; + } + + /* Check whether we have enough room in the section. */ + if (unit_length < 2 + length + 5 * 1 + || unlikely (linep + unit_length > lineendp)) + goto invalid_data; + lineendp = linep + unit_length; + + /* The next element of the header is the version identifier. */ + uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); + if (unlikely (version != DWARF_VERSION)) + { + __libdw_seterrno (DWARF_E_VERSION); + goto out; + } + + /* Next comes the header length. */ + Dwarf_Word header_length; + if (length == 4) + header_length = read_4ubyte_unaligned_inc (dbg, linep); + else + header_length = read_8ubyte_unaligned_inc (dbg, linep); + const unsigned char *header_start = linep; + + /* Next the minimum instruction length. */ + uint_fast8_t minimum_instr_len = *linep++; + + /* Then the flag determining the default value of the is_stmt + register. */ + uint_fast8_t default_is_stmt = *linep++; + + /* Now the line base. */ + int_fast8_t line_base = *((int_fast8_t *) linep); + ++linep; + + /* And the line range. */ + uint_fast8_t line_range = *linep++; + + /* The opcode base. */ + uint_fast8_t opcode_base = *linep++; + + /* Remember array with the standard opcode length (-1 to account for + the opcode with value zero not being mentioned). */ + const uint8_t *standard_opcode_lengths = linep - 1; + linep += opcode_base - 1; + if (unlikely (linep >= lineendp)) + goto invalid_data; + + /* First comes the list of directories. Add the compilation + directory first since the index zero is used for it. */ + struct dirlist + { + const char *dir; + size_t len; + struct dirlist *next; + } comp_dir_elem = + { + .dir = comp_dir, + .len = comp_dir ? strlen (comp_dir) : 0, + .next = NULL + }; + struct dirlist *dirlist = &comp_dir_elem; + unsigned int ndirlist = 1; + + // XXX Directly construct array to conserve memory? + while (*linep != 0) + { + struct dirlist *new_dir = + (struct dirlist *) alloca (sizeof (*new_dir)); + + new_dir->dir = (char *) linep; + uint8_t *endp = memchr (linep, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + new_dir->len = endp - linep; + new_dir->next = dirlist; + dirlist = new_dir; + ++ndirlist; + linep = endp + 1; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Rearrange the list in array form. */ + struct dirlist **dirarray + = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray)); + while (ndirlist-- > 0) + { + dirarray[ndirlist] = dirlist; + dirlist = dirlist->next; + } + + /* Now read the files. */ + struct filelist null_file = + { + .info = + { + .name = "???", + .mtime = 0, + .length = 0 + }, + .next = NULL + }; + struct filelist *filelist = &null_file; + unsigned int nfilelist = 1; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + while (*linep != 0) + { + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + + /* First comes the file name. */ + char *fname = (char *) linep; + uint8_t *endp = memchr (fname, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + size_t fnamelen = endp - (uint8_t *) fname; + linep = endp + 1; + + /* Then the index. */ + Dwarf_Word diridx; + get_uleb128 (diridx, linep); + if (unlikely (diridx >= ndirlist)) + { + __libdw_seterrno (DWARF_E_INVALID_DIR_IDX); + goto out; + } + + if (*fname == '/') + /* It's an absolute path. */ + new_file->info.name = fname; + else + { + new_file->info.name = libdw_alloc (dbg, char, 1, + dirarray[diridx]->len + 1 + + fnamelen + 1); + char *cp = new_file->info.name; + + if (dirarray[diridx]->dir != NULL) + { + /* This value could be NULL in case the DW_AT_comp_dir + was not present. We cannot do much in this case. + The easiest thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + } + *cp++ = '/'; + strcpy (cp, fname); + assert (strlen (new_file->info.name) + < dirarray[diridx]->len + 1 + fnamelen + 1); + } + + /* Next comes the modification time. */ + get_uleb128 (new_file->info.mtime, linep); + + /* Finally the length of the file. */ + get_uleb128 (new_file->info.length, linep); + + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Consistency check. */ + if (unlikely (linep != header_start + header_length)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + goto out; + } + + /* We are about to process the statement program. Initialize the + state machine registers (see 6.2.2 in the v2.1 specification). */ + Dwarf_Word address = 0; + size_t file = 1; + size_t line = 1; + size_t column = 0; + uint_fast8_t is_stmt = default_is_stmt; + int basic_block = 0; + int prologue_end = 0; + int epilogue_begin = 0; + + /* Process the instructions. */ + struct linelist *linelist = NULL; + unsigned int nlinelist = 0; + while (linep < lineendp) + { + struct linelist *new_line; + unsigned int opcode; + unsigned int u128; + int s128; + + /* Read the opcode. */ + opcode = *linep++; + + /* Is this a special opcode? */ + if (likely (opcode >= opcode_base)) + { + /* Yes. Handling this is quite easy since the opcode value + is computed with + + opcode = (desired line increment - line_base) + + (line_range * address advance) + opcode_base + */ + int line_increment = (line_base + + (opcode - opcode_base) % line_range); + unsigned int address_increment = (minimum_instr_len + * ((opcode - opcode_base) + / line_range)); + + /* Perform the increments. */ + line += line_increment; + address += address_increment; + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = 0; + prologue_end = 0; + epilogue_begin = 0; + } + else if (opcode == 0) + { + /* This an extended opcode. */ + if (unlikely (linep + 2 > lineendp)) + goto invalid_data; + + /* The length. */ + unsigned int len = *linep++; + + if (unlikely (linep + len > lineendp)) + goto invalid_data; + + /* The sub-opcode. */ + opcode = *linep++; + + switch (opcode) + { + case DW_LNE_end_sequence: + /* Add a new line with the current state machine values. + The is the end of the sequence. */ + NEW_LINE (1); + + /* Reset the registers. */ + address = 0; + file = 1; + line = 1; + column = 0; + is_stmt = default_is_stmt; + basic_block = 0; + prologue_end = 0; + epilogue_begin = 0; + break; + + case DW_LNE_set_address: + /* The value is an address. The size is defined as + apporiate for the target machine. We use the + address size field from the CU header. */ + if (cu->address_size == 4) + address = read_4ubyte_unaligned_inc (dbg, linep); + else + address = read_8ubyte_unaligned_inc (dbg, linep); + break; + + case DW_LNE_define_file: + { + char *fname = (char *) linep; + uint8_t *endp = memchr (linep, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + size_t fnamelen = endp - linep; + linep = endp + 1; + + unsigned int diridx; + get_uleb128 (diridx, linep); + Dwarf_Word mtime; + get_uleb128 (mtime, linep); + Dwarf_Word filelength; + get_uleb128 (filelength, linep); + + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + if (fname[0] == '/') + new_file->info.name = fname; + else + { + new_file->info.name = + libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1 + + fnamelen + 1)); + char *cp = new_file->info.name; + + if (dirarray[diridx]->dir != NULL) + /* This value could be NULL in case the + DW_AT_comp_dir was not present. We + cannot do much in this case. The easiest + thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + *cp++ = '/'; + strcpy (cp, fname); + } + + new_file->info.mtime = mtime; + new_file->info.length = filelength; + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + break; + + default: + /* Unknown, ignore it. */ + linep += len - 1; + break; + } + } + else if (opcode <= DW_LNS_set_epilog_begin) + { + /* This is a known standard opcode. */ + switch (opcode) + { + case DW_LNS_copy: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = 0; + /* XXX Whether the following two lines are necessary is + unclear. I guess the current v2.1 specification has + a bug in that it says clearing these two registers is + not necessary. */ + prologue_end = 0; + epilogue_begin = 0; + break; + + case DW_LNS_advance_pc: + /* Takes one uleb128 parameter which is added to the + address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_uleb128 (u128, linep); + address += minimum_instr_len * u128; + break; + + case DW_LNS_advance_line: + /* Takes one sleb128 parameter which is added to the + line. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_sleb128 (s128, linep); + line += s128; + break; + + case DW_LNS_set_file: + /* Takes one uleb128 parameter which is stored in file. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_uleb128 (u128, linep); + file = u128; + break; + + case DW_LNS_set_column: + /* Takes one uleb128 parameter which is stored in column. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + get_uleb128 (u128, linep); + column = u128; + break; + + case DW_LNS_negate_stmt: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + is_stmt = 1 - is_stmt; + break; + + case DW_LNS_set_basic_block: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + basic_block = 1; + break; + + case DW_LNS_const_add_pc: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + address += (minimum_instr_len + * ((255 - opcode_base) / line_range)); + break; + + case DW_LNS_fixed_advance_pc: + /* Takes one 16 bit parameter which is added to the + address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + address += read_2ubyte_unaligned_inc (dbg, linep); + break; + + case DW_LNS_set_prologue_end: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + prologue_end = 1; + break; + + case DW_LNS_set_epilog_begin: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + epilogue_begin = 1; + break; + } + } + else + { + /* This is a new opcode the generator but not we know about. + Read the parameters associated with it but then discard + everything. Read all the parameters for this opcode. */ + for (int n = standard_opcode_lengths[opcode]; n > 0; --n) + get_uleb128 (u128, linep); + + /* Next round, ignore this opcode. */ + continue; + } + } + + /* Put all the files in an array. */ + Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files, + sizeof (Dwarf_Files) + + nfilelist * sizeof (Dwarf_Fileinfo), + 1); + files->nfiles = nfilelist; + while (nfilelist-- > 0) + { + files->info[nfilelist] = filelist->info; + filelist = filelist->next; + } + assert (filelist == NULL); + + /* Remember the debugging descriptor. */ + files->dbg = dbg; + + /* Make the file data structure available through the CU. */ + cu->files = files; + + void *buf = libdw_alloc (dbg, Dwarf_Lines, (sizeof (Dwarf_Lines) + + (sizeof (Dwarf_Line) + * nlinelist)), 1); + + /* First use the buffer for the pointers, and sort the entries. + We'll write the pointers in the end of the buffer, and then + copy into the buffer from the beginning so the overlap works. */ + assert (sizeof (Dwarf_Line) >= sizeof (Dwarf_Line *)); + Dwarf_Line **sortlines = (buf + sizeof (Dwarf_Lines) + + ((sizeof (Dwarf_Line) + - sizeof (Dwarf_Line *)) * nlinelist)); + + /* The list is in LIFO order and usually they come in clumps with + ascending addresses. So fill from the back to probably start with + runs already in order before we sort. */ + unsigned int i = nlinelist; + while (i-- > 0) + { + sortlines[i] = &linelist->line; + linelist = linelist->next; + } + assert (linelist == NULL); + + /* Sort by ascending address. */ + qsort (sortlines, nlinelist, sizeof sortlines[0], &compare_lines); + + /* Now that they are sorted, put them in the final array. + The buffers overlap, so we've clobbered the early elements + of SORTLINES by the time we're reading the later ones. */ + cu->lines = buf; + cu->lines->nlines = nlinelist; + for (i = 0; i < nlinelist; ++i) + { + cu->lines->info[i] = *sortlines[i]; + cu->lines->info[i].files = files; + } + + /* Success. */ + res = 0; + } + else if (cu->lines != (void *) -1l) + /* We already have the information. */ + res = 0; + + if (likely (res == 0)) + { + *lines = cu->lines; + *nlines = cu->lines->nlines; + } + out: + + // XXX Eventually: unlocking here. + + return res; +} +INTDEF(dwarf_getsrclines) diff --git a/libdw/dwarf_getstring.c b/libdw/dwarf_getstring.c new file mode 100644 index 00000000..e4abe8cb --- /dev/null +++ b/libdw/dwarf_getstring.c @@ -0,0 +1,51 @@ +/* Get string. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "libdwP.h" + + +const char * +dwarf_getstring (dbg, offset, lenp) + Dwarf *dbg; + Dwarf_Off offset; + size_t *lenp; +{ + if (dbg == NULL) + return NULL; + + if (dbg->sectiondata[IDX_debug_str] == NULL + || offset >= dbg->sectiondata[IDX_debug_str]->d_size) + { + no_string: + __libdw_seterrno (DWARF_E_NO_STRING); + return NULL; + } + + const char *result = ((const char *) dbg->sectiondata[IDX_debug_str]->d_buf + + offset); + const char *endp = memchr (result, '\0', + dbg->sectiondata[IDX_debug_str]->d_size - offset); + if (endp == NULL) + goto no_string; + + if (lenp != NULL) + *lenp = endp - result; + + return result; +} diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c new file mode 100644 index 00000000..88dbee49 --- /dev/null +++ b/libdw/dwarf_hasattr.c @@ -0,0 +1,37 @@ +/* Check whether given DIE has specific attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_hasattr (die, search_name) + Dwarf_Die *die; + unsigned int search_name; +{ + if (die == NULL) + return 0; + + /* Search for the attribute with the given name. */ + unsigned int code; + (void) __libdw_find_attr (die, search_name, &code, NULL); + + return code == search_name; +} +INTDEF (dwarf_hasattr) diff --git a/libdw/dwarf_hasattr_integrate.c b/libdw/dwarf_hasattr_integrate.c new file mode 100644 index 00000000..423aa2a2 --- /dev/null +++ b/libdw/dwarf_hasattr_integrate.c @@ -0,0 +1,42 @@ +/* Check whether DIE has specific attribute, integrating DW_AT_abstract_origin. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + +int +dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name) +{ + Dwarf_Die die_mem; + + do + { + if (INTUSE(dwarf_hasattr) (die, search_name)) + return 1; + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, + &attr_mem); + if (attr == NULL) + break; + + die = INTUSE(dwarf_formref_die) (attr, &die_mem); + } + while (die != NULL); + + return 0; +} diff --git a/libdw/dwarf_haschildren.c b/libdw/dwarf_haschildren.c new file mode 100644 index 00000000..05a5b526 --- /dev/null +++ b/libdw/dwarf_haschildren.c @@ -0,0 +1,49 @@ +/* Return string associated with given attribute. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <string.h> + + +int +dwarf_haschildren (die) + Dwarf_Die *die; +{ + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = die->abbrev; + if (abbrevp != (Dwarf_Abbrev *) -1l) + { + const unsigned char *readp = (unsigned char *) die->addr; + + /* First we have to get the abbreviation code so that we can decode + the data in the DIE. */ + unsigned int abbrev_code; + get_uleb128 (abbrev_code, readp); + + abbrevp = __libdw_findabbrev (die->cu, abbrev_code); + die->abbrev = abbrevp ?: (Dwarf_Abbrev *) -1l; + } + if (unlikely (die->abbrev == (Dwarf_Abbrev *) -1l)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return 0; + } + + return die->abbrev->has_children; +} +INTDEF (dwarf_haschildren) diff --git a/libdw/dwarf_hasform.c b/libdw/dwarf_hasform.c new file mode 100644 index 00000000..392b1f13 --- /dev/null +++ b/libdw/dwarf_hasform.c @@ -0,0 +1,32 @@ +/* Check whether given attribute has specific form. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_hasform (attr, search_form) + Dwarf_Attribute *attr; + unsigned int search_form; +{ + if (attr == NULL) + return 0; + + return attr->form == search_form; +} diff --git a/libdw/dwarf_haspc.c b/libdw/dwarf_haspc.c new file mode 100644 index 00000000..7f29296d --- /dev/null +++ b/libdw/dwarf_haspc.c @@ -0,0 +1,105 @@ +/* Determine whether a DIE covers a PC address. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> + + +int +dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc) +{ + if (die == NULL) + return -1; + + /* Usually there is a single contiguous range. */ + Dwarf_Addr lowpc, highpc; + if (INTUSE(dwarf_highpc) (die, &highpc) == 0 + && INTUSE(dwarf_lowpc) (die, &lowpc) == 0) + return pc >= lowpc && pc < highpc; + + /* We have to look for a noncontiguous range. */ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, &attr_mem); + if (attr == NULL) + return -1; + + /* Must have the form data4 or data8 which act as an offset. */ + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (attr, &offset) != 0) + return -1; + + const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_ranges]; + if (d == NULL) + { + __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES); + return -1; + } + + /* Fetch the CU's base address. */ + Dwarf_Addr base; + Dwarf_Die cudie = + { + .cu = attr->cu, + .addr = ((char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf + + attr->cu->start + 3 * attr->cu->offset_size - 4 + 3), + }; + if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0) + return -1; + + unsigned char *readp = d->d_buf + offset; + Dwarf_Addr begin; + Dwarf_Addr end; + do + { + next: + if ((unsigned char *) d->d_buf + d->d_size - readp + < attr->cu->address_size * 2) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + if (attr->cu->address_size == 8) + { + begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); + } + else + { + begin = (Dwarf_Sword) read_4sbyte_unaligned_inc (attr->cu->dbg, + readp); + end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); + } + + if (begin == (Dwarf_Addr) -1l) /* Base address entry. */ + { + base = end; + goto next; + } + + if (begin == 0 && end == 0) /* End of list entry. */ + /* This is not the droid you are looking for. */ + return 0; + + /* We have an address range entry. */ + } + while (pc < base + begin || pc >= base + end); + + /* This one matches the address. */ + return 1; +} +INTDEF (dwarf_haspc) diff --git a/libdw/dwarf_highpc.c b/libdw/dwarf_highpc.c new file mode 100644 index 00000000..d842569a --- /dev/null +++ b/libdw/dwarf_highpc.c @@ -0,0 +1,34 @@ +/* Return high PC attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_highpc (die, return_addr) + Dwarf_Die *die; + Dwarf_Addr *return_addr; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_high_pc, + &attr_mem), + return_addr); +} +INTDEF(dwarf_highpc) diff --git a/libdw/dwarf_lineaddr.c b/libdw/dwarf_lineaddr.c new file mode 100644 index 00000000..ddfc01ba --- /dev/null +++ b/libdw/dwarf_lineaddr.c @@ -0,0 +1,31 @@ +/* Return line address. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp) +{ + if (line == NULL) + return -1; + + *addrp = line->addr; + + return 0; +} diff --git a/libdw/dwarf_linebeginstatement.c b/libdw/dwarf_linebeginstatement.c new file mode 100644 index 00000000..d974d8f4 --- /dev/null +++ b/libdw/dwarf_linebeginstatement.c @@ -0,0 +1,31 @@ +/* Return true if record is for beginning of a statement. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->is_stmt; + + return 0; +} diff --git a/libdw/dwarf_lineblock.c b/libdw/dwarf_lineblock.c new file mode 100644 index 00000000..a6b8e0c2 --- /dev/null +++ b/libdw/dwarf_lineblock.c @@ -0,0 +1,31 @@ +/* Return true if record is for beginning of a basic block. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineblock (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->basic_block; + + return 0; +} diff --git a/libdw/dwarf_linecol.c b/libdw/dwarf_linecol.c new file mode 100644 index 00000000..2430d372 --- /dev/null +++ b/libdw/dwarf_linecol.c @@ -0,0 +1,31 @@ +/* Return column in line. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_linecol (Dwarf_Line *line, int *colp) +{ + if (line == NULL) + return -1; + + *colp = line->column; + + return 0; +} diff --git a/libdw/dwarf_lineendsequence.c b/libdw/dwarf_lineendsequence.c new file mode 100644 index 00000000..c49fabe2 --- /dev/null +++ b/libdw/dwarf_lineendsequence.c @@ -0,0 +1,31 @@ +/* Return true if record is for end of sequence. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineendsequence (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->end_sequence; + + return 0; +} diff --git a/libdw/dwarf_lineepiloguebegin.c b/libdw/dwarf_lineepiloguebegin.c new file mode 100644 index 00000000..ee4f5bb7 --- /dev/null +++ b/libdw/dwarf_lineepiloguebegin.c @@ -0,0 +1,31 @@ +/* Return true if record is for beginning of epilogue. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->epilogue_begin; + + return 0; +} diff --git a/libdw/dwarf_lineno.c b/libdw/dwarf_lineno.c new file mode 100644 index 00000000..5ad24067 --- /dev/null +++ b/libdw/dwarf_lineno.c @@ -0,0 +1,31 @@ +/* Return line number. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineno (Dwarf_Line *line, int *linep) +{ + if (line == NULL) + return -1; + + *linep = line->line; + + return 0; +} diff --git a/libdw/dwarf_lineprologueend.c b/libdw/dwarf_lineprologueend.c new file mode 100644 index 00000000..e869025c --- /dev/null +++ b/libdw/dwarf_lineprologueend.c @@ -0,0 +1,31 @@ +/* Return true if record is for end of prologue. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineprologueend (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->prologue_end; + + return 0; +} diff --git a/libdw/dwarf_linesrc.c b/libdw/dwarf_linesrc.c new file mode 100644 index 00000000..0aca1d6f --- /dev/null +++ b/libdw/dwarf_linesrc.c @@ -0,0 +1,41 @@ +/* Find line information for address. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +const char * +dwarf_linesrc (Dwarf_Line *line, Dwarf_Word *mtime, Dwarf_Word *length) +{ + if (line == NULL) + return NULL; + + if (line->file >= line->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + if (mtime != NULL) + *mtime = line->files->info[line->file].mtime; + + if (length != NULL) + *length = line->files->info[line->file].length; + + return line->files->info[line->file].name; +} diff --git a/libdw/dwarf_lowpc.c b/libdw/dwarf_lowpc.c new file mode 100644 index 00000000..c8cec0c1 --- /dev/null +++ b/libdw/dwarf_lowpc.c @@ -0,0 +1,34 @@ +/* Return low PC attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_lowpc (die, return_addr) + Dwarf_Die *die; + Dwarf_Addr *return_addr; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc, + &attr_mem), + return_addr); +} +INTDEF(dwarf_lowpc) diff --git a/libdw/dwarf_macro_opcode.c b/libdw/dwarf_macro_opcode.c new file mode 100644 index 00000000..1401db2d --- /dev/null +++ b/libdw/dwarf_macro_opcode.c @@ -0,0 +1,31 @@ +/* Return macro opcode. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep) +{ + if (macro == NULL) + return -1; + + *opcodep = macro->opcode; + + return 0; +} diff --git a/libdw/dwarf_macro_param1.c b/libdw/dwarf_macro_param1.c new file mode 100644 index 00000000..adac7613 --- /dev/null +++ b/libdw/dwarf_macro_param1.c @@ -0,0 +1,31 @@ +/* Return first macro parameter. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp) +{ + if (macro == NULL) + return -1; + + *paramp = macro->param1; + + return 0; +} diff --git a/libdw/dwarf_macro_param2.c b/libdw/dwarf_macro_param2.c new file mode 100644 index 00000000..1b49aa7f --- /dev/null +++ b/libdw/dwarf_macro_param2.c @@ -0,0 +1,34 @@ +/* Return second macro parameter. + Copyright (C) 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, const char **strp) +{ + if (macro == NULL) + return -1; + + if (paramp != NULL) + *paramp = macro->param2.u; + if (strp != NULL) + *strp = macro->param2.s; + + return 0; +} diff --git a/libdw/dwarf_nextcu.c b/libdw/dwarf_nextcu.c new file mode 100644 index 00000000..9dc7633e --- /dev/null +++ b/libdw/dwarf_nextcu.c @@ -0,0 +1,132 @@ +/* Advance to next CU header. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libdwP.h> + + +int +dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp, + address_sizep, offset_sizep) + Dwarf *dwarf; + Dwarf_Off off; + Dwarf_Off *next_off; + size_t *header_sizep; + Dwarf_Off *abbrev_offsetp; + uint8_t *address_sizep; + uint8_t *offset_sizep; +{ + /* Maybe there has been an error before. */ + if (dwarf == NULL) + return -1; + + /* If we reached the end before don't do anything. */ + if (off == (Dwarf_Off) -1l + /* Make sure there is enough space in the .debug_info section + for at least the initial word. We cannot test the rest since + we don't know yet whether this is a 64-bit object or not. */ + || unlikely (off + 4 >= dwarf->sectiondata[IDX_debug_info]->d_size)) + { + *next_off = (Dwarf_Off) -1l; + return 1; + } + + /* This points into the .debug_info section to the beginning of the + CU entry. */ + char *bytes = (char *) dwarf->sectiondata[IDX_debug_info]->d_buf + off; + + /* The format of the CU header is described in dwarf2p1 7.5.1: + + 1. A 4-byte or 12-byte unsigned integer representing the length + of the .debug_info contribution for that compilation unit, not + including the length field itself. In the 32-bit DWARF format, + this is a 4-byte unsigned integer (which must be less than + 0xffffff00); in the 64-bit DWARF format, this consists of the + 4-byte value 0xffffffff followed by an 8-byte unsigned integer + that gives the actual length (see Section 7.4). + + 2. A 2-byte unsigned integer representing the version of the + DWARF information for that compilation unit. For DWARF Version + 2.1, the value in this field is 2. + + 3. A 4-byte or 8-byte unsigned offset into the .debug_abbrev + section. This offset associates the compilation unit with a + particular set of debugging information entry abbreviations. In + the 32-bit DWARF format, this is a 4-byte unsigned length; in + the 64-bit DWARF format, this is an 8-byte unsigned length (see + Section 7.4). + + 4. 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. */ + uint64_t length = read_4ubyte_unaligned_inc (dwarf, bytes); + size_t offset_size = 4; + if (length == 0xffffffffu) + offset_size = 8; + + /* Now we know how large the header is. Note the trick in the + computation. If the offset_size is 4 the '- 4' term undoes the + '2 *'. If offset_size is 8 this term computes the size of the + escape value plus the 8 byte offset. */ + if (unlikely (off + 2 * offset_size - 4 + sizeof (uint16_t) + + offset_size + sizeof (uint8_t) + >= dwarf->sectiondata[IDX_debug_info]->d_size)) + { + *next_off = -1; + return 1; + } + + if (length == 0xffffffffu) + /* This is a 64-bit DWARF format. */ + length = read_8ubyte_unaligned_inc (dwarf, bytes); + + /* Read the version stamp. Always a 16-bit value. + XXX Do we need the value? */ + read_2ubyte_unaligned_inc (dwarf, bytes); + + /* Get offset in .debug_abbrev. Note that the size of the entry + depends on whether this is a 32-bit or 64-bit DWARF definition. */ + uint64_t abbrev_offset; + if (offset_size == 4) + abbrev_offset = read_4ubyte_unaligned_inc (dwarf, bytes); + else + abbrev_offset = read_8ubyte_unaligned_inc (dwarf, bytes); + if (abbrev_offsetp != NULL) + *abbrev_offsetp = abbrev_offset; + + /* The address size. Always an 8-bit value. */ + uint8_t address_size = *bytes++; + if (address_sizep != NULL) + *address_sizep = address_size; + + /* Store the offset size. */ + if (offset_sizep != NULL) + *offset_sizep = offset_size; + + /* Store the header length. */ + if (header_sizep != NULL) + *header_sizep = (bytes + - ((char *) dwarf->sectiondata[IDX_debug_info]->d_buf + + off)); + + /* See above for an explanation of the trick in this formula. */ + *next_off = off + 2 * offset_size - 4 + length; + + return 0; +} +INTDEF(dwarf_nextcu) diff --git a/libdw/dwarf_offabbrev.c b/libdw/dwarf_offabbrev.c new file mode 100644 index 00000000..97370d60 --- /dev/null +++ b/libdw/dwarf_offabbrev.c @@ -0,0 +1,36 @@ +/* Get abbreviation at given offset. + Copyright (C) 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *abbrevp) +{ + if (dbg == NULL) + return -1; + + Dwarf_Abbrev *abbrev = __libdw_getabbrev (dbg, NULL, offset, lengthp, + abbrevp); + + if (abbrev == NULL) + return -1; + + return abbrev == DWARF_END_ABBREV ? 1 : 0; +} diff --git a/libdw/dwarf_offdie.c b/libdw/dwarf_offdie.c new file mode 100644 index 00000000..84300e1a --- /dev/null +++ b/libdw/dwarf_offdie.c @@ -0,0 +1,55 @@ +/* Return DIE at given offset. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "libdwP.h" + + +Dwarf_Die * +dwarf_offdie (dbg, offset, result) + Dwarf *dbg; + Dwarf_Off offset; + Dwarf_Die *result; +{ + if (dbg == NULL) + return NULL; + + if (offset >= dbg->sectiondata[IDX_debug_info]->d_size) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + result->addr = (char *) dbg->sectiondata[IDX_debug_info]->d_buf + offset; + + /* Get the CU. */ + result->cu = __libdw_findcu (dbg, offset); + if (result->cu == NULL) + { + /* This should never happen. The input file is malformed. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + result = NULL; + } + + return result; +} +INTDEF(dwarf_offdie) diff --git a/libdw/dwarf_onearange.c b/libdw/dwarf_onearange.c new file mode 100644 index 00000000..0c372526 --- /dev/null +++ b/libdw/dwarf_onearange.c @@ -0,0 +1,35 @@ +/* Return one of the address range entries. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Arange * +dwarf_onearange (Dwarf_Aranges *aranges, size_t idx) +{ + if (aranges == NULL) + return NULL; + + if (idx >= aranges->naranges) + { + __libdw_seterrno (DWARF_E_INVALID_ARANGE_IDX); + return NULL; + } + + return &aranges->info[idx]; +} diff --git a/libdw/dwarf_onesrcline.c b/libdw/dwarf_onesrcline.c new file mode 100644 index 00000000..9234ef9a --- /dev/null +++ b/libdw/dwarf_onesrcline.c @@ -0,0 +1,35 @@ +/* Return one of the sources lines of a CU. + Copyright (C) 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Line * +dwarf_onesrcline (Dwarf_Lines *lines, size_t idx) +{ + if (lines == NULL) + return NULL; + + if (idx >= lines->nlines) + { + __libdw_seterrno (DWARF_E_INVALID_LINE_IDX); + return NULL; + } + + return &lines->info[idx]; +} diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c new file mode 100644 index 00000000..bd965ea8 --- /dev/null +++ b/libdw/dwarf_siblingof.c @@ -0,0 +1,115 @@ +/* Return sibling of given DIE. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> +#include <string.h> + + +int +dwarf_siblingof (die, result) + Dwarf_Die *die; + Dwarf_Die *result; +{ + /* Ignore previous errors. */ + if (die == NULL) + return -1; + + unsigned int level = 0; + + /* Copy of the current DIE. */ + Dwarf_Die this_die = *die; + /* Temporary attributes we create. */ + Dwarf_Attribute sibattr; + /* Copy of the CU in the request. */ + sibattr.cu = this_die.cu; + /* That's the address we start looking. */ + unsigned char *addr = this_die.addr; + /* End of the buffer. */ + unsigned char *endp + = ((unsigned char *) sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf + + sibattr.cu->end); + + /* Search for the beginning of the next die on this level. We + must not return the dies for children of the given die. */ + do + { + /* Find the end of the DIE or the sibling attribute. */ + addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code, + &sibattr.form); + if (sibattr.code == DW_AT_sibling) + { + Dwarf_Off offset; + sibattr.valp = addr; + if (INTUSE(dwarf_formref) (&sibattr, &offset) != 0) + /* Something went wrong. */ + return -1; + + /* Compute the next address. */ + addr = ((unsigned char *) + sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf + + sibattr.cu->start + offset); + } + else if (unlikely (addr == NULL) + || unlikely (this_die.abbrev == (Dwarf_Abbrev *) -1l)) + return -1; + else if (this_die.abbrev->has_children) + /* This abbreviation has children. */ + ++level; + + + while (1) + { + /* Make sure we are still in range. Some producers might skip + the trailing NUL bytes. */ + if (addr >= endp) + return 1; + + if (*addr != '\0') + break; + + if (level-- == 0) + /* No more sibling at all. */ + return 1; + + ++addr; + } + + /* Initialize the 'current DIE'. */ + this_die.addr = addr; + this_die.abbrev = NULL; + } + while (level > 0); + + /* Maybe we reached the end of the CU. */ + if (addr >= endp) + return 1; + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + /* We have the address. */ + result->addr = addr; + + /* Same CU as the parent. */ + result->cu = sibattr.cu; + + return 0; +} +INTDEF(dwarf_siblingof) diff --git a/libdw/dwarf_srclang.c b/libdw/dwarf_srclang.c new file mode 100644 index 00000000..3fb06a1e --- /dev/null +++ b/libdw/dwarf_srclang.c @@ -0,0 +1,33 @@ +/* Return source language attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_srclang (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_language, + &attr_mem), + &value) == 0 ? (int) value : -1; +} diff --git a/libdw/dwarf_tag.c b/libdw/dwarf_tag.c new file mode 100644 index 00000000..939b6811 --- /dev/null +++ b/libdw/dwarf_tag.c @@ -0,0 +1,82 @@ +/* Return tag of given DIE. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Abbrev * +internal_function_def +__libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code) +{ + Dwarf_Abbrev *abb; + + /* See whether the entry is already in the hash table. */ + abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL); + if (abb == NULL) + while (cu->last_abbrev_offset != (size_t) -1l) + { + size_t length; + + /* Find the next entry. It gets automatically added to the + hash table. */ + abb = __libdw_getabbrev (cu->dbg, cu, cu->last_abbrev_offset, &length, + NULL); + if (abb == NULL || abb == DWARF_END_ABBREV) + { + /* Make sure we do not try to search for it again. */ + cu->last_abbrev_offset = (size_t) -1l; + abb = (void *) -1l; + break; + } + + cu->last_abbrev_offset += length; + + /* Is this the code we are looking for? */ + if (abb->code == code) + break; + } + + return abb; +} + + +int +dwarf_tag (die) + Dwarf_Die *die; +{ + /* Do we already know the abbreviation? */ + if (die->abbrev == NULL) + { + /* Get the abbreviation code. */ + unsigned int u128; + const unsigned char *addr = die->addr; + get_uleb128 (u128, addr); + + /* Find the abbreviation. */ + die->abbrev = __libdw_findabbrev (die->cu, u128); + } + + if (die->abbrev == (Dwarf_Abbrev *) -1l) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return DW_TAG_invalid; + } + + return die->abbrev->tag; +} +INTDEF(dwarf_tag) diff --git a/libdw/dwarf_whatattr.c b/libdw/dwarf_whatattr.c new file mode 100644 index 00000000..ad5d868f --- /dev/null +++ b/libdw/dwarf_whatattr.c @@ -0,0 +1,28 @@ +/* Return attribute code of given attribute. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_whatattr (attr) + Dwarf_Attribute *attr; +{ + return attr == NULL ? 0 : attr->code; +} diff --git a/libdw/dwarf_whatform.c b/libdw/dwarf_whatform.c new file mode 100644 index 00000000..99da1c97 --- /dev/null +++ b/libdw/dwarf_whatform.c @@ -0,0 +1,28 @@ +/* Return form code of given attribute. + Copyright (C) 2003 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_whatform (attr) + Dwarf_Attribute *attr; +{ + return attr == NULL ? 0 : attr->form; +} diff --git a/libdw/libdw.h b/libdw/libdw.h new file mode 100644 index 00000000..786be22a --- /dev/null +++ b/libdw/libdw.h @@ -0,0 +1,564 @@ +/* Interfaces for libdw. + Copyright (C) 2002, 2004, 2005 Red Hat, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDW_H +#define _LIBDW_H 1 + +#include <gelf.h> +#include <stdbool.h> +#include <stddef.h> + + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +# define __nonnull_attribute__(...) __attribute__ ((__nonnull__ (__VA_ARGS__))) +#else +# define __nonnull_attribute__(args...) +#endif + + +/* Mode for the session. */ +typedef enum + { + DWARF_C_READ, /* Read .. */ + DWARF_C_RDWR, /* Read and write .. */ + DWARF_C_WRITE, /* Write .. */ + } +Dwarf_Cmd; + + +/* Callback results. */ +enum +{ + DWARF_CB_OK = 0, + DWARF_CB_ABORT +}; + + +/* Error values. */ +enum + { + DW_TAG_invalid = 0 +#define DW_TAG_invalid DW_TAG_invalid + }; + + +/* Type for offset in DWARF file. */ +typedef GElf_Off Dwarf_Off; + +/* Type for address in DWARF file. */ +typedef GElf_Addr Dwarf_Addr; + +/* Integer types. Big enough to hold any numeric value. */ +typedef GElf_Xword Dwarf_Word; +typedef GElf_Sxword Dwarf_Sword; +/* For the times we know we do not need that much. */ +typedef GElf_Half Dwarf_Half; + + +/* DWARF abbreviation record. */ +typedef struct Dwarf_Abbrev Dwarf_Abbrev; + +/* Returned to show the last DIE has be returned. */ +#define DWARF_END_ABBREV ((Dwarf_Abbrev *) -1l) + +/* Source code line information for CU. */ +typedef struct Dwarf_Lines_s Dwarf_Lines; + +/* One source code line information. */ +typedef struct Dwarf_Line_s Dwarf_Line; + +/* Source file information. */ +typedef struct Dwarf_Files_s Dwarf_Files; + +/* One address range record. */ +typedef struct Dwarf_Arange_s Dwarf_Arange; + +/* Address ranges of a file. */ +typedef struct Dwarf_Aranges_s Dwarf_Aranges; + +/* CU representation. */ +struct Dwarf_CU; + +/* Function information. */ +typedef struct Dwarf_Func_s Dwarf_Func; + +/* Macro information. */ +typedef struct Dwarf_Macro_s Dwarf_Macro; + +/* Attribute representation. */ +typedef struct +{ + unsigned int code; + unsigned int form; + unsigned char *valp; + struct Dwarf_CU *cu; +} Dwarf_Attribute; + + +/* Data block representation. */ +typedef struct +{ + Dwarf_Word length; + unsigned char *data; +} Dwarf_Block; + + +/* DIE information. */ +typedef struct +{ + /* The offset can be computed from the address. */ + void *addr; + struct Dwarf_CU *cu; + Dwarf_Abbrev *abbrev; + // XXX We'll see what other information will be needed. + long int padding__; +} Dwarf_Die; + +/* Returned to show the last DIE has be returned. */ +#define DWARF_END_DIE ((Dwarf_Die *) -1l) + + +/* Global symbol information. */ +typedef struct +{ + Dwarf_Off cu_offset; + Dwarf_Off die_offset; + const char *name; +} Dwarf_Global; + + +// XXX It remains to be seen whether the next two need to be exported. +/* Location record. */ +typedef struct +{ + uint8_t atom; /* Operation */ + Dwarf_Word number; /* Operand */ + Dwarf_Word number2; /* Possible second operand */ + Dwarf_Word offset; /* Offset in location expression */ +} Dwarf_Loc; + + +/* Handle for debug sessions. */ +typedef struct Dwarf Dwarf; + + +/* Out-Of-Memory handler. */ +#if __GNUC__ < 4 +typedef void (*Dwarf_OOM) (void); +#else +typedef void (*__attribute__ ((noreturn)) Dwarf_OOM) (void); +#endif + + +/* Create a handle for a new debug session. */ +extern Dwarf *dwarf_begin (int fildes, Dwarf_Cmd cmd); + +/* Create a handle for a new debug session for an ELF file. */ +extern Dwarf *dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp); + +/* Retrieve ELF descriptor used for DWARF access. */ +extern Elf *dwarf_getelf (Dwarf *dwarf); + +/* Release debugging handling context. */ +extern int dwarf_end (Dwarf *dwarf); + + +/* Get the data block for the .debug_info section. */ +extern Elf_Data *dwarf_getscn_info (Dwarf *dwarf); + +/* Read the header for the DWARF CU header. */ +extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off, + size_t *header_sizep, Dwarf_Off *abbrev_offsetp, + uint8_t *address_sizep, uint8_t *offset_sizep) + __nonnull_attribute__ (3); + + +/* Return DIE at given offset. */ +extern Dwarf_Die *dwarf_offdie (Dwarf *dbg, Dwarf_Off offset, + Dwarf_Die *result) __nonnull_attribute__ (3); + +/* Return offset of DIE. */ +extern Dwarf_Off dwarf_dieoffset (Dwarf_Die *die); + +/* Return offset of DIE in CU. */ +extern Dwarf_Off dwarf_cuoffset (Dwarf_Die *die); + +/* Return CU DIE containing given address. */ +extern Dwarf_Die *dwarf_addrdie (Dwarf *dbg, Dwarf_Addr addr, + Dwarf_Die *result) __nonnull_attribute__ (3); + +/* Return child of current DIE. */ +extern int dwarf_child (Dwarf_Die *die, Dwarf_Die *result) + __nonnull_attribute__ (2); + +/* Return sibling of given DIE. */ +extern int dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result) + __nonnull_attribute__ (2); + +/* Check whether the DIE has children. */ +extern int dwarf_haschildren (Dwarf_Die *die); + +/* Get attributes of the DIE. */ +extern ptrdiff_t dwarf_getattrs (Dwarf_Die *die, + int (*callback) (Dwarf_Attribute *, void *), + void *arg, ptrdiff_t offset); + +/* Return tag of given DIE. */ +extern int dwarf_tag (Dwarf_Die *die); + + +/* Return specific attribute of DIE. */ +extern Dwarf_Attribute *dwarf_attr (Dwarf_Die *die, unsigned int search_name, + Dwarf_Attribute *result) + __nonnull_attribute__ (3); + +/* Check whether given DIE has specific attribute. */ +extern int dwarf_hasattr (Dwarf_Die *die, unsigned int search_name); + +/* These are the same as dwarf_attr and dwarf_hasattr, respectively, + but they resolve an indirect attribute through DW_AT_abstract_origin. */ +extern Dwarf_Attribute *dwarf_attr_integrate (Dwarf_Die *die, + unsigned int search_name, + Dwarf_Attribute *result) + __nonnull_attribute__ (3); +extern int dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name); + + + + +/* Check whether given attribute has specific form. */ +extern int dwarf_hasform (Dwarf_Attribute *attr, unsigned int search_form); + +/* Return attribute code of given attribute. */ +extern unsigned int dwarf_whatattr (Dwarf_Attribute *attr); + +/* Return form code of given attribute. */ +extern unsigned int dwarf_whatform (Dwarf_Attribute *attr); + + +/* Return string associated with given attribute. */ +extern const char *dwarf_formstring (Dwarf_Attribute *attrp); + +/* Return unsigned constant represented by attribute. */ +extern int dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) + __nonnull_attribute__ (2); + +/* Return signed constant represented by attribute. */ +extern int dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_uval) + __nonnull_attribute__ (2); + +/* Return address represented by attribute. */ +extern int dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return reference offset represented by attribute. */ +extern int dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset) + __nonnull_attribute__ (2); + +/* Look up the DIE in a reference-form attribute. */ +extern Dwarf_Die *dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem) + __nonnull_attribute__ (2); + +/* Return block represented by attribute. */ +extern int dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block) + __nonnull_attribute__ (2); + +/* Return flag represented by attribute. */ +extern int dwarf_formflag (Dwarf_Attribute *attr, bool *return_bool) + __nonnull_attribute__ (2); + + +/* Simplified attribute value access functions. */ + +/* Return string in name attribute of DIE. */ +extern const char *dwarf_diename (Dwarf_Die *die); + +/* Return high PC attribute of DIE. */ +extern int dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return low PC attribute of DIE. */ +extern int dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return 1 if DIE's lowpc/highpc or ranges attributes match the PC address, + 0 if not, or -1 for errors. */ +extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc); + +/* Return byte size attribute of DIE. */ +extern int dwarf_bytesize (Dwarf_Die *die); + +/* Return bit size attribute of DIE. */ +extern int dwarf_bitsize (Dwarf_Die *die); + +/* Return bit offset attribute of DIE. */ +extern int dwarf_bitoffset (Dwarf_Die *die); + +/* Return array order attribute of DIE. */ +extern int dwarf_arrayorder (Dwarf_Die *die); + +/* Return source language attribute of DIE. */ +extern int dwarf_srclang (Dwarf_Die *die); + + +/* Get abbreviation at given offset for given DIE. */ +extern Dwarf_Abbrev *dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, + size_t *lengthp); + +/* Get abbreviation at given offset in .debug_abbrev section. */ +extern int dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *abbrevp) + __nonnull_attribute__ (4); + +/* Get abbreviation code. */ +extern unsigned int dwarf_getabbrevcode (Dwarf_Abbrev *abbrev); + +/* Get abbreviation tag. */ +extern unsigned int dwarf_getabbrevtag (Dwarf_Abbrev *abbrev); + +/* Return true if abbreviation is children flag set. */ +extern int dwarf_abbrevhaschildren (Dwarf_Abbrev *abbrev); + +/* Get number of attributes of abbreviation. */ +extern int dwarf_getattrcnt (Dwarf_Abbrev *abbrev, size_t *attrcntp) + __nonnull_attribute__ (2); + +/* Get specific attribute of abbreviation. */ +extern int dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, + unsigned int *namep, unsigned int *formp, + Dwarf_Off *offset); + + +/* Get string from-debug_str section. */ +extern const char *dwarf_getstring (Dwarf *dbg, Dwarf_Off offset, + size_t *lenp); + + +/* Get public symbol information. */ +extern ptrdiff_t dwarf_getpubnames (Dwarf *dbg, + int (*callback) (Dwarf *, Dwarf_Global *, + void *), + void *arg, ptrdiff_t offset) + __nonnull_attribute__ (2); + + +/* Get source file information for CU. */ +extern int dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, + size_t *nlines) __nonnull_attribute__ (2, 3); + +/* Return one of the source lines of the CU. */ +extern Dwarf_Line *dwarf_onesrcline (Dwarf_Lines *lines, size_t idx); + +/* Get the file source files used in the CU. */ +extern int dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, + size_t *nfiles) + __nonnull_attribute__ (2); + + +/* Get source for address in CU. */ +extern Dwarf_Line *dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr); + +/* Get source for file and line number. */ +extern int dwarf_getsrc_file (Dwarf *dbg, const char *fname, int line, int col, + Dwarf_Line ***srcsp, size_t *nsrcs) + __nonnull_attribute__ (2, 5, 6); + + +/* Return line address. */ +extern int dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp); + +/* Return line number. */ +extern int dwarf_lineno (Dwarf_Line *line, int *linep) + __nonnull_attribute__ (2); + +/* Return column in line. */ +extern int dwarf_linecol (Dwarf_Line *line, int *colp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of a statement. */ +extern int dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for end of sequence. */ +extern int dwarf_lineendsequence (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of a basic block. */ +extern int dwarf_lineblock (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for end of prologue. */ +extern int dwarf_lineprologueend (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of epilogue. */ +extern int dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + + +/* Find line information for address. */ +extern const char *dwarf_linesrc (Dwarf_Line *line, + Dwarf_Word *mtime, Dwarf_Word *length); + +/* Return file information. */ +extern const char *dwarf_filesrc (Dwarf_Files *file, size_t idx, + Dwarf_Word *mtime, Dwarf_Word *length); + + +/* Return location expression list. */ +extern int dwarf_getloclist (Dwarf_Attribute *attr, Dwarf_Loc **llbuf, + size_t *listlen) __nonnull_attribute__ (2, 3); + +/* Return location expression lists. If the attribute uses a location + list, ADDRESS selects the relevant location expressions from the list. + There can be multiple matches, resulting in multiple expressions to + return. LLBUFS and LISTLENS are parallel arrays of NLOCS slots to fill + in. Returns the number of locations filled in, or -1 for errors. If + LLBUFS is a null pointer, stores nothing and returns the total number of + locations. A return value of zero means that the location list + indicated no value is accessible. */ +extern int dwarf_addrloclists (Dwarf_Attribute *attr, Dwarf_Addr address, + Dwarf_Loc **llbufs, size_t *listlens, + size_t nlocs); + + +/* Return scope DIEs containing PC address. + Sets *SCOPES to a malloc'd array of Dwarf_Die structures, + and returns the number of elements in the array. + (*SCOPES)[0] is the DIE for the innermost scope containing PC, + (*SCOPES)[1] is the DIE for the scope containing that scope, and so on. + Returns -1 for errors or 0 if no scopes match PC. */ +extern int dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, + Dwarf_Die **scopes); + +/* Search SCOPES[0..NSCOPES-1] for a variable called NAME. + Ignore the first SKIP_SHADOWS scopes that match the name. + If MATCH_FILE is not null, accept only declaration in that source file; + if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration + at that line and column. + + If successful, fill in *RESULT with the DIE of the variable found, + and return N where SCOPES[N] is the scope defining the variable. + Return -1 for errors or -2 for no matching variable found. */ +extern int dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, + const char *name, int skip_shadows, + const char *match_file, + int match_lineno, int match_linecol, + Dwarf_Die *result); + + + +/* Return list address ranges. */ +extern int dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, + size_t *naranges) + __nonnull_attribute__ (2); + +/* Return one of the address range entries. */ +extern Dwarf_Arange *dwarf_onearange (Dwarf_Aranges *aranges, size_t idx); + +/* Return information in address range record. */ +extern int dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp, + Dwarf_Word *lengthp, Dwarf_Off *offsetp); + +/* Get address range which includes given address. */ +extern Dwarf_Arange *dwarf_getarange_addr (Dwarf_Aranges *aranges, + Dwarf_Addr addr); + + + +/* Get functions in CUDIE. */ +extern ptrdiff_t dwarf_getfuncs (Dwarf_Die *cudie, + int (*callback) (Dwarf_Func *, void *), + void *arg, ptrdiff_t offset); + +/* Return name of function. */ +extern const char *dwarf_func_name (Dwarf_Func *func); + +/* Return start address of function. */ +extern int dwarf_func_lowpc (Dwarf_Func *func, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return end address of function. */ +extern int dwarf_func_highpc (Dwarf_Func *func, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return entry point address of function. */ +extern int dwarf_func_entrypc (Dwarf_Func *func, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return file name containing definition of the given function. */ +extern const char *dwarf_func_file (Dwarf_Func *func); + +/* Get line number of beginning of given function. */ +extern int dwarf_func_line (Dwarf_Func *func, int *linep) + __nonnull_attribute__ (2); + +/* Get column number of beginning of given function. */ +extern int dwarf_func_col (Dwarf_Func *func, int *colp) + __nonnull_attribute__ (2); + + +/* Call callback function for each of the macro information entry for + the CU. */ +extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie, + int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t offset) + __nonnull_attribute__ (2); + +/* Return macro opcode. */ +extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep) + __nonnull_attribute__ (2); + +/* Return first macro parameter. */ +extern int dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp) + __nonnull_attribute__ (2); + +/* Return second macro parameter. */ +extern int dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, + const char **strp); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int dwarf_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *dwarf_errmsg (int err); + + +/* Register new Out-Of-Memory handler. The old handler is returned. */ +extern Dwarf_OOM dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler); + + +/* Inline optimizations. */ +#ifdef __OPTIMIZE__ +/* Return attribute code of given attribute. */ +extern inline unsigned int +dwarf_whatattr (Dwarf_Attribute *attr) +{ + return attr == NULL ? 0 : attr->code; +} + +/* Return attribute code of given attribute. */ +extern inline unsigned int +dwarf_whatform (Dwarf_Attribute *attr) +{ + return attr == NULL ? 0 : attr->form; +} +#endif /* Optimize. */ + +#endif /* libdw.h */ diff --git a/libdw/libdw.map b/libdw/libdw.map new file mode 100644 index 00000000..ed3c989a --- /dev/null +++ b/libdw/libdw.map @@ -0,0 +1,92 @@ +ELFUTILS_1.0 { + global: + dwarf_abbrevhaschildren; + dwarf_addrdie; + dwarf_addrloclists; + dwarf_attr; + dwarf_attr_integrate; + dwarf_arrayorder; + dwarf_begin; + dwarf_begin_elf; + dwarf_bitoffset; + dwarf_bitsize; + dwarf_bytesize; + dwarf_child; + dwarf_cuoffset; + dwarf_diename; + dwarf_dieoffset; + dwarf_end; + dwarf_errmsg; + dwarf_errno; + dwarf_filesrc; + dwarf_formaddr; + dwarf_formblock; + dwarf_formflag; + dwarf_formref; + dwarf_formref_die; + dwarf_formsdata; + dwarf_formstring; + dwarf_formudata; + dwarf_func_col; + dwarf_func_entrypc; + dwarf_func_file; + dwarf_func_highpc; + dwarf_func_line; + dwarf_func_lowpc; + dwarf_func_name; + dwarf_getabbrev; + dwarf_getabbrevattr; + dwarf_getabbrevcode; + dwarf_getabbrevtag; + dwarf_getarange_addr; + dwarf_getarangeinfo; + dwarf_getaranges; + dwarf_getattrcnt; + dwarf_getattrs; + dwarf_getelf; + dwarf_getfuncs; + dwarf_getloclist; + dwarf_getmacros; + dwarf_getpubnames; + dwarf_getscopes; + dwarf_getscopevar; + dwarf_getscn_info; + dwarf_getsrc_die; + dwarf_getsrc_file; + dwarf_getsrcfiles; + dwarf_getsrclines; + dwarf_getstring; + dwarf_hasattr; + dwarf_hasattr_integrate; + dwarf_haspc; + dwarf_haschildren; + dwarf_hasform; + dwarf_highpc; + dwarf_lineaddr; + dwarf_linebeginstatement; + dwarf_lineblock; + dwarf_linecol; + dwarf_lineendsequence; + dwarf_lineepiloguebegin; + dwarf_lineno; + dwarf_lineprologueend; + dwarf_linesrc; + dwarf_lowpc; + dwarf_macro_opcode; + dwarf_macro_param1; + dwarf_macro_param2; + dwarf_offabbrev; + dwarf_offdie; + dwarf_onearange; + dwarf_onesrcline; + dwarf_nextcu; + dwarf_new_oom_handler; + dwarf_siblingof; + dwarf_srclang; + dwarf_tag; + dwarf_whatattr; + dwarf_whatform; + + local: + *; +}; diff --git a/libdw/libdwP.h b/libdw/libdwP.h new file mode 100644 index 00000000..05e02aa3 --- /dev/null +++ b/libdw/libdwP.h @@ -0,0 +1,378 @@ +/* Internal definitions for libdwarf. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _LIBDWP_H +#define _LIBDWP_H 1 + +#include <libintl.h> +#include <stdbool.h> + +#include <libdw.h> + + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +/* Version of the DWARF specification we support. */ +#define DWARF_VERSION 2 + +/* Version of the CIE format. */ +#define CIE_VERSION 1 + + +/* Known location lists. */ +struct loc_s +{ + void *addr; + Dwarf_Loc *loc; + size_t nloc; +}; + +/* Valid indeces for the section data. */ +enum + { + IDX_debug_info = 0, + IDX_debug_abbrev, + IDX_debug_aranges, + IDX_debug_line, + IDX_debug_frame, + IDX_eh_frame, + IDX_debug_loc, + IDX_debug_pubnames, + IDX_debug_str, + IDX_debug_funcnames, + IDX_debug_typenames, + IDX_debug_varnames, + IDX_debug_weaknames, + IDX_debug_macinfo, + IDX_debug_ranges, + IDX_last + }; + + +/* Error values. */ +enum +{ + DWARF_E_NOERROR = 0, + DWARF_E_UNKNOWN_ERROR, + DWARF_E_INVALID_ACCESS, + DWARF_E_NO_REGFILE, + DWARF_E_IO_ERROR, + DWARF_E_INVALID_ELF, + DWARF_E_NO_DWARF, + DWARF_E_NOELF, + DWARF_E_GETEHDR_ERROR, + DWARF_E_NOMEM, + DWARF_E_UNIMPL, + DWARF_E_INVALID_CMD, + DWARF_E_INVALID_VERSION, + DWARF_E_INVALID_FILE, + DWARF_E_NO_ENTRY, + DWARF_E_INVALID_DWARF, + DWARF_E_NO_STRING, + DWARF_E_NO_ADDR, + DWARF_E_NO_CONSTANT, + DWARF_E_NO_REFERENCE, + DWARF_E_INVALID_REFERENCE, + DWARF_E_NO_DEBUG_LINE, + DWARF_E_INVALID_DEBUG_LINE, + DWARF_E_TOO_BIG, + DWARF_E_VERSION, + DWARF_E_INVALID_DIR_IDX, + DWARF_E_ADDR_OUTOFRANGE, + DWARF_E_NO_LOCLIST, + DWARF_E_NO_BLOCK, + DWARF_E_INVALID_LINE_IDX, + DWARF_E_INVALID_ARANGE_IDX, + DWARF_E_NO_MATCH, + DWARF_E_NO_FLAG, + DWARF_E_INVALID_OFFSET, + DWARF_E_NO_DEBUG_RANGES, +}; + + +/* This is the structure representing the debugging state. */ +struct Dwarf +{ + /* The underlying ELF file. */ + Elf *elf; + + /* The section data. */ + Elf_Data *sectiondata[IDX_last]; + + /* True if the file has a byte order different from the host. */ + bool other_byte_order; + + /* If true, we allocated the ELF descriptor ourselves. */ + bool free_elf; + + /* Information for traversing the .debug_pubnames section. This is + an array and separately allocated with malloc. */ + struct pubnames_s + { + Dwarf_Off cu_offset; + Dwarf_Off set_start; + unsigned int cu_header_size; + int address_len; + } *pubnames_sets; + size_t pubnames_nsets; + + /* Search tree for the CUs. */ + void *cu_tree; + Dwarf_Off next_cu_offset; + + /* Address ranges. */ + Dwarf_Aranges *aranges; + + /* Internal memory handling. This is basically a simplified + reimplementation of obstacks. Unfortunately the standard obstack + implementation is not usable in libraries. */ + struct libdw_memblock + { + size_t size; + size_t remaining; + struct libdw_memblock *prev; + char mem[0]; + } *mem_tail; + + /* Default size of allocated memory blocks. */ + size_t mem_default_size; + + /* Registered OOM handler. */ + Dwarf_OOM oom_handler; +}; + + +/* Abbreviation representation. */ +struct Dwarf_Abbrev +{ + unsigned int code; + unsigned int tag; + int has_children; + unsigned int attrcnt; + unsigned char *attrp; + Dwarf_Off offset; +}; + +#include "dwarf_abbrev_hash.h" + + +/* Files in line information records. */ +struct Dwarf_Files_s + { + Dwarf *dbg; + unsigned int nfiles; + struct Dwarf_Fileinfo_s + { + char *name; + Dwarf_Word mtime; + Dwarf_Word length; + } info[0]; + }; +typedef struct Dwarf_Fileinfo_s Dwarf_Fileinfo; + + +/* Representation of a row in the line table. */ +struct Dwarf_Lines_s + { + size_t nlines; + + struct Dwarf_Line_s + { + Dwarf_Addr addr; + unsigned int file; + int line; + unsigned short int column; + unsigned int is_stmt:1; + unsigned int basic_block:1; + unsigned int end_sequence:1; + unsigned int prologue_end:1; + unsigned int epilogue_begin:1; + + Dwarf_Files *files; + } info[0]; + }; + + +/* Representation of address ranges. */ +struct Dwarf_Aranges_s +{ + Dwarf *dbg; + size_t naranges; + + struct Dwarf_Arange_s + { + Dwarf_Addr addr; + Dwarf_Word length; + Dwarf_Off offset; + } info[0]; +}; + + +/* CU representation. */ +struct Dwarf_CU +{ + Dwarf *dbg; + Dwarf_Off start; + Dwarf_Off end; + uint8_t address_size; + uint8_t offset_size; + + /* Hash table for the abbreviations. */ + Dwarf_Abbrev_Hash abbrev_hash; + /* Offset of the first abbreviation. */ + size_t orig_abbrev_offset; + /* Offset past last read abbreviation. */ + size_t last_abbrev_offset; + + /* The srcline information. */ + Dwarf_Lines *lines; + + /* The source file information. */ + Dwarf_Files *files; + + /* Known location lists. */ + void *locs; +}; + + +/* Function information. */ +struct Dwarf_Func_s +{ + // XXX If we want to cache functions, we need to change this struct. + Dwarf_Die *die; + Dwarf_Die *cudie; +}; + + +/* Macro information. */ +struct Dwarf_Macro_s +{ + unsigned int opcode; + Dwarf_Word param1; + union + { + Dwarf_Word u; + const char *s; + } param2; +}; + + +/* We have to include the file at this point because the inline + functions access internals of the Dwarf structure. */ +#include "memory-access.h" + + +/* Set error value. */ +extern void __libdw_seterrno (int value) internal_function; + + +/* Memory handling, the easy parts. This macro does not do any locking. */ +#define libdw_alloc(dbg, type, tsize, cnt) \ + ({ struct libdw_memblock *_tail = (dbg)->mem_tail; \ + size_t _required = (tsize) * (cnt); \ + type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\ + size_t _padding = ((__alignof (type) \ + - ((uintptr_t) _result & (__alignof (type) - 1))) \ + & (__alignof (type) - 1)); \ + if (unlikely (_tail->remaining < _required + _padding)) \ + { \ + _result = (type *) __libdw_allocate (dbg, _required); \ + _tail = (dbg)->mem_tail; \ + } \ + else \ + { \ + _required += _padding; \ + _result = (type *) ((char *) _result + _padding); \ + } \ + _tail->remaining -= _required; \ + _result; }) + +#define libdw_typed_alloc(dbg, type) \ + libdw_alloc (dbg, type, sizeof (type), 1) + +/* Callback to allocate more. */ +extern void *__libdw_allocate (Dwarf *dbg, size_t minsize) + __attribute__ ((__malloc__)) __nonnull_attribute__ (1); + +/* Default OOM handler. */ +extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden"))); + +/* Find CU for given offset. */ +extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset) + __nonnull_attribute__ (1) internal_function; + +/* Return tag of given DIE. */ +extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu, + unsigned int code) + __nonnull_attribute__ (1) internal_function; + +/* Get abbreviation at given offset. */ +extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, + Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *result) + __nonnull_attribute__ (1) internal_function; + +/* Helper functions for form handling. */ +extern size_t __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, + unsigned int form, + const unsigned char *valp) + __nonnull_attribute__ (1, 2, 4) internal_function; + +/* Helper function to locate attribute. */ +extern unsigned char *__libdw_find_attr (Dwarf_Die *die, + unsigned int search_name, + unsigned int *codep, + unsigned int *formp) + __nonnull_attribute__ (1) internal_function; + +/* Helper function to access integer attribute. */ +extern int __libdw_func_intval (Dwarf_Func *func, int *linep, int attval) + __nonnull_attribute__ (1, 2) internal_function; + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int __dwarf_errno_internal (void); + + +/* Aliases to avoid PLTs. */ +INTDECL (dwarf_attr) +INTDECL (dwarf_attr_integrate) +INTDECL (dwarf_begin_elf) +INTDECL (dwarf_child) +INTDECL (dwarf_dieoffset) +INTDECL (dwarf_formaddr) +INTDECL (dwarf_formblock) +INTDECL (dwarf_formref) +INTDECL (dwarf_formref_die) +INTDECL (dwarf_formsdata) +INTDECL (dwarf_formstring) +INTDECL (dwarf_formudata) +INTDECL (dwarf_getarange_addr) +INTDECL (dwarf_getarangeinfo) +INTDECL (dwarf_getaranges) +INTDECL (dwarf_getsrcfiles) +INTDECL (dwarf_getsrclines) +INTDECL (dwarf_hasattr) +INTDECL (dwarf_haschildren) +INTDECL (dwarf_haspc) +INTDECL (dwarf_highpc) +INTDECL (dwarf_lowpc) +INTDECL (dwarf_nextcu) +INTDECL (dwarf_offdie) +INTDECL (dwarf_siblingof) +INTDECL (dwarf_tag) + +#endif /* libdwP.h */ diff --git a/libdw/libdw_alloc.c b/libdw/libdw_alloc.c new file mode 100644 index 00000000..1c53d366 --- /dev/null +++ b/libdw/libdw_alloc.c @@ -0,0 +1,59 @@ +/* Memory handling for libdw. + Copyright (C) 2003, 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <error.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/param.h> +#include "libdwP.h" + + +void * +__libdw_allocate (Dwarf *dbg, size_t minsize) +{ + size_t size = MAX (dbg->mem_default_size, + 2 * minsize + offsetof (struct libdw_memblock, mem)); + struct libdw_memblock *newp = malloc (size); + if (newp == NULL) + dbg->oom_handler (); + + newp->size = newp->remaining = size - offsetof (struct libdw_memblock, mem); + + newp->prev = dbg->mem_tail; + dbg->mem_tail = newp; + + return newp->mem; +} + + +Dwarf_OOM +dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler) +{ + Dwarf_OOM old = dbg->oom_handler; + dbg->oom_handler = handler; + return old; +} + + +void +__attribute ((noreturn, visibility ("hidden"))) +__libdw_oom (void) +{ + while (1) + error (EXIT_FAILURE, ENOMEM, "libdw"); +} diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c new file mode 100644 index 00000000..c1d3a451 --- /dev/null +++ b/libdw/libdw_findcu.c @@ -0,0 +1,110 @@ +/* Find CU for given offset. + Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <search.h> +#include "libdwP.h" + + +static int +findcu_cb (const void *arg1, const void *arg2) +{ + struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1; + struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2; + + /* Find out which of the two arguments is the search value. It has + end offset 0. */ + if (cu1->end == 0) + { + if (cu1->start < cu2->start) + return -1; + if (cu1->start >= cu2->end) + return 1; + } + else + { + if (cu2->start < cu1->start) + return 1; + if (cu2->start >= cu1->end) + return -1; + } + + return 0; +} + + +struct Dwarf_CU * +__libdw_findcu (dbg, start) + Dwarf *dbg; + Dwarf_Off start; +{ + /* Maybe we already know that CU. */ + struct Dwarf_CU fake = { .start = start, .end = 0 }; + struct Dwarf_CU **found = tfind (&fake, &dbg->cu_tree, findcu_cb); + if (found != NULL) + return *found; + + if (start < dbg->next_cu_offset) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* No. Then read more CUs. */ + while (1) + { + Dwarf_Off oldoff = dbg->next_cu_offset; + uint8_t address_size; + uint8_t offset_size; + Dwarf_Off abbrev_offset; + + if (INTUSE(dwarf_nextcu) (dbg, oldoff, &dbg->next_cu_offset, NULL, + &abbrev_offset, &address_size, &offset_size) + != 0) + /* No more entries. */ + return NULL; + + /* Create an entry for this CU. */ + struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU); + + newp->dbg = dbg; + newp->start = oldoff; + newp->end = dbg->next_cu_offset; + newp->address_size = address_size; + newp->offset_size = offset_size; + Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41); + newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset; + newp->lines = NULL; + newp->locs = NULL; + + /* Add the new entry to the search tree. */ + if (tsearch (newp, &dbg->cu_tree, findcu_cb) == NULL) + { + /* Something went wrong. Unfo the operation. */ + dbg->next_cu_offset = oldoff; + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + /* Is this the one we are looking for? */ + if (start < dbg->next_cu_offset) + // XXX Match exact offset. + return newp; + } + /* NOTREACHED */ +} diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c new file mode 100644 index 00000000..95d47140 --- /dev/null +++ b/libdw/libdw_form.c @@ -0,0 +1,112 @@ +/* Helper functions for form handling. + Copyright (C) 2003, 2004 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include <string.h> + +#include "libdwP.h" + + +size_t +internal_function_def +__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form, + const unsigned char *valp) +{ + const unsigned char *saved; + Dwarf_Word u128; + size_t result; + + switch (form) + { + case DW_FORM_addr: + result = cu->address_size; + break; + + case DW_FORM_strp: + case DW_FORM_ref_addr: + result = cu->offset_size; + break; + + case DW_FORM_block1: + result = *valp + 1; + break; + + case DW_FORM_block2: + result = read_2ubyte_unaligned (dbg, valp) + 2; + break; + + case DW_FORM_block4: + result = read_4ubyte_unaligned (dbg, valp) + 4; + break; + + case DW_FORM_block: + saved = valp; + get_uleb128 (u128, valp); + result = u128 + (valp - saved); + break; + + case DW_FORM_ref1: + case DW_FORM_data1: + case DW_FORM_flag: + result = 1; + break; + + case DW_FORM_data2: + case DW_FORM_ref2: + result = 2; + break; + + case DW_FORM_data4: + case DW_FORM_ref4: + result = 4; + break; + + case DW_FORM_data8: + case DW_FORM_ref8: + result = 8; + break; + + case DW_FORM_string: + result = strlen ((char *) valp) + 1; + break; + + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + saved = valp; + get_uleb128 (u128, valp); + result = valp - saved; + break; + + case DW_FORM_indirect: + saved = valp; + get_uleb128 (u128, valp); + // XXX Is this really correct? + result = __libdw_form_val_len (dbg, cu, u128, valp); + if (result != (size_t) -1) + result += valp - saved; + break; + + default: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + result = (size_t) -1l; + break; + } + + return result; +} diff --git a/libdw/memory-access.c b/libdw/memory-access.c new file mode 100644 index 00000000..04899a81 --- /dev/null +++ b/libdw/memory-access.c @@ -0,0 +1,35 @@ +/* Out of line functions for memory-access.h macros. + Copyright (C) 2005 Red Hat, Inc. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "libdwP.h" +#include "memory-access.h" + +uint64_t +internal_function_def +__libdw_get_uleb128 (uint64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + get_uleb128_rest_return (acc, i, addrp); +} + +int64_t +internal_function_def +__libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + int64_t _v = acc; + get_sleb128_rest_return (acc, i, addrp); +} diff --git a/libdw/memory-access.h b/libdw/memory-access.h new file mode 100644 index 00000000..8efd8993 --- /dev/null +++ b/libdw/memory-access.h @@ -0,0 +1,240 @@ +/* Unaligned memory access functionality. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifndef _MEMORY_ACCESS_H +#define _MEMORY_ACCESS_H 1 + +#include <byteswap.h> +#include <limits.h> +#include <stdint.h> + + +/* Number decoding macros. See 7.6 Variable Length Data. */ + +#define get_uleb128_step(var, addr, nth, break) \ + __b = *(addr)++; \ + var |= (uintmax_t) (__b & 0x7f) << (nth * 7); \ + if (likely ((__b & 0x80) == 0)) \ + break + +#define get_uleb128(var, addr) \ + do { \ + unsigned char __b; \ + var = 0; \ + get_uleb128_step (var, addr, 0, break); \ + var = __libdw_get_uleb128 (var, 1, &(addr)); \ + } while (0) + +#define get_uleb128_rest_return(var, i, addrp) \ + do { \ + for (; i < 10; ++i) \ + { \ + get_uleb128_step (var, *addrp, i, return var); \ + } \ + /* Other implementations set VALUE to UINT_MAX in this \ + case. So we better do this as well. */ \ + return UINT64_MAX; \ + } while (0) + +/* The signed case is similar, but we sign-extend the result. */ + +#define get_sleb128_step(var, addr, nth, break) \ + __b = *(addr)++; \ + _v |= (uint64_t) (__b & 0x7f) << (nth * 7); \ + if (likely ((__b & 0x80) == 0)) \ + { \ + var = (_v << (64 - (nth * 7) - 7) >> (64 - (nth * 7) - 7)); \ + break; \ + } \ + else do {} while (0) + +#define get_sleb128(var, addr) \ + do { \ + unsigned char __b; \ + int64_t _v = 0; \ + get_sleb128_step (var, addr, 0, break); \ + var = __libdw_get_sleb128 (_v, 1, &(addr)); \ + } while (0) + +#define get_sleb128_rest_return(var, i, addrp) \ + do { \ + for (; i < 9; ++i) \ + { \ + get_sleb128_step (var, *addrp, i, return var); \ + } \ + /* Other implementations set VALUE to INT_MAX in this \ + case. So we better do this as well. */ \ + return INT64_MAX; \ + } while (0) + +#ifdef IS_LIBDW +extern uint64_t __libdw_get_uleb128 (uint64_t acc, unsigned int i, + const unsigned char **addrp) + internal_function attribute_hidden; +extern int64_t __libdw_get_sleb128 (int64_t acc, unsigned int i, + const unsigned char **addrp) + internal_function attribute_hidden; +#else +static uint64_t +__attribute__ ((unused)) +__libdw_get_uleb128 (uint64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + get_uleb128_rest_return (acc, i, addrp); +} +static int64_t +__attribute__ ((unused)) +__libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp) +{ + unsigned char __b; + int64_t _v = acc; + get_sleb128_rest_return (acc, i, addrp); +} +#endif + + +/* We use simple memory access functions in case the hardware allows it. + The caller has to make sure we don't have alias problems. */ +#if ALLOW_UNALIGNED + +# define read_2ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_16 (*((const uint16_t *) (Addr))) \ + : *((const uint16_t *) (Addr))) +# define read_2sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \ + : *((const int16_t *) (Addr))) + +# define read_4ubyte_unaligned_noncvt(Addr) \ + *((const uint32_t *) (Addr)) +# define read_4ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_32 (*((const uint32_t *) (Addr))) \ + : *((const uint32_t *) (Addr))) +# define read_4sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \ + : *((const int32_t *) (Addr))) + +# define read_8ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_64 (*((const uint64_t *) (Addr))) \ + : *((const uint64_t *) (Addr))) +# define read_8sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \ + : *((const int64_t *) (Addr))) + +#else + +union unaligned + { + void *p; + uint16_t u2; + uint32_t u4; + uint64_t u8; + int16_t s2; + int32_t s4; + int64_t s8; + } __attribute__ ((packed)); + +static inline uint16_t +read_2ubyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_16 (up->u2); + return up->u2; +} +static inline int16_t +read_2sbyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return (int16_t) bswap_16 (up->u2); + return up->s2; +} + +static inline uint32_t +read_4ubyte_unaligned_noncvt (const void *p) +{ + const union unaligned *up = p; + return up->u4; +} +static inline uint32_t +read_4ubyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_32 (up->u4); + return up->u4; +} +static inline int32_t +read_4sbyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return (int32_t) bswap_32 (up->u4); + return up->s4; +} + +static inline uint64_t +read_8ubyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return bswap_64 (up->u8); + return up->u8; +} +static inline int64_t +read_8sbyte_unaligned (Dwarf *dbg, const void *p) +{ + const union unaligned *up = p; + if (dbg->other_byte_order) + return (int64_t) bswap_64 (up->u8); + return up->s8; +} + +#endif /* allow unaligned */ + + +#define read_2ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) +#define read_2sbyte_unaligned_inc(Dbg, Addr) \ + ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) + +#define read_4ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) +#define read_4sbyte_unaligned_inc(Dbg, Addr) \ + ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) + +#define read_8ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) +#define read_8sbyte_unaligned_inc(Dbg, Addr) \ + ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) + +#endif /* memory-access.h */ |