summaryrefslogtreecommitdiff
path: root/elfutils/libdw
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2009-10-05 17:36:43 +0000
committerDmitry V. Levin <ldv@altlinux.org>2009-10-05 17:36:43 +0000
commitfcaf740c16004e36e5bdb7152ae49d25805d9dea (patch)
tree82367c77356c38df5ed8fb6f51bcd66e9f3bbd30 /elfutils/libdw
parent5a4cef9b6c2899944308fdb8f78559fc0df766cc (diff)
downloadelfutils-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')
-rw-r--r--elfutils/libdw/ChangeLog217
-rw-r--r--elfutils/libdw/Makefile.am10
-rw-r--r--elfutils/libdw/Makefile.in202
-rw-r--r--elfutils/libdw/cfi.c500
-rw-r--r--elfutils/libdw/cfi.h250
-rw-r--r--elfutils/libdw/cie.c193
-rw-r--r--elfutils/libdw/dwarf.h14
-rw-r--r--elfutils/libdw/dwarf_arrayorder.c8
-rw-r--r--elfutils/libdw/dwarf_begin_elf.c3
-rw-r--r--elfutils/libdw/dwarf_bitoffset.c8
-rw-r--r--elfutils/libdw/dwarf_bitsize.c8
-rw-r--r--elfutils/libdw/dwarf_bytesize.c8
-rw-r--r--elfutils/libdw/dwarf_cfi_addrframe.c78
-rw-r--r--elfutils/libdw/dwarf_cfi_end.c70
-rw-r--r--elfutils/libdw/dwarf_decl_column.c4
-rw-r--r--elfutils/libdw/dwarf_decl_file.c9
-rw-r--r--elfutils/libdw/dwarf_decl_line.c9
-rw-r--r--elfutils/libdw/dwarf_end.c8
-rw-r--r--elfutils/libdw/dwarf_entry_breakpoints.c4
-rw-r--r--elfutils/libdw/dwarf_error.c1
-rw-r--r--elfutils/libdw/dwarf_formaddr.c8
-rw-r--r--elfutils/libdw/dwarf_formflag.c8
-rw-r--r--elfutils/libdw/dwarf_formref_die.c7
-rw-r--r--elfutils/libdw/dwarf_formstring.c12
-rw-r--r--elfutils/libdw/dwarf_formudata.c65
-rw-r--r--elfutils/libdw/dwarf_frame_cfa.c96
-rw-r--r--elfutils/libdw/dwarf_frame_info.c74
-rw-r--r--elfutils/libdw/dwarf_frame_register.c142
-rw-r--r--elfutils/libdw/dwarf_getaranges.c36
-rw-r--r--elfutils/libdw/dwarf_getcfi.c94
-rw-r--r--elfutils/libdw/dwarf_getcfi_elf.c334
-rw-r--r--elfutils/libdw/dwarf_getlocation.c304
-rw-r--r--elfutils/libdw/dwarf_getmacros.c46
-rw-r--r--elfutils/libdw/dwarf_getpubnames.c15
-rw-r--r--elfutils/libdw/dwarf_getscopevar.c6
-rw-r--r--elfutils/libdw/dwarf_getsrc_file.c19
-rw-r--r--elfutils/libdw/dwarf_getsrclines.c26
-rw-r--r--elfutils/libdw/dwarf_hasattr_integrate.c2
-rw-r--r--elfutils/libdw/dwarf_next_cfi.c234
-rw-r--r--elfutils/libdw/dwarf_nextcu.c17
-rw-r--r--elfutils/libdw/dwarf_ranges.c105
-rw-r--r--elfutils/libdw/dwarf_srclang.c8
-rw-r--r--elfutils/libdw/encoded-value.h202
-rw-r--r--elfutils/libdw/fde.c306
-rw-r--r--elfutils/libdw/frame-cache.c87
-rw-r--r--elfutils/libdw/libdw.h169
-rw-r--r--elfutils/libdw/libdw.map33
-rw-r--r--elfutils/libdw/libdwP.h181
-rw-r--r--elfutils/libdw/memory-access.h37
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;
}