diff options
author | Roland McGrath <roland@redhat.com> | 2009-10-05 17:36:43 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2009-10-05 17:36:43 +0000 |
commit | fcaf740c16004e36e5bdb7152ae49d25805d9dea (patch) | |
tree | 82367c77356c38df5ed8fb6f51bcd66e9f3bbd30 /elfutils/libdw | |
parent | 5a4cef9b6c2899944308fdb8f78559fc0df766cc (diff) | |
download | elfutils-196fbacf6ba3d672b7b9c93261503eaeebcee3c1.tar.gz |
0.143-10.143-1
- Update to 0.143
- libdw: Various convenience functions for individual attributes now use
dwarf_attr_integrate to look up indirect inherited attributes.
Location expression handling now supports DW_OP_implicit_value.
- libdwfl: Support automatic decompression of files in XZ format,
and of Linux kernel images made with bzip2 or LZMA
(as well as gzip).
Diffstat (limited to 'elfutils/libdw')
49 files changed, 3941 insertions, 336 deletions
diff --git a/elfutils/libdw/ChangeLog b/elfutils/libdw/ChangeLog index 93a59673..2208f772 100644 --- a/elfutils/libdw/ChangeLog +++ b/elfutils/libdw/ChangeLog @@ -1,3 +1,220 @@ +2009-09-17 Roland McGrath <roland@redhat.com> + + * dwarf_getlocation.c (dwarf_getlocation_implicit_value): Make OP + argument a pointer to const. + * libdw.h: Update decl. + +2009-09-10 Roland McGrath <roland@redhat.com> + + * dwarf_getlocation.c (store_implicit_value): New function. + (__libdw_intern_expression): Use it, handle DW_OP_implicit_value. + (dwarf_getlocation_implicit_value): New function. + * libdw.h: Declare it. + * libdw.map (ELFUTILS_0.143): Add it. + +2009-09-09 Mark Wielaard <mjw@redhat.com> + + * dwarf_getcfi.c (dwarf_getcfi): Clear cfi->ebl. + +2009-08-21 Josh Stone <jistone@redhat.com> + + * dwarf_hasattr_integrate.c: Integrate DW_AT_specification too. + +2009-08-10 Roland McGrath <roland@redhat.com> + + * dwarf_getscopevar.c: Use dwarf_diename. + +2009-08-09 Roland McGrath <roland@redhat.com> + + * libdw.map (ELFUTILS_0.143): New version set, + inherits from ELFUTILS_0.142. + * dwarf_arrayorder.c: Use OLD_VERSION and NEW_VERSION to define an + alias in the ELFUTILS_0.122 version set and the default in the new set. + * dwarf_srclang.c: Likewise. + * dwarf_decl_file.c: Likewise. + * dwarf_decl_line.c: Likewise. + * dwarf_decl_column.c: Likewise. + * dwarf_bytesize.c: Likewise. + * dwarf_bitsize.c: Likewise. + * dwarf_bitoffset.c: Likewise. + +2009-08-07 Roland McGrath <roland@redhat.com> + + * dwarf_arrayorder.c: Use dwarf_attr_integrate. + * dwarf_srclang.c: Likewise. + * dwarf_decl_file.c: Likewise. + * dwarf_decl_line.c (__libdw_attr_intval): Likewise. + * dwarf_bytesize.c: Likewise. + * dwarf_bitsize.c: Likewise. + * dwarf_bitoffset.c: Likewise. + +2009-07-22 Roland McGrath <roland@redhat.com> + + * dwarf_frame_cfa.c: Change calling convention. + * libdw.h: Update decl. + + * dwarf_frame_register.c: Change calling/return-value convention for + value-only results and undefined/same_value. + * libdw.h: Update decl. + + * dwarf_getlocation.c (__libdw_intern_expression): Take new bool + argument, append DW_OP_stack_value if set. Don't take NOPS argument, + return that value instead. + (getlocation): Update caller. + * dwarf_frame_cfa.c: Likewise. + * libdwP.h: Update decl. + +2009-07-21 Roland McGrath <roland@redhat.com> + + * dwarf_getsrc_file.c: Ignore a CU that just has no DW_AT_stmt_list. + Fix loop iteration after skipping a bogus or useless CU. + + * dwarf_entry_breakpoints.c: Handle 0 dwarf_errno () as harmless + absence, not DWARF_E_NO_DEBUG_LINE. + +2009-07-20 Roland McGrath <roland@redhat.com> + + * dwarf_getlocation.c (__libdw_intern_expression): + Handle DW_OP_stack_value. + +2009-07-16 Roland McGrath <roland@redhat.com> + + * dwarf_formudata.c (__libdw_formptr): Handle DW_FORM_sec_offset, + reject others when CU's version > 3. + + * dwarf_formflag.c: Handle DW_FORM_flag_present. + + * dwarf.h: Add DW_OP_{implicit,stack}_value from DWARF 4 draft. + Also DW_TAG_type_unit and DW_TAG_rvalue_reference_type. + Also DW_AT_signature, DW_AT_main_subprogram, DW_AT_data_bit_offset, + and DW_AT_const_expr. + Also DW_FORM_sec_offset, DW_FORM_exprloc, DW_FORM_flag_present, + and DW_FORM_ref_sig8. + +2009-07-15 Roland McGrath <roland@redhat.com> + + * dwarf_getlocation.c: Grok DW_OP_form_tls_address, + DW_OP_GNU_push_tls_address, and DW_OP_bit_piece. + +2009-07-13 Roland McGrath <roland@redhat.com> + + * dwarf_getlocation.c: Grok DW_OP_call_frame_cfa. + +2009-07-08 Roland McGrath <roland@redhat.com> + + * libdw.map (ELFUTILS_0.142): Add dwfl_module_dwarf_cfi, + dwfl_module_eh_cfi. + + * libdwP.h (struct Dwarf): Add member `cfi'. + * dwarf_end.c (dwarf_end): Call __libdw_destroy_frame_cache on it. + * dwarf_getcfi.c: New file. + * dwarf_getcfi_elf.c: New file. + * dwarf_cfi_end.c: New file. + * dwarf_cfi_addrframe.c: New file. + * dwarf_frame_cfa.c: New file. + * dwarf_frame_register.c: New file. + * dwarf_frame_return_address_register.c: New file. + * Makefile.am (libdw_a_SOURCES): Add them. + * unwind.h: Declare those functions. + * libdw.map (ELFUTILS_0.142): Export them. + + * dwarf_getlocation.c (__libdw_intern_expression): New function, + broken out of ... + (getlocation): ... here, call it. + * libdwP.h: Declare it. + + * cie.c: New file. + * fde.c: New file. + * frame-cache.c: New file. + * cfi.c: New file. + * cfi.h: New file. + * encoded-value.h: New file. + * Makefile.am (libdw_a_SOURCES, noinst_HEADERS): Add them. + * libdwP.h: Add DWARF_E_INVALID_CFI to errors enum. + * dwarf_error.c (errmsgs): Add element for it. + + * dwarf_next_cfi.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.h (Dwarf_CIE, Dwarf_FDE, Dwarf_CIE_Entry): New types. + Declare dwarf_next_cfi. + * libdw.map (ELFUTILS_0.142): New set, inherits from ELFUTILS_0.136. + Add dwarf_next_cfi. + + * memory-access.h [! ALLOW_UNALIGNED] + (read_2ubyte_unaligned): Renamed to ... + (read_2ubyte_unaligned_1): ... this. Take bool rather than Dwarf *. + (read_2ubyte_unaligned): Define as macro passing dbg->other_byte_order. + (read_2sbyte_unaligned): Likewise. + (read_4ubyte_unaligned): Likewise. + (read_4sbyte_unaligned): Likewise. + (read_8ubyte_unaligned): Likewise. + (read_8sbyte_unaligned): Likewise. + + * libdwP.h (IDX_eh_frame): Remove it. + * dwarf_begin_elf.c (dwarf_scnnames): Remove its element. + +2009-07-08 Roland McGrath <roland@redhat.com> + + * libdwP.h (struct Dwarf_Line_s): Reorder members to pack better. + + * dwarf_getlocation.c (check_constant_offset): New function. + (dwarf_getlocation, dwarf_getlocation_addr): Call it to + handle DW_AT_data_member_location of data[48] as constant offset. + +2009-06-18 Roland McGrath <roland@redhat.com> + + * libdwP.h (__libdw_read_address_inc): Constify. + (__libdw_read_offset_inc): Likewise. + * dwarf_getaranges.c: Likewise. + * dwarf_getlocation.c: Likewise. + * dwarf_getsrclines.c: Likewise. + * dwarf_nextcu.c: Likewise. + +2009-05-05 Petr Machata <pmachata@redhat.com> + + * libdwP.h (__libdw_formptr): Declare new function. + * dwarf_formudata.c: Implement it here. + * dwarf_getlocation.c (dwarf_getlocation_addr): + Call it instead of hand-rolled offset handling code. + * dwarf_getsrclines.c (dwarf_getsrclines): Likewise. + * dwarf_ranges.c (dwarf_ranges): Likewise. + +2009-05-04 Petr Machata <pmachata@redhat.com> + + * libdwP.h (__libdw_read_begin_end_pair_inc): Declare new function. + * dwarf_ranges.c: Implement it here. + (dwarf_ranges): Call it. + * dwarf_getlocation.c (dwarf_getlocation_addr): Call it also here. + +2009-04-23 Petr Machata <pmachata@redhat.com> + + * dwarf_formaddr.c (dwarf_formaddr): Call __libdw_read_* instead + of read_*ubyte_unaligned. + * dwarf_formref_die.c (dwarf_formref_die): Likewise. + * dwarf_formstring.c (dwarf_formstring): Likewise. + * dwarf_formudate.c (dwarf_formudata): Likewise. + * dwarf_getaranges.c (dwarf_getaranges): Likewise. + * dwarf_getlocation.c (dwarf_getlocation_addr): Likewise. + * dwarf_getpubnames.c (get_offsets): Likewise. + * dwarf_nextcu.c (dwarf_nextcu): Likewise. + +2009-04-23 Petr Machata <pmachata@redhat.com> + + * libdwP.h (__libdw_read_addr_inc, __libdw_read_off_inc, + __libdw_read_addr, __libdw_read_off): Add four new internal + functions. + +2009-05-07 Roland McGrath <roland@redhat.com> + + * dwarf_getmacros.c (dwarf_getmacros): Use absolute section offset in + return value and OFFSET argument, not CU-relative. Only fetch the + attribute data when called with OFFSET of 0. + +2009-05-07 Petr Machata <pmachata@redhat.com> + + * dwarf_getmacros.c (dwarf_getmacros): Take into account offset in + DW_AT_macro_info attribute of CU DIE. + 2009-04-15 Roland McGrath <roland@redhat.com> * dwarf.h (DW_CIE_ID): Removed. diff --git a/elfutils/libdw/Makefile.am b/elfutils/libdw/Makefile.am index e624ac10..4d041cf7 100644 --- a/elfutils/libdw/Makefile.am +++ b/elfutils/libdw/Makefile.am @@ -83,7 +83,12 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ dwarf_func_inline.c dwarf_getsrc_file.c \ libdw_findcu.c libdw_form.c libdw_alloc.c memory-access.c \ libdw_visit_scopes.c \ - dwarf_entry_breakpoints.c + dwarf_entry_breakpoints.c \ + dwarf_next_cfi.c \ + cie.c fde.c cfi.c frame-cache.c \ + dwarf_frame_info.c dwarf_frame_cfa.c dwarf_frame_register.c \ + dwarf_cfi_addrframe.c \ + dwarf_getcfi.c dwarf_getcfi_elf.c dwarf_cfi_end.c if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h @@ -134,7 +139,8 @@ endif libdw_a_LIBADD = $(addprefix ../libdwfl/,$(shell $(AR) t ../libdwfl/libdwfl.a)) -noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h +noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \ + cfi.h encoded-value.h EXTRA_DIST = libdw.map diff --git a/elfutils/libdw/Makefile.in b/elfutils/libdw/Makefile.in index 690b2eec..33f80456 100644 --- a/elfutils/libdw/Makefile.in +++ b/elfutils/libdw/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.11 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -18,8 +19,9 @@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -50,15 +52,30 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; -am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" \ "$(DESTDIR)$(pkgincludedir)" -libLIBRARIES_INSTALL = $(INSTALL_DATA) LIBRARIES = $(lib_LIBRARIES) $(noinst_LIBRARIES) AR = ar ARFLAGS = cru @@ -111,7 +128,12 @@ am_libdw_a_OBJECTS = dwarf_begin.$(OBJEXT) dwarf_begin_elf.$(OBJEXT) \ dwarf_func_inline.$(OBJEXT) dwarf_getsrc_file.$(OBJEXT) \ libdw_findcu.$(OBJEXT) libdw_form.$(OBJEXT) \ libdw_alloc.$(OBJEXT) memory-access.$(OBJEXT) \ - libdw_visit_scopes.$(OBJEXT) dwarf_entry_breakpoints.$(OBJEXT) + libdw_visit_scopes.$(OBJEXT) dwarf_entry_breakpoints.$(OBJEXT) \ + dwarf_next_cfi.$(OBJEXT) cie.$(OBJEXT) fde.$(OBJEXT) \ + cfi.$(OBJEXT) frame-cache.$(OBJEXT) dwarf_frame_info.$(OBJEXT) \ + dwarf_frame_cfa.$(OBJEXT) dwarf_frame_register.$(OBJEXT) \ + dwarf_cfi_addrframe.$(OBJEXT) dwarf_getcfi.$(OBJEXT) \ + dwarf_getcfi_elf.$(OBJEXT) dwarf_cfi_end.$(OBJEXT) libdw_a_OBJECTS = $(am_libdw_a_OBJECTS) libdw_pic_a_AR = $(AR) $(ARFLAGS) libdw_pic_a_LIBADD = @@ -124,6 +146,7 @@ libdw_so_LDADD = $(LDADD) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/config/depcomp am__depfiles_maybe = depfiles +am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -132,8 +155,6 @@ SOURCES = $(libdw_a_SOURCES) $(libdw_pic_a_SOURCES) \ $(libdw_so_SOURCES) DIST_SOURCES = $(libdw_a_SOURCES) $(libdw_pic_a_SOURCES) \ $(libdw_so_SOURCES) -includeHEADERS_INSTALL = $(INSTALL_HEADER) -pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(include_HEADERS) $(noinst_HEADERS) $(pkginclude_HEADERS) ETAGS = etags CTAGS = ctags @@ -247,6 +268,7 @@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zip_LIBS = @zip_LIBS@ @@ -296,7 +318,12 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ dwarf_func_inline.c dwarf_getsrc_file.c \ libdw_findcu.c libdw_form.c libdw_alloc.c memory-access.c \ libdw_visit_scopes.c \ - dwarf_entry_breakpoints.c + dwarf_entry_breakpoints.c \ + dwarf_next_cfi.c \ + cie.c fde.c cfi.c frame-cache.c \ + dwarf_frame_info.c dwarf_frame_cfa.c dwarf_frame_register.c \ + dwarf_cfi_addrframe.c \ + dwarf_getcfi.c dwarf_getcfi_elf.c dwarf_cfi_end.c @MAINTAINER_MODE_TRUE@BUILT_SOURCES = $(srcdir)/known-dwarf.h @MAINTAINER_MODE_TRUE@MAINTAINERCLEANFILES = $(srcdir)/known-dwarf.h @@ -304,7 +331,9 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ @MUDFLAP_FALSE@am_libdw_pic_a_OBJECTS = $(libdw_a_SOURCES:.c=.os) @MUDFLAP_FALSE@libdw_so_SOURCES = libdw_a_LIBADD = $(addprefix ../libdwfl/,$(shell $(AR) t ../libdwfl/libdwfl.a)) -noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h +noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \ + cfi.h encoded-value.h + EXTRA_DIST = libdw.map MOSTLYCLEANFILES = $(am_libdw_pic_a_OBJECTS) *.gcno *.gcda libdw.so.$(VERSION) all: $(BUILT_SOURCES) @@ -316,14 +345,14 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits libdw/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnits libdw/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits libdw/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnits libdw/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -341,32 +370,36 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): install-libLIBRARIES: $(lib_LIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" - @list='$(lib_LIBRARIES)'; for p in $$list; do \ + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ if test -f $$p; then \ - f=$(am__strip_dir) \ - echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ - $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + list2="$$list2 $$p"; \ else :; fi; \ - done + done; \ + test -z "$$list2" || { \ + echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(INSTALL_DATA) $$list2 "$(DESTDIR)$(libdir)" || exit $$?; } @$(POST_INSTALL) - @list='$(lib_LIBRARIES)'; for p in $$list; do \ + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ if test -f $$p; then \ - p=$(am__strip_dir) \ - echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ - $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ + $(am__strip_dir) \ + echo " ( cd '$(DESTDIR)$(libdir)' && $(RANLIB) $$f )"; \ + ( cd "$(DESTDIR)$(libdir)" && $(RANLIB) $$f ) || exit $$?; \ else :; fi; \ done uninstall-libLIBRARIES: @$(NORMAL_UNINSTALL) - @list='$(lib_LIBRARIES)'; for p in $$list; do \ - p=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ - rm -f "$(DESTDIR)$(libdir)/$$p"; \ - done + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libdir)' && rm -f "$$files" )"; \ + cd "$(DESTDIR)$(libdir)" && rm -f $$files clean-libLIBRARIES: -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) @@ -394,6 +427,8 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cfi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cie.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_abbrev_hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_abbrevhaschildren.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_addrdie.Po@am__quote@ @@ -405,6 +440,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_bitoffset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_bitsize.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_bytesize.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_cfi_addrframe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_cfi_end.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_child.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_cuoffset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_decl_column.Po@am__quote@ @@ -426,6 +463,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_formsdata.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_formstring.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_formudata.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_frame_cfa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_frame_info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_frame_register.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_func_inline.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getabbrev.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getabbrevattr.Po@am__quote@ @@ -436,6 +476,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getaranges.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getattrcnt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getattrs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getcfi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getcfi_elf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getelf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getfuncs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_getlocation.Po@am__quote@ @@ -469,6 +511,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_macro_opcode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_macro_param1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_macro_param2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_next_cfi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_nextcu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_offabbrev.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_offdie.Po@am__quote@ @@ -480,6 +523,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_tag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_whatattr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_whatform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fde.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frame-cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdw_alloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdw_findcu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdw_form.Po@am__quote@ @@ -488,65 +533,71 @@ distclean-compile: .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" - @list='$(include_HEADERS)'; for p in $$list; do \ + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(am__strip_dir) \ - echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ - $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) - @list='$(include_HEADERS)'; for p in $$list; do \ - f=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ - rm -f "$(DESTDIR)$(includedir)/$$f"; \ - done + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includedir)" && rm -f $$files install-pkgincludeHEADERS: $(pkginclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(pkgincludedir)" || $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" - @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(am__strip_dir) \ - echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \ - $(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ done uninstall-pkgincludeHEADERS: @$(NORMAL_UNINSTALL) - @list='$(pkginclude_HEADERS)'; for p in $$list; do \ - f=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \ - rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \ - done + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgincludedir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ + set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -554,29 +605,34 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags @@ -597,13 +653,17 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @@ -637,6 +697,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -660,6 +721,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -668,18 +731,28 @@ install-data-am: install-includeHEADERS install-pkgincludeHEADERS install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-libLIBRARIES install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -702,7 +775,7 @@ ps-am: uninstall-am: uninstall-includeHEADERS uninstall-libLIBRARIES \ uninstall-pkgincludeHEADERS -.MAKE: install-am install-strip +.MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLIBRARIES clean-noinstLIBRARIES clean-noinstPROGRAMS \ @@ -754,6 +827,7 @@ uninstall-am: uninstall-includeHEADERS uninstall-libLIBRARIES \ @MUDFLAP_FALSE@ rm -f $(DESTDIR)$(libdir)/libdw.so.$(VERSION) @MUDFLAP_FALSE@ rm -f $(DESTDIR)$(libdir)/libdw.so @MUDFLAP_FALSE@ rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/elfutils/libdw/cfi.c b/elfutils/libdw/cfi.c new file mode 100644 index 00000000..ac197833 --- /dev/null +++ b/elfutils/libdw/cfi.c @@ -0,0 +1,500 @@ +/* CFI program execution. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "../libebl/libebl.h" +#include "cfi.h" +#include "memory-access.h" +#include "encoded-value.h" +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#define CFI_PRIMARY_MAX 0x3f + +static Dwarf_Frame * +duplicate_frame_state (const Dwarf_Frame *original, + Dwarf_Frame *prev) +{ + size_t size = offsetof (Dwarf_Frame, regs[original->nregs]); + Dwarf_Frame *copy = malloc (size); + if (likely (copy != NULL)) + { + memcpy (copy, original, size); + copy->prev = prev; + } + return copy; +} + +/* Returns a DWARF_E_* error code, usually NOERROR or INVALID_CFI. */ +static int +execute_cfi (Dwarf_CFI *cache, + const struct dwarf_cie *cie, + Dwarf_Frame **state, + const uint8_t *program, const uint8_t *const end, bool abi_cfi, + Dwarf_Addr loc, Dwarf_Addr find_pc) +{ + /* The caller should not give us anything out of range. */ + assert (loc <= find_pc); + + int result = DWARF_E_NOERROR; + +#define cfi_assert(ok) do { \ + if (likely (ok)) break; \ + result = DWARF_E_INVALID_CFI; \ + goto out; \ + } while (0) + + Dwarf_Frame *fs = *state; + inline bool enough_registers (Dwarf_Word reg) + { + if (fs->nregs <= reg) + { + size_t size = offsetof (Dwarf_Frame, regs[reg + 1]); + Dwarf_Frame *bigger = realloc (fs, size); + if (unlikely (bigger == NULL)) + { + result = DWARF_E_NOMEM; + return false; + } + else + { + bigger->nregs = reg + 1; + fs = bigger; + } + } + return true; + } + +#define register_rule(regno, r_rule, r_value) do { \ + if (unlikely (! enough_registers (regno))) \ + goto out; \ + fs->regs[regno].rule = reg_##r_rule; \ + fs->regs[regno].value = (r_value); \ + } while (0) + + while (program < end) + { + uint8_t opcode = *program++; + Dwarf_Word regno; + Dwarf_Word offset; + Dwarf_Word sf_offset; + Dwarf_Word operand = opcode & CFI_PRIMARY_MAX; + switch (opcode) + { + /* These cases move LOC, i.e. "create a new table row". */ + + case DW_CFA_advance_loc1: + operand = *program++; + case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX: + advance_loc: + loc += operand * cie->code_alignment_factor; + break; + + case DW_CFA_advance_loc2: + operand = read_2ubyte_unaligned_inc (cache, program); + goto advance_loc; + case DW_CFA_advance_loc4: + operand = read_4ubyte_unaligned_inc (cache, program); + goto advance_loc; + case DW_CFA_MIPS_advance_loc8: + operand = read_8ubyte_unaligned_inc (cache, program); + goto advance_loc; + + case DW_CFA_set_loc: + if (unlikely (read_encoded_value (cache, cie->fde_encoding, &program, + &loc))) + return INTUSE(dwarf_errno) (); + break; + + /* Now all following cases affect this row, but do not touch LOC. + These cases end with 'continue'. We only get out of the + switch block for the row-copying (LOC-moving) cases above. */ + + case DW_CFA_def_cfa: + get_uleb128 (operand, program); + get_uleb128 (offset, program); + def_cfa: + fs->cfa_rule = cfa_offset; + fs->cfa_val_reg = operand; + fs->cfa_val_offset = offset; + /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it. */ + fs->cfa_data.offset.atom = DW_OP_bregx; + fs->cfa_data.offset.offset = 0; + continue; + + case DW_CFA_def_cfa_register: + get_uleb128 (regno, program); + cfi_assert (fs->cfa_rule == cfa_offset); + fs->cfa_val_reg = regno; + continue; + + case DW_CFA_def_cfa_sf: + get_uleb128 (operand, program); + get_sleb128 (sf_offset, program); + offset = sf_offset * cie->data_alignment_factor; + goto def_cfa; + + case DW_CFA_def_cfa_offset: + get_uleb128 (offset, program); + def_cfa_offset: + cfi_assert (fs->cfa_rule == cfa_offset); + fs->cfa_val_offset = offset; + continue; + + case DW_CFA_def_cfa_offset_sf: + get_sleb128 (sf_offset, program); + offset = sf_offset * cie->data_alignment_factor; + goto def_cfa_offset; + + case DW_CFA_def_cfa_expression: + /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ + get_uleb128 (operand, program); + cfi_assert (operand <= (Dwarf_Word) (end - program)); + fs->cfa_rule = cfa_expr; + fs->cfa_data.expr.data = (unsigned char *) program; + fs->cfa_data.expr.length = operand; + program += operand; + continue; + + case DW_CFA_undefined: + get_uleb128 (regno, program); + register_rule (regno, undefined, 0); + continue; + + case DW_CFA_same_value: + get_uleb128 (regno, program); + register_rule (regno, same_value, 0); + continue; + + case DW_CFA_offset_extended: + get_uleb128 (operand, program); + case DW_CFA_offset + 0 ... DW_CFA_offset + CFI_PRIMARY_MAX: + get_uleb128 (offset, program); + offset *= cie->data_alignment_factor; + offset_extended: + register_rule (operand, offset, offset); + continue; + + case DW_CFA_offset_extended_sf: + get_uleb128 (operand, program); + get_sleb128 (sf_offset, program); + offset_extended_sf: + offset = sf_offset * cie->data_alignment_factor; + goto offset_extended; + + case DW_CFA_GNU_negative_offset_extended: + /* GNU extension obsoleted by DW_CFA_offset_extended_sf. */ + get_uleb128 (operand, program); + get_uleb128 (offset, program); + sf_offset = -offset; + goto offset_extended_sf; + + case DW_CFA_val_offset: + get_uleb128 (operand, program); + get_uleb128 (offset, program); + offset *= cie->data_alignment_factor; + val_offset: + register_rule (operand, val_offset, offset); + continue; + + case DW_CFA_val_offset_sf: + get_uleb128 (operand, program); + get_sleb128 (sf_offset, program); + offset = sf_offset * cie->data_alignment_factor; + goto val_offset; + + case DW_CFA_register: + get_uleb128 (regno, program); + get_uleb128 (operand, program); + register_rule (regno, register, operand); + continue; + + case DW_CFA_expression: + get_uleb128 (regno, program); + offset = program - (const uint8_t *) cache->data->d.d_buf; + /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ + get_uleb128 (operand, program); + cfi_assert (operand <= (Dwarf_Word) (end - program)); + program += operand; + register_rule (regno, expression, offset); + continue; + + case DW_CFA_val_expression: + get_uleb128 (regno, program); + /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ + offset = program - (const uint8_t *) cache->data->d.d_buf; + get_uleb128 (operand, program); + cfi_assert (operand <= (Dwarf_Word) (end - program)); + program += operand; + register_rule (regno, val_expression, offset); + continue; + + case DW_CFA_restore_extended: + get_uleb128 (operand, program); + case DW_CFA_restore + 0 ... DW_CFA_restore + CFI_PRIMARY_MAX: + + if (unlikely (abi_cfi) && likely (opcode == DW_CFA_restore)) + { + /* Special case hack to give backend abi_cfi a shorthand. */ + cache->default_same_value = true; + continue; + } + + /* This can't be used in the CIE's own initial instructions. */ + cfi_assert (cie->initial_state != NULL); + + /* Restore the CIE's initial rule for this register. */ + if (unlikely (! enough_registers (operand))) + goto out; + if (cie->initial_state->nregs > operand) + fs->regs[operand] = cie->initial_state->regs[operand]; + else + fs->regs[operand].rule = reg_unspecified; + continue; + + case DW_CFA_remember_state: + { + /* Duplicate the state and chain the copy on. */ + Dwarf_Frame *copy = duplicate_frame_state (fs, fs); + if (unlikely (copy == NULL)) + { + result = DWARF_E_NOMEM; + goto out; + } + fs = copy; + continue; + } + + case DW_CFA_restore_state: + { + /* Pop the current state off and use the old one instead. */ + Dwarf_Frame *prev = fs->prev; + cfi_assert (prev != NULL); + free (fs); + fs = prev; + } + continue; + + case DW_CFA_nop: + continue; + + case DW_CFA_GNU_window_save: + /* This is magic shorthand used only by SPARC. It's equivalent + to a bunch of DW_CFA_register and DW_CFA_offset operations. */ + if (unlikely (! enough_registers (31))) + goto out; + for (regno = 8; regno < 16; ++regno) + { + /* Find each %oN in %iN. */ + fs->regs[regno].rule = reg_register; + fs->regs[regno].value = regno + 16; + } + unsigned int address_size = (cache->e_ident[EI_CLASS] == ELFCLASS32 + ? 4 : 8); + for (; regno < 32; ++regno) + { + /* Find %l0..%l7 and %i0..%i7 in a block at the CFA. */ + fs->regs[regno].rule = reg_offset; + fs->regs[regno].value = (regno - 16) * address_size; + } + continue; + + case DW_CFA_GNU_args_size: + /* XXX is this useful for anything? */ + get_uleb128 (operand, program); + continue; + + default: + cfi_assert (false); + continue; + } + + /* We get here only for the cases that have just moved LOC. */ + if (find_pc >= loc) + /* This advance has not yet reached FIND_PC. */ + fs->start = loc; + else + { + /* We have just advanced past the address we're looking for. + The state currently described is what we want to see. */ + fs->end = loc; + break; + } + } + + /* "The end of the instruction stream can be thought of as a + DW_CFA_set_loc (initial_location + address_range) instruction." + (DWARF 3.0 Section 6.4.3) + + When we fall off the end of the program without an advance_loc/set_loc + that put us past FIND_PC, the final state left by the FDE program + applies to this address (the caller ensured it was inside the FDE). + This address (FDE->end) is already in FS->end as set by the caller. */ + +#undef register_rule +#undef cfi_assert + + out: + + /* Pop any remembered states left on the stack. */ + while (fs->prev != NULL) + { + Dwarf_Frame *prev = fs->prev; + fs->prev = prev->prev; + free (prev); + } + + if (result == DWARF_E_NOERROR) + *state = fs; + + return result; +} + +static int +cie_cache_initial_state (Dwarf_CFI *cache, struct dwarf_cie *cie) +{ + int result = DWARF_E_NOERROR; + + if (likely (cie->initial_state != NULL)) + return result; + + /* This CIE has not been used before. Play out its initial + instructions and cache the initial state that results. + First we'll let the backend fill in the default initial + state for this machine's ABI. */ + + Dwarf_CIE abi_info = { DW_CIE_ID_64, NULL, NULL, 1, 1, -1, "", NULL, 0, 0 }; + + /* Make sure we have a backend handle cached. */ + if (unlikely (cache->ebl == NULL)) + { + cache->ebl = ebl_openbackend (cache->data->s->elf); + if (unlikely (cache->ebl == NULL)) + cache->ebl = (void *) -1l; + } + + /* Fetch the ABI's default CFI program. */ + if (likely (cache->ebl != (void *) -1l) + && unlikely (ebl_abi_cfi (cache->ebl, &abi_info) < 0)) + return DWARF_E_UNKNOWN_ERROR; + + Dwarf_Frame *cie_fs = calloc (1, sizeof (Dwarf_Frame)); + if (unlikely (cie_fs == NULL)) + return DWARF_E_NOMEM; + + /* If the default state of any register is not "undefined" + (i.e. call-clobbered), then the backend supplies instructions + for the standard initial state. */ + if (abi_info.initial_instructions_end > abi_info.initial_instructions) + { + /* Dummy CIE for backend's instructions. */ + struct dwarf_cie abi_cie = + { + .code_alignment_factor = abi_info.code_alignment_factor, + .data_alignment_factor = abi_info.data_alignment_factor, + }; + result = execute_cfi (cache, &abi_cie, &cie_fs, + abi_info.initial_instructions, + abi_info.initial_instructions_end, true, + 0, (Dwarf_Addr) -1l); + } + + /* Now run the CIE's initial instructions. */ + if (cie->initial_instructions_end > cie->initial_instructions + && likely (result == DWARF_E_NOERROR)) + result = execute_cfi (cache, cie, &cie_fs, + cie->initial_instructions, + cie->initial_instructions_end, false, + 0, (Dwarf_Addr) -1l); + + if (unlikely (result != DWARF_E_NOERROR)) + { + free (cie_fs); + return result; + } + + /* Now we have the initial state of things that all + FDEs using this CIE will start from. */ + cie_fs->cache = cache; + cie->initial_state = cie_fs; + + return result; +} + +int +internal_function +__libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, + Dwarf_Addr address, Dwarf_Frame **frame) +{ + int result = cie_cache_initial_state (cache, fde->cie); + if (likely (result == DWARF_E_NOERROR)) + { + Dwarf_Frame *fs = duplicate_frame_state (fde->cie->initial_state, NULL); + if (unlikely (fs == NULL)) + return DWARF_E_NOMEM; + + fs->fde = fde; + fs->start = fde->start; + fs->end = fde->end; + + result = execute_cfi (cache, fde->cie, &fs, + fde->instructions, fde->instructions_end, false, + fde->start, address); + if (unlikely (result != DWARF_E_NOERROR)) + free (fs); + else + *frame = fs; + } + return result; +} diff --git a/elfutils/libdw/cfi.h b/elfutils/libdw/cfi.h new file mode 100644 index 00000000..64f3f157 --- /dev/null +++ b/elfutils/libdw/cfi.h @@ -0,0 +1,250 @@ +/* Internal definitions for libdw CFI interpreter. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifndef _UNWINDP_H +#define _UNWINDP_H 1 + +#include "libdwP.h" +#include "libelfP.h" +struct ebl; + +#define dwarf_cfi_cie_p(entry) ((entry)->cie.CIE_id == DW_CIE_ID_64) + +/* Cached CIE representation. */ +struct dwarf_cie +{ + Dwarf_Off offset; /* Our position, as seen in FDEs' CIE_pointer. */ + + Dwarf_Word code_alignment_factor; + Dwarf_Sword data_alignment_factor; + Dwarf_Word return_address_register; + + size_t fde_augmentation_data_size; + + // play out to initial state + const uint8_t *initial_instructions; + const uint8_t *initial_instructions_end; + + const Dwarf_Frame *initial_state; + + uint8_t fde_encoding; /* DW_EH_PE_* for addresses in FDEs. */ + uint8_t lsda_encoding; /* DW_EH_PE_* for LSDA in FDE augmentation. */ + + bool sized_augmentation_data; /* Saw 'z': FDEs have self-sized data. */ + bool signal_frame; /* Saw 'S': FDE is for a signal frame. */ +}; + +/* Cached FDE representation. */ +struct dwarf_fde +{ + struct dwarf_cie *cie; + + /* This FDE describes PC values in [start, end). */ + Dwarf_Addr start; + Dwarf_Addr end; + + const uint8_t *instructions; + const uint8_t *instructions_end; +}; + +/* This holds everything we cache about the CFI from each ELF file's + .debug_frame or .eh_frame section. */ +struct Dwarf_CFI_s +{ + /* Dwarf handle we came from. If null, this is .eh_frame data. */ + Dwarf *dbg; +#define CFI_IS_EH(cfi) ((cfi)->dbg == NULL) + + /* Data of the .debug_frame or .eh_frame section. */ + Elf_Data_Scn *data; + const unsigned char *e_ident; /* For EI_DATA and EI_CLASS. */ + + Dwarf_Addr frame_vaddr; /* DW_EH_PE_pcrel, address of frame section. */ + Dwarf_Addr textrel; /* DW_EH_PE_textrel base address. */ + Dwarf_Addr datarel; /* DW_EH_PE_datarel base address. */ + + /* Location of next unread entry in the section. */ + Dwarf_Off next_offset; + + /* Search tree for the CIEs, indexed by CIE_pointer (section offset). */ + void *cie_tree; + + /* Search tree for the FDEs, indexed by PC address. */ + void *fde_tree; + + /* Search tree for parsed DWARF expressions, indexed by raw pointer. */ + void *expr_tree; + + /* Backend hook. */ + struct ebl *ebl; + + /* Binary search table in .eh_frame_hdr section. */ + const uint8_t *search_table; + Dwarf_Addr search_table_vaddr; + size_t search_table_entries; + uint8_t search_table_encoding; + + /* True if the file has a byte order different from the host. */ + bool other_byte_order; + + /* Default rule for registers not previously mentioned + is same_value, not undefined. */ + bool default_same_value; +}; + + +enum dwarf_frame_rule + { + reg_unspecified, /* Uninitialized state. */ + reg_undefined, /* DW_CFA_undefined */ + reg_same_value, /* DW_CFA_same_value */ + reg_offset, /* DW_CFA_offset_extended et al */ + reg_val_offset, /* DW_CFA_val_offset et al */ + reg_register, /* DW_CFA_register */ + reg_expression, /* DW_CFA_expression */ + reg_val_expression, /* DW_CFA_val_expression */ + }; + +/* This describes what we know about an individual register. */ +struct dwarf_frame_register +{ + enum dwarf_frame_rule rule:3; + + /* The meaning of the value bits depends on the rule: + + Rule Value + ---- ----- + undefined unused + same_value unused + offset(N) N (register saved at CFA + value) + val_offset(N) N (register = CFA + value) + register(R) R (register = register #value) + expression(E) section offset of DW_FORM_block containing E + (register saved at address E computes) + val_expression(E) section offset of DW_FORM_block containing E + (register = value E computes) + */ + Dwarf_Sword value:(sizeof (Dwarf_Sword) * 8 - 3); +}; + +/* This holds everything we know about the state of the frame + at a particular PC location described by an FDE. */ +struct Dwarf_Frame_s +{ + /* This frame description covers PC values in [start, end). */ + Dwarf_Addr start; + Dwarf_Addr end; + + Dwarf_CFI *cache; + + /* Previous state saved by DW_CFA_remember_state, or .cie->initial_state, + or NULL in an initial_state pseudo-frame. */ + Dwarf_Frame *prev; + + /* The FDE that generated this frame state. This points to its CIE, + which has the return_address_register and signal_frame flag. */ + struct dwarf_fde *fde; + + /* The CFA is unknown, is R+N, or is computed by a DWARF expression. */ + enum { cfa_undefined, cfa_offset, cfa_expr } cfa_rule; + union + { + Dwarf_Op offset; + Dwarf_Block expr; + } cfa_data; + /* We store an offset rule as a DW_OP_bregx operation. */ +#define cfa_val_reg cfa_data.offset.number +#define cfa_val_offset cfa_data.offset.number2 + + size_t nregs; + struct dwarf_frame_register regs[]; +}; + + +/* Clean up the data structure and all it points to. */ +extern void __libdw_destroy_frame_cache (Dwarf_CFI *cache) + __nonnull_attribute__ (1) internal_function; + +/* Enter a CIE encountered while reading through for FDEs. */ +extern void __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, + const Dwarf_CIE *info) + __nonnull_attribute__ (1, 3) internal_function; + +/* Look up a CIE_pointer for random access. */ +extern struct dwarf_cie *__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) + __nonnull_attribute__ (1) internal_function; + + +/* Look for an FDE covering the given PC address. */ +extern struct dwarf_fde *__libdw_find_fde (Dwarf_CFI *cache, + Dwarf_Addr address) + __nonnull_attribute__ (1) internal_function; + +/* Process the FDE that contains the given PC address, + to yield the frame state when stopped there. + The return value is a DWARF_E_* error code. */ +extern int __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, + Dwarf_Addr address, Dwarf_Frame **frame) + __nonnull_attribute__ (1, 2, 4) internal_function; + + +/* Dummy struct for memory-access.h macros. */ +#define BYTE_ORDER_DUMMY(var, e_ident) \ + const struct { bool other_byte_order; } var = \ + { ((BYTE_ORDER == LITTLE_ENDIAN && e_ident[EI_DATA] == ELFDATA2MSB) \ + || (BYTE_ORDER == BIG_ENDIAN && e_ident[EI_DATA] == ELFDATA2LSB)) } + + +INTDECL (dwarf_next_cfi) +INTDECL (dwarf_getcfi) +INTDECL (dwarf_getcfi_elf) +INTDECL (dwarf_cfi_end) +INTDECL (dwarf_cfi_addrframe) + +#endif /* unwindP.h */ diff --git a/elfutils/libdw/cie.c b/elfutils/libdw/cie.c new file mode 100644 index 00000000..08752a6d --- /dev/null +++ b/elfutils/libdw/cie.c @@ -0,0 +1,193 @@ +/* CIE reading. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include "encoded-value.h" +#include <search.h> +#include <stdlib.h> + + +static int +compare_cie (const void *a, const void *b) +{ + const struct dwarf_cie *cie1 = a; + const struct dwarf_cie *cie2 = b; + if (cie1->offset < cie2->offset) + return -1; + if (cie1->offset > cie2->offset) + return 1; + return 0; +} + +/* There is no CIE at OFFSET in the tree. Add it. */ +static struct dwarf_cie * +intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) +{ + struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie)); + if (cie == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + cie->offset = offset; + cie->code_alignment_factor = info->code_alignment_factor; + cie->data_alignment_factor = info->data_alignment_factor; + cie->return_address_register = info->return_address_register; + + cie->fde_augmentation_data_size = 0; + cie->sized_augmentation_data = false; + cie->signal_frame = false; + + cie->fde_encoding = DW_EH_PE_absptr; + cie->lsda_encoding = DW_EH_PE_omit; + + /* Grok the augmentation string and its data. */ + const uint8_t *data = info->augmentation_data; + for (const char *ap = info->augmentation; *ap != '\0'; ++ap) + { + uint8_t encoding; + switch (*ap) + { + case 'z': + cie->sized_augmentation_data = true; + continue; + + case 'S': + cie->signal_frame = true; + continue; + + case 'L': /* LSDA pointer encoding byte. */ + cie->lsda_encoding = *data++; + if (!cie->sized_augmentation_data) + cie->fde_augmentation_data_size + += encoded_value_size (&cache->data->d, cache->e_ident, + cie->lsda_encoding, NULL); + continue; + + case 'R': /* FDE address encoding byte. */ + cie->fde_encoding = *data++; + continue; + + case 'P': /* Skip personality routine. */ + encoding = *data++; + data += encoded_value_size (&cache->data->d, cache->e_ident, + encoding, data); + continue; + + default: + /* Unknown augmentation string. If we have 'z' we can ignore it, + otherwise we must bail out. */ + if (cie->sized_augmentation_data) + continue; + } + /* We only get here when we need to bail out. */ + break; + } + + /* Save the initial instructions to be played out into initial state. */ + cie->initial_instructions = info->initial_instructions; + cie->initial_instructions_end = info->initial_instructions_end; + cie->initial_state = NULL; + + /* Add the new entry to the search tree. */ + if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL) + { + free (cie); + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + return cie; +} + +/* Look up a CIE_pointer for random access. */ +struct dwarf_cie * +internal_function +__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) +{ + const struct dwarf_cie cie_key = { .offset = offset }; + struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); + if (found != NULL) + return *found; + + /* We have not read this CIE yet. Go find it. */ + Dwarf_Off next_offset = offset; + Dwarf_CFI_Entry entry; + int result = INTUSE(dwarf_next_cfi) (cache->e_ident, + &cache->data->d, CFI_IS_EH (cache), + offset, &next_offset, &entry); + if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* If this happened to be what we would have read next, notice it. */ + if (cache->next_offset == offset) + cache->next_offset = next_offset; + + return intern_new_cie (cache, offset, &entry.cie); +} + +/* Enter a CIE encountered while reading through for FDEs. */ +void +internal_function +__libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) +{ + const struct dwarf_cie cie_key = { .offset = offset }; + struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); + if (found == NULL) + /* We have not read this CIE yet. Enter it. */ + (void) intern_new_cie (cache, offset, info); +} diff --git a/elfutils/libdw/dwarf.h b/elfutils/libdw/dwarf.h index 0546e3eb..196ef85e 100644 --- a/elfutils/libdw/dwarf.h +++ b/elfutils/libdw/dwarf.h @@ -111,6 +111,8 @@ enum DW_TAG_mutable_type = 0x3e, DW_TAG_condition = 0x3f, DW_TAG_shared_type = 0x40, + DW_TAG_type_unit = 0x41, + DW_TAG_rvalue_reference_type = 0x42, DW_TAG_lo_user = 0x4080, DW_TAG_MIPS_loop = 0x4081, DW_TAG_format_label = 0x4101, @@ -220,6 +222,10 @@ enum DW_AT_elemental = 0x66, DW_AT_pure = 0x67, DW_AT_recursive = 0x68, + DW_AT_signature = 0x69, + DW_AT_main_subprogram = 0x6a, + DW_AT_data_bit_offset = 0x6b, + DW_AT_const_expr = 0x6c, DW_AT_lo_user = 0x2000, DW_AT_MIPS_fde = 0x2001, @@ -272,7 +278,11 @@ enum DW_FORM_ref4 = 0x13, DW_FORM_ref8 = 0x14, DW_FORM_ref_udata = 0x15, - DW_FORM_indirect = 0x16 + DW_FORM_indirect = 0x16, + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, + DW_FORM_ref_sig8 = 0x20 }; @@ -431,6 +441,8 @@ enum DW_OP_form_tls_address = 0x9b,/* TLS offset to address in current thread */ DW_OP_call_frame_cfa = 0x9c,/* CFA as determined by CFI. */ DW_OP_bit_piece = 0x9d, /* ULEB128 size and ULEB128 offset in bits. */ + DW_OP_implicit_value = 0x9e, /* DW_FORM_block follows opcode. */ + DW_OP_stack_value = 0x9f, /* No operands, special like DW_OP_piece. */ /* GNU extensions. */ DW_OP_GNU_push_tls_address = 0xe0, diff --git a/elfutils/libdw/dwarf_arrayorder.c b/elfutils/libdw/dwarf_arrayorder.c index 6d5a42d7..4929fb3c 100644 --- a/elfutils/libdw/dwarf_arrayorder.c +++ b/elfutils/libdw/dwarf_arrayorder.c @@ -1,5 +1,5 @@ /* Return array order attribute of DIE. - Copyright (C) 2003, 2005 Red Hat, Inc. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -63,7 +63,9 @@ dwarf_arrayorder (die) Dwarf_Attribute attr_mem; Dwarf_Word value; - return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_ordering, - &attr_mem), + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_ordering, &attr_mem), &value) == 0 ? (int) value : -1; } +OLD_VERSION (dwarf_arrayorder, ELFUTILS_0.122) +NEW_VERSION (dwarf_arrayorder, ELFUTILS_0.143) diff --git a/elfutils/libdw/dwarf_begin_elf.c b/elfutils/libdw/dwarf_begin_elf.c index aaac3999..391a8b85 100644 --- a/elfutils/libdw/dwarf_begin_elf.c +++ b/elfutils/libdw/dwarf_begin_elf.c @@ -1,5 +1,5 @@ /* Create descriptor from ELF descriptor for processing file. - Copyright (C) 2002, 2003, 2004, 2005, 2007 Red Hat, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2007, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -70,7 +70,6 @@ static const char dwarf_scnnames[IDX_last][17] = [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", diff --git a/elfutils/libdw/dwarf_bitoffset.c b/elfutils/libdw/dwarf_bitoffset.c index 235b7ee6..3ab14683 100644 --- a/elfutils/libdw/dwarf_bitoffset.c +++ b/elfutils/libdw/dwarf_bitoffset.c @@ -1,5 +1,5 @@ /* Return bit offset attribute of DIE. - Copyright (C) 2003, 2005 Red Hat, Inc. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -63,7 +63,9 @@ dwarf_bitoffset (die) Dwarf_Attribute attr_mem; Dwarf_Word value; - return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_bit_offset, - &attr_mem), + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_bit_offset, &attr_mem), &value) == 0 ? (int) value : -1; } +OLD_VERSION (dwarf_bitoffset, ELFUTILS_0.122) +NEW_VERSION (dwarf_bitoffset, ELFUTILS_0.143) diff --git a/elfutils/libdw/dwarf_bitsize.c b/elfutils/libdw/dwarf_bitsize.c index 57d7fba0..67d97dc1 100644 --- a/elfutils/libdw/dwarf_bitsize.c +++ b/elfutils/libdw/dwarf_bitsize.c @@ -1,5 +1,5 @@ /* Return bit size attribute of DIE. - Copyright (C) 2003, 2005 Red Hat, Inc. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -63,7 +63,9 @@ dwarf_bitsize (die) Dwarf_Attribute attr_mem; Dwarf_Word value; - return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_bit_size, - &attr_mem), + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_bit_size, &attr_mem), &value) == 0 ? (int) value : -1; } +OLD_VERSION (dwarf_bitsize, ELFUTILS_0.122) +NEW_VERSION (dwarf_bitsize, ELFUTILS_0.143) diff --git a/elfutils/libdw/dwarf_bytesize.c b/elfutils/libdw/dwarf_bytesize.c index 635a3c16..2f2e1985 100644 --- a/elfutils/libdw/dwarf_bytesize.c +++ b/elfutils/libdw/dwarf_bytesize.c @@ -1,5 +1,5 @@ /* Return byte size attribute of DIE. - Copyright (C) 2003, 2005 Red Hat, Inc. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -63,7 +63,9 @@ dwarf_bytesize (die) Dwarf_Attribute attr_mem; Dwarf_Word value; - return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_byte_size, - &attr_mem), + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_byte_size, &attr_mem), &value) == 0 ? (int) value : -1; } +OLD_VERSION (dwarf_bytesize, ELFUTILS_0.122) +NEW_VERSION (dwarf_bytesize, ELFUTILS_0.143) diff --git a/elfutils/libdw/dwarf_cfi_addrframe.c b/elfutils/libdw/dwarf_cfi_addrframe.c new file mode 100644 index 00000000..79d0e125 --- /dev/null +++ b/elfutils/libdw/dwarf_cfi_addrframe.c @@ -0,0 +1,78 @@ +/* Compute frame state at PC. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" + +int +dwarf_cfi_addrframe (cache, address, frame) + Dwarf_CFI *cache; + Dwarf_Addr address; + Dwarf_Frame **frame; +{ + /* Maybe there was a previous error. */ + if (cache == NULL) + return -1; + + struct dwarf_fde *fde = __libdw_find_fde (cache, address); + if (fde == NULL) + return -1; + + int error = __libdw_frame_at_address (cache, fde, address, frame); + if (error != DWARF_E_NOERROR) + { + __libdw_seterrno (error); + return -1; + } + return 0; +} +INTDEF (dwarf_cfi_addrframe) diff --git a/elfutils/libdw/dwarf_cfi_end.c b/elfutils/libdw/dwarf_cfi_end.c new file mode 100644 index 00000000..5591e2a9 --- /dev/null +++ b/elfutils/libdw/dwarf_cfi_end.c @@ -0,0 +1,70 @@ +/* Clean up Dwarf_CFI structure. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include "cfi.h" +#include <stdlib.h> + +int +dwarf_cfi_end (cache) + Dwarf_CFI *cache; +{ + if (cache != NULL) + { + __libdw_destroy_frame_cache (cache); + free (cache); + } + + return 0; +} +INTDEF (dwarf_cfi_end) diff --git a/elfutils/libdw/dwarf_decl_column.c b/elfutils/libdw/dwarf_decl_column.c index 5e0f3e0c..11ba5d74 100644 --- a/elfutils/libdw/dwarf_decl_column.c +++ b/elfutils/libdw/dwarf_decl_column.c @@ -1,5 +1,5 @@ /* Get column number of beginning of given declaration. - Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -61,3 +61,5 @@ dwarf_decl_column (Dwarf_Die *decl, int *colp) { return __libdw_attr_intval (decl, colp, DW_AT_decl_column); } +OLD_VERSION (dwarf_decl_column, ELFUTILS_0.122) +NEW_VERSION (dwarf_decl_column, ELFUTILS_0.143) diff --git a/elfutils/libdw/dwarf_decl_file.c b/elfutils/libdw/dwarf_decl_file.c index b1d62df2..c81e35b8 100644 --- a/elfutils/libdw/dwarf_decl_file.c +++ b/elfutils/libdw/dwarf_decl_file.c @@ -1,5 +1,5 @@ /* Return file name containing definition of the given function. - Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -63,8 +63,9 @@ dwarf_decl_file (Dwarf_Die *die) Dwarf_Attribute attr_mem; Dwarf_Sword idx = 0; - if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr) (die, DW_AT_decl_file, - &attr_mem), &idx) != 0) + if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_decl_file, &attr_mem), + &idx) != 0) return NULL; /* Zero means no source file information available. */ @@ -105,3 +106,5 @@ dwarf_decl_file (Dwarf_Die *die) return cu->files->info[idx].name; } +OLD_VERSION (dwarf_decl_file, ELFUTILS_0.122) +NEW_VERSION (dwarf_decl_file, ELFUTILS_0.143) diff --git a/elfutils/libdw/dwarf_decl_line.c b/elfutils/libdw/dwarf_decl_line.c index b4e3c42e..ab64e510 100644 --- a/elfutils/libdw/dwarf_decl_line.c +++ b/elfutils/libdw/dwarf_decl_line.c @@ -1,5 +1,5 @@ /* Get line number of beginning of given function. - Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -63,6 +63,8 @@ dwarf_decl_line (Dwarf_Die *func, int *linep) { return __libdw_attr_intval (func, linep, DW_AT_decl_line); } +OLD_VERSION (dwarf_decl_line, ELFUTILS_0.122) +NEW_VERSION (dwarf_decl_line, ELFUTILS_0.143) int internal_function @@ -71,8 +73,9 @@ __libdw_attr_intval (Dwarf_Die *die, int *linep, int attval) Dwarf_Attribute attr_mem; Dwarf_Sword line; - int res = INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr) (die, attval, - &attr_mem), &line); + int res = INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate) + (die, attval, &attr_mem), + &line); if (res == 0) { assert (line >= 0 && line <= INT_MAX); diff --git a/elfutils/libdw/dwarf_end.c b/elfutils/libdw/dwarf_end.c index 60c9716e..fda37fc1 100644 --- a/elfutils/libdw/dwarf_end.c +++ b/elfutils/libdw/dwarf_end.c @@ -1,5 +1,5 @@ /* Release debugging handling context. - Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -56,7 +56,7 @@ #include <stdlib.h> #include "libdwP.h" - +#include "cfi.h" static void @@ -82,6 +82,10 @@ dwarf_end (dwarf) { if (dwarf != NULL) { + if (dwarf->cfi != NULL) + /* Clean up the CFI cache. */ + __libdw_destroy_frame_cache (dwarf->cfi); + /* The search tree for the CUs. NB: the CU data itself is allocated separately, but the abbreviation hash tables need to be handled. */ diff --git a/elfutils/libdw/dwarf_entry_breakpoints.c b/elfutils/libdw/dwarf_entry_breakpoints.c index 578464f3..1e5c1b81 100644 --- a/elfutils/libdw/dwarf_entry_breakpoints.c +++ b/elfutils/libdw/dwarf_entry_breakpoints.c @@ -1,5 +1,5 @@ /* Find entry breakpoint locations for a function. - Copyright (C) 2005, 2008 Red Hat, Inc. + Copyright (C) 2005-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -93,7 +93,7 @@ dwarf_entry_breakpoints (die, bkpts) if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0) { int error = INTUSE (dwarf_errno) (); - if (error == DWARF_E_NO_DEBUG_LINE) + if (error == 0) /* CU has no DW_AT_stmt_list. */ return entrypc_bkpt (); __libdw_seterrno (error); return -1; diff --git a/elfutils/libdw/dwarf_error.c b/elfutils/libdw/dwarf_error.c index 86ff8213..0d95b8d2 100644 --- a/elfutils/libdw/dwarf_error.c +++ b/elfutils/libdw/dwarf_error.c @@ -111,6 +111,7 @@ static const char *errmsgs[] = [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"), + [DWARF_E_INVALID_CFI] = N_("invalid CFI section"), }; #define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0])) diff --git a/elfutils/libdw/dwarf_formaddr.c b/elfutils/libdw/dwarf_formaddr.c index dcb58d43..9938be7e 100644 --- a/elfutils/libdw/dwarf_formaddr.c +++ b/elfutils/libdw/dwarf_formaddr.c @@ -70,10 +70,10 @@ dwarf_formaddr (attr, return_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); + if (__libdw_read_address (attr->cu->dbg, + IDX_debug_info, attr->valp, + attr->cu->address_size, return_addr)) + return -1; return 0; } diff --git a/elfutils/libdw/dwarf_formflag.c b/elfutils/libdw/dwarf_formflag.c index 4e57c3af..fb60c8e6 100644 --- a/elfutils/libdw/dwarf_formflag.c +++ b/elfutils/libdw/dwarf_formflag.c @@ -1,5 +1,5 @@ /* Return flag represented by attribute. - Copyright (C) 2004 Red Hat, Inc. + Copyright (C) 2004-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2004. @@ -64,6 +64,12 @@ dwarf_formflag (attr, return_bool) if (attr == NULL) return -1; + if (attr->form == DW_FORM_flag_present) + { + *return_bool = true; + return 0; + } + if (unlikely (attr->form != DW_FORM_flag)) { __libdw_seterrno (DWARF_E_NO_FLAG); diff --git a/elfutils/libdw/dwarf_formref_die.c b/elfutils/libdw/dwarf_formref_die.c index 90a4b2d3..a004a0fd 100644 --- a/elfutils/libdw/dwarf_formref_die.c +++ b/elfutils/libdw/dwarf_formref_die.c @@ -72,10 +72,9 @@ dwarf_formref_die (attr, die_mem) ? attr->cu->address_size : attr->cu->offset_size); - if (ref_size == 8) - offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); - else - offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp, + ref_size, &offset, IDX_debug_info, 0)) + return NULL; } else { diff --git a/elfutils/libdw/dwarf_formstring.c b/elfutils/libdw/dwarf_formstring.c index 790831ea..f95d31b8 100644 --- a/elfutils/libdw/dwarf_formstring.c +++ b/elfutils/libdw/dwarf_formstring.c @@ -74,20 +74,14 @@ dwarf_formstring (attrp) 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; + if (__libdw_read_offset (dbg, IDX_debug_info, attrp->valp, + attrp->cu->offset_size, &off, IDX_debug_str, 1)) + return NULL; return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off; } diff --git a/elfutils/libdw/dwarf_formudata.c b/elfutils/libdw/dwarf_formudata.c index b5c40bb5..d9d0a1cd 100644 --- a/elfutils/libdw/dwarf_formudata.c +++ b/elfutils/libdw/dwarf_formudata.c @@ -1,5 +1,5 @@ /* Return unsigned constant represented by attribute. - Copyright (C) 2003, 2005 Red Hat, Inc. + Copyright (C) 2003-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -55,6 +55,61 @@ #include <dwarf.h> #include "libdwP.h" +internal_function unsigned char * +__libdw_formptr (Dwarf_Attribute *attr, int sec_index, + int err_nodata, unsigned char **endpp, + Dwarf_Off *offsetp) +{ + if (attr == NULL) + return NULL; + + const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index]; + if (unlikely (d == NULL)) + { + __libdw_seterrno (err_nodata); + return NULL; + } + + Dwarf_Word offset; + if (attr->form == DW_FORM_sec_offset) + { + if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp, + attr->cu->offset_size, &offset, sec_index, 0)) + return NULL; + } + else if (attr->cu->version > 3) + goto invalid; + + switch (attr->form) + { + case DW_FORM_data4: + case DW_FORM_data8: + if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp, + attr->form == DW_FORM_data4 ? 4 : 8, + &offset, sec_index, 0)) + return NULL; + break; + + default: + if (INTUSE(dwarf_formudata) (attr, &offset)) + return NULL; + }; + + unsigned char *readp = d->d_buf + offset; + unsigned char *endp = d->d_buf + d->d_size; + if (unlikely (readp >= endp)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + if (endpp != NULL) + *endpp = endp; + if (offsetp != NULL) + *offsetp = offset; + return readp; +} int dwarf_formudata (attr, return_uval) @@ -77,11 +132,11 @@ dwarf_formudata (attr, return_uval) 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); + if (__libdw_read_address (attr->cu->dbg, IDX_debug_info, attr->valp, + attr->form == DW_FORM_data4 ? 4 : 8, + return_uval)) + return -1; break; case DW_FORM_sdata: diff --git a/elfutils/libdw/dwarf_frame_cfa.c b/elfutils/libdw/dwarf_frame_cfa.c new file mode 100644 index 00000000..d1c57108 --- /dev/null +++ b/elfutils/libdw/dwarf_frame_cfa.c @@ -0,0 +1,96 @@ +/* Get CFA expression for frame. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <dwarf.h> +#include <stdlib.h> + +int +dwarf_frame_cfa (fs, ops, nops) + Dwarf_Frame *fs; + Dwarf_Op **ops; + size_t *nops; +{ + /* Maybe there was a previous error. */ + if (fs == NULL) + return -1; + + int result = 0; + switch (fs->cfa_rule) + { + case cfa_undefined: + *ops = NULL; + *nops = 0; + break; + + case cfa_offset: + /* The Dwarf_Op was already fully initialized by execute_cfi. */ + *ops = &fs->cfa_data.offset; + *nops = 1; + break; + + case cfa_expr: + /* Parse the expression into internal form. */ + result = __libdw_intern_expression + (NULL, fs->cache->other_byte_order, + fs->cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8, + &fs->cache->expr_tree, &fs->cfa_data.expr, false, + ops, nops, IDX_debug_frame); + break; + + default: + abort (); + } + + return result; +} diff --git a/elfutils/libdw/dwarf_frame_info.c b/elfutils/libdw/dwarf_frame_info.c new file mode 100644 index 00000000..4bdd8068 --- /dev/null +++ b/elfutils/libdw/dwarf_frame_info.c @@ -0,0 +1,74 @@ +/* Get return address register for frame. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" + +int +dwarf_frame_info (fs, start, end, signalp) + Dwarf_Frame *fs; + Dwarf_Addr *start; + Dwarf_Addr *end; + bool *signalp; +{ + /* Maybe there was a previous error. */ + if (fs == NULL) + return -1; + + if (start != NULL) + *start = fs->start; + if (end != NULL) + *end = fs->end; + if (signalp != NULL) + *signalp = fs->fde->cie->signal_frame; + return fs->fde->cie->return_address_register; +} diff --git a/elfutils/libdw/dwarf_frame_register.c b/elfutils/libdw/dwarf_frame_register.c new file mode 100644 index 00000000..3d232e95 --- /dev/null +++ b/elfutils/libdw/dwarf_frame_register.c @@ -0,0 +1,142 @@ +/* Get register location expression for frame. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <dwarf.h> + +int +dwarf_frame_register (fs, regno, ops_mem, ops, nops) + Dwarf_Frame *fs; + int regno; + Dwarf_Op ops_mem[3]; + Dwarf_Op **ops; + size_t *nops; +{ + /* Maybe there was a previous error. */ + if (fs == NULL) + return -1; + + if (unlikely (regno < 0)) + { + __libdw_seterrno (DWARF_E_INVALID_ACCESS); + return -1; + } + + *ops = ops_mem; + *nops = 0; + + if (unlikely ((size_t) regno >= fs->nregs)) + goto default_rule; + + const struct dwarf_frame_register *reg = &fs->regs[regno]; + + switch (reg->rule) + { + case reg_unspecified: + default_rule: + /* Use the default rule for registers not yet mentioned in CFI. */ + if (fs->cache->default_same_value) + goto same_value; + /*FALLTHROUGH*/ + case reg_undefined: + /* The value is known to be unavailable. */ + break; + + case reg_same_value: + same_value: + /* The location is not known here, but the caller might know it. */ + *ops = NULL; + break; + + case reg_offset: + case reg_val_offset: + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa }; + if (reg->value != 0) + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_plus_uconst, + .number = reg->value }; + if (reg->rule == reg_val_offset) + /* A value, not a location. */ + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_stack_value }; + *ops = ops_mem; + break; + + case reg_register: + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_regx, + .number = reg->value }; + break; + + case reg_val_expression: + case reg_expression: + { + unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32 + ? 4 : 8); + + Dwarf_Block block; + const uint8_t *p = fs->cache->data->d.d_buf + reg->value; + get_uleb128 (block.length, p); + block.data = (void *) p; + + /* Parse the expression into internal form. */ + if (__libdw_intern_expression (NULL, + fs->cache->other_byte_order, + address_size, + &fs->cache->expr_tree, &block, + reg->rule == reg_val_expression, + ops, nops, IDX_debug_frame) < 0) + return -1; + break; + } + } + + return 0; +} diff --git a/elfutils/libdw/dwarf_getaranges.c b/elfutils/libdw/dwarf_getaranges.c index 96e99620..72334f5f 100644 --- a/elfutils/libdw/dwarf_getaranges.c +++ b/elfutils/libdw/dwarf_getaranges.c @@ -1,5 +1,5 @@ /* Return list address ranges. - Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2008 Red Hat, Inc. + Copyright (C) 2000-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2000. @@ -104,13 +104,13 @@ dwarf_getaranges (dbg, aranges, naranges) 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; + const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf; + const unsigned char *readendp + = readp + dbg->sectiondata[IDX_debug_aranges]->d_size; while (readp < readendp) { - const char *hdrstart = readp; + const unsigned char *hdrstart = readp; /* Each entry starts with a header: @@ -149,14 +149,10 @@ dwarf_getaranges (dbg, aranges, naranges) } Dwarf_Word offset; - if (length_bytes == 4) - offset = read_4ubyte_unaligned_inc (dbg, readp); - else - offset = read_8ubyte_unaligned_inc (dbg, readp); - - /* Sanity-check the offset. */ - if (offset + 4 > dbg->sectiondata[IDX_debug_info]->d_size) - goto invalid; + if (__libdw_read_offset_inc (dbg, + IDX_debug_aranges, &readp, + length_bytes, &offset, IDX_debug_info, 4)) + return -1; unsigned int address_size = *readp++; if (address_size != 4 && address_size != 8) @@ -175,16 +171,14 @@ dwarf_getaranges (dbg, aranges, naranges) Dwarf_Word range_address; Dwarf_Word range_length; + if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp, + address_size, &range_address)) + return -1; + if (address_size == 4) - { - range_address = read_4ubyte_unaligned_inc (dbg, readp); - range_length = 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); - } + range_length = read_8ubyte_unaligned_inc (dbg, readp); /* Two zero values mark the end. */ if (range_address == 0 && range_length == 0) diff --git a/elfutils/libdw/dwarf_getcfi.c b/elfutils/libdw/dwarf_getcfi.c new file mode 100644 index 00000000..c935631e --- /dev/null +++ b/elfutils/libdw/dwarf_getcfi.c @@ -0,0 +1,94 @@ +/* Get CFI from DWARF file. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include "cfi.h" +#include <dwarf.h> + +Dwarf_CFI * +dwarf_getcfi (dbg) + Dwarf *dbg; +{ + if (dbg == NULL) + return NULL; + + if (dbg->cfi == NULL && dbg->sectiondata[IDX_debug_frame] != NULL) + { + Dwarf_CFI *cfi = libdw_typed_alloc (dbg, Dwarf_CFI); + + cfi->dbg = dbg; + cfi->data = (Elf_Data_Scn *) dbg->sectiondata[IDX_debug_frame]; + + cfi->search_table = NULL; + cfi->search_table_vaddr = 0; + cfi->search_table_entries = 0; + cfi->search_table_encoding = DW_EH_PE_omit; + + cfi->frame_vaddr = 0; + cfi->textrel = 0; + cfi->datarel = 0; + + cfi->e_ident = (unsigned char *) elf_getident (dbg->elf, NULL); + cfi->other_byte_order = dbg->other_byte_order; + + cfi->next_offset = 0; + cfi->cie_tree = cfi->fde_tree = cfi->expr_tree = NULL; + + cfi->ebl = NULL; + + dbg->cfi = cfi; + } + + return dbg->cfi; +} +INTDEF (dwarf_getcfi) diff --git a/elfutils/libdw/dwarf_getcfi_elf.c b/elfutils/libdw/dwarf_getcfi_elf.c new file mode 100644 index 00000000..949515e5 --- /dev/null +++ b/elfutils/libdw/dwarf_getcfi_elf.c @@ -0,0 +1,334 @@ +/* Get CFI from ELF file's exception-handling info. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "libdwP.h" +#include "cfi.h" +#include "encoded-value.h" +#include <dwarf.h> + + +static Dwarf_CFI * +allocate_cfi (Elf *elf, GElf_Addr vaddr) +{ + Dwarf_CFI *cfi = calloc (1, sizeof *cfi); + if (cfi == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + cfi->e_ident = (unsigned char *) elf_getident (elf, NULL); + if (cfi->e_ident == NULL) + { + free (cfi); + __libdw_seterrno (DWARF_E_GETEHDR_ERROR); + return NULL; + } + + if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB) + || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB)) + cfi->other_byte_order = true; + + cfi->frame_vaddr = vaddr; + cfi->textrel = 0; /* XXX ? */ + cfi->datarel = 0; /* XXX ? */ + + return cfi; +} + +static const uint8_t * +parse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr, + const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr, + size_t *table_entries, uint8_t *table_encoding) +{ + const uint8_t *h = hdr; + + if (*h++ != 1) /* version */ + return (void *) -1l; + + uint8_t eh_frame_ptr_encoding = *h++; + uint8_t fde_count_encoding = *h++; + uint8_t fde_table_encoding = *h++; + + if (eh_frame_ptr_encoding == DW_EH_PE_omit) + return (void *) -1l; + + /* Dummy used by read_encoded_value. */ + Elf_Data_Scn dummy_cfi_hdr_data = + { + .d = { .d_buf = (void *) hdr, .d_size = hdr_size } + }; + Dwarf_CFI dummy_cfi = + { + .e_ident = ehdr->e_ident, + .datarel = hdr_vaddr, + .frame_vaddr = hdr_vaddr, + .data = &dummy_cfi_hdr_data, + }; + + if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h, + eh_frame_vaddr))) + return (void *) -1l; + + if (fde_count_encoding != DW_EH_PE_omit) + { + Dwarf_Word fde_count; + if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h, + &fde_count))) + return (void *) -1l; + if (fde_count != 0 && (size_t) fde_count == fde_count + && fde_table_encoding != DW_EH_PE_omit + && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128) + { + *table_entries = fde_count; + *table_encoding = fde_table_encoding; + return h; + } + } + + return NULL; +} + +static Dwarf_CFI * +getcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr) +{ + if (unlikely (phdr->p_filesz < 4)) + goto invalid; + + Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz, + ELF_T_BYTE); + if (data == NULL) + { + invalid_hdr: + invalid: + /* XXX might be read error or corrupt phdr */ + __libdw_seterrno (DWARF_E_INVALID_CFI); + return NULL; + } + + Dwarf_Addr eh_frame_ptr; + size_t search_table_entries; + uint8_t search_table_encoding; + const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz, + phdr->p_vaddr, ehdr, + &eh_frame_ptr, + &search_table_entries, + &search_table_encoding); + if (search_table == (void *) -1l) + goto invalid_hdr; + + Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset; + Dwarf_Word eh_frame_size = 0; + + /* XXX we have no way without section headers to know the size + of the .eh_frame data. Calculate the largest it might possibly be. + This won't be wasteful if the file is already mmap'd, but if it isn't + it might be quite excessive. */ + size_t filesize; + if (elf_rawfile (elf, &filesize) != NULL) + eh_frame_size = filesize - eh_frame_offset; + + data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE); + if (data == NULL) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */ + return NULL; + } + Dwarf_CFI *cfi = allocate_cfi (elf, eh_frame_ptr); + if (cfi != NULL) + { + cfi->data = (Elf_Data_Scn *) data; + + if (search_table != NULL) + { + cfi->search_table = search_table; + cfi->search_table_vaddr = phdr->p_vaddr; + cfi->search_table_encoding = search_table_encoding; + cfi->search_table_entries = search_table_entries; + } + } + return cfi; +} + +/* Search the phdrs for PT_GNU_EH_FRAME. */ +static Dwarf_CFI * +getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr) +{ + const uint_fast16_t phnum = ehdr->e_phnum; + + for (uint_fast16_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (unlikely (phdr == NULL)) + return NULL; + if (phdr->p_type == PT_GNU_EH_FRAME) + return getcfi_gnu_eh_frame (elf, ehdr, phdr); + } + + __libdw_seterrno (DWARF_E_NO_DWARF); + return NULL; +} + +static Dwarf_CFI * +getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, + Elf_Scn *scn, GElf_Shdr *shdr, + Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr) +{ + Elf_Data *data = elf_rawdata (scn, NULL); + if (data == NULL) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); + return NULL; + } + Dwarf_CFI *cfi = allocate_cfi (elf, shdr->sh_addr); + if (cfi != NULL) + { + cfi->data = (Elf_Data_Scn *) data; + if (hdr_scn != NULL) + { + Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL); + if (hdr_data != NULL) + { + GElf_Addr eh_frame_vaddr; + cfi->search_table_vaddr = hdr_vaddr; + cfi->search_table + = parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size, + hdr_vaddr, ehdr, &eh_frame_vaddr, + &cfi->search_table_entries, + &cfi->search_table_encoding); + if (cfi->search_table == (void *) -1l) + { + free (cfi); + /* XXX might be read error or corrupt phdr */ + __libdw_seterrno (DWARF_E_INVALID_CFI); + return NULL; + } + + /* Sanity check. */ + if (unlikely (eh_frame_vaddr != shdr->sh_addr)) + cfi->search_table = NULL; + } + } + } + return cfi; +} + +/* Search for the sections named ".eh_frame" and ".eh_frame_hdr". */ +static Dwarf_CFI * +getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr) +{ + size_t shstrndx; + if (elf_getshdrstrndx (elf, &shstrndx) != 0) + { + __libdw_seterrno (DWARF_E_GETEHDR_ERROR); + return NULL; + } + + if (shstrndx != 0) + { + Elf_Scn *hdr_scn = NULL; + GElf_Addr hdr_vaddr = 0; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + continue; + const char *name = elf_strptr (elf, shstrndx, shdr->sh_name); + if (name == NULL) + continue; + if (!strcmp (name, ".eh_frame_hdr")) + { + hdr_scn = scn; + hdr_vaddr = shdr->sh_addr; + } + else if (!strcmp (name, ".eh_frame")) + return getcfi_scn_eh_frame (elf, ehdr, scn, shdr, + hdr_scn, hdr_vaddr); + } + } + + return (void *) -1l; +} + +Dwarf_CFI * +dwarf_getcfi_elf (elf) + Elf *elf; +{ + if (elf_kind (elf) != ELF_K_ELF) + { + __libdw_seterrno (DWARF_E_NOELF); + return NULL; + } + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (unlikely (ehdr == NULL)) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); + return NULL; + } + + Dwarf_CFI *result = getcfi_shdr (elf, ehdr); + if (result == (void *) -1l) + result = getcfi_phdr (elf, ehdr); + + return result; +} +INTDEF (dwarf_getcfi_elf) diff --git a/elfutils/libdw/dwarf_getlocation.c b/elfutils/libdw/dwarf_getlocation.c index f680aa96..17df8fe9 100644 --- a/elfutils/libdw/dwarf_getlocation.c +++ b/elfutils/libdw/dwarf_getlocation.c @@ -1,5 +1,5 @@ /* Return location expression list. - Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc. + Copyright (C) 2000-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2000. @@ -55,6 +55,7 @@ #include <dwarf.h> #include <search.h> #include <stdlib.h> +#include <assert.h> #include <libdwP.h> @@ -111,27 +112,123 @@ loc_compare (const void *p1, const void *p2) return 0; } +/* For each DW_OP_implicit_value, we store a special entry in the cache. + This points us directly to the block data for later fetching. */ +static void +store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op, + unsigned char *data) +{ + struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s, + sizeof (struct loc_block_s), 1); + block->addr = op; + block->data = data + op->number2; + block->length = op->number; + (void) tsearch (block, cache, loc_compare); +} + +int +dwarf_getlocation_implicit_value (attr, op, return_block) + Dwarf_Attribute *attr; + const Dwarf_Op *op; + Dwarf_Block *return_block; +{ + if (attr == NULL) + return -1; + + struct loc_block_s fake = { .addr = (void *) op }; + struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare); + if (unlikely (found == NULL)) + { + __libdw_seterrno (DWARF_E_NO_BLOCK); + return -1; + } + + return_block->length = (*found)->length; + return_block->data = (*found)->data; + return 0; +} + +/* DW_AT_data_member_location can be a constant as well as a loclistptr. + Only data[48] indicate a loclistptr. */ static int -getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, - Dwarf_Op **llbuf, size_t *listlen) +check_constant_offset (Dwarf_Attribute *attr, + Dwarf_Op **llbuf, size_t *listlen) { - Dwarf *dbg = cu->dbg; + if (attr->code != DW_AT_data_member_location + || attr->form == DW_FORM_data4 + || attr->form == DW_FORM_data8) + return 1; + + /* Check whether we already cached this location. */ + struct loc_s fake = { .addr = attr->valp }; + struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare); + + if (found == NULL) + { + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (attr, &offset) != 0) + return -1; + + Dwarf_Op *result = libdw_alloc (attr->cu->dbg, + Dwarf_Op, sizeof (Dwarf_Op), 1); + + result->atom = DW_OP_plus_uconst; + result->number = offset; + result->number2 = 0; + result->offset = 0; + + /* Insert a record in the search tree so we can find it again later. */ + struct loc_s *newp = libdw_alloc (attr->cu->dbg, + struct loc_s, sizeof (struct loc_s), + 1); + newp->addr = attr->valp; + newp->loc = result; + newp->nloc = 1; + + found = tsearch (newp, &attr->cu->locs, loc_compare); + } + assert ((*found)->nloc == 1); + + if (llbuf != NULL) + { + *llbuf = (*found)->loc; + *listlen = 1; + } + + return 0; +} + +int +internal_function +__libdw_intern_expression (Dwarf *dbg, + bool other_byte_order, unsigned int address_size, + void **cache, const Dwarf_Block *block, bool valuep, + Dwarf_Op **llbuf, size_t *listlen, int sec_index) +{ /* 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); + struct loc_s **found = tfind (&fake, cache, loc_compare); if (found != NULL) { /* We already saw it. */ *llbuf = (*found)->loc; *listlen = (*found)->nloc; + if (valuep) + { + assert (*listlen > 1); + assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value); + } + return 0; } const unsigned char *data = block->data; const unsigned char *const end_data = data + block->length; + const struct { bool other_byte_order; } bo = { other_byte_order }; + struct loclist *loclist = NULL; unsigned int n = 0; /* Decode the opcodes. It is possible in some situations to have a @@ -151,24 +248,9 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, { 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); - } + if (__libdw_read_address_inc (dbg, sec_index, &data, + address_size, &newloc->number)) + return -1; break; case DW_OP_deref: @@ -203,6 +285,10 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, case DW_OP_nop: case DW_OP_push_object_address: case DW_OP_call_ref: + case DW_OP_call_frame_cfa: + case DW_OP_form_tls_address: + case DW_OP_GNU_push_tls_address: + case DW_OP_stack_value: /* No operand. */ break; @@ -211,7 +297,11 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, case DW_OP_deref_size: case DW_OP_xderef_size: if (unlikely (data >= end_data)) - goto invalid; + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } newloc->number = *data++; break; @@ -228,7 +318,7 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, if (unlikely (data + 2 > end_data)) goto invalid; - newloc->number = read_2ubyte_unaligned_inc (dbg, data); + newloc->number = read_2ubyte_unaligned_inc (&bo, data); break; case DW_OP_const2s: @@ -238,14 +328,14 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, if (unlikely (data + 2 > end_data)) goto invalid; - newloc->number = read_2sbyte_unaligned_inc (dbg, data); + newloc->number = read_2sbyte_unaligned_inc (&bo, data); break; case DW_OP_const4u: if (unlikely (data + 4 > end_data)) goto invalid; - newloc->number = read_4ubyte_unaligned_inc (dbg, data); + newloc->number = read_4ubyte_unaligned_inc (&bo, data); break; case DW_OP_const4s: @@ -253,21 +343,21 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, if (unlikely (data + 4 > end_data)) goto invalid; - newloc->number = read_4sbyte_unaligned_inc (dbg, data); + newloc->number = read_4sbyte_unaligned_inc (&bo, data); break; case DW_OP_const8u: if (unlikely (data + 8 > end_data)) goto invalid; - newloc->number = read_8ubyte_unaligned_inc (dbg, data); + newloc->number = read_8ubyte_unaligned_inc (&bo, data); break; case DW_OP_const8s: if (unlikely (data + 8 > end_data)) goto invalid; - newloc->number = read_8sbyte_unaligned_inc (dbg, data); + newloc->number = read_8sbyte_unaligned_inc (&bo, data); break; case DW_OP_constu: @@ -291,6 +381,25 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, get_sleb128 (newloc->number2, data); break; + case DW_OP_bit_piece: + /* XXX Check size. */ + get_uleb128 (newloc->number, data); + get_uleb128 (newloc->number2, data); + break; + + case DW_OP_implicit_value: + /* This cannot be used in a CFI expression. */ + if (unlikely (dbg == NULL)) + goto invalid; + + /* XXX Check size. */ + get_uleb128 (newloc->number, data); /* Block length. */ + if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number)) + goto invalid; + newloc->number2 = data - block->data; /* Relative block offset. */ + data += newloc->number; /* Skip the block. */ + break; + default: goto invalid; } @@ -304,8 +413,33 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, goto invalid; } + if (valuep) + { + struct loclist *newloc; + newloc = (struct loclist *) alloca (sizeof (struct loclist)); + newloc->atom = DW_OP_stack_value; + newloc->number = 0; + newloc->number2 = 0; + newloc->offset = data - block->data; + newloc->next = loclist; + loclist = newloc; + ++n; + } + /* Allocate the array. */ - Dwarf_Op *result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); + Dwarf_Op *result; + if (dbg != NULL) + result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); + else + { + result = malloc (sizeof *result * n); + if (result == NULL) + { + nomem: + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + } /* Store the result. */ *llbuf = result; @@ -313,37 +447,62 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, do { - /* We populate the array from the back since the list is - backwards. */ + /* 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; + if (result[n].atom == DW_OP_implicit_value) + store_implicit_value (dbg, cache, &result[n], block->data); + 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); + /* Insert a record in the search tree so that we can find it again later. */ + struct loc_s *newp; + if (dbg != NULL) + newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1); + else + { + newp = malloc (sizeof *newp); + if (newp == NULL) + { + free (result); + goto nomem; + } + } + newp->addr = block->data; newp->loc = result; newp->nloc = *listlen; - (void) tsearch (newp, &cu->locs, loc_compare); + (void) tsearch (newp, cache, loc_compare); /* We did it. */ return 0; } +static int +getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, + Dwarf_Op **llbuf, size_t *listlen, int sec_index) +{ + return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order, + cu->address_size, &cu->locs, block, false, + llbuf, listlen, sec_index); +} + int dwarf_getlocation (attr, llbuf, listlen) Dwarf_Attribute *attr; Dwarf_Op **llbuf; size_t *listlen; { + int result = check_constant_offset (attr, llbuf, listlen); + if (result != 1) + return result; + if (! attr_ok (attr)) return -1; @@ -352,7 +511,7 @@ dwarf_getlocation (attr, llbuf, listlen) if (INTUSE(dwarf_formblock) (attr, &block) != 0) return -1; - return getlocation (attr->cu, &block, llbuf, listlen); + return getlocation (attr->cu, &block, llbuf, listlen, IDX_debug_info); } int @@ -376,7 +535,8 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) if (maxlocs == 0) return 0; if (llbufs != NULL && - getlocation (attr->cu, &block, &llbufs[0], &listlens[0]) != 0) + getlocation (attr->cu, &block, &llbufs[0], &listlens[0], + IDX_debug_info) != 0) return -1; return listlens[0] == 0 ? 0 : 1; } @@ -388,25 +548,21 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) return -1; } - /* Must have the form data4 or data8 which act as an offset. */ - Dwarf_Word offset; - if (unlikely (INTUSE(dwarf_formudata) (attr, &offset) != 0)) - return -1; + int result = check_constant_offset (attr, &llbufs[0], &listlens[0]); + if (result != 1) + return result ?: 1; - const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc]; - if (unlikely (d == NULL)) - { - __libdw_seterrno (DWARF_E_NO_LOCLIST); - return -1; - } + unsigned char *endp; + unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc, + DWARF_E_NO_LOCLIST, &endp, NULL); + if (readp == NULL) + return -1; Dwarf_Addr base = (Dwarf_Addr) -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) + if (endp - readp < attr->cu->address_size * 2) { invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); @@ -415,42 +571,25 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) 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; - if (unlikely (base == (Dwarf_Addr) -1)) - goto invalid; - 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. */ + int status + = __libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc, + &readp, attr->cu->address_size, + &begin, &end, &base); + if (status == 2) /* End of list entry. */ break; + else if (status == 1) /* Base address selected. */ + continue; + else if (status < 0) + return status; - if ((unsigned char *) d->d_buf + d->d_size - readp < 2) + if (endp - readp < 2) goto invalid; /* 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) + if (endp - readp < (ptrdiff_t) block.length) goto invalid; readp += block.length; @@ -486,7 +625,8 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) /* This one matches the address. */ if (llbufs != NULL && unlikely (getlocation (attr->cu, &block, - &llbufs[got], &listlens[got]) != 0)) + &llbufs[got], &listlens[got], + IDX_debug_loc) != 0)) return -1; ++got; } diff --git a/elfutils/libdw/dwarf_getmacros.c b/elfutils/libdw/dwarf_getmacros.c index 743ade3b..b9ec34b9 100644 --- a/elfutils/libdw/dwarf_getmacros.c +++ b/elfutils/libdw/dwarf_getmacros.c @@ -1,5 +1,5 @@ /* Get macro information. - Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + Copyright (C) 2002-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -65,27 +65,39 @@ dwarf_getmacros (die, callback, arg, offset) void *arg; ptrdiff_t offset; { - /* Get the appropriate attribute. */ - Dwarf_Attribute attr; - if (INTUSE(dwarf_attr) (die, DW_AT_macro_info, &attr) == NULL) + if (die == NULL) return -1; - /* Offset into the .debug_macinfo section. */ - Dwarf_Word macoff; - if (INTUSE(dwarf_formudata) (&attr, &macoff) != 0) - return -1; + Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_macinfo]; + if (unlikely (d == NULL) || unlikely (d->d_buf == NULL)) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + 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 (offset == 0) + { + /* Get the appropriate attribute. */ + Dwarf_Attribute attr; + if (INTUSE(dwarf_attr) (die, DW_AT_macro_info, &attr) == NULL) + return -1; - if (readp == readendp) - return 0; + /* Offset into the .debug_macinfo section. */ + Dwarf_Word macoff; + if (INTUSE(dwarf_formudata) (&attr, &macoff) != 0) + return -1; - if (*readp != DW_MACINFO_start_file) + offset = macoff; + } + if (unlikely (offset > (ptrdiff_t) d->d_size)) goto invalid; + const unsigned char *readp = d->d_buf + offset; + const unsigned char *readendp = d->d_buf + d->d_size; + + if (readp == readendp) + return 0; + while (readp < readendp) { unsigned int opcode = *readp++; @@ -142,9 +154,7 @@ dwarf_getmacros (die, callback, arg, offset) 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)); + return readp - (const unsigned char *) d->d_buf; } /* If we come here the termination of the data for the CU is not diff --git a/elfutils/libdw/dwarf_getpubnames.c b/elfutils/libdw/dwarf_getpubnames.c index 1b054e26..5560a758 100644 --- a/elfutils/libdw/dwarf_getpubnames.c +++ b/elfutils/libdw/dwarf_getpubnames.c @@ -102,7 +102,6 @@ get_offsets (Dwarf *dbg) else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE)) { - invalid_dwarf: __libdw_seterrno (DWARF_E_INVALID_DWARF); goto err_return; } @@ -124,18 +123,12 @@ get_offsets (Dwarf *dbg) } /* 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); + if (__libdw_read_offset (dbg, IDX_debug_pubnames, readp + 2, len_bytes, + &mem[cnt].cu_offset, IDX_debug_info, 3)) + /* Error has been already set in reader. */ + goto err_return; /* Determine the size of the CU header. */ - if (unlikely (dbg->sectiondata[IDX_debug_info] == NULL - || dbg->sectiondata[IDX_debug_info]->d_buf == NULL - || (mem[cnt].cu_offset + 3 - >= dbg->sectiondata[IDX_debug_info]->d_size))) - goto invalid_dwarf; - unsigned char *infop = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf + mem[cnt].cu_offset); diff --git a/elfutils/libdw/dwarf_getscopevar.c b/elfutils/libdw/dwarf_getscopevar.c index 4e5b429e..6ce214f5 100644 --- a/elfutils/libdw/dwarf_getscopevar.c +++ b/elfutils/libdw/dwarf_getscopevar.c @@ -1,5 +1,5 @@ /* Find a named variable or parameter within given scopes. - Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -129,9 +129,7 @@ dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, } /* 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)); + const char *diename = INTUSE(dwarf_diename) (result); if (diename != NULL && !strcmp (name, diename)) { /* We have a matching name. */ diff --git a/elfutils/libdw/dwarf_getsrc_file.c b/elfutils/libdw/dwarf_getsrc_file.c index 91abbaeb..bc612f6c 100644 --- a/elfutils/libdw/dwarf_getsrc_file.c +++ b/elfutils/libdw/dwarf_getsrc_file.c @@ -1,5 +1,5 @@ /* Find line information for given file/line/column triple. - Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -74,11 +74,11 @@ dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, 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) + for (Dwarf_Off off = 0; + INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0; + off = noff) { Dwarf_Die cudie_mem; Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem); @@ -89,7 +89,14 @@ dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, Dwarf_Lines *lines; size_t nlines; if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) - return -1; + { + /* Ignore a CU that just has no DW_AT_stmt_list at all. */ + int error = INTUSE(dwarf_errno) (); + if (error == 0) + continue; + __libdw_seterrno (error); + return -1; + } /* Search through all the line number records for a matching file and line/column number. If any of the numbers is zero, @@ -175,8 +182,6 @@ dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, already, there is no need to go on to the next CU. */ if (cur_match == max_match) break; - - off = noff; } if (cur_match > 0) diff --git a/elfutils/libdw/dwarf_getsrclines.c b/elfutils/libdw/dwarf_getsrclines.c index fe0e67d6..43fad99a 100644 --- a/elfutils/libdw/dwarf_getsrclines.c +++ b/elfutils/libdw/dwarf_getsrclines.c @@ -135,20 +135,13 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) /* 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) + const unsigned char *lineendp; + const unsigned char *linep + = __libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE, + (unsigned char **) &lineendp, NULL); + if (linep == NULL) 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, @@ -162,6 +155,8 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); goto out; } + + Dwarf *dbg = cu->dbg; Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); unsigned int length = 4; if (unlikely (unit_length == DWARF3_LENGTH_64_BIT)) @@ -429,10 +424,9 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) /* 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); + if (__libdw_read_address_inc (dbg, IDX_debug_line, &linep, + cu->address_size, &address)) + goto out; break; case DW_LNE_define_file: diff --git a/elfutils/libdw/dwarf_hasattr_integrate.c b/elfutils/libdw/dwarf_hasattr_integrate.c index 12b48631..806742d6 100644 --- a/elfutils/libdw/dwarf_hasattr_integrate.c +++ b/elfutils/libdw/dwarf_hasattr_integrate.c @@ -68,6 +68,8 @@ dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name) Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, &attr_mem); if (attr == NULL) + attr = INTUSE(dwarf_attr) (die, DW_AT_specification, &attr_mem); + if (attr == NULL) break; die = INTUSE(dwarf_formref_die) (attr, &die_mem); diff --git a/elfutils/libdw/dwarf_next_cfi.c b/elfutils/libdw/dwarf_next_cfi.c new file mode 100644 index 00000000..d5d4cfdb --- /dev/null +++ b/elfutils/libdw/dwarf_next_cfi.c @@ -0,0 +1,234 @@ +/* Advance to next CFI entry. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include "encoded-value.h" + +#include <string.h> + + +int +dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry) + const unsigned char e_ident[]; + Elf_Data *data; + bool eh_frame_p; + Dwarf_Off off; + Dwarf_Off *next_off; + Dwarf_CFI_Entry *entry; +{ + /* Dummy struct for memory-access.h macros. */ + BYTE_ORDER_DUMMY (dw, e_ident); + + /* If we reached the end before don't do anything. */ + if (off == (Dwarf_Off) -1l + /* Make sure there is enough space in the .debug_frame 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 >= data->d_size)) + { + *next_off = (Dwarf_Off) -1l; + return 1; + } + + /* This points into the .debug_frame section at the start of the entry. */ + const uint8_t *bytes = data->d_buf + off; + const uint8_t *limit = data->d_buf + data->d_size; + + /* The format of a CFI entry is described in DWARF3 6.4.1: + */ + + uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes); + size_t offset_size = 4; + if (length == DWARF3_LENGTH_64_BIT) + { + /* This is the 64-bit DWARF format. */ + offset_size = 8; + if (unlikely (limit - bytes < 8)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + length = read_8ubyte_unaligned_inc (&dw, bytes); + } + if (unlikely ((uint64_t) (limit - bytes) < length) + || unlikely (length < offset_size + 1)) + goto invalid; + + /* Now we know how large the entry 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. */ + *next_off = off + (2 * offset_size - 4) + length; + + limit = bytes + length; + + const uint8_t *const cie_pointer_start = bytes; + if (offset_size == 8) + entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes); + else + { + entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes); + /* Canonicalize the 32-bit CIE_ID value to 64 bits. */ + if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32) + entry->cie.CIE_id = DW_CIE_ID_64; + } + if (eh_frame_p) + { + /* Canonicalize the .eh_frame CIE pointer to .debug_frame format. */ + if (entry->cie.CIE_id == 0) + entry->cie.CIE_id = DW_CIE_ID_64; + else + { + /* In .eh_frame format, a CIE pointer is the distance from where + it appears back to the beginning of the CIE. */ + ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf; + if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos) + || unlikely (pos <= (ptrdiff_t) offset_size)) + goto invalid; + entry->cie.CIE_id = pos - entry->cie.CIE_id; + } + } + + if (entry->cie.CIE_id == DW_CIE_ID_64) + { + /* Read the version stamp. Always an 8-bit value. */ + uint8_t version = *bytes++; + + if (version != 1 && version != 3) + goto invalid; + + entry->cie.augmentation = (const char *) bytes; + + bytes = memchr (bytes, '\0', limit - bytes); + if (bytes == NULL) + goto invalid; + ++bytes; + + const char *ap = entry->cie.augmentation; + + /* g++ v2 "eh" has pointer immediately following augmentation string, + so it must be handled first. */ + if (unlikely (ap[0] == 'e' && ap[1] == 'h')) + { + /* The address size for CFI is implicit in the ELF class. */ + unsigned int address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + ap += 2; + bytes += address_size; + } + + get_uleb128 (entry->cie.code_alignment_factor, bytes); + get_sleb128 (entry->cie.data_alignment_factor, bytes); + + if (version == 3) /* DWARF 3 */ + get_uleb128 (entry->cie.return_address_register, bytes); + else /* DWARF 2 */ + entry->cie.return_address_register = *bytes++; + + /* If we have sized augmentation data, + we don't need to grok it all. */ + entry->cie.fde_augmentation_data_size = 0; + bool sized_augmentation = *ap == 'z'; + if (sized_augmentation) + { + get_uleb128 (entry->cie.augmentation_data_size, bytes); + if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size) + goto invalid; + entry->cie.augmentation_data = bytes; + bytes += entry->cie.augmentation_data_size; + } + else + { + entry->cie.augmentation_data = bytes; + + for (; *ap != '\0'; ++ap) + { + uint8_t encoding; + switch (*ap) + { + case 'L': /* Skip LSDA pointer encoding byte. */ + case 'R': /* Skip FDE address encoding byte. */ + encoding = *bytes++; + entry->cie.fde_augmentation_data_size + += encoded_value_size (data, e_ident, encoding, NULL); + continue; + case 'P': /* Skip encoded personality routine pointer. */ + encoding = *bytes++; + bytes += encoded_value_size (data, e_ident, encoding, bytes); + continue; + case 'S': /* Skip signal-frame flag. */ + continue; + default: + /* Unknown augmentation string. initial_instructions might + actually start with some augmentation data. */ + break; + } + break; + } + entry->cie.augmentation_data_size + = bytes - entry->cie.augmentation_data; + } + + entry->cie.initial_instructions = bytes; + entry->cie.initial_instructions_end = limit; + } + else + { + entry->fde.start = bytes; + entry->fde.end = limit; + } + + return 0; +} +INTDEF (dwarf_next_cfi) diff --git a/elfutils/libdw/dwarf_nextcu.c b/elfutils/libdw/dwarf_nextcu.c index 9e5a96bc..e436e115 100644 --- a/elfutils/libdw/dwarf_nextcu.c +++ b/elfutils/libdw/dwarf_nextcu.c @@ -1,5 +1,5 @@ /* Advance to next CU header. - Copyright (C) 2002, 2003, 2004, 2005, 2008 Red Hat, Inc. + Copyright (C) 2002-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -84,7 +84,8 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp, /* 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; + const unsigned char *data = dwarf->sectiondata[IDX_debug_info]->d_buf; + const unsigned char *bytes = data + off; /* The format of the CU header is described in dwarf2p1 7.5.1: @@ -144,10 +145,10 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp, /* 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 (__libdw_read_offset_inc (dwarf, IDX_debug_info, &bytes, offset_size, + &abbrev_offset, IDX_debug_abbrev, 0)) + return -1; + if (abbrev_offsetp != NULL) *abbrev_offsetp = abbrev_offset; @@ -162,9 +163,7 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp, /* Store the header length. */ if (header_sizep != NULL) - *header_sizep = (bytes - - ((char *) dwarf->sectiondata[IDX_debug_info]->d_buf - + off)); + *header_sizep = bytes - (data + off); /* See definition of DIE_OFFSET_FROM_CU_OFFSET macro for an explanation of the trick in this expression. */ diff --git a/elfutils/libdw/dwarf_ranges.c b/elfutils/libdw/dwarf_ranges.c index 1eef617b..50fb6ba2 100644 --- a/elfutils/libdw/dwarf_ranges.c +++ b/elfutils/libdw/dwarf_ranges.c @@ -55,6 +55,52 @@ #include <dwarf.h> #include <assert.h> +/* Read up begin/end pair and increment read pointer. + - If it's normal range record, set up `*beginp' and `*endp' and return 0. + - If it's base address selection record, set up `*basep' and return 1. + - If it's end of rangelist, don't set anything and return 2 + - If an error occurs, don't set anything and return -1. */ +internal_function int +__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index, + unsigned char **addrp, int width, + Dwarf_Addr *beginp, Dwarf_Addr *endp, + Dwarf_Addr *basep) +{ + Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1 + : (Elf64_Addr) (Elf32_Addr) -1); + Dwarf_Addr begin; + Dwarf_Addr end; + + unsigned char *addr = *addrp; + bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address, begin); + bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address, end); + *addrp = addr; + + /* Unrelocated escape for begin means base address selection. */ + if (begin == escape && !begin_relocated) + { + if (unlikely (end == escape)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + if (basep != NULL) + *basep = end; + return 1; + } + + /* Unrelocated pair of zeroes means end of range list. */ + if (begin == 0 && end == 0 && !begin_relocated && !end_relocated) + return 2; + + /* Don't check for begin_relocated == end_relocated. Serve the data + to the client even though it may be buggy. */ + *beginp = begin; + *endp = end; + + return 0; +} ptrdiff_t dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep, @@ -80,11 +126,12 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep, const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges]; if (d == NULL && offset != 0) { - no_ranges: __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES); return -1; } + unsigned char *readp; + unsigned char *readendp; if (offset == 0) { Dwarf_Attribute attr_mem; @@ -94,14 +141,12 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep, /* No PC attributes in this DIE at all, so an empty range list. */ return 0; - /* Must have the form data4 or data8 which act as an offset. */ Dwarf_Word start_offset; - if (INTUSE(dwarf_formudata) (attr, &start_offset) != 0) + if ((readp = __libdw_formptr (attr, IDX_debug_ranges, + DWARF_E_NO_DEBUG_RANGES, + &readendp, &start_offset)) == NULL) return -1; - if (d == NULL) - goto no_ranges; - offset = start_offset; assert ((Dwarf_Word) offset == start_offset); @@ -127,45 +172,37 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep, return -1; } } - else if (offset < 0 || (size_t) offset >= d->d_size) + else { - __libdw_seterrno (DWARF_E_INVALID_OFFSET); - return -1l; - } + if (__libdw_offset_in_section (die->cu->dbg, + IDX_debug_ranges, offset, 1)) + return -1l; - unsigned char *readp = d->d_buf + offset; + readp = d->d_buf + offset; + readendp = d->d_buf + d->d_size; + } next: - if ((unsigned char *) d->d_buf + d->d_size - readp - < die->cu->address_size * 2) + if (readendp - readp < die->cu->address_size * 2) goto invalid; Dwarf_Addr begin; Dwarf_Addr end; - if (die->cu->address_size == 8) - { - begin = read_8ubyte_unaligned_inc (die->cu->dbg, readp); - end = read_8ubyte_unaligned_inc (die->cu->dbg, readp); - if (begin == (uint64_t) -1l) /* Base address entry. */ - { - *basep = end; - goto next; - } - } - else + + switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges, + &readp, die->cu->address_size, + &begin, &end, basep)) { - begin = read_4ubyte_unaligned_inc (die->cu->dbg, readp); - end = read_4ubyte_unaligned_inc (die->cu->dbg, readp); - if (begin == (uint32_t) -1) /* Base address entry. */ - { - *basep = end; - goto next; - } + case 0: + break; + case 1: + goto next; + case 2: + return 0; + default: + return -1l; } - if (begin == 0 && end == 0) /* End of list entry. */ - return 0; - /* We have an address range entry. */ *startp = *basep + begin; *endp = *basep + end; diff --git a/elfutils/libdw/dwarf_srclang.c b/elfutils/libdw/dwarf_srclang.c index 2efa0954..f1ff954c 100644 --- a/elfutils/libdw/dwarf_srclang.c +++ b/elfutils/libdw/dwarf_srclang.c @@ -1,5 +1,5 @@ /* Return source language attribute of DIE. - Copyright (C) 2003, 2005 Red Hat, Inc. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -63,7 +63,9 @@ dwarf_srclang (die) Dwarf_Attribute attr_mem; Dwarf_Word value; - return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_language, - &attr_mem), + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_language, &attr_mem), &value) == 0 ? (int) value : -1; } +OLD_VERSION (dwarf_srclang, ELFUTILS_0.122) +NEW_VERSION (dwarf_srclang, ELFUTILS_0.143) diff --git a/elfutils/libdw/encoded-value.h b/elfutils/libdw/encoded-value.h new file mode 100644 index 00000000..3f9b2440 --- /dev/null +++ b/elfutils/libdw/encoded-value.h @@ -0,0 +1,202 @@ +/* DW_EH_PE_* support for libdw unwinder. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifndef _ENCODED_VALUE_H +#define _ENCODED_VALUE_H 1 + +#include <dwarf.h> +#include <stdlib.h> +#include "libdwP.h" + + +static size_t __attribute__ ((unused)) +encoded_value_size (const Elf_Data *data, const unsigned char e_ident[], + uint8_t encoding, const uint8_t *p) +{ + if (encoding == DW_EH_PE_omit) + return 0; + + switch (encoding & 0x07) + { + case DW_EH_PE_udata2: + return 2; + case DW_EH_PE_udata4: + return 4; + case DW_EH_PE_udata8: + return 8; + + case DW_EH_PE_absptr: + return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + case DW_EH_PE_uleb128: + if (p != NULL) + { + const uint8_t *end = p; + while (end < (uint8_t *) data->d_buf + data->d_size) + if (*end++ & 0x80u) + return end - p; + } + + default: + abort (); + return 0; + } +} + +static inline int __attribute__ ((unused)) +__libdw_cfi_read_address_inc (const Dwarf_CFI *cache, + const unsigned char **addrp, + int width, Dwarf_Addr *ret) +{ + width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + if (cache->dbg != NULL) + return __libdw_read_address_inc (cache->dbg, IDX_debug_frame, + addrp, width, ret); + + /* Only .debug_frame might have relocation to consider. + Read plain values from .eh_frame data. */ + + if (width == 4) + *ret = read_4ubyte_unaligned_inc (cache, *addrp); + else + *ret = read_8ubyte_unaligned_inc (cache, *addrp); + return 0; +} + +static bool __attribute__ ((unused)) +read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p, + Dwarf_Addr *result) +{ + *result = 0; + switch (encoding & 0x70) + { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + *result = (cache->frame_vaddr + + (*p - (const uint8_t *) cache->data->d.d_buf)); + break; + case DW_EH_PE_textrel: + // ia64: segrel + *result = cache->textrel; + break; + case DW_EH_PE_datarel: + // i386: GOTOFF + // ia64: gprel + *result = cache->datarel; + break; + case DW_EH_PE_funcrel: /* XXX */ + break; + case DW_EH_PE_aligned: + { + const size_t address_size + = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + size_t align = ((cache->frame_vaddr + + (*p - (const uint8_t *) cache->data->d.d_buf)) + & (address_size - 1)); + if (align != 0) + *p += address_size - align; + break; + } + + default: + abort (); + } + + Dwarf_Addr value; + switch (encoding & 0x0f) + { + case DW_EH_PE_udata2: + value = read_2ubyte_unaligned_inc (cache, *p); + break; + + case DW_EH_PE_sdata2: + value = read_2sbyte_unaligned_inc (cache, *p); + break; + + case DW_EH_PE_udata4: + if (__libdw_cfi_read_address_inc (cache, p, 4, &value)) + return false; + break; + + case DW_EH_PE_sdata4: + if (__libdw_cfi_read_address_inc (cache, p, 4, &value)) + return false; + value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend. */ + break; + + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: + if (__libdw_cfi_read_address_inc (cache, p, 8, &value)) + return false; + break; + + case DW_EH_PE_absptr: + if (__libdw_cfi_read_address_inc (cache, p, 0, &value)) + return false; + break; + + case DW_EH_PE_uleb128: + get_uleb128 (value, *p); + break; + + case DW_EH_PE_sleb128: + get_sleb128 (value, *p); + break; + + default: + abort (); + } + + *result += value; + return false; +} + +#endif /* encoded-value.h */ diff --git a/elfutils/libdw/fde.c b/elfutils/libdw/fde.c new file mode 100644 index 00000000..f38eed7e --- /dev/null +++ b/elfutils/libdw/fde.c @@ -0,0 +1,306 @@ +/* FDE reading. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <search.h> +#include <stdlib.h> + +#include "encoded-value.h" + +static int +compare_fde (const void *a, const void *b) +{ + const struct dwarf_fde *fde1 = a; + const struct dwarf_fde *fde2 = b; + + /* Find out which of the two arguments is the search value. + It has end offset 0. */ + if (fde1->end == 0) + { + if (fde1->start < fde2->start) + return -1; + if (fde1->start >= fde2->end) + return 1; + } + else + { + if (fde2->start < fde1->start) + return 1; + if (fde2->start >= fde1->end) + return -1; + } + + return 0; +} + +static struct dwarf_fde * +intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry) +{ + /* Look up the new entry's CIE. */ + struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer); + if (cie == NULL) + return (void *) -1l; + + struct dwarf_fde *fde = malloc (sizeof (struct dwarf_fde)); + if (fde == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + fde->instructions = entry->start; + fde->instructions_end = entry->end; + if (unlikely (read_encoded_value (cache, cie->fde_encoding, + &fde->instructions, &fde->start)) + || unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f, + &fde->instructions, &fde->end))) + return NULL; + fde->end += fde->start; + + fde->cie = cie; + + if (cie->sized_augmentation_data) + { + /* The CIE augmentation says the FDE has a DW_FORM_block + before its actual instruction stream. */ + Dwarf_Word len; + get_uleb128 (len, fde->instructions); + if ((Dwarf_Word) (fde->instructions_end < fde->instructions) < len) + { + free (fde); + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + fde->instructions += len; + } + else + /* We had to understand all of the CIE augmentation string. + We've recorded the number of data bytes in FDEs. */ + fde->instructions += cie->fde_augmentation_data_size; + + /* Add the new entry to the search tree. */ + if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL) + { + free (fde); + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + return fde; +} + +static struct dwarf_fde * +fde_by_offset (Dwarf_CFI *cache, Dwarf_Addr address, Dwarf_Off offset) +{ + Dwarf_CFI_Entry entry; + Dwarf_Off next_offset; + int result = INTUSE(dwarf_next_cfi) (cache->e_ident, + &cache->data->d, CFI_IS_EH (cache), + offset, &next_offset, &entry); + if (result != 0) + { + if (result > 0) + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + if (unlikely (dwarf_cfi_cie_p (&entry))) + goto invalid; + + /* We have a new FDE to consider. */ + struct dwarf_fde *fde = intern_fde (cache, &entry.fde); + if (fde == (void *) -1l || fde == NULL) + return NULL; + + /* If this happened to be what we would have read next, notice it. */ + if (cache->next_offset == offset) + cache->next_offset = next_offset; + + /* Sanity check the address range. */ + if (address < fde->start || address >= fde->end) + goto invalid; + + return fde; +} + +/* Use a binary search table in .eh_frame_hdr format, yield an FDE offset. */ +static Dwarf_Off +binary_search_fde (Dwarf_CFI *cache, Dwarf_Addr address) +{ + const size_t size = 2 * encoded_value_size (&cache->data->d, cache->e_ident, + cache->search_table_encoding, + NULL); + + /* Dummy used by read_encoded_value. */ + Dwarf_CFI dummy_cfi = + { + .e_ident = cache->e_ident, + .datarel = cache->search_table_vaddr, + .frame_vaddr = cache->search_table_vaddr, + }; + + size_t l = 0, u = cache->search_table_entries; + while (l < u) + { + size_t idx = (l + u) / 2; + + const uint8_t *p = &cache->search_table[idx * size]; + Dwarf_Addr start; + if (unlikely (read_encoded_value (&dummy_cfi, + cache->search_table_encoding, &p, + &start))) + break; + if (address < start) + u = idx; + else + { + Dwarf_Addr fde; + if (unlikely (read_encoded_value (&dummy_cfi, + cache->search_table_encoding, &p, + &fde))) + break; + if (address >= start) + { + l = idx + 1; + + /* If this is the last entry, its upper bound is assumed to be + the end of the module. + XXX really should be end of containing PT_LOAD segment */ + if (l < cache->search_table_entries) + { + /* Look at the start address in the following entry. */ + Dwarf_Addr end; + if (unlikely (read_encoded_value + (&dummy_cfi, cache->search_table_encoding, &p, + &end))) + break; + if (address >= end) + continue; + } + + return fde - cache->frame_vaddr; + } + } + } + + return (Dwarf_Off) -1l; +} + +struct dwarf_fde * +internal_function +__libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address) +{ + /* Look for a cached FDE covering this address. */ + + const struct dwarf_fde fde_key = { .start = address, .end = 0 }; + struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde); + if (found != NULL) + return *found; + + /* Use .eh_frame_hdr binary search table if possible. */ + if (cache->search_table != NULL) + { + Dwarf_Off offset = binary_search_fde (cache, address); + if (offset == (Dwarf_Off) -1l) + goto no_match; + return fde_by_offset (cache, address, offset); + } + + /* It's not there. Read more CFI entries until we find it. */ + while (1) + { + Dwarf_Off last_offset = cache->next_offset; + Dwarf_CFI_Entry entry; + int result = INTUSE(dwarf_next_cfi) (cache->e_ident, + &cache->data->d, CFI_IS_EH (cache), + last_offset, &cache->next_offset, + &entry); + if (result > 0) + break; + if (result < 0) + { + if (cache->next_offset == last_offset) + /* We couldn't progress past the bogus FDE. */ + break; + /* Skip the loser and look at the next entry. */ + continue; + } + + if (dwarf_cfi_cie_p (&entry)) + { + /* This is a CIE, not an FDE. We eagerly intern these + because the next FDE will usually refer to this CIE. */ + __libdw_intern_cie (cache, last_offset, &entry.cie); + continue; + } + + /* We have a new FDE to consider. */ + struct dwarf_fde *fde = intern_fde (cache, &entry.fde); + + if (fde == (void *) -1l) /* Bad FDE, but we can keep looking. */ + continue; + + if (fde == NULL) /* Bad data. */ + return NULL; + + /* Is this the one we're looking for? */ + if (fde->start <= address && fde->end > address) + return fde; + } + + no_match: + /* We found no FDE covering this address. */ + __libdw_seterrno (DWARF_E_NO_MATCH); + return NULL; +} diff --git a/elfutils/libdw/frame-cache.c b/elfutils/libdw/frame-cache.c new file mode 100644 index 00000000..f4876638 --- /dev/null +++ b/elfutils/libdw/frame-cache.c @@ -0,0 +1,87 @@ +/* Frame cache handling. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <search.h> +#include <stdlib.h> + + +static void +free_cie (void *arg) +{ + struct dwarf_cie *cie = arg; + + free ((Dwarf_Frame *) cie->initial_state); + free (cie); +} + +#define free_fde free + +static void +free_expr (void *arg) +{ + struct loc_s *loc = arg; + + free (loc->loc); + free (loc); +} + +void +internal_function +__libdw_destroy_frame_cache (Dwarf_CFI *cache) +{ + /* Most of the data is in our two search trees. */ + tdestroy (cache->fde_tree, free_fde); + tdestroy (cache->cie_tree, free_cie); + tdestroy (cache->expr_tree, free_expr); +} diff --git a/elfutils/libdw/libdw.h b/elfutils/libdw/libdw.h index 3f3e5a09..7602e611 100644 --- a/elfutils/libdw/libdw.h +++ b/elfutils/libdw/libdw.h @@ -1,5 +1,5 @@ /* Interfaces for libdw. - Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. + Copyright (C) 2002-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -190,6 +190,70 @@ typedef struct } Dwarf_Op; +/* This describes one Common Information Entry read from a CFI section. + Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */ +typedef struct +{ + Dwarf_Off CIE_id; /* Always DW_CIE_ID_64 in Dwarf_CIE structures. */ + + /* Instruction stream describing initial state used by FDEs. If + we did not understand the whole augmentation string and it did + not use 'z', then there might be more augmentation data here + (and in FDEs) before the actual instructions. */ + const uint8_t *initial_instructions; + const uint8_t *initial_instructions_end; + + Dwarf_Word code_alignment_factor; + Dwarf_Sword data_alignment_factor; + Dwarf_Word return_address_register; + + const char *augmentation; /* Augmentation string. */ + + /* Augmentation data, might be NULL. The size is correct only if + we understood the augmentation string sufficiently. */ + const uint8_t *augmentation_data; + size_t augmentation_data_size; + size_t fde_augmentation_data_size; +} Dwarf_CIE; + +/* This describes one Frame Description Entry read from a CFI section. + Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */ +typedef struct +{ + /* Section offset of CIE this FDE refers to. This will never be + DW_CIE_ID_64 in an FDE. If this value is DW_CIE_ID_64, this is + actually a Dwarf_CIE structure. */ + Dwarf_Off CIE_pointer; + + /* We can't really decode anything further without looking up the CIE + and checking its augmentation string. Here follows the encoded + initial_location and address_range, then any augmentation data, + then the instruction stream. This FDE describes PC locations in + the byte range [initial_location, initial_location+address_range). + When the CIE augmentation string uses 'z', the augmentation data is + a DW_FORM_block (self-sized). Otherwise, when we understand the + augmentation string completely, fde_augmentation_data_size gives + the number of bytes of augmentation data before the instructions. */ + const uint8_t *start; + const uint8_t *end; +} Dwarf_FDE; + +/* Each entry in a CFI section is either a CIE described by Dwarf_CIE or + an FDE described by Dward_FDE. Check CIE_id to see which you have. */ +typedef union +{ + Dwarf_Off CIE_id; /* Always DW_CIE_ID_64 in Dwarf_CIE structures. */ + Dwarf_CIE cie; + Dwarf_FDE fde; +} Dwarf_CFI_Entry; + +/* Opaque type representing a frame state described by CFI. */ +typedef struct Dwarf_Frame_s Dwarf_Frame; + +/* Opaque type representing a CFI section found in a DWARF or ELF file. */ +typedef struct Dwarf_CFI_s Dwarf_CFI; + + /* Handle for debug sessions. */ typedef struct Dwarf Dwarf; @@ -229,6 +293,47 @@ extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off, __nonnull_attribute__ (3); +/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data. + The E_IDENT from the originating ELF file indicates the address + size and byte order used in the CFI section contained in DATA; + EH_FRAME_P should be true for .eh_frame format and false for + .debug_frame format. OFFSET is the byte position in the section + to start at; on return *NEXT_OFFSET is filled in with the byte + position immediately after this entry. + + On success, returns 0 and fills in *ENTRY; use dwarf_cfi_cie_p to + see whether ENTRY->cie or ENTRY->fde is valid. + + On errors, returns -1. Some format errors will permit safely + skipping to the next CFI entry though the current one is unusable. + In that case, *NEXT_OFF will be updated before a -1 return. + + If there are no more CFI entries left in the section, + returns 1 and sets *NEXT_OFFSET to (Dwarf_Off) -1. */ +extern int dwarf_next_cfi (const unsigned char e_ident[], + Elf_Data *data, bool eh_frame_p, + Dwarf_Off offset, Dwarf_Off *next_offset, + Dwarf_CFI_Entry *entry) + __nonnull_attribute__ (1, 2, 5, 6); + +/* Use the CFI in the DWARF .debug_frame section. + Returns NULL if there is no such section (not an error). + The pointer returned can be used until dwarf_end is called on DWARF, + and must not be passed to dwarf_cfi_end. + Calling this more than once returns the same pointer. */ +extern Dwarf_CFI *dwarf_getcfi (Dwarf *dwarf); + +/* Use the CFI in the ELF file's exception-handling data. + Returns NULL if there is no such data. + The pointer returned can be used until elf_end is called on ELF, + and must be passed to dwarf_cfi_end before then. + Calling this more than once allocates independent data structures. */ +extern Dwarf_CFI *dwarf_getcfi_elf (Elf *elf); + +/* Release resources allocated by dwarf_getcfi_elf. */ +extern int dwarf_cfi_end (Dwarf_CFI *cache); + + /* Return DIE at given offset. */ extern Dwarf_Die *dwarf_offdie (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result) __nonnull_attribute__ (3); @@ -518,6 +623,15 @@ extern int dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address, Dwarf_Op **exprs, size_t *exprlens, size_t nlocs); +/* Return the block associated with a DW_OP_implicit_value operation. + The OP pointer must point into an expression that dwarf_getlocation + or dwarf_getlocation_addr has returned given the same ATTR. */ +extern int dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, + const Dwarf_Op *op, + Dwarf_Block *return_block) + __nonnull_attribute__ (2, 3); + + /* Return scope DIEs containing PC address. Sets *SCOPES to a malloc'd array of Dwarf_Die structures, @@ -626,6 +740,59 @@ extern int dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, const char **strp); +/* Compute what's known about a call frame when the PC is at ADDRESS. + Returns 0 for success or -1 for errors. + On success, *FRAME is a malloc'd pointer. */ +extern int dwarf_cfi_addrframe (Dwarf_CFI *cache, + Dwarf_Addr address, Dwarf_Frame **frame) + __nonnull_attribute__ (3); + +/* Return the DWARF register number used in FRAME to denote + the return address in FRAME's caller frame. The remaining + arguments can be non-null to fill in more information. + + Fill [*START, *END) with the PC range to which FRAME's information applies. + Fill in *SIGNALP to indicate whether this is a signal-handling frame. + If true, this is the implicit call frame that calls a signal handler. + This frame's "caller" is actually the interrupted state, not a call; + its return address is an exact PC, not a PC after a call instruction. */ +extern int dwarf_frame_info (Dwarf_Frame *frame, + Dwarf_Addr *start, Dwarf_Addr *end, bool *signalp); + +/* Return a DWARF expression that yields the Canonical Frame Address at + this frame state. Returns -1 for errors, or zero for success, with + *NOPS set to the number of operations stored at *OPS. That pointer + can be used only as long as FRAME is alive and unchanged. *NOPS is + zero if the CFA cannot be determined here. Note that if nonempty, + *OPS is a DWARF expression, not a location description--append + DW_OP_stack_value to a get a location description for the CFA. */ +extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops, size_t *nops) + __nonnull_attribute__ (2); + +/* Deliver a DWARF location description that yields the location or + value of DWARF register number REGNO in the state described by FRAME. + + Returns -1 for errors or zero for success, setting *NOPS to the + number of operations in the array stored at *OPS. Note the last + operation is DW_OP_stack_value if there is no mutable location but + only a computable value. + + *NOPS zero with *OPS set to OPS_MEM means CFI says the caller's + REGNO is "undefined", i.e. it's call-clobbered and cannot be recovered. + + *NOPS zero with *OPS set to a null pointer means CFI says the + caller's REGNO is "same_value", i.e. this frame did not change it; + ask the caller frame where to find it. + + For common simple expressions *OPS is OPS_MEM. For arbitrary DWARF + expressions in the CFI, *OPS is an internal pointer that can be used as + long as the Dwarf_CFI used to create FRAME remains alive. */ +extern int dwarf_frame_register (Dwarf_Frame *frame, int regno, + Dwarf_Op ops_mem[3], + Dwarf_Op **ops, size_t *nops) + __nonnull_attribute__ (3, 4, 5); + + /* Return error code of last failing function call. This value is kept separately for each thread. */ extern int dwarf_errno (void); diff --git a/elfutils/libdw/libdw.map b/elfutils/libdw/libdw.map index eb3abc28..b39db481 100644 --- a/elfutils/libdw/libdw.map +++ b/elfutils/libdw/libdw.map @@ -194,3 +194,36 @@ ELFUTILS_0.138 { local: *; } ELFUTILS_0.136; + +ELFUTILS_0.142 { + global: + dwarf_next_cfi; + dwarf_getcfi; + dwarf_getcfi_elf; + dwarf_cfi_addrframe; + dwarf_cfi_end; + dwarf_frame_cfa; + dwarf_frame_register; + dwarf_frame_info; + + dwfl_module_dwarf_cfi; + dwfl_module_eh_cfi; +} ELFUTILS_0.138; + +ELFUTILS_0.143 { + global: + dwarf_getlocation_implicit_value; + + # Replaced ELFUTILS_0.122 versions. Both versions point to the + # same implementation, but users of the new symbol version can + # presume that they use dwarf_attr_integrate properly. + dwarf_arrayorder; + dwarf_bitoffset; + dwarf_bitsize; + dwarf_bytesize; + dwarf_decl_column; + dwarf_decl_file; + dwarf_decl_line; + dwarf_srclang; + +} ELFUTILS_0.142; diff --git a/elfutils/libdw/libdwP.h b/elfutils/libdw/libdwP.h index 1d5a9b27..0284580f 100644 --- a/elfutils/libdw/libdwP.h +++ b/elfutils/libdw/libdwP.h @@ -76,6 +76,16 @@ struct loc_s size_t nloc; }; +/* Known DW_OP_implicit_value blocks already decoded. + This overlaps struct loc_s exactly, but only the + first member really has to match. */ +struct loc_block_s +{ + void *addr; + unsigned char *data; + size_t length; +}; + /* Valid indeces for the section data. */ enum { @@ -84,7 +94,6 @@ enum IDX_debug_aranges, IDX_debug_line, IDX_debug_frame, - IDX_eh_frame, IDX_debug_loc, IDX_debug_pubnames, IDX_debug_str, @@ -136,6 +145,7 @@ enum DWARF_E_NO_FLAG, DWARF_E_INVALID_OFFSET, DWARF_E_NO_DEBUG_RANGES, + DWARF_E_INVALID_CFI, }; @@ -172,6 +182,9 @@ struct Dwarf /* Address ranges. */ Dwarf_Aranges *aranges; + /* Cached info from the CFI section. */ + struct Dwarf_CFI_s *cfi; + /* Internal memory handling. This is basically a simplified reimplementation of obstacks. Unfortunately the standard obstack implementation is not usable in libraries. */ @@ -226,6 +239,8 @@ typedef struct Dwarf_Fileinfo_s Dwarf_Fileinfo; struct Dwarf_Line_s { + Dwarf_Files *files; + Dwarf_Addr addr; unsigned int file; int line; @@ -235,8 +250,6 @@ struct Dwarf_Line_s unsigned int end_sequence:1; unsigned int prologue_end:1; unsigned int epilogue_begin:1; - - Dwarf_Files *files; }; struct Dwarf_Lines_s @@ -414,11 +427,173 @@ extern int __libdw_visit_scopes (unsigned int depth, void *arg) __nonnull_attribute__ (2, 3) internal_function; +/* Parse a DWARF Dwarf_Block into an array of Dwarf_Op's, + and cache the result (via tsearch). */ +extern int __libdw_intern_expression (Dwarf *dbg, + bool other_byte_order, + unsigned int address_size, + void **cache, const Dwarf_Block *block, + bool valuep, + Dwarf_Op **llbuf, size_t *listlen, + int sec_index) + __nonnull_attribute__ (4, 5, 7, 8) internal_function; + + /* Return error code of last failing function call. This value is kept separately for each thread. */ extern int __dwarf_errno_internal (void); +/* Reader hooks. */ + +/* Relocation hooks return -1 on error (in that case the error code + must already have been set), 0 if there is no relocation and 1 if a + relocation was present.*/ + +static inline int +__libdw_relocate_address (Dwarf *dbg __attribute__ ((unused)), + int sec_index __attribute__ ((unused)), + const void *addr __attribute__ ((unused)), + int width __attribute__ ((unused)), + Dwarf_Addr *val __attribute__ ((unused))) +{ + return 0; +} + +static inline int +__libdw_relocate_offset (Dwarf *dbg __attribute__ ((unused)), + int sec_index __attribute__ ((unused)), + const void *addr __attribute__ ((unused)), + int width __attribute__ ((unused)), + Dwarf_Off *val __attribute__ ((unused))) +{ + return 0; +} + +static inline Elf_Data * +__libdw_checked_get_data (Dwarf *dbg, int sec_index) +{ + Elf_Data *data = dbg->sectiondata[sec_index]; + if (unlikely (data == NULL) + || unlikely (data->d_buf == NULL)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + return data; +} + +static inline int +__libdw_offset_in_section (Dwarf *dbg, int sec_index, + Dwarf_Off offset, size_t size) +{ + Elf_Data *data = __libdw_checked_get_data (dbg, sec_index); + if (data == NULL) + return -1; + if (unlikely (offset > data->d_size) + || unlikely (data->d_size - offset < size)) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return -1; + } + + return 0; +} + +static inline bool +__libdw_in_section (Dwarf *dbg, int sec_index, + const void *addr, size_t size) +{ + Elf_Data *data = __libdw_checked_get_data (dbg, sec_index); + if (data == NULL) + return false; + if (unlikely (addr < data->d_buf) + || unlikely (data->d_size - (addr - data->d_buf) < size)) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return false; + } + + return true; +} + +#define READ_AND_RELOCATE(RELOC_HOOK, VAL) \ + ({ \ + if (!__libdw_in_section (dbg, sec_index, addr, width)) \ + return -1; \ + \ + const unsigned char *orig_addr = addr; \ + if (width == 4) \ + VAL = read_4ubyte_unaligned_inc (dbg, addr); \ + else \ + VAL = read_8ubyte_unaligned_inc (dbg, addr); \ + \ + int status = RELOC_HOOK (dbg, sec_index, orig_addr, width, &VAL); \ + if (status < 0) \ + return status; \ + status > 0; \ + }) + +static inline int +__libdw_read_address_inc (Dwarf *dbg, + int sec_index, const unsigned char **addrp, + int width, Dwarf_Addr *ret) +{ + const unsigned char *addr = *addrp; + READ_AND_RELOCATE (__libdw_relocate_address, (*ret)); + *addrp = addr; + return 0; +} + +static inline int +__libdw_read_address (Dwarf *dbg, + int sec_index, const unsigned char *addr, + int width, Dwarf_Addr *ret) +{ + READ_AND_RELOCATE (__libdw_relocate_address, (*ret)); + return 0; +} + +static inline int +__libdw_read_offset_inc (Dwarf *dbg, + int sec_index, const unsigned char **addrp, + int width, Dwarf_Off *ret, int sec_ret, + size_t size) +{ + const unsigned char *addr = *addrp; + READ_AND_RELOCATE (__libdw_relocate_offset, (*ret)); + *addrp = addr; + return __libdw_offset_in_section (dbg, sec_ret, *ret, size); +} + +static inline int +__libdw_read_offset (Dwarf *dbg, + int sec_index, const unsigned char *addr, + int width, Dwarf_Off *ret, int sec_ret, + size_t size) +{ + READ_AND_RELOCATE (__libdw_relocate_offset, (*ret)); + return __libdw_offset_in_section (dbg, sec_ret, *ret, size); +} + +/* Read up begin/end pair and increment read pointer. + - If it's normal range record, set up *BEGINP and *ENDP and return 0. + - If it's base address selection record, set up *BASEP and return 1. + - If it's end of rangelist, don't set anything and return 2 + - If an error occurs, don't set anything and return <0. */ +int __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index, + unsigned char **addr, int width, + Dwarf_Addr *beginp, Dwarf_Addr *endp, + Dwarf_Addr *basep) + internal_function; + +unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index, + int err_nodata, unsigned char **endpp, + Dwarf_Off *offsetp) + internal_function; + + + /* Aliases to avoid PLTs. */ INTDECL (dwarf_attr) INTDECL (dwarf_attr_integrate) diff --git a/elfutils/libdw/memory-access.h b/elfutils/libdw/memory-access.h index 74054f95..13f79ec2 100644 --- a/elfutils/libdw/memory-access.h +++ b/elfutils/libdw/memory-access.h @@ -186,19 +186,32 @@ union unaligned int64_t s8; } __attribute__ ((packed)); +# define read_2ubyte_unaligned(Dbg, Addr) \ + read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_2sbyte_unaligned(Dbg, Addr) \ + read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_4ubyte_unaligned(Dbg, Addr) \ + read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_4sbyte_unaligned(Dbg, Addr) \ + read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_8ubyte_unaligned(Dbg, Addr) \ + read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_8sbyte_unaligned(Dbg, Addr) \ + read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) + static inline uint16_t -read_2ubyte_unaligned (Dwarf *dbg, const void *p) +read_2ubyte_unaligned_1 (bool other_byte_order, const void *p) { const union unaligned *up = p; - if (dbg->other_byte_order) + if (unlikely (other_byte_order)) return bswap_16 (up->u2); return up->u2; } static inline int16_t -read_2sbyte_unaligned (Dwarf *dbg, const void *p) +read_2sbyte_unaligned_1 (bool other_byte_order, const void *p) { const union unaligned *up = p; - if (dbg->other_byte_order) + if (unlikely (other_byte_order)) return (int16_t) bswap_16 (up->u2); return up->s2; } @@ -210,35 +223,35 @@ read_4ubyte_unaligned_noncvt (const void *p) return up->u4; } static inline uint32_t -read_4ubyte_unaligned (Dwarf *dbg, const void *p) +read_4ubyte_unaligned_1 (bool other_byte_order, const void *p) { const union unaligned *up = p; - if (dbg->other_byte_order) + if (unlikely (other_byte_order)) return bswap_32 (up->u4); return up->u4; } static inline int32_t -read_4sbyte_unaligned (Dwarf *dbg, const void *p) +read_4sbyte_unaligned_1 (bool other_byte_order, const void *p) { const union unaligned *up = p; - if (dbg->other_byte_order) + if (unlikely (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) +read_8ubyte_unaligned_1 (bool other_byte_order, const void *p) { const union unaligned *up = p; - if (dbg->other_byte_order) + if (unlikely (other_byte_order)) return bswap_64 (up->u8); return up->u8; } static inline int64_t -read_8sbyte_unaligned (Dwarf *dbg, const void *p) +read_8sbyte_unaligned_1 (bool other_byte_order, const void *p) { const union unaligned *up = p; - if (dbg->other_byte_order) + if (unlikely (other_byte_order)) return (int64_t) bswap_64 (up->u8); return up->s8; } |