Squashed 'third_party/elfutils/' content from commit 555e15e

Change-Id: I61cde98949e47e5c8c09c33260de17f30921be79
git-subtree-dir: third_party/elfutils
git-subtree-split: 555e15ebe8bf1eb33d00747173cfc80cc65648a4
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
new file mode 100644
index 0000000..7a6d311
--- /dev/null
+++ b/libdw/ChangeLog
@@ -0,0 +1,2856 @@
+2018-02-09  Joshua Watt  <JPEWhacker@gmail.com>
+
+	* cfi.c (execute_cfi): Use FALLTHROUGH macro instead of comment.
+	* dwarf_frame_register.c (dwarf_frame_register): Likewise.
+
+2018-01-22  Mark Wielaard  <mark@klomp.org>
+
+	* Makefile.am (AM_CPPFLAGS): Add -I libdwelf.
+	* dwarf_begin_elf.c (dwarf_begin_elf): Initialize Dwarf alt_fd to -1.
+	* dwarf_end.c (dwarf_end): Call dwarf_end and close on the alt_dwarf
+	and alt_fd if we allocated them.
+	* dwarf_fromref_die.c (dwarf_formref_die): Call dwarf_getalt.
+	* dwarf_formstring.c (dwarf_formstring): Likewise.
+	* dwarf_getalt.c (__libdw_filepath): New internal function.
+	(find_debug_altlink): New static function.
+	(dwarf_getalt): Check Dwarf alt_dwarf and call find_debug_altlink.
+	Cache result.
+	* dwarf_setalt.c (dwarf_setalt): Clean up Dwarf alt_dwarf and alt_fd
+	if we allocated.
+	* libdw.h (dwarf_getalt): Extend documentation.
+	(dwarf_setalt): Likewise.
+	* libdwP.h (struct Dwarf): Add alt_fd field.
+	(filepath): Declare new internal function.
+
+2018-01-14  Petr Machata  <pmachata@gmail.com>
+
+	* dwarf_formsdata.c (dwarf_formsdata):
+	<DW_FORM_data1>: Cast to signed char.
+	<DW_FORM_data2,4,8>: Use read_*sbyte_unaligned instead of
+	read_*ubyte_unaligned.
+
+2017-12-26  Mark Wielaard  <mark@klomp.org>
+
+	* libdwP.h (struct Dwarf_Abbrev): Pack struct. Remove attrcnt,
+	use bitfields for has_children and code.
+	* dwarf_getabbrev.c (__libdw_getabbrev): Don't count attrs.
+	* dwarf_getattrcnt.c (dwarf_getattrcnt): Count attrs.
+
+2017-12-26  Mark Wielaard  <mark@klomp.org>
+
+	* memory-access.h (__libdw_get_uleb128_unchecked): New function.
+	(get_uleb128_unchecked): New define.
+	* dwarf_child.c (__libdw_find_attr): Use get_uleb128_unchecked to
+	read attr name and form.
+	* dwarf_getabbrevattr.c (dwarf_getabbrevattr): Likewise.
+	* dwarf_getattrs.c (dwarf_getattrs): Likewise.
+	* dwarf_hasattr.c (dwarf_hasattr): Likewise.
+
+2017-12-28  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_offdie.c (__libdw_offdie): Check sectiondata exists.
+
+2017-05-09  Ulf Hermann  <ulf.hermann@qt.io>
+	    Mark Wielaard  <mark@klomp.org>
+
+	* libdwP.h (__libdw_in_section): Fix check for the upper border of
+	the range.
+	(__libdw_offset_in_section): Likewise.
+
+2017-12-20  Mark Wielaard  <mark@klomp.org>
+
+	* libdwP.h (struct Dwarf_CU): Add sec_idx field.
+	(cu_sec_idx): Return cu->sec_idx.
+	* libdw_findcu.c (__libdw_intern_next_unit): Set cu sec_idx to
+	IDX_debug_info or IDX_debug_types.
+	* dwarf_begin_elf.c (valid_p): Set fake_loc_cu->sec_idx to
+	IDX_debug_loc.
+	* dwarf_getmacros.c (read_macros): Set fake_cu->sec_idx to
+	IDX_debug_macro or IDX_debug_macinfo.
+
+2017-12-12  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_aggregate_size.c (dwarf_aggregate_size): Don't peel the
+	given DIE. Reserve memory for a new DIE first.
+
+2017-12-11  Dima Kogan  <dima@secretsauce.net>
+
+	* dwarf_aggregate_size.c (array_size): Handle multi-dimensional
+	arrays properly.
+
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Handle
+	DW_OP_GNU_variable_value.
+	* dwarf_getlocation_attr.c (dwarf_getlocation_attr): Likewise.
+	* dwarf_getlocation_die.c (dwarf_getlocation_die): Likewise.
+
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_getlocation.c (attr_ok): Always accept DW_FORM_exprloc.
+	Update list of acceptable attribute codes based on DWARF5.
+
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_OP_GNU_variable_value.
+
+2017-10-03  Mark Wielaard  <mark@klomp.org>
+
+	* libdw.h: Define LIBDW_CIE_ID and use it in dwarf_cfi_cie_p.
+
+2017-08-18  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* memory-access.h: Use attribute_packed.
+
+2017-02-27  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* libdwP.h: Use attribute_hidden.
+	* libdw_alloc.c: Likewise.
+
+2017-02-27  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* Makefile.am: Use fpic_CFLAGS and dso_LDFLAGS.
+
+2017-07-26  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_MACRO_* and compat defines for DW_MACRO_GNU_*.
+	* dwarf_getmacros.c (get_table_for_offset): Accept either version
+	4 or 5. Use DW_MACRO names instead of DW_MACRO_GNU names.
+	(read_macros): Use table version for fake_cu.
+
+2017-07-26  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_peel_type.c (dwarf_peel_type): Handle DW_TAG_immutable_type,
+	DW_TAG_packed_type and DW_TAG_shared_type.
+	* libdw.h (dwarf_peel_type): Extend documentation.
+
+2017-07-26  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_DEFAULTED_no, DW_DEFAULTED_in_class and
+	DW_DEFAULTED_out_of_class.
+
+2017-07-26  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_CC_pass_by_reference and DW_CC_pass_by_reference.
+
+2017-07-26  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_default_lower_bound.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_default_lower_bound.c.
+	* dwarf_aggregate_size.c (array_size): Use dwarf_default_lower_bound.
+	* dwarf_error.c (errmsgs): Add DWARF_E_UNKNOWN_LANGUAGE.
+	* libdw.h: Add dwarf_default_lower_bound.
+	* libdw.map (ELFUTILS_0.170): Add dwarf_default_lower_bound.
+	* libdwP.h: Add DWARF_E_UNKNOWN_LANGUAGE and
+	dwarf_default_lower_bound INTDECL.
+
+2017-07-26  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_LANG_OpenCL, DW_LANG_Modula3,
+	DW_LANG_C_plus_plus_03, DW_LANG_OCaml, DW_LANG_Rust, DW_LANG_Swift,
+	DW_LANG_Julia, DW_LANG_Dylan, DW_LANG_RenderScript, DW_LANG_BLISS.
+	* dwarf_aggregate_size.c (array_size): Add lower bound for
+	DW_LANG_C_plus_plus_03, DW_LANG_Python, DW_LANG_OpenCL,
+	DW_LANG_Haskell, DW_LANG_OCaml, DW_LANG_Rust, DW_LANG_Swift,
+	DW_LANG_Dylan, DW_LANG_RenderScript, DW_LANG_Modula3,
+	DW_LANG_Julia and DW_LANG_BLISS.
+
+2017-07-26  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_ATE_UCS and DW_ATE_ASCII.
+
+2017-07-25  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_TAG_coarray_type, DW_TAG_generic_subrange,
+	DW_TAG_dynamic_type, DW_TAG_call_site, DW_TAG_call_site_parameter,
+	DW_TAG_skeleton_unit, DW_TAG_immutable_type. Add reserved comments
+	for currently unused numbers.
+
+2017-07-25  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h (DWARF attributes enum): Remove DW_AT_subscr_data,
+	DW_AT_element_list and DW_AT_member. Add DWARF5 attribute constants.
+	(DW_AT_subscr_data, DW_AT_element_list, DW_AT_member): New defines.
+
+2017-07-21  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf_line_file.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_line_file.c.
+	* libdw.h (dwarf_line_file): New function declaration.
+	* libdw.map (ELFUTILS_0.170): New. Add dwarf_line_file.
+
+2017-02-17  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* Makefile.am: Add libdw_so_LIBS to specify the archives libdw is is
+	made of, libdw_so_DEPS for libraries it depends on (including
+	libeu.a), libdw_so_LDLIBS to specify libraries libdw links against.
+	(libdw.so$(EXEEXT)): Add $(libdw_so_LDLIBS), remove enumeration of
+	library dependencies, use libdw_so_LIBS rather than relying on the
+	order of dependencies specified, add -z,relro.
+
+2017-04-20  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* libdw.h: Remove attribute macro declarations and use
+	__noreturn_attribute__ as defined in libelf.h.
+
+2017-04-20  Ulf Hermann  <ulf.hermann@qt.io>
+
+	* dwarf_begin_elf.c: Include endian.h.
+
+2017-03-30  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_peel_type.c (dwarf_peel_type): Call dwarf_attr_integrate on
+	result.
+
+2016-10-22  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Correct spelling of DW_LANG_PLI. Add compatibility define.
+	* dwarf_aggregate_size.c (array_size): Use correct spelling of
+	DW_LANG_PLI.
+
+2016-11-02  Mark Wielaard  <mjw@redhat.com>
+
+	* cfi.c (execute_cfi): Add fallthrough comments.
+	* encoded-value.h (encoded_value_size): Add explicit return instead
+	of relying on fallthrough.
+	* dwfl_report_elf.c (__libdwfl_elf_address_range): Add fallthrough
+	comment.
+
+2016-10-11  Akihiko Odaki  <akihiko.odaki.4i@stu.hosei.ac.jp>
+
+	* dwarf_getpubnames.c: Remove sys/param.h include, add system.h.
+	* libdw_alloc.c: Likewise.
+
+2016-07-08  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.167): New. Add dwelf_strtab_init,
+	dwelf_strtab_add, dwelf_strtab_add_len, dwelf_strtab_finalize,
+	dwelf_strent_off, dwelf_strent_str and dwelf_strtab_free.
+
+2016-02-13  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Calculate ndirs first, then
+	assign to ndirlist.
+
+2015-12-18  Mark Wielaard  <mjw@redhat.com>
+
+	* libdwP.h (struct Dwarf): Remove sectiondata_gzip_mask.
+	(__libdw_free_zdata): Remove.
+	* dwarf_begin_elf.c (inflate_section): Remove.
+	(check_section): Remove __libdw_free_zdata calls. Use elf_compress
+	and elf_compress_gnu to decompress if necessary.
+	(valid_p): Remove __libdw_free_zdata calls.
+	(scngrp_read): Use elf_compress if section is compressed. Remove
+	__libdw_free_zdata calls.
+	* dwarf_end.c (__libdw_free_zdata): Remove.
+	(dwarf_end): Don't call __libdw_free_zdata.
+
+2015-10-28  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.165): New. Add dwelf_scn_gnu_compressed_size.
+
+2015-12-02  Mark Wielaard  <mjw@redhat.com>
+
+	* fde.c (intern_fde): Don't leak duplicate FDEs.
+
+2015-12-01  Mark Wielaard  <mjw@redhat.com>
+
+	* fde.c (intern_fde): Don't intern an fde that doesn't cover a
+	valid code range.
+
+2015-12-01  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_end.c (dwarf_end): Call cu_free on fake_loc_cu if it exists.
+
+2015-10-14  Chih-Hung Hsieh  <chh@google.com>
+
+	* dwarf_entry_breakpoints.c (dwarf_entry_breakpoints): Move recursive
+	functions 'add_bkpt', 'entrypc_bkpt', and 'search_range' to file scope.
+
+2015-10-14  Chih-Hung Hsieh  <chh@google.com>
+
+	* libdw_visit_scopes.c (__libdw_visit_scopes): Move recursive nested
+	function 'walk_children' to file scope; inline 'recurse' at its call
+	site.
+
+2015-10-19  Mark Wielaard  <mjw@redhat.com>
+
+	* frame-cache.c (__libdw_destroy_frame_cache): Call ebl_closebackend
+	if necessary.
+
+2015-10-16  Dmitry V. Levin  <ldv@altlinux.org>
+
+	* dwarf_getsrclines.c (read_srclines): Initialize state early.
+
+2015-10-13  Chih-Hung Hsieh  <chh@google.com>
+
+	* dwarf_getsrclines.c (read_srclines): Move nested functions
+	'advance_pc' and 'add_new_line' to file scope and keep many
+	local state variables within one structure.
+
+2015-10-13  Chih-Hung Hsieh  <chh@google.com>
+
+	* dwarf_getscopevar.c (dwarf_getscopevar): Move nested
+	function 'file_matches' to file scope.
+
+2015-10-16  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (libdw.so): Add -lz.
+
+2015-10-14  Chih-Hung Hsieh  <chh@google.com>
+
+	* cfi.c (execute_cfi): Move nested functions 'enough_registers'
+	and 'require_cfa_offset' to file scope.
+
+2015-10-09  Josh Stone  <jistone@redhat.com>
+
+	* dwarf_begin.c (dwarf_begin): Replace stat64 and fstat64 with stat
+	and fstat.
+
+2015-10-05  Josh Stone  <jistone@redhat.com>
+
+	* Makefile.am (libdw.so): Add AM_V_CCLD and AM_V_at silencers.
+
+2015-09-24  Jose E. Marchesi  <jose.marchesi@oracle.com>
+
+	* Makefile.am (AM_CFLAGS): Use -fPIC instead of -fpic to avoid
+	relocation overflows in some platforms.
+
+2015-09-23  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_error.c (__libdw_seterrno): Mark as internal_function.
+	* dwarf_formref.c (__libdw_formref): Likewise.
+	* libdw_findcu.c (__libdw_findcu): Likewise.
+	* libdw_visit_scopes.c (__libdw_visit_scopes): Likewise.
+
+2015-09-22  Mark Wielaard  <mjw@redhat.com>
+
+	* *.c: Remove old-style function definitions.
+
+2015-09-15  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_peel_type.c (dwarf_peel_type): Don't reassign result pointer.
+
+2015-09-09  Chih-Hung Hsieh  <chh@google.com>
+
+	* dwarf_macro_getsrcfiles.c (dwarf_macro_getsrcfiles): Remove
+	redundant NULL tests on parameters declared with __nonnull_attribute__.
+	* dwarf_siblingof.c (dwarf_siblingof): Likewise.
+	* libdw_visit_scopes.c (__libdw_visit_scopes): Likewise.
+
+2015-09-04  Chih-Hung Hsieh  <chh@google.com>
+	    Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getlocation.c (getlocations_addr): Replace K&R function
+	definition with ansi-C definition and add const qualifier to
+	locs argument.
+
+2015-09-04  Chih-Hung Hsieh  <chh@google.com>
+
+	* libdw_findcu.c (__libdw_intern_next_unit): Replace K&R function
+	definition with ansi-C definitions.
+	(__libdw_findcu): Likewise.
+
+2015-08-25  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_LANG_Haskell.
+
+2015-06-18  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_begin_elf.c (dwarf_begin_elf): Assert page size is big enough
+	to hold a Dwarf.
+
+2015-06-18  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getpubnames.c (get_offsets): Always free mem on error.
+
+2015-06-18  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getmacros.c (get_macinfo_table): Return NULL when
+	dwarf_formudata reports an error.
+	(get_table_for_offset): Likewise.
+
+2015-06-08  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Initialize dirarray early.
+
+2015-06-06  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Initialize filelist early.
+
+2015-05-27  Mark Wielaard  <mjw@redhat.com>
+
+	* encoded-value.h (read_encoded_value): Check data d_size contains
+	at least enough data to hold a pointer for DW_EH_PE_indirect.
+
+2015-05-22  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Limit stack usage of lines
+	with MAX_STACK_LINES, files with MAX_STACK_LINES and dirs with
+	MAX_STACK_DIRS. Calculate number of dirs needed first, then
+	create dirarray directly, without needing the next field. Free
+	not stack allocated lines and files at the end.
+
+2015-05-19  Mark Wielaard <mjw@redhat.com>
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Create a stack
+	allocated array to hold locs. Allocate locs bigger than the array
+	with malloc and free them when done.
+
+2015-05-11  Jonathan Lebon  <jlebon@redhat.com>
+
+	* libdwP.h (DWARF_E_COMPRESSED_ERROR): New enumerator.
+	* dwarf_error.c (errmsgs): Add DWARF_E_COMPRESSED_ERROR message.
+	* dwarf_begin_elf.c (inflate_section): New static function, lifted
+	from...
+	(check_section): ... here. Call inflate_section, set libdw errno to
+	DWARF_E_COMPRESSED_ERROR if .debug_info section couldn't be inflated.
+
+2015-05-11  Jonathan Lebon  <jlebon@redhat.com>
+
+	* dwarf_begin_elf.c (check_section): Add compressed flag. Always
+	check for .zdebug sections. Only wrap decompression in #if USE_ZLIB.
+
+2015-05-06  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Use an int64_t to store and
+	check the line number.
+
+2015-05-05  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getaranges.c (dwarf_getaranges): Check there is enough data
+	left before reading values.
+
+2015-05-04  Anthony G. Basile  <blueness@gentoo.org>
+
+	* Makefile.am (libdw_so_SOURCES): Append $(argp_LDADD) to link
+	command.
+
+2015-04-22  Mark Wielaard  <mjw@redhat.com>
+
+	* memory-access.h (__libdw_max_len_leb128): Take type_len as argument.
+	(__libdw_max_len_uleb128): New function.
+	(__libdw_max_len_sleb128): Likewise.
+	(__libdw_get_uleb128): Use __libdw_max_len_uleb128.
+	(__libdw_get_sleb128): Use __libdw_max_len_sleb128.
+
+2015-04-21  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getmacros.c (read_macros): Allocate attributes dynamically
+	when there are more than 8.
+
+2015-04-01  Petr Machata  <pmachata@redhat.com>
+
+	* libdwP.h (DWARF_E_NOT_CUDIE): New enumerator.
+	(is_cudie): New function.
+	* dwarf_error.c (errmsgs): Add message for DWARF_E_NOT_CUDIE.
+	* dwarf_getsrcfiles.c (dwarf_getsrcfiles): Call is_cudie instead
+	of white-listing valid tags.
+	* dwarf_getsrclines.c (dwarf_getsrclines): Likewise.
+
+2015-03-18  Petr Machata  <pmachata@redhat.com>
+
+	* Makefile.am (pkginclude_HEADERS): Add known-dwarf.h.
+	(EXTRA_DIST): Remove known-dwarf.h.
+
+2015-02-09  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_LANG_Fortran03 and DW_LANG_Fortran08.
+	* dwarf_aggregate_size.c (array_size): Recognize array lower bound
+	for new Fortran language codes is 1.
+
+2015-02-09  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_TAG_atomic_type.
+	* libdw.h (dwarf_peel_type): Document DW_TAG_atomic_type.
+	* dwarf_peel_type.c (dwarf_peel_type): Handle DW_TAG_atomic_type.
+
+2015-02-11  Josh Stone  <jistone@redhat.com>
+
+	* encoded-value.h (read_encoded_value): Initialize value.
+
+2015-02-11  Petr Machata  <pmachata@redhat.com>
+
+	* dwarf_ranges.c (dwarf_ranges): Do not bail out when neither
+	DW_AT_entry_pc nor DW_AT_low_pc are available.  Instead remember
+	the fact in *BASEP and bail out later if it hasn't been updated by
+	__libdw_read_begin_end_pair_inc.
+
+2014-12-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrc_die.c (dwarf_getsrc_die): Return the last line record
+	smaller than or equal to addr, rather than returning immediately on
+	a match.
+
+2015-01-07  Mark Wielaard  <mjw@redhat.com>
+
+	* cfi.h (struct Dwarf_CFI_s): Add search_table_len.
+	* dwarf_getcfi_elf.c (getcfi_gnu_eh_frame): Check there is enough
+	room in the search table for all entries. Store search_table_len.
+	(getcfi_scn_eh_frame): Likewise.
+	* encoded-value.h (encoded_value_size): Don't abort, return zero.
+	(__libdw_cfi_read_address_inc): Check there is enough room to read
+	values. Pass other byte order to read functions.
+	(read_encoded_value): Check encoded_value_size. Don't abort, but
+	set libdw errno and report failure. Check there is enough room to
+	read values.
+	* fde.c (binary_search_fde): Check encoded value size. Add hdr
+	data buf and size to dummy_cfi.
+
+2015-01-04  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_siblingof.c (dwarf_siblingof): Check sibling attribute
+	is after current DIE.
+
+2015-01-04  Mark Wielaard  <mjw@redhat.com>
+
+	* cfi.c (enough_registers): Check reg < INT32_MAX / sizeof
+	(dwarf_frame_register).
+
+2015-01-02  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getcfi_elf.c (parse_eh_frame_hdr): Add size check.
+	(getcfi_gnu_eh_frame): Remove size check. Check d_buf is not NULL.
+	(getcfi_scn_eh_frame): Check d_buf is not NULL.
+
+2015-01-02  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Check dbg is not
+	NULL for DW_OP_call_ref and DW_OP_GNU_implicit_pointer. For
+	DW_OP_addr if dbg is NULL then read argument directly.
+
+2015-01-14  Jason P. Leasure <jpleasu@super.org>
+
+	* dwarf_formref_die.c (dwarf_formref_die): Offset is cu->type_offset
+	plus cu->start.
+
+2014-12-27  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_siblingof.c (dwarf_siblingof): Check sibling attribute offset
+	still falls inside CU data.
+
+2015-01-11  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_func_inline.c (dwarf_func_inline_instances): Call
+	__libdw_visit_scopes with NULL imports.
+	* dwarf_getfuncs.c (dwarf_getfuncs): Likewise.
+	* dwarf_getscopes.c (pc_record): Likewise.
+	(dwarf_getscopes): Likewise.
+	* dwarf_getscopes_die.c (dwarf_getscopes_die): Likewise.
+	* libdwP.h (__libdw_visit_scopes): Add imports argument.
+	* libdw_visit_scopes.c (__libdw_visit_scopes): Likewise. Add new
+	function imports_contains. Push and pop imports around walk_children
+	when processing DW_TAG_imported_unit.
+
+2014-12-18  Ulrich Drepper  <drepper@gmail.com>
+
+	* Makefile.am: Suppress output of textrel_check command.
+
+2014-12-16  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Check diridx is valid under
+	DW_LNE_define_file.
+
+2014-12-16  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getpubnames.c (dwarf_getpubnames): Make sure there is enough
+	space to read die offset.
+
+2014-12-16  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Correct overflow check for
+	unit_length.
+
+2014-12-15  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getpubnames.c (get_offsets): Make sure whole unit fall inside
+	section data. Set error to DWARF_E_NO_ENTRY if cnt is zero.
+	(dwarf_getpubnames): Make sure section data contains string zero
+	terminator.
+
+2014-12-16  Mark Wielaard  <mjw@redhat.com>
+
+	* memory-access.h (__libdw_get_sleb128): Unroll the first step to help
+	the compiler optimize for the common single-byte case.
+
+2014-12-15  Josh Stone  <jistone@redhat.com>
+
+	* memory-access.h (__libdw_max_len_leb128): New.
+	(__libdw_get_uleb128): Use __libdw_max_len_leb128.
+	(__libdw_get_sleb128): Likewise.
+
+2014-12-14  Mark Wielaard  <mjw@redhat.com>
+
+	* cfi.c (execute_cfi): Add program bounds checks.
+	* dwarf_child.c (__libdw_find_attr): Add attrp bounds checks.
+	* dwarf_formblock.c (dwarf_formblock): Call get_uleb128 with endp.
+	* dwarf_formref.c (__libdw_formref): Add datap bounds checks.
+	* dwarf_formsdata.c (dwarf_formsdata): Likewise.
+	* dwarf_formudata.c (dwarf_formudata): Likewise.
+	* dwarf_frame_register.c (dwarf_frame_register): Call get_uleb128
+	with end of data buf.
+	* dwarf_getabbrev.c (__libdw_getabbrev): Add abbrevp bounds checks.
+	* dwarf_getabbrevattr.c (dwarf_getabbrevattr): Assume get_uleb128
+	call gets enough data.
+	* dwarf_getattrs,c (dwarf_getattrs): Call get_uleb128 with endp.
+	* dwarf_getlocation.c (store_implicit_value): Call get_uleb128
+	with enough data.
+	(__libdw_intern_expression): Call get_uleb128/get_sleb128 with
+	end_data.
+	* dwarf_getmacros.c (get_table_for_offset): Add nforms bounds check.
+	* dwarf_getsrclines.c (read_srclines): Bounds check linep and call
+	get_uleb128 with lineendp.
+	* dwarf_hasattr.c (dwarf_hasattr): Bounds check attrp and call
+	get_uleb128 with endp.
+	* dwarf_next_cfi.c (dwarf_next_cfi): Bounds check bytes and call
+	get_uleb128/get_sleb128 with limit.
+	* encoded-value.h (read_encoded_value): Assume get_uleb128 and
+	get_sleb128 get called with enough data.
+	* fde.c (intern_fde): Call get_uleb128 with instructions_end.
+	* libdwP.h (__libdw_dieabbrev): Call get_uleb128 with die->cu->endp.
+	* libdw_form.c (__libdw_form_val_compute_len): Call get_uleb128 with
+	endp.
+	* memory-access.h (__libdw_get_uleb128): Take an extra endp.
+	Don't call get_uleb128_step if out of data.
+	(__libdw_get_sleb128): Likewise for get_sleb128_step.
+
+2014-12-12  Mark Wielaard  <mjw@redhat.com>
+
+	* libdwP.h (struct Dwarf): Add fake_loc_cu.
+	(cu_data): Removed.
+	(DIE_OFFSET_FROM_CU_OFFSET): Don't use cu_data, use cu_sec_idx.
+	(__libdw_form_val_compute_len): Drop dbg and endp arguments.
+	(__libdw_form_val_len): Likewise.
+	* libdw_form.c (__libdw_form_val_compute_len): Likewise.
+	* libdw_findcu.c (__libdw_intern_next_unit): Don't use cu_data, use
+	the already found data buffer directly.
+	* dwarf_begin_elf.c (valid_p): Setup fake_loc_cu.
+	* dwarf_end.c (dwarf_end): Free fake_loc_cu.
+	* dwarf_child.c (__libdw_find_attr): Call __libdw_form_val_len with
+	just cu.
+	* dwarf_getattrs.c (dwarf_getattrs): Likewise.
+	* dwarf_formblock.c (dwarf_formblock): Add bounds checking.
+	* dwarf_getlocation_attr.c (attr_form_cu): New function.
+	(dwarf_getlocation_attr): Use attr_form_cu to set result->cu.
+	(getlocation): Handle empty blocks immediately.
+	* dwarf_getlocation_implicit_pointer.c (empty_cu): New static var.
+	(__libdw_empty_loc_attr): Drop cu argument, use empty_cu.
+	(dwarf_getlocation_implicit_pointer): Call __libdw_empty_loc_attr with
+	one argument.
+	* dwarf_getmacros.c (read_macros): Also setup startp and endp for
+	fake_cu. Call __libdw_form_val_len with just fake_cu.
+	* dwarf_formref_die.c (dwarf_formref_die): Don't use cu_data, get
+	datap and size directly from cu startp and endp.
+
+2014-12-11  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw_findcu.c (__libdw_intern_next_unit): Sanity check offset.
+
+2014-12-13  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getaranges.c (compare_aranges): Make sure Dwarf_Addr
+	difference doesn't wrap around before returning as int.
+
+2014-12-11  Josh Stone  <jistone@redhat.com>
+
+	* dwarf_getsrclines.c (struct linelist): Add sequence.
+	(compare_lines): Take linelists, and break ties by sequence.
+	(read_srclines): Use linelists for sorting.
+	(read_srclines::add_new_line): Set sequence.
+
+2014-12-10  Josh Stone  <jistone@redhat.com>
+
+	* libdwP.h (Dwarf_CU): Add startp and endp boundaries.
+	* libdw_findcu.c (__libdw_intern_next_unit): Set startp and endp.
+	* dwarf_child.c (dwarf_child): Use cu->endp.
+	* dwarf_cuoffset.c (dwarf_cuoffset): Use cu->startp.
+	* dwarf_dieoffset.c (dwarf_dieoffset): Use cu->startp.
+	* dwarf_siblingof.c (dwarf_siblingof): Use both.
+
+2014-12-10  Josh Stone  <jistone@redhat.com>
+
+	* dwarf_hasattr.c (dwarf_hasattr): Just walk abbrev for presence.
+
+2014-12-10  Josh Stone  <jistone@redhat.com>
+
+	* libdwP.h (__libdw_dieabbrev): New die->abbrev lookup function.
+	* dwarf_child.c (__libdw_find_attr, dwarf_child): Use it.
+	* dwarf_getattrs.c (dwarf_getattrs): Likewise.
+	* dwarf_haschildren.c (dwarf_haschildren): Likewise.
+	* dwarf_tag.c (dwarf_tag): Likewise.
+
+2014-12-04  Mark Wielaard  <mjw@redhat.com>
+
+	* libdwP.h (__libdw_form_val_compute_len): Add endp argument.
+	(__libdw_form_val_len): Likewise and check len doesn't overflow.
+	* libdw_form.c (__libdw_form_val_compute_len): Likewise.
+	* dwarf_child.c (__libdw_find_attr): Call __libdw_form_val_len
+	with endp.
+	* dwarf_getattrs.c (dwarf_getattrs): Likewise.
+	* dwarf_getmacros.c (read_macros): Likewise and check for errors.
+
+2014-12-02  Petr Machata  <pmachata@redhat.com>
+
+	* dwarf_getmacros.c (token_from_offset, offset_from_token): New
+	helper functions.
+	(do_dwarf_getmacros_die): Merge into dwarf_getmacros.
+	* libdw.h (DWARF_GETMACROS_START): New macro.
+
+2014-11-27  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (libdw.so): Use textrel_check.
+
+2014-11-27  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getcfi_elf.c (getcfi_gnu_eh_frame): Initialize
+	search_table_entries and search_table_encoding.
+
+2014-11-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Check line_range is not zero
+	before usage.
+
+2014-11-23  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_attr.c (dwarf_attr): Check __libdw_find_attr return value.
+	* dwarf_hasattr.c (dwarf_hasattr): Likewise.
+	* dwarf_siblingof.c (dwarf_siblingof): Likewise.
+
+2014-11-23  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getabbrev.c (__libdw_getabbrev): Don't assert on bad DWARF.
+	Set libdw errno and return NULL.
+
+2014-11-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h (DW_LANG_C_plus_plus_11): Added.
+	(DW_LANG_C11): Likewise.
+	(DW_LANG_C_plus_plus_14): Likewise.
+	* dwarf_aggregate_size.c (array_size): Handle DW_LANG_C11,
+	DW_LANG_C_plus_plus_11, DW_LANG_C_plus_plus_14 and DW_LANG_Go
+	lower bound.
+	* dwarf_getfuncs.c (dwarf_getfuncs): Set c_cu to true for
+	DW_LANG_C11.
+
+2014-11-26  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h (DW_AT_noreturn): Added.
+
+2014-11-11  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (read_srclines): Do address_size comparison
+	explicitly as uint8_t.
+	(__libdw_getsrclines): Add internal_function to declaration.
+
+2014-09-10  Petr Machata  <pmachata@redhat.com>
+
+	* dwarf_macro_getparamcnt.c: New file.
+	* dwarf_macro_param.c: New file.
+	* dwarf_macro_getsrcfiles.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add the new files.
+	* libdwP.h (struct files_lines_s): New structure.
+	(DWARF_E_INVALID_OPCODE): New enumerator.
+	(struct Dwarf): New fields macro_ops, files_lines.
+	(Dwarf_Macro_Op_Proto, Dwarf_Macro_Op_Table): New structures for
+	keeping macro opcode prototypes in.
+	(Dwarf_Macro_s): Redefine from scratch.
+	(__libdw_getsrclines, __libdw_getcompdir, libdw_macro_nforms): New
+	internal interfaces.
+	* dwarf_error.c (errmsgs): Add a message for
+	DWARF_E_INVALID_OPCODE.
+	* dwarf_end.c (dwarf_end): Destroy struct Dwarf.macro_ops and
+	files_lines.
+	* libdw.h (dwarf_getmacros_off, dwarf_macro_getparamcnt)
+	(dwarf_macro_getsrcfiles, dwarf_macro_param): New public
+	interfaces.
+	* dwarf_getmacros.c (dwarf_getmacros_off): New function,
+	(get_offset_from, macro_op_compare, build_table)
+	(init_macinfo_table, get_macinfo_table, get_table_for_offset)
+	(cache_op_table, read_macros, gnu_macros_getmacros_off)
+	(macro_info_getmacros_off, do_dwarf_getmacros_die): New helper
+	functions.
+	(dwarf_getmacros): Adjust to dispatch to the new interfaces.
+	* dwarf_getsrclines.c (read_srclines): New function with guts
+	taken from dwarf_getsrclines.
+	(__libdw_getsrclines): Likewise.
+	(__libdw_getcompdir, files_lines_compare): New functions.
+	(dwarf_getsrclines): Make it dispatch to the new interfaces.
+	* dwarf_macro_param1.c (dwarf_macro_param1): Adjust to dispatch to
+	the new interfaces.
+	* dwarf_macro_param2.c (dwarf_macro_param2): Likewise.
+	* libdw.map (ELFUTILS_0.161): New. Add dwarf_getmacros_off,
+	dwarf_macro_getsrcfiles, dwarf_macro_getparamcnt, dwarf_macro_param.
+
+2014-10-06  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_peel_type.c.
+	* dwarf_aggregate_size.c (get_type): Use dwarf_peel_type.
+	(aggregate_size): Likewise. Add old and new version.
+	* dwarf_peel_type.c: New file.
+	* libdw.h (dwarf_peel_type): New function declaration.
+	* libdwP.h (dwarf_peel_type): New internal declaration.
+	* libdw.map (ELFUTILS_0.161): New section.
+
+2014-10-15  Petr Machata  <pmachata@redhat.com>
+
+	* libdwP.h (struct Dwarf_Files_s.cu): Drop field.
+	* dwarf_getsrclines.c (dwarf_getsrclines): Don't set it.
+
+2014-10-05  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_AT_GNU_deleted.
+
+2014-10-02  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_aggregate_size.c (aggregate_size): Return CU address_size
+	for sizeless DW_TAG_pointer_type, DW_TAG_reference_type or
+	DW_TAG_rvalue_reference_type.
+
+2014-09-12  Petr Machata  <pmachata@redhat.com>
+
+	* memory-access.h (read_ubyte_unaligned_inc): Allow only 4- and
+	8-byte quantities.  Consequently, rename to...
+	(read_addr_unaligned_inc): ... this.
+	(read_sbyte_unaligned_inc, read_ubyte_unaligned): Drop.
+	(read_sbyte_unaligned): Drop.
+
+2014-09-10  Petr Machata  <pmachata@redhat.com>
+
+	* dwarf_getlocation.c (attr_ok): Also accept
+	DW_AT_GNU_call_site_value, DW_AT_GNU_call_site_data_value,
+	DW_AT_GNU_call_site_target, DW_AT_GNU_call_site_target_clobbered.
+
+2014-08-15  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_cu_die.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_cu_die.c.
+	* libdw.h (dwarf_cu_die): New function declaration.
+	* libdw.map (ELFUTILS_0.160): Add dwarf_cu_die.
+
+2014-08-15  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_cu_getdwarf.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_cu_getdwarf.c.
+	* libdw.h (Dwarf_CU): New typedef.
+	(dwarf_cu_getdwarf): New function declaration.
+	* libdw.map (ELFUTILS_0.160): New. Add dwarf_cu_getdwarf.
+
+2014-06-18  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Remove DW_TAG_mutable_type.
+
+2014-05-02  Mark Wielaard  <mjw@redhat.com>
+
+	* libdwP.h (__check_build_id): Removed now unused.
+
+2014-05-01  Mark Wielaard  <mjw@redhat.com>
+
+	* libdwP.h (struct Dwarf): Remove free_alt.
+	* dwarf_end.c (dwarf_end): Don't check free_alt, don't end alt_dwarf.
+	* dwarf_setalt.c (dwarf_setalt): Don't check or set free_alt.
+
+2014-04-30  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.159): Add dwelf_elf_gnu_build_id.
+
+2014-04-15  Florian Weimer  <fweimer@redhat.com>
+
+	* dwarf_begin_elf.c (__check_build_id, try_debugaltlink)
+	(open_debugaltlink): Move to libdwfl.
+	(check_section): Do not locate alternate debuginfo.
+
+2014-04-24  Florian Weimer  <fweimer@redhat.com>
+
+	* libdw.map (ELFUTILS_0.159): Export dwelf_dwarf_gnu_debugaltlink.
+
+2014-04-22  Florian Weimer  <fweimer@redhat.com>
+
+	* dwarf_getalt.c, dwarf_setalt.c: New files.
+	* Makefile.am (libdw_a_SOURCES): Add them.
+	* libdw.h (dwarf_getalt, dwarf_setalt): Add function declarations.
+	* libdwP.h (dwarf_getalt, dwarf_setalt): Add internal function
+	declarations.
+	* libdw.map (ELFUTILS_0.159): Export the two new functions.
+
+2014-04-15  Florian Weimer  <fweimer@redhat.com>
+
+	* libdwP.h (enum IDX_gnu_debugaltlink): New.
+	* dwarf_begin_elf.c (dwarf_scnnames): Increase string size and add
+	.gnu_debugaltlink.
+	(check_section): Obtain .gnu_debugaltlink section from the
+	setiondata array.
+
+2014-04-11  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.159): New. Add dwelf_elf_gnu_debuglink.
+	* Makefile.am (libdw.so): Depend on libdwelf_pic.a.
+	(libdwelf_objects): New variable.
+	(libdw_a_LIBADD): Add libdwelf objects.
+
+2014-04-22  Mark Wielaard  <mjw@redhat.com>
+
+	* memory-access.h (get_sleb128_step): Remove undefined behavior
+	of left shifting a signed value. Replace it with a multiplication.
+
+2014-04-13  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am: Remove !MUDFLAP conditions.
+
+2014-04-09  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_begin_elf.c (check_section): Check for unsigned overflow
+	before calling malloc to uncompress data.
+
+2014-03-03  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	Fix abort() on missing section headers.
+	* dwarf_begin_elf.c (check_section): Replace abort call by goto err.
+	New label err to return NULL.
+
+2014-02-05  Josh Stone  <jistone@redhat.com>
+
+	* dwarf_decl_file.c (dwarf_decl_file): Read the idx as unsigned.
+	* dwarf_decl_line.c (__libdw_attr_intval): Read the line/column as
+	unsigned.  Change the range assert to DWARF_E_INVALID_DWARF.
+
+2013-12-30  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.158): Add dwfl_core_file_attach and
+	dwfl_linux_proc_attach.
+
+2013-12-20  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.158): Add dwfl_getthread_frames.
+
+2013-12-18  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.158): Remove dwfl_module_addrsym_elf and
+	dwfl_module_getsym_elf. Add dwfl_module_addrinfo and
+	dwfl_module_getsym_info.
+
+2013-12-16  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.158): Add dwfl_module_getsymtab_first_global.
+
+2013-12-10  Josh Stone  <jistone@redhat.com>
+
+	* memory-access.h (get_uleb128_rest_return): Removed.
+	(get_sleb128_rest_return): Removed.
+	(get_uleb128_step): Make this a self-contained block.
+	(get_sleb128_step): Ditto, and use a bitfield to extend signs.
+	(get_uleb128): Make this wholly implemented by __libdw_get_uleb128.
+	(get_sleb128): Make this wholly implemented by __libdw_get_sleb128.
+	(__libdw_get_uleb128): Simplify and inline for all callers.
+	(__libdw_get_sleb128): Ditto.
+	* dwarf_getlocation.c (store_implicit_value): Void the unused uleb128.
+	* memory-access.c: Delete file.
+	* Makefile.am (libdw_a_SOURCES): Remove it.
+	(DEFS): Remove the now unused -DIS_LIBDW.
+
+2013-12-09  Josh Stone  <jistone@redhat.com>
+
+	* libdw_form.c (__libdw_form_val_compute_len): Renamed function from
+	__libdw_form_val_len, now handling only non-constant form lengths.
+	* libdwP.h (__libdw_form_val_len): New inlined function.
+
+2013-12-09  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Handle empty
+	location expressions.
+	* dwarf_getlocation_attr.c (dwarf_getlocation_attr): When no
+	location found, return empty location expression.
+	* dwarf_getlocation_implicit_pointer.c
+	(dwarf_getlocation_implicit_pointer): Likewise.
+	(__libdw_empty_loc_attr): New internal function.
+	* libdwP.h (__libdw_empty_loc_attr): Define.
+
+2013-11-27  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.158): Add dwfl_module_addrsym_elf and
+	dwfl_module_getsym_elf.
+
+2013-11-26  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.map (ELFUTILS_0.156): Move dwfl_attach_state, dwfl_pid,
+	dwfl_thread_dwfl, dwfl_thread_tid, dwfl_frame_thread,
+	dwfl_thread_state_registers, dwfl_thread_state_register_pc,
+	dwfl_getthreads, dwfl_thread_getframes and dwfl_frame_pc to ...
+	(ELFUTILS_0.158): ... here.
+
+2013-11-09  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getaranges.c (dwarf_getaranges): Read segment_size and
+	check that it is zero.
+
+2013-11-07  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* cfi.h (struct Dwarf_Frame_s): Make the comment more specific.
+	* libdw.map (ELFUTILS_0.156): Add dwfl_attach_state, dwfl_pid,
+	dwfl_thread_dwfl, dwfl_thread_tid, dwfl_frame_thread,
+	dwfl_thread_state_registers, dwfl_thread_state_register_pc,
+	dwfl_getthreads, dwfl_thread_getframes and dwfl_frame_pc.
+
+2013-11-01  Michael Forney  <mforney@mforney.org>
+
+	* Makefile.am (libdwfl_objects): New definition.
+	(libdw_a_LIBADD): Use libdwfl_objects.
+
+2013-11-01  Michael Forney  <mforney@mforney.org>
+
+	* Makefile.am: Use READELF.
+
+2013-10-30  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* libdw.map (ELFUTILS_0.158): New.
+
+2013-10-10  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getfuncs.c (struct visitor_info): Rename start_offset to
+	start_addr and rename last_offset to last_addr. Now both void *.
+	(tree_visitor): Use start_add and die_addr instead of start_offset
+	and die_offset.
+	(dwarf_getfuncs): Use last_addr instead of last_offset.
+
+2013-10-06  Mark Wielaard  <mjw@redhat.com>
+
+	* cfi.c (execute_cfi): Make sure DW_CFA_expression and
+	DW_CFA_val_expression are not used with abi_cfi.
+
+2013-10-03  Josh Stone  <jistone@redhat.com>
+
+	* dwarf_formref_die.c (dwarf_formref_die): Don't hash the sig8 here.
+	* libdw_findcu.c (__libdw_intern_next_unit): Since this never revisits
+	a unit, make sure to always hash the sig8 here, so none are missed.
+
+2013-09-29  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getlocation.c (store_implicit_value): Cast op->number2 to
+	uintptr_t before casting to char *.
+	(__libdw_intern_expression): Cast data to uintptr_t before casting
+	to Dwarf_Word.
+	* dwarf_getlocation_attr.c (dwarf_getlocation_attr): Cast
+	op->number2 to uintptr_t before casting to char *.
+
+2013-09-24  Josh Stone  <jistone@redhat.com>
+
+	* libdw_visit_scopes.c (classify_die): Removed.
+	(may_have_scopes): New function to replace classify_die.  There's no
+	need for full classification; just find tags that may contain scopes.
+	(__libdw_visit_scopes): Use a direct tag comparison for imported
+	units, and use may_have_scopes to test if recursion is needed.
+
+2013-09-20  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getfuncs.c (visitor_info): New struct.
+	(tree_visitor): New function.
+	(dwarf_getfuncs): Use __libdw_visit_scopes with tree_visitor.
+	* libdw.h (dwarf_getfuncs): Expand function documentation.
+
+2013-09-12  Mark Wielaard  <mjw@redhat.com>
+
+	* fde.c (intern_fde): Free fde and set libdw errno when start
+	or end could not be read.
+
+2013-08-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getlocation.c (store_implicit_value): Don't take data
+	as argument, get block data from op number2. Return false when
+	block data length and op number don't match up.
+	(__libdw_intern_expression): Store start of block for
+	DW_OP_implicit_value and DW_OP_GNU_entry_value instead of
+	relative data offset. Also store block start (including length)
+	for DW_OP_GNU_const_type. Don't pass data to store_implicit_value.
+	* dwarf_getlocation_attr.c: New file.
+	* dwarf_getlocation_die.c: Likewise.
+	* libdw.h (dwarf_getlocation_die): New function definition.
+	(dwarf_getlocation_attr): Likewise.
+	* libdwP.h: Declare internal dwarf_getlocation_die.
+	* libdw.map (ELFUTILS_0.157): Add dwarf_getlocation_die and
+	dwarf_getlocation_attr.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getlocation_die.c and
+	dwarf_getlocation_attr.c.
+
+2013-08-23  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getlocation.c (attr_ok): Also accept DW_AT_segment.
+	(attr_base_address): New function.
+	(initial_offset_base): New function.
+	(getlocations_addr): New function. Taken from...
+	(dwarf_getlocation_addr): here. Use new initial_offset_base and
+	getlocations_addr.
+	(dwarf_getlocations): New function.
+	* libdw.h (dwarf_getlocations): New function definition.
+	* libdw.map (ELFUTILS_0.157): New.
+
+2013-07-02  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (dwarf_getsrclines): Add new stack allocation
+	limit MAX_STACK_ALLOC.  After MAX_STACK_ALLOC lines use malloc in
+	NEW_LINE macro.  Free malloced line records if any at the end.
+
+2013-07-02  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getcfi_elf.c (getcfi_shdr): Check sh_type == SHT_PROGBITS.
+
+2013-06-26  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw_visit_scopes.c (__libdw_visit_scopes): Don't reject root
+	DIEs without children. Return an error whenever dwarf_child or
+	dwarf_siblingof return an error. Don't call recurse and increase
+	the depth for an imported unit. Walk the children of an imported
+	unit as if they are logical children of the parent root DIE.
+
+2013-05-03  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (dwarf_getsrclines): Only set end_sequence
+	when nlinelist > 0.
+
+2013-04-28  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* libdw.map (ELFUTILS_0.156): New.
+
+2013-04-24  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am: Use AM_CPPFLAGS instead of INCLUDES.
+
+2013-04-10  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_formref_die.c (dwarf_formref_die): Reference size is only
+	equal to address size when we have a DW_FORM_ref_addr for DWARF
+	version 2.
+
+2013-03-25  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrclines.c (dwarf_getsrclines): Mark highest address as
+	end_sequence.
+
+2013-03-12  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrcfiles.c (dwarf_getsrcfiles): Allow DW_TAG_partial_unit.
+	* dwarf_getsrclines.c (dwarf_getsrclines): Likewise.
+
+2013-02-15  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_formstring.c (dwarf_formstring): Check dbg_ret->sectiondata,
+	not dbg->sectiondata.
+
+2013-01-07  Roland McGrath  <roland@hack.frob.com>
+
+	* memory-access.h
+	[ALLOW_UNALIGNED] (read_8ubyte_unaligned_noncvt): New macro.
+	[!ALLOW_UNALIGNED] (read_8ubyte_unaligned_noncvt): New inline function.
+
+2012-12-18  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_begin_elf.c (valid_p): Call Dwarf_Sig8_Hash_free if invalid.
+	(check_section): Likewise on error.
+	(scngrp_read): Likewise.
+	(dwarf_begin_elf): Likewise.
+
+2012-10-09  Petr Machata  <pmachata@redhat.com>
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Handle
+	DW_OP_GNU_parameter_ref, DW_OP_GNU_convert, DW_OP_GNU_reinterpret,
+	DW_OP_GNU_regval_type, DW_OP_GNU_entry_value,
+	DW_OP_GNU_deref_type, DW_OP_GNU_const_type.
+
+2012-10-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* cfi.c: New include system.h.
+	(execute_cfi) (enough_registers): Clear new memory after realloc.
+
+2012-10-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* fde.c (__libdw_find_fde): Change <fde != NULL> to likely.  Return
+	DWARF_E_NO_MATCH if .eh_frame_hdr points to FDE which is too short for
+	searched PC.
+
+2012-10-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* dwarf_getlocation.c (__libdw_intern_expression) <cfap>: Make new
+	loclist element DW_OP_call_frame_cfa before decoding the opcodes.
+	Remove the later DW_OP_call_frame_cfa push to RESULT.
+
+2012-10-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	Code cleanup.
+	* fde.c (binary_search_fde): Remove always true <address >= start>
+	conditional.  Move L initialization upwards.
+
+2012-08-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_begin_elf.c (check_section): Only probe for dwz multi files
+	when ENABLE_DWZ is defined.
+	* libdwP.h (__check_build_id): Only declare when ENABLE_DWZ is
+	defined.
+
+2012-08-16  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (EXTRA_DIST): Add known-dwarf.h.
+	* dwarf.h (DW_LANG_Go): Update comment.
+	(DW_LANG_Mips_Assembler): Likewise.
+
+2012-06-27  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt.
+	* dwarf_begin.c (dwarf_begin): Add INTDEF.
+	* dwarf_begin_elf.c (__check_build_id): New internal_function.
+	(try_debugaltlink): New function.
+	(open_debugaltlink): Likewise.
+	(check_section): Try open_debugaltlink for .gnu_debugaltlink.
+	* dwarf_end.c (dwarf_end): Free the alternative Dwarf descriptor if
+	necessary.
+	* dwarf_error.c (errmsgs): Add DWARF_E_NO_ALT_DEBUGLINK.
+	* dwarf_formref.c (__libdw_formref): Using DW_FORM_GNU_ref_alt
+	is an error here.
+	* dwarf_formref_die.c (dwarf_formref_die): Handle DW_FORM_GNU_ref_alt.
+	* dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_GNU_strp_alt.
+	* dwarf_formudata.c (__libdw_formptr): Adjust __libdw_read_offset
+	calls.
+	* dwarf_getpubnames.c (get_offsets): Adjust __libdw_read_offset call.
+	* libdwP.h: Add DWARF_E_NO_ALT_DEBUGLINK.
+	(struct Dwarf): Add alt_dwarf and free_alt fields.
+	(__libdw_read_offset): Add dbg_ret argument, use to check with
+	__libdw_offset_in_section.
+	(__check_build_id): New function declaration.
+	(dwarf_begin): Define as INTDECL.
+	* libdw_form.c (__libdw_form_val_len): Handle DW_FORM_GNU_ref_alt
+	and DW_FORM_GNU_strp_alt.
+
+2012-07-19  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_OP_GNU_parameter_ref.
+
+2012-07-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Correct spelling of DW_LANG_ObjC.
+	* dwarf_aggregate_size.c (array_size): Use correct spelling of
+	DW_LANG_ObjC.
+
+2012-07-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_ATE_UTF.
+
+2012-06-27  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_MACRO_GNU .debug_macro type encodings.
+
+2012-06-26  Mark Wielaard  <mjw@redhat.com>
+
+	* libdwP.h: Add IDX_debug_macro.
+	* dwarf.h: Add DW_AT_GNU_macros.
+	* dwarf_begin_elf.c (dwarf_scnnames): Add .debug_macro.
+	* dwarf_formudata.c (dwarf_formudata): Recognize DW_AT_GNU_macros.
+
+2012-04-27  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw/dwarf_highpc.c (dwarf_highpc): Handle DW_AT_high_pc being
+	a constant offset from DW_AT_low_pc.
+
+2012-03-19  Tom Tromey  <tromey@redhat.com>
+
+	* libdw_findcu.c (findcu_cb): Move earlier.
+	(__libdw_intern_next_unit): Add new CU to search tree here...
+	(__libdw_findcu): ... not here.
+
+2012-01-31  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_formudata.c (dwarf_formudata): Handle DW_FORM_sec_offset.
+
+2011-11-31  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (known-dwarf.h): Run gawk on config/known-dwarf.awk.
+
+2011-07-14  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw.h (dwarf_offdie): Fix documentation to mention .debug_info.
+
+2011-05-16  Jakub Jelinek  <jakub@redhat.com>
+
+	* dwarf.h (DW_OP_GNU_const_type, DW_OP_GNU_regval_type,
+	DW_OP_GNU_deref_type, DW_OP_GNU_convert, DW_OP_GNU_reinterpret):
+	New.
+
+2011-04-26  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_child (dwarf_child): Sanity check end of section against
+	cu_data () of die->cu.
+
+2011-03-22  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Add DW_TAG_GNU_call_site,
+	DW_TAG_GNU_call_site_parameter,
+	DW_AT_GNU_call_site_value,
+	DW_AT_GNU_call_site_data_value,
+	DW_AT_GNU_call_site_target,
+	DW_AT_GNU_call_site_target_clobbered,
+	DW_AT_GNU_tail_call,
+	DW_AT_GNU_all_tail_call_sites,
+	DW_AT_GNU_all_call_sites,
+	DW_AT_GNU_all_source_call_sites,
+	and DW_OP_GNU_entry_value.
+
+2011-03-10  Petr Machata  <pmachata@redhat.com>
+
+	* libdw/dwarf_tag.c (__libdw_findabbrev): Reject requests for
+	abbreviation with code 0.
+
+2011-03-09  Petr Machata  <pmachata@redhat.com>
+
+	* libdw/dwarf_child.c (dwarf_child): Check for section overrun.
+
+2011-02-23  Roland McGrath  <roland@redhat.com>
+
+	* libdwP.h (struct Dwarf) [USE_ZLIB]: New member sectiondata_gzip_mask.
+	Declare __libdw_free_zdata.
+	* dwarf_end.c [USE_ZLIB] (__libdw_free_zdata): New function.
+	(dwarf_end): Call it.
+
+	* dwarf_begin_elf.c (valid_p): Likewise.
+	(check_section, scngrp_read): Likewise.
+	(check_section) [USE_ZLIB]: Grok .z* flavors of sections.
+
+2010-10-13  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h: Add DW_LANG_Go.
+
+2010-10-05  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getaranges.c: Use malloc rather than alloca,
+	since the total number of elements can be quite huge.
+
+2010-07-26  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getlocation_implicit_pointer.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.map (ELFUTILS_0.149): New set.
+	Add dwarf_getlocation_implicit_pointer.
+	* libdw.h: Declare it.
+
+	* dwarf_offdie.c (do_offdie): Renamed to __libdw_offdie, made global.
+	(dwarf_offdie, dwarf_offdie_types): Update callers.
+	* libdwP.h: Declare it.
+
+	* dwarf.h: Add DW_OP_GNU_implicit_pointer.
+	* dwarf_getlocation.c (__libdw_intern_expression): Handle it.
+
+2010-08-24  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map (ELFUTILS_0.149): New set.  Add dwfl_dwarf_line.
+
+2010-07-27  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_formref_die.c: Fix sig8 hash insertion.
+
+2010-06-23  Roland McGrath  <roland@redhat.com>
+
+	* cfi.c (dwarf_cfi_validate_fde): Function removed.
+	* libdw.h: Remove it.
+	* libdw.map: Likewise.
+
+2010-06-22  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getlocation.c (check_constant_offset): data[48] are constant.
+
+	* dwarf_getsrclines.c: Fix signed comparison warning in extended
+	opcode parsing.
+
+2010-06-21  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h: Add DW_TAG_GNU_* constants.
+
+	* memory-access.h (get_sleb128_rest_return): Fix sign extension for
+	10-byte case.
+
+2010-06-20  Roland McGrath  <roland@redhat.com>
+
+	* libdw_findcu.c (__libdw_findcu): Take new flag argument,
+	to search TUs instead of CUs.
+	* libdwP.h: Update decl.
+	(struct Dwarf): New member tu_tree.
+	* dwarf_end.c (dwarf_end): Clean up tu_tree.
+	* dwarf_offdie.c (do_offdie): New function, broken out of ...
+	(dwarf_offdie): ... here.
+	(dwarf_offdie_types): New function.
+	* libdw.h: Declare it.
+	* libdw.map (ELFUTILS_0.148): Add it.
+
+	* libdwP.h (CUDIE): Use cu_data.
+	* dwarf_formblock.c: Likewise.
+	* dwarf_formref_die.c: Likewise.
+	* dwarf_diecu.c: Use CUDIE macro.
+	* dwarf_formaddr.c: Use cu_sec_idx.
+
+2010-06-16  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_formref_die.c: Use dwarf_offdie only for DW_FORM_ref_addr, so
+	we don't repeat a CU lookup we've already done.  Handle
+	DW_FORM_ref_sig8 using sig8_hash table and __libdw_intern_next_unit.
+
+	* libdw_findcu.c (__libdw_intern_next_unit): New function,
+	broken out of ...
+	(__libdw_findcu): ... here.  Call it.
+	* libdwP.h: Declare it.
+	(struct Dwarf): New member next_tu_offset.
+
+	* dwarf_sig8_hash.c: New file.
+	* dwarf_sig8_hash.h: New file.
+	* Makefile.am (libdw_a_SOURCES, noinst_HEADERS): Add them.
+	* dwarf_abbrev_hash.c: Include dwarf_sig8_hash.h before
+	defining NO_UNDEF.
+	* libdwP.h (struct Dwarf): New member sig8_hash.
+	* dwarf_begin_elf.c: Call Dwarf_Sig8_Hash_init on it.
+	* dwarf_end.c: Call Dwarf_Sig8_Hash_free on it.
+
+	* dwarf_nextcu.c (dwarf_next_unit): New function, broken out of ...
+	(dwarf_nextcu): ... here.  Call it.
+	* libdw.h: Declare it.
+	* libdwP.h: Add INTDECL.
+	* libdw_findcu.c (__libdw_findcu): Use it instead of dwarf_nextcu.
+	* libdw.map (ELFUTILS_0.148): New set, add dwarf_next_unit.
+
+	* libdwP.h (cu_sec_idx, cu_data): New functions.
+	Use .debug_types when CU is a TU.
+	* dwarf_cuoffset.c: Use that instead of assuming IDX_debug_info.
+	* dwarf_siblingof.c: Likewise.
+	* dwarf_formstring.c: Likewise.
+	* dwarf_formudata.c (__libdw_formptr, dwarf_formudata): Likewise.
+	* dwarf_getlocation.c (dwarf_getlocation): Likewise.
+	(dwarf_getlocation_addr): Likewise.
+
+	* libdwP.h (struct Dwarf_CU): Add new members type_offset, type_sig8.
+	(DIE_OFFSET_FROM_CU_OFFSET): Take flag argument; if true, compute
+	.debug_types header size instead of .debug_info header size.
+	(CUDIE): Use it.
+	* dwarf_diecu.c: Update caller.
+	* dwarf_getaranges.c: Likewise.
+	* dwarf_nextcu.c: Likewise.
+	* libdw_findcu.c (__libdw_findcu): Initialize new members.
+
+	* fde.c (fde_by_offset): Renamed to ...
+	(__libdw_fde_by_offset): ... this, made global and internal_function.
+	Don't take ADDRESS argument.
+	(__libdw_find_fde): Update caller.  Do address sanity check here.
+	* cfi.h: Declare __libdw_fde_by_offset.
+	* cfi.c (dwarf_cfi_validate_fde): New function.
+	* libdw.h: Declare it.
+	* libdw.map (ELFUTILS_0.148): Add it.
+
+	* cie.c (intern_new_cie): Canonicalize DW_EH_PE_absptr FDE encoding to
+	either DW_EH_PE_udata8 or DW_EH_PE_udata4.
+
+	* encoded-value.h (read_encoded_value): Handle DW_EH_PE_indirect.
+	Don't assume DW_EH_PE_aligned refers to native address size.
+
+	* cfi.c (execute_cfi): Barf on CIE initial instructions changing the
+	address.
+
+2010-06-17  Roland McGrath  <roland@redhat.com>
+
+	* libdwP.h (struct Dwarf_Line_s): Add members isa, discriminator, and
+	op_index.
+	* dwarf_getsrclines.c (dwarf_getsrclines): Move NEW_FILE macro guts
+	into an inner inline function.  Set new fields.  Check all fields for
+	overflow when setting.
+	* dwarf_lineisa.c: New file.
+	* dwarf_linediscriminator.c: New file.
+	* dwarf_lineop_index.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add them.
+	* libdw.map (ELFUTILS_0.148): Add them.
+	* libdw.h: Declare them.
+
+2010-06-16  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_next_cfi.c: Fix version 4 return_address_register decoding.
+
+	* fde.c (fde_by_offset): Renamed to ...
+	(__libdw_fde_by_offset): ... this, made global and internal_function.
+	Don't take ADDRESS argument.
+	(__libdw_find_fde): Update caller.  Do address sanity check here.
+	* cfi.h: Declare __libdw_fde_by_offset.
+	* cfi.c (dwarf_cfi_validate_fde): New function.
+	* libdw.h: Declare it.
+	* libdw.map (ELFUTILS_0.148): Add it.
+
+	* cie.c (intern_new_cie): Canonicalize DW_EH_PE_absptr FDE encoding to
+	either DW_EH_PE_udata8 or DW_EH_PE_udata4.
+
+	* encoded-value.h (read_encoded_value): Handle DW_EH_PE_indirect.
+	Don't assume DW_EH_PE_aligned refers to native address size.
+
+	* cfi.c (execute_cfi): Barf on CIE initial instructions changing the
+	address.
+
+2010-06-15  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_formref.c (__libdw_formref): Diagnose DW_FORM_ref_sig8 like
+	DW_FORM_ref_addr.
+	* dwarf_formref_die.c (dwarf_formref_die): Diagnose it the same way
+	here, since we don't support it yet.
+
+	* dwarf_next_cfi.c: Handle version 4 format.
+
+	* dwarf_getsrclines.c: Handle version 4 format.
+
+2010-06-01  Roland McGrath  <roland@redhat.com>
+
+	* libdwP.h: Remove unused IDX_debug_*names, add IDX_debug_types.
+	* dwarf_begin_elf.c (dwarf_scnnames): Likewise.
+
+	* libdwP.h (CIE_VERSION): Remove unused macro.
+
+	* dwarf_getsrclines.c: Fix version field test.
+	* libdwP.h (DWARF_VERSION): Remove useless macro.
+
+	* dwarf_formudata.c (__libdw_formptr): Fix DW_FORM_sec_offset handling.
+
+	* dwarf_formblock.c (dwarf_formblock): Handle DW_FORM_exprloc.
+
+	* libdw_findcu.c (__libdw_findcu): Accept version 4.
+
+2010-05-31  Mark Wielaard  <mjw@redhat.com>
+
+	* cfi.h (dwarf_cfi_cie_p): Move definition from here, to ..
+	* libdw.h (dwarf_cfi_cie_p): ... here.
+
+2010-05-31  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf.h: Fix DW_LANG_Python constant.
+
+2010-05-28  Eduardo Santiago  <santiago@redhat.com>
+
+	* dwarf_getlocation.c (dwarf_getlocation): Do attr_ok check first
+	thing.
+
+2010-05-27  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h: Add DW_AT_enum_class, DW_AT_linkage_name,
+	DW_TAG_template_alias, DW_LANG_Python, DW_LNE_set_discriminator.
+
+2010-05-08  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Take new argument
+	REF_SIZE.  Use that to handle DW_OP_call_ref correctly.
+	(getlocation): Update caller.
+	* dwarf_frame_cfa.c (dwarf_frame_cfa): Likewise.
+	* dwarf_frame_register.c (dwarf_frame_register): Likewise.
+	* libdwP.h: Update decl.
+
+2010-04-26  Roland McGrath  <roland@redhat.com>
+
+	* cfi.h (struct Dwarf_Frame_s): Add cfa_invalid alternative in cfa_rule.
+	* cfi.c (execute_cfi): Set that instead of doing cfi_assert for
+	DW_CFA_def_cfa_{offset*,register} when a non-offset rule is in force.
+	* dwarf_frame_cfa.c (dwarf_frame_cfa): Handle cfa_invalid.
+
+	* dwarf_getlocation.c (__libdw_intern_expression): Take new arg CFAP.
+	Prepend DW_OP_call_frame_cfa if true.
+	(getlocation): Update caller.
+	* dwarf_frame_cfa.c (dwarf_frame_cfa): Likewise.
+	* dwarf_frame_register.c (dwarf_frame_register): Likewise.
+	* libdwP.h: Update decl.
+
+2010-04-22  Roland McGrath  <roland@redhat.com>
+
+	* cfi.c (execute_cfi): Never return without cleanup.
+	Free FS on failure.
+	(cie_cache_initial_state): Adjust caller to expect that free.
+	(__libdw_frame_at_address): Likewise.
+
+2010-03-10  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map (ELFUTILS_0.146): New set.  Add dwfl_core_file_report.
+
+2010-02-15  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am: Use config/eu.am for common stuff.
+
+2010-02-02  Mark Wielaard  <mjw@redhat.com>
+
+	* fde.c (intern_fde): Fix length check for sized_augmentation_data.
+
+2010-01-07  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getcfi_elf.c (getcfi_phdr): Use elf_getphdrnum.
+
+2010-01-05  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_aggregate_size.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare it.
+	* libdwP.h: Add INTDECL.
+	* libdw.map (ELFUTILS_0.144): New set.  Add dwarf_aggregate_size.
+
+	* dwarf_srclang.c: Add INTDEF.
+	* libdwP.h: Add INTDECL.
+
+	* dwarf.h: Add some more DW_AT_GNU_* types from gcc.
+
+	* dwarf.h: Add DW_AT_GNU_vector, DW_AT_GNU_template_name.
+
+2009-11-21  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getlocation.c (check_constant_offset): Return 1 for all
+	non-constant forms.
+
+2009-10-15  Roland McGrath  <roland@redhat.com>
+
+	* libdw_form.c (__libdw_form_val_len): Grok DW_FORM_sec_offset,
+	DW_FORM_exprloc, DW_FORM_flag_present, and DW_FORM_ref_sig8.
+
+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.
+	(DW_CIE_ID_32, DW_CIE_ID_64): New constants replace it.
+
+2009-04-01  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h: Add DW_CFA_GNU_negative_offset_extended.
+
+2009-01-28  Roland McGrath  <roland@redhat.com>
+
+	* libdwP.h (struct Dwarf_Line_s): Move out of struct Dwarf_Lines_s
+	defn so C++ doesn't scope the name to not match the Dwarf_Line typedef.
+
+	* libdwP.h (struct Dwarf_Files_s): Replace dbg field with cu field.
+
+2009-01-26  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_ranges.c: Return 0 when no ranges or *_pc attrs at all.
+
+2009-01-25  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getattrs.c: Correctly skip attribute values when restarting.
+
+2009-01-23  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am ($(srcdir)/known-dwarf.h): Target renamed back.
+	Put these rules under if MAINTAINER_MODE.
+
+2009-01-22  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h: Add DW_OP_GNU_encoded_addr.
+
+2009-01-21  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (CLEANFILES): Renamed to ...
+	(MOSTLYCLEANFILES): ... here.
+	(CLEANFILES): New variable, add known-dwarf.h.
+
+2009-01-17  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (known-dwarf.h): Target renamed, not in $(srcdir).
+	Make it unconditional.
+	(BUILT_SOURCES): Updated.
+
+	* dwarf.h: Add description comments for DW_LANG_* values.
+
+	* Makefile.am [MAINTAINER_MODE]
+	($(srcdir)/known-dwarf.h): New target.
+	(BUILT_SOURCES): Add it.
+
+	* dwarf.h: Add DW_OP_GNU_push_tls_address, DW_OP_GNU_uninit.
+
+2009-01-10  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_error.c: Always use __thread.  Remove all !USE_TLS code.
+
+2009-01-08  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (libdw.so): Don't depend on $(zip_LIBS), just link it in.
+
+2008-01-06  Roland McGrath  <roland@redhat.com>
+
+	* libdwP.h (struct Dwarf_Abbrev): Change type of 'has_children' to bool.
+	Reorder members.
+	* dwarf_haschildren.c: Return -1 for error case, not 0.
+
+	* Makefile.am (libdw.so): Link in $(zip_LIBS).
+
+2009-01-06  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf.h: Add definition for unwind and call frame information.
+
+	* memory-access.h: Define read_ubyte_unaligned, read_sbyte_unaligned,
+	read_ubyte_unaligned_inc, and read_sbyte_unaligned_inc.
+
+2008-08-15  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map (ELFUTILS_0.136): New version set, inherits from
+	ELFUTILS_0.130.  Add dwfl_addrsegment, dwfl_report_segment.
+
+2008-01-21  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_child.c: Minor optimizations.
+	* dwarf_getattrs.c: Likewise.
+	* dwarf_getpubnames.c: Likewise.
+	* dwarf_siblingof.c: Likewise.
+	* dwarf_tag.c: Likewise.
+
+2008-01-18  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getsrclines.c (dwarf_getsrclines): Don't require exact match
+	of DWARF_VERSION comparison, just fail if the file's version is newer.
+
+2008-01-17  Nick Clifton  <nickc@redhat.com>
+
+	* dwarf.h (DWARF3_LENGTH_MIN_ESCAPE_CODE): New define.
+	(DWARF3_LENGTH_MAX_ESCAPE_CODE): New define.
+	(DWARF3_LENGTH_64_BIT): New define.
+	* dwarf_getaranges (dwarf_getaranges): Use the new definitions.
+	* dwarf_getpubnames: Include dwarf.h.
+	(get_offsets): Use the new definitions.
+	* dwarf_getsrclines.c (dwarf_getsrclines): Use the new defintions.
+	* dwarf_nextcu.c: Include dwarf.h.  Correct comment.
+	(dwarf_nextcu): Use the new definitions.
+
+	* libdwP.h (DIE_OFFSET_FROM_CU_OFFSET): New macro.
+	* dwarf_diecu.c (dwarf_diecu): Use the new macro.
+	* dwarf_getaranges (dwarf_getaranges): Use the new macro.
+	* dwarf_nextcu.c (dwarf_nextcu): Use the new macro.
+
+	* dwarf_getpubnames (get_offsets): Replace assertion with test and
+	error return.
+
+	* dwarf_entry_breakpoints.c (dwarf_entry_breakpoints): Use CUDIE.
+
+	* dwarf_siblingof (dwarf_siblingof): Detect a NULL return pointer.
+	Set the address in the return structure to the address of the next
+	non-sibling die, if there is no sibling and the return pointer is
+	not the same as the die pointer.
+	* libdw.h: Expand the description of the dwarf_siblingof prototype.
+
+	* dwarf_child.c: Fix typo in comment.
+
+	* libdwP.h (DWARF_VERSION): Change to 3.
+
+	* dwarf_formref.c (__libdw_formref.c): Handle attributes which do
+	not have a initialised valp pointer.
+
+	* dwarf_getattrs.c (dwarf_getattrs): Return 1 rather than 0 when
+	the end of the attributes is reached.  When the callback fails,
+	return the address of the failing attribute, not the address of
+	its successor.
+	* libdw.h: Expand the description of the dwarf_getattrs prototype.
+
+	* dwarf_child.c (__libdw_find_attr): Use the new definition.
+	(dwarf_child): Likewise.
+	* dwarf_tag.c (__libdw_findabbrev): Likewise.
+	(dwarf_tag): Likewise.
+
+2008-01-08  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (euinclude): Variable removed.
+	(pkginclude_HEADERS): Set this instead of euinclude_HEADERS.
+	(libdw.so): Pass -Wl,--enable-new-dtags,-rpath,$(pkglibdir).
+
+2007-10-17  Roland McGrath  <roland@redhat.com>
+
+	* libdw.h (__deprecated_attribute__): New macro.
+	(dwarf_formref): Mark it deprecated.
+	* dwarf_formref.c (__libdw_formref): New function, broken out of ...
+	(dwarf_formref): ... here.  Call it.  Remove INTDEF.
+	* libdwP.h: Remove INTDECL.
+	Declare __libdw_formref.
+	* dwarf_siblingof.c (dwarf_siblingof): Call __libdw_formref instead.
+	* dwarf_formref_die.c: Likewise.  Handle DW_FORM_ref_addr here.
+
+	* libdw_form.c (__libdw_form_val_len): Fix DW_FORM_ref_addr result,
+	needs to check CU->version.
+
+	* libdwP.h (struct Dwarf_CU): New member `version'.
+	* libdw_findcu.c (__libdw_findcu): Initialize it.
+
+	* dwarf_child.c: Return 1 for null entry as first child.
+
+2007-10-05  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_begin_elf.c (check_section): Punt on SHT_NOBITS sections.
+
+	* libdw.h (__extern_inline): Rename to __libdw_extern_inline.
+	[__OPTIMIZE__] (dwarf_whatattr, dwarf_whatform): Update uses.
+
+2007-10-03  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map (ELFUTILS_0.130: Add dwfl_build_id_find_elf
+	and dwfl_build_id_find_debuginfo.
+
+	* libdw.map (ELFUTILS_0.130): New version set, inherits from
+	ELFUTILS_0.127.  Add dwfl_module_build_id, dwfl_module_report_build_id.
+
+2007-10-02  Roland McGrath  <roland@redhat.com>
+
+	* libdw_visit_scopes.c (classify_die): Return walk for class_type and
+	structure_type.
+
+2007-08-07  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getscopes.c (pc_match): Swallow dwarf_haspc error return when
+	error code is DWARF_E_NOERROR (0).
+
+	* dwarf_getscopes.c (pc_record): Always bail early if DIE->prune.
+	Fix typo in __libdw_visit_scopes argument.
+
+	* dwarf_getscopes.c (pc_match): Check dwarf_haspc error return,
+	swallow DWARF_E_NO_DEBUG_RANGES but not other errors.
+
+2007-07-03  Roland McGrath  <roland@redhat.com>
+
+	* libdw.h (__extern_inline): New macro.
+	[__OPTIMIZE__] (dwarf_whatattr, dwarf_whatform): Use it.
+
+2007-04-16  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map (ELFUTILS_0.127): Add dwfl_module_address_section.
+
+2007-04-05  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getsrcdirs.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_getsrcdirs.
+	* libdw.map (ELFUTILS_0.127): Add it.
+
+	* libdwP.h (struct Dwarf_Files_s): New member ndirs.
+	* dwarf_getsrclines.c (dwarf_getsrclines): Don't clobber NDIRLIST to
+	zero before we use it to check for DWARF_E_INVALID_DIR_IDX.
+	Save DIRARRAY in the Dwarf_Files.
+
+	* dwarf_ranges.c (dwarf_ranges): Don't sign-extend 32-bit BEGIN
+	address to check for all-ones base address entry.  Check directly.
+	Reported by Sébastien Dugué <sebastien.dugue@bull.net>.
+
+2007-03-25  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_begin_elf.c (check_section): Return Dwarf * instead of void.
+	Return NULL when freeing RESULT on error.
+	(global_read, scngrp_read): Check return value from check_section,
+	break out of loop after it has freed RESULT.
+	(valid_p): Handle null argument.
+
+2007-03-12  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map (ELFUTILS_0.127): Add dwfl_report_begin_add.
+
+2007-03-04  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map (ELFUTILS_0.127): New version set, inherits from
+	ELFUTILS_0.126.  Add dwfl_module_addrsym.
+
+2007-02-10  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h (DW_OP_fbreg): Comment fix.
+
+2007-02-03  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getelf.c (dwarf_getelf): Renamed from dwarf_get_elf.
+	* libdw.map (ELFUTILS_0.126): New version set, inherits from
+	ELFUTILS_0.122.  Move dwarf_getelf there; it was never truly
+	exported in the past.
+
+2006-12-17  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getlocation.c (dwarf_getlocation_addr): Use zero as base
+	address when the CU is missing attributes due to buggy GCC.
+
+2006-08-29  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (CLEANFILES): Add libdw.so.$(VERSION).
+
+	* libdw.h (dwarf_diecu): Add __nonnull_attribute__.
+	(dwarf_child): Don't list arg 1 in __nonnull_attribute__.
+
+	* libdw_alloc.c (__libdw_allocate): Take new ALIGN argument, make sure
+	result is aligned.  Adjust NEWP->remaining here for this allocation.
+	* libdwP.h: Update decl.
+	(libdw_alloc): Update caller.
+
+2006-07-12  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_child.c: Adjust for internal_function_def removal.
+	* dwarf_getabbrev.c: Likewise.
+	* dwarf_tag.c: Likewise.
+	* libdw_form.c: Likewise.
+	* memory-access.c: Likewise.
+
+2006-06-28  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map: Export dwfl_linecu, dwfl_line_comp_dir.
+
+	* libdw.map: Bump to 0.122; export dwfl_module_getsymtab and
+	dwfl_module_getsym.
+
+2006-05-27  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h: Add extern "C".
+
+2006-05-22  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getaranges.c (dwarf_getaranges): Handle files without
+	aranges information.
+
+2006-05-21  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h: Add nonnull attributes to dwarf_tag, dwarf_getattrs,
+	dwarf_haschildren.
+
+2006-02-28  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h: Add missing DW_ATE_*, DW_TAG_*, DW_LANG_*, DW_CFA_*,
+	DW_OP_* values, to match DWARF 3.0.  Add new DW_DS_*, DW_END_*
+	values from DWARF 3.0.
+
+2006-02-22  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map: Bump to 0.120; export dwfl_version.
+
+2005-12-22  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map: Bump to 0.119; export dwfl_linux_proc_maps_report.
+
+2005-12-12  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_ranges.c: Copy CU base address-finding code from
+	dwarf_getlocation.
+
+2005-12-09  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getlocation.c (dwarf_getlocation_addr): Add some unlikelys.
+	Delay CU base lookup until it's needed.
+	If CU base lookup fails with no error, flag invalid DWARF.
+
+2005-11-25  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map: Bump to 0.118; export dwfl_module_register_names.
+
+2005-11-15  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am [BUILD_STATIC] (AM_CFLAGS): Add -fpic.
+
+2005-11-13  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map: Bump to 0.117; export dwfl_module_return_value_location.
+
+2005-10-27  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_entry_breakpoints.c (search_range): Fix binary search code;
+	don't match end_sequence markers.
+
+	* dwarf_getsrclines.c (compare_lines): Sort end_sequence markers
+	before normal records at the same address.
+	* dwarf_getsrc_die.c (dwarf_getsrc_die): Don't match an end_sequence
+	marker.
+
+2005-10-26  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getfuncs.c (dwarf_getfuncs): Use Dwarf_Die, not Dwarf_Func.
+	* dwarf_func_file.c: Renamed to ...
+	* dwarf_decl_file.c: ... here.
+	* dwarf_func_col.c: Renamed to ...
+	* dwarf_decl_column.c: ... here.
+	* dwarf_func_line.c: Renamed to ...
+	* dwarf_decl_line.c: ... here.
+	(dwarf_func_line): Renamed to ...
+	(dwarf_decl_line): ... this.  Take a Dwarf_Die * argument.
+	(__libdw_func_intval): Renamed __libdw_attr_intval.
+	* dwarf_func_name.c: File removed.
+	* dwarf_func_lowpc.c: File removed.
+	* dwarf_func_highpc.c: File removed.
+	* dwarf_func_entrypc.c: File removed.
+	* dwarf_func_die.c: File removed.
+	* Makefile.am (libdw_a_SOURCES): Updated.
+	* libdw.h: Update decls.
+	(Dwarf_Func): Type removed.
+	* libdwP.h: Update decls.
+	(struct Dwarf_Func_s): Type removed.
+	* libdw.map: Updated.
+
+	* libdwP.h (CUDIE): New macro.
+	* dwarf_getlocation.c (dwarf_getlocation_addr): Use it.
+	* dwarf_getscopes_die.c (dwarf_getscopes_die): Likewise.
+	* dwarf_ranges.c (dwarf_ranges): Likewise.
+
+	* dwarf_getloclist.c: Renamed to ...
+	* dwarf_getlocation.c: ... here.
+	(getloclist): Renamed to getlocation.
+	(dwarf_getloclist): Renamed to dwarf_getlocation.
+	(dwarf_addrloclists): Renamed to dwarf_getlocation_addr.
+	* Makefile.am (libdw_a_SOURCES): Updated.
+	* libdw.h (dwarf_getloclist): Renamed to dwarf_getlocation.
+	(dwarf_addrloclists): Renamed dwarf_getlocation_addr.
+	(Dwarf_Loc): Renamed Dwarf_Op.
+	* libdwP.h (struct loc_s): Update use.
+	* libdw.map: Update map.
+
+	* dwarf_entry_breakpoints.c: Use the second line record within the
+	function, regardless of its source location data.
+
+2005-10-25  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_entry_breakpoints.c: Fall back to entrypc for contiguous too.
+
+	* libdw.map: Add dwarf_entrypc, dwarf_entry_breakpoints.
+
+2005-10-14  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_diecu.c (dwarf_diecu): New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_diecu.
+	* libdw.map: Export it.
+
+	* libdw.map: Bump to 0.116; export dwarf_ranges.
+
+2005-09-20  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_haspc.c: Use dwarf_ranges.
+	* dwarf_entry_breakpoints.c: Likewise.
+
+	* dwarf_ranges.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_ranges.
+	* libdwP.h: Add INTDECL.
+
+2005-09-14  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_entry_breakpoints.c (dwarf_entry_breakpoints): Fix braino in
+	prologue_end marker scanning loop.
+
+2005-09-11  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h: Comment typo fix.
+
+2005-09-07  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_entry_breakpoints.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_entry_breakpoints.
+
+	* dwarf_entrypc.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_entrypc.
+	* libdwP.h: Add INTDECL.
+
+2005-08-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Use $(LINK) not $(CC) when creating DSO.
+	(%.os): Use COMPILE.os.
+	(COMPILE.os): Filter out gconv options.
+
+2005-08-27  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getscopes.c (dwarf_getscopes): Rewritten using
+	__libdw_visit_scopes.
+
+	* dwarf_getscopes_die.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_getscopes_die.
+	* libdw.map: Bump to 0.115 and add it.
+
+	* libdw_visit_scopes.c (__libdw_visit_scopes): Pass a struct
+	containing a DIE and its parent pointer, instead of just Dwarf_Die.
+	Take two functions for both preorder and postorder visitors.
+	* libdwP.h: Update decl.
+	(struct Dwarf_Die_Chain): New type.
+	* dwarf_func_inline.c: Update uses.
+
+	* dwarf_diename.c (dwarf_diename): Use dwarf_attr_integrate.
+	Add INTDEF.
+	* libdwP.h: Add INTDECL.
+	* dwarf_func_name.c (dwarf_func_name): Use dwarf_diename.
+
+2005-08-23  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_attr_integrate.c (dwarf_attr_integrate): Treat
+	DW_AT_specification the same as DW_AT_abstract_origin.
+
+2005-08-20  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map: Add dwfl_cumodule, remove dwfl_linecu.
+	Add dwfl_linux_kernel_report_offline, dwfl_offline_section_address,
+	and dwfl_report_offline.
+
+2005-08-19  Roland McGrath  <roland@redhat.com>
+
+	* libdw.map: Bump version to ELFUTILS_0.114 for libdwfl changes.
+	Add dwfl_module_relocate_address, dwfl_module_relocations,
+	dwfl_module_relocation_info.
+
+2005-08-18  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getscopes.c (dwarf_getscopes): Include the CU itself as
+	outermost scope in the results.
+
+2005-08-15  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_func_inline.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_func_inline, dwarf_func_inline_instances.
+	* libdw.map: Add them.
+
+	* dwarf_func_die.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_func_die.
+	* libdw.map: Add it.  Bump version to ELFUTILS_0.114.
+
+2005-08-10  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getsrclines.c (dwarf_getsrclines): Correct fallout of renaming
+	of DW_LNS_set_epilog_begin.
+
+2005-08-09  Roland McGrath  <roland@redhat.com>
+
+	* dwarf.h (DW_LNS_set_epilog_begin): Renamed DW_LNS_set_epilogue_begin.
+
+	* dwarf_end.c: Add INTDEF.
+	* dwarf_error.c (dwarf_errmsg): Likewise.
+	* libdwP.h (dwarf_end, dwarf_errmsg): Add INTDECLs.
+
+2005-08-01  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getaranges.c (dwarf_getaranges): Check for bogus offset.
+	* dwarf_getabbrev.c (__libdw_getabbrev): Likewise.
+
+2005-07-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am (libdw.so): No need to link with libeu.a anymore.
+	(libdw_a_LIBADD): Add all files from libdwfl.a.
+
+2005-07-27  Roland McGrath  <roland@redhat.com>
+
+	* Makefile.am (libdw.so): Link ../libdwfl/libdwfl_pic.a in,
+	along with ../libebl/libebl.a and ../lib/libeu.a;
+	depend on ../libelf/libelf.so.
+	(libdw_so_LDADD): New variable.
+	* libdw.map: Add dwfl_* symbols formerly in ../libdwfl/libdwfl.map.
+
+	* libdw.map: Define an empty base version and move all symbols to
+	version ELFUTILS_0.111; don't define ELFUTILS_1.0 at all yet.
+
+2005-07-23  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_error.c: Add internal alias for dwarf_errno.
+	* libdwP.h: Declare __dwarf_errno_internal.
+	* dwarf_getloclist.c: Use INTDEF for dwarf_errno.
+
+	* dwarf_error.c [USE_TLS]: Actually use __thread in definition of
+	global_error.
+
+2005-06-01  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getaranges.c (dwarf_getaranges): Sort result array.
+	* dwarf_getarange_addr.c (dwarf_getarange_addr): Use binary search.
+
+2005-06-08  Roland McGrath  <roland@redhat.com>
+
+	* memory-access.h (get_uleb128_step, get_uleb128): Remove casts.
+	(get_sleb128_step, get_sleb128): Likewise.
+	* dwarf_getattrs.c (dwarf_getattrs): Add consts.
+	* dwarf_getloclist.c (getloclist): Likewise.
+	* dwarf_formblock.c (dwarf_formblock): Likewise.
+	* dwarf_getsrclines.c (dwarf_getsrclines): Likewise.
+	* dwarf_getabbrevattr.c (dwarf_getabbrevattr): Likewise.
+	* dwarf_formref.c (dwarf_formref): Likewise.
+	* dwarf_formsdata.c (dwarf_formsdata): Likewise.
+	* dwarf_formudata.c (dwarf_formudata): Likewise.
+	* dwarf_haschildren.c (dwarf_haschildren): Likewise.
+	* dwarf_child.c (__libdw_find_attr, __libdw_find_attr): Likewise.
+	* dwarf_tag.c (dwarf_tag): Likewise.
+	* dwarf_getabbrev.c (__libdw_getabbrev): Likewise.
+	* memory-access.c (__libdw_get_uleb128, __libdw_get_sleb128): Likewise.
+	* libdw_form.c (__libdw_form_val_len): Likewise.
+	* libdwP.h: Update decl.
+
+2005-06-04  Roland McGrath  <roland@redhat.com>
+
+	* memory-access.h (get_uleb128_rest_return): New macro.
+	[! IS_LIBDW] (__libdw_get_uleb128): New static, defined using it.
+	(get_sleb128_rest_return): New macro.
+	[! IS_LIBDW] (__libdw_get_sleb128): New static, defined using it.
+	* memory-access.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	(DEFS): Add -DIS_LIBDW.
+
+2005-05-31  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_formref_die.c (dwarf_formref_die): Add CU header offset to
+	formref offset.
+
+2005-05-30  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getloclist.c (dwarf_addrloclists): Use DW_AT_entry_pc for base
+	address if DW_AT_low_pc is missing.  Not to spec, but GCC generates it.
+
+	* dwarf_getloclist.c (dwarf_addrloclists): Don't sign-extend 4-byte
+	BEGIN value.  Instead, match base address entries separately for
+	32/64 size cases.
+
+2005-05-28  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getloclist.c (dwarf_addrloclists): Fix decoding to advance
+	past location expression contents.
+
+2005-05-23  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getsrclines.c: Comment typo fix.
+
+	* dwarf_haspc.c (dwarf_haspc): Fix CU DIE address calculation.
+	* dwarf_getloclist.c (dwarf_addrloclists): Likewise.
+
+2005-05-22  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdwP.h: Only use INTDECL for alias prototypes.
+
+2005-05-19  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getloclist.c (attr_ok): Permit DW_AT_static_link too.
+
+	* dwarf_getscopevar.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_getscopevar.
+
+	* dwarf_getsrcfiles.c: Add INTDEF.
+	* dwarf_haschildren.c: Likewise.
+	* libdwP.h (dwarf_getsrcfiles, dwarf_haschildren): Add INTDECL.
+
+	* dwarf_getscopes.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h: Declare dwarf_getscopes.
+	* libdw.map: Add it.
+
+2005-05-18  Roland McGrath  <roland@redhat.com>
+
+	* libdwP.h (IDX_debug_ranges): New enum constant.
+	* dwarf_begin_elf.c (dwarf_scnnames): Add it for ".debug_ranges".
+	* libdwP.h (DWARF_E_NO_DEBUG_RANGES): New enum constant.
+	* dwarf_error.c (errmsgs): Add it.
+	* dwarf_haspc.c: New file.
+	* libdw.h: Declare dwarf_haspc.
+	* libdw.map: Add it.
+	* libdwP.h: Add INTDECL.
+
+	* dwarf_attr_integrate.c: New file.
+	* dwarf_hasattr_integrate.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add them.
+	* libdw.h: Declare dwarf_attr_integrate, dwarf_hasattr_integrate.
+	* libdw.map: Add them.
+
+	* dwarf_hasattr.c: Add INTDEF.
+	* libdwP.h: Add INTDECL for it.
+
+	* dwarf_formref_die.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add it.
+	* libdw.h (dwarf_formref_die): Declare it.
+	* libdwP.h (dwarf_formref_die): Add INTDECL.
+	* libdw.map: Add it.
+
+	* dwarf_getloclist.c (attr_ok, getloclist): New functions, broken out
+	of ...
+	(dwarf_getloclist): ... here.  Call them.
+	(dwarf_addrloclists): New function.
+	* libdw.h: Declare it.
+	* libdw.map: Add it.
+
+	* dwarf_getmacros.c (dwarf_getmacros): Don't bail at
+	DW_MACINFO_end_file.  Recognize type 0 as terminator.
+
+2005-05-05  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getsrc_die.c (dwarf_getsrc_die): Use binary search.
+
+	* dwarf_getsrclines.c (dwarf_getsrclines): Sort result array, since
+	the line program does not produce all entries in ascending order.
+
+2005-04-25  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getsrc_file.c (dwarf_getsrc_file): Handle multiple
+	occurences (e.g., inlines) better.
+
+2005-04-24  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h (DWARF_END_ABBREV): Define.
+	* dwarf_getabbrev.c (__libdw_getabbrev): Return DWARF_END_ABBREV if
+	end is reached.
+	* dwarf_offabbrev.c (dwarf_offabbrev): Return -1 on error, 1 if end
+	of records reached.
+	* dwarf_tag.c (__libdw_findabbrev): Also recognize DWARF_END_ABBREV
+	as error of __libdw_getabbrev.
+
+2005-04-04  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getsrc_file.c (dwarf_getsrc_file): Minor optimization.
+
+	* dwarf_getsrc_file.c (dwarf_getsrc_file): Always pass number of
+	results back to caller.
+
+2005-04-04  Roland McGrath  <roland@redhat.com>
+
+	* dwarf_getsrc_file.c (dwarf_getsrc_file): Use size_t for CUHL.
+
+	* dwarf_func_line.c (__libdw_func_intval): Use internal_function in
+	defn.
+
+2005-04-04  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getsrc_file.c (dwarf_getsrc_file): Use INTUSE.
+
+	* dwarf_getsrc_file.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getsrc_file.c.
+	* libdw.h: Declare dwarf_getsrc_file.
+	* libdw.map: Add dwarf_getsrc_file.
+
+2005-04-02  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_func_entrypc.c: New file.
+	* dwarf_func_col.c: New file.
+	* dwarf_func_line.c: New file.
+	* dwarf_func_file.c: New file.
+	* libdw.h: Add prototypes for new functions.
+	* libdw.map: Add dwarf_func_entrypc, dwarf_func_col, dwarf_func_line,
+	dwarf_func_file.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_func_entrypc.c,
+	dwarf_func_col.c, dwarf_func_line.c, dwarf_func_file.c.
+	* libdwP.h (struct Dwarf_Func_s): Add cudie element.
+	Declare __libdw_func_intval and __dwarf_formsdata_internal.
+	* dwarf_getfuncs.c: Also fill in cudie in Dwarf_Func object.
+	* dwarf_formsdata.c: Use INTUSE and INTDEF to avoid PLTs.
+
+	* dwarf.h: Add some DWARF3 definitions.
+
+2005-04-01  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getfuncs.c: New file.
+	* dwarf_func_highpc.c: New file.
+	* dwarf_func_lowpc.c: New file.
+	* dwarf_func_name.c: New file.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getfuncs.c,
+	dwarf_func_highpc.c, dwarf_func_lowpc.c, and dwarf_func_name.c.
+	* libdw.map: Add dwarf_getfuncs, dwarf_func_highpc, dwarf_func_lowpc,
+	and dwarf_func_name.
+	* libdw.h: Add prototypes for new functions.
+	* dwarf_child.c: Use INTUSE and INTDEF to avoid PLTs.
+	* dwarf_siblingof.c: Likewise.
+	* dwarf_dieoffset.c: Likewise.
+	* dwarf_highpc.c: Likewise.
+	* dwarf_lowpc.c: Likewise.
+	* libdwP.h: Add prototypes for internal functions.
+	Define Dwarf_Func_s structure.
+
+2005-03-29  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h: Add padding in Dwarf_die.
+
+	* dwarf_arrayorder.c: Use INTUSE and INTDEF to avoid PLTs.
+	* dwarf_attr.c: Likewise.
+	* dwarf_begin.c: Likewise.
+	* dwarf_begin_elf.c: Likewise.
+	* dwarf_bitoffset.c: Likewise.
+	* dwarf_bitsize.c: Likewise.
+	* dwarf_bytesize.c: Likewise.
+	* dwarf_diename.c: Likewise.
+	* dwarf_formaddr.c: Likewise.
+	* dwarf_formblock.c: Likewise.
+	* dwarf_formref.c: Likewise.
+	* dwarf_formstring.c: Likewise.
+	* dwarf_formudata.c: Likewise.
+	* dwarf_getarange_addr.c: Likewise.
+	* dwarf_getarangeinfo.c: Likewise.
+	* dwarf_getaranges.c: Likewise.
+	* dwarf_getloclist.c: Likewise.
+	* dwarf_getmacros.c: Likewise.
+	* dwarf_getsrc_die.c: Likewise.
+	* dwarf_getsrcfiles.c: Likewise.
+	* dwarf_getsrclines.c: Likewise.
+	* dwarf_highpc.c: Likewise.
+	* dwarf_lowpc.c: Likewise.
+	* dwarf_nextcu.c: Likewise.
+	* dwarf_offdie.c: Likewise.
+	* dwarf_siblingof.c: Likewise.
+	* dwarf_srclang.c: Likewise.
+	* dwarf_tag.c: Likewise.
+	* libdw_findcu.c: Likewise.
+	* libdwP.h: Add prototypes for internal functions.
+
+	* dwarf_addrdie.c: New file.
+	* dwarf_macro_opcode.c: New file.
+	* dwarf_macro_param1.c: New file.
+	* dwarf_macro_param2.c: New file.
+	* libdw.h: Add declarations.  Move Dwarf_Macro definition to libdwP.h.
+	* libdwP.h: Remove Dwarf_Macro definition.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_addrdie.c,
+	dwarf_macro_opcode.c, dwarf_macro_param1.c, and dwarf_macro_param2.c.
+	* libdw.map: Add entries for new functions.
+
+2005-03-21  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h: Handle broken gcc < 4.
+
+2005-02-15  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile (AM_CFLAGS): Add -Wunused -Wextra -Wformat=2.
+
+	* dwarf_begin_elf.c: Fix warnings.
+	* dwarf_dieoffset.c: Likewise.
+	* dwarf_end.c: Likewise.
+	* dwarf_error.c: Likewise.
+	* dwarf_getpubnames.c: Likewise.
+
+	* libdwP.h: Add new error values.
+	* dwarf_error.c: Support new error values.
+	* dwarf_getpubnames.c: Check parameter value.
+
+2005-02-05  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Check for text relocations in constructed DSO.
+
+	* Makefile.am [MUDFLAP] (AM_CFLAGS): Add -fmudflap.
+
+2005-02-04  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_siblingof.c (dwarf_siblingof): Add some buffer boundary
+	checks to not read over buffer boundaries for ill-formed DWARF data.
+
+2004-09-25  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_child.c: Make compile with gcc 4.0.
+	* dwarf_error.c: Likewise.
+	* dwarf_formblock.c: Likewise.
+	* dwarf_getabbrev.c: Likewise.
+	* dwarf_getattrs.c: Likewise.
+	* dwarf_getsrclines.c: Likewise.
+	* dwarf_tag.c: Likewise.
+	* libdw_form.c: Likewise.
+
+2004-01-20  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Support building with mudflap.
+
+	* dwarf_getloclist.c: Fix warnings gcc 3.4 spits out.
+	* dwarf_getsrclines.c: Likewise.
+	* dwarf_memory-access.h: Likewise.
+
+2004-01-19  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getsrcfiles.c: Third parameter can be NULL.
+
+	* libdw.h: Define Dwarf_macro.  Declare dwarf_getmacros.
+	Third parameter of dwarf_getsrcfiles can be NULL.
+
+	* libdw.map: Add dwarf_getmacros.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getmacros.
+	* dwarf_getmacros.c: New file.
+
+2004-01-18  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h: Second parameter of dwarf_getaranges can be NULL.
+
+	* dwarf_nextcu.c: Return -1 if dwarf parameter is NULL.
+
+	* dwarf_getsrclines.c:
+	Use read_2ubyte_unaligned_inc instead of _inc-less variant.
+
+	* dwarf_getaranges.c: Allow naranges parameter to be NULL.
+
+	* libdwP.h (_): Use elfutils domain.
+
+	* dwarf_getsrclines.c (dwarf_getsrclines): Add more branch prediction.
+
+	* dwarf_getsrclines.c: Fix typo in comment.
+
+2004-01-17  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am: Support building with mudflap.
+
+2004-01-16  Ulrich Drepper  <drepper@redhat.com>
+
+	* memory-access.h: Add lots of const in case a pointer passed is const.
+
+	* dwarf_formflag.c: New file.
+	* dwarf_getattrs.c: New file.
+	* dwarf_error.c: Add new error value.
+	* libdw.h: Add prototypes for new functions.  Adjust prototype for
+	dwarf_getpubnames.
+	* libdw.map: Add new functions.
+	* dwarf_getpubnames.c: Change type of return value and fourth parameter
+	to ptrdiff_t.
+	* libdwP.h: Add new error value.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getattrs.c and
+	dwarf_formflag.c.
+
+	* dwarf_getpubnames.c (dwarf_getpubnames): Just fail if dbg is NULL.
+
+2004-01-12  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getarange_addr.c: New file
+	* dwarf_getarangeinfo.c: New file.
+	* dwarf_getaranges.c: New file.
+	* dwarf_onerange.c: New file.
+	* libdw.h: Declare new functions.  Define Dwarf_Arange and
+	Dwarf_Aranges.
+	* libdw.map: Add new functions.
+	* libdwP.h: Add new errors.  Add aranges member to struct Dwarf.
+	Define Dwarf_Aranges_s and Dwarf_Arange_s.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getaranges.c,
+	dwarf_onearange.c, dwarf_getarangeinfo.c, dwarf_getarange_addr.c.
+	* dwarf_error.c: Add new message.
+
+2004-01-11  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_lineaddr.c, dwarf_linecol.c,
+	dwarf_linebeginstatement.c, dwarf_lineendsequence.c, dwarf_lineblock.c,
+	dwarf_lineprologueend.c, dwarf_lineepiloguebegin.c, dwarf_onesrcline.c.
+	* dwarf_error.c: Add another message.
+	* dwarf_getsrc_die.c: Adjust for Dwarf_Files and Dwarf_Lines
+	introduction.
+	* dwarf_filesrc.c: Likewise.
+	* dwarf_getsrcfiles.c: Likewise.
+	* dwarf_getsrclines.c: Likewise.
+	* dwarf_lineaddr.c: New file.
+	* dwarf_linebeginstatement.c: New file.
+	* dwarf_lineblock.c: New file.
+	* dwarf_linecol.c: New file.
+	* dwarf_lineendsequence.c: New file.
+	* dwarf_lineepiloguebegin.c: New file.
+	* dwarf_lineno.c: New file.
+	* dwarf_lineprologueend.c: New file.
+	* dwarf_onesrcline.c: New file.
+	* dwarf_lineno.c: Change interface to store result in object pointed
+	to by second parameter.
+	* libdw.h: Add prototypes for new functions.  Change dwarf_lineno
+	prototype.  Define Dwarf_Files and Dwarf_Lines.
+	* libdw.map: Add new functions.
+	* libdwP.h: Define Dwarf_Files_s and Dwarf_Lines_s.
+	* libdw_findcu.c: Don't initialize nlines field.
+
+	* dwarf_siblingof: Little optimization.
+
+	* dwarf_begin.c: Remember that the ELF descriptor must be closed.
+	* dwarf_end.c: Close ELF descriptor if free_elf is set.
+	* libdwP.h (struct Dwarf): Add free_elf field.
+
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getstring.c and
+	dwarf_offabbrev.c.
+	* dwarf_getstring.c: New file.
+	* dwarf_offabbrev.c: New file.
+	* libdw.map: Add dwarf_getstring and dwarf_offabbrev.
+	* dwarf_getabbrev.c (__libdw_getabbrev): Add new dbg and result
+	parameters.  Don't allocate memory if not necessary and don't lookup
+	previous results if no CU given.
+	(dwarf_getabbrev): Adjust call to __libdw_getabbrev.
+	* dwarf_tag.c: Adjust call to __libdw_getabbrev.
+	* libdw.h: Declare dwarf_offabbrev and dwarf_getstring.
+	* libdwP.h: Change prototype for __libdw_getabbrev.
+
+	* dwarf_getabbrevattr.c: Add offsetp parameter.  Fill in before
+	returning if this is wanted.
+
+2004-01-09  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_nextcu.c: Add new parameter offset_sizep.  Initialize it
+	with offset_size value.
+	* libdw.h: Adjust dwarf_nextcu prototype.
+	* libdwP.h (struct Dwarf_CU): Add offset_size member.
+	* libdw_findcu.c: Adjust dwarf_nextcu call.  Initialize offset_size
+	member of new CU struct.
+	* dwarf_formstring.c: Depend on offset_size not address_size for
+	DW_FORM_strp handling.
+	* dwarf_form.c: Likewise for DW_FORM_strp and DW_FORM_ref_addr.
+
+	* dwarf_tag.c (__libdw_findabbrev): Return correct value for
+	failing lookup.
+	(dwarf_tag): Correctly recognize failed lookup.
+
+	* dwarf_end.c (cu_free):  Call tdestroy for locs member.  Use new
+	function noop_free.
+	* dwarf_error.c: Add message for DWARF_E_NO_BLOCK.
+	* dwarf_formblock.c: New file.
+	* dwarf_getloclist.c: Rewrite to handle a single block.
+	* libdw.h: Define Dwarf_Block.  Rename Dwarf_Loc members.  Remove
+	Dwarf_Locdesc definition.  Declare dwarf_formblock.  Remove
+	dwarf_getloclistent declaration.
+	* libdw.map: Add dwarf_formblock, remove dwarf_getloclistent.
+	* libdwP.h: Define struct loc_s and DWARF_E_NO_BLOCK.
+	Add locs member to struct Dwarf_CU.
+	* libdw_fundcu.c: Initialize locs member of new CU.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_formblock.c.
+	Remove dwarf_getloclistent.c.
+
+2004-01-07  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h: Use __nonnull__ attribute only for gcc >= 3.3.
+	* libdwP.h: Likewise.
+
+	* dwarf_getloclist.c: New file.
+	* dwarf_getloclistent.c: New file.
+	* libdw.h: Define Dwarf_Loc and Dwarf_Locdesc.
+	Declare dwarf_getloclistent and dwarf_getloclist.
+	* libdw.map: Add dwarf_getloclistent and dwarf_getloclist.
+	* libdwP.h: Define DWARF_E_NO_LOCLIST.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getloclistent.c and
+	dwarf_getloclist.c.
+
+	* dwarf_error.c: More error messages.
+
+2004-01-06  Ulrich Drepper  <drepper@redhat.com>
+
+	* dwarf_getsrclines.c: Remove debugging support.
+
+	* dwarf_getsrcfiles.c: New file.
+	* dwarf_filesrc.c: New file.
+	* libdw.h: Declare these functions.  Define Dwarf_File.
+	* libdwP.c: Adjust Dwarf_File_s definition.
+	* libdw.map: Add these functions.
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getsrcfiles.c and
+	dwarf_filesrc.c.
+	* dwarf_getsrclines.c: Initialize cu->files.
+
+2004-01-05  Ulrich Drepper  <drepper@redhat.com>
+
+	* libdw.h: Add more nonnull function attributes.
+
+	* dwarf_begin_elf.c (dwarf_begin_elf): Don't initialize mem_tail->next.
+	* dwarf_end.c (cu_free): New function.
+	(dwarf_end): Also free CU tree.  Correct freeing of memory blocks.
+	* dwarf_error.c (errmsgs): Add new messages.
+	* dwarf_getsrc_die.c: New file.
+	* dwarf_getsrclines.c: New file.
+	* dwarf_lineno.c: New file.
+	* dwarf_linesrc.c: New file.
+	* dwarf_nextcu.c (dwarf_nextcu): Use read_*byte_unaligned_inc
+	instead of the *_inc-less variants.
+	* libdw.h: Define Dwarf_Line.  Add some function attributes.  Declare
+	dwarf_getsrclines, dwarf_getsrc_die, dwarf_lineno, and dwarf_linesrc.
+	* libdw.map: Add dwarf_getsrclines, dwarf_getsrc_die, dwarf_lineno,
+	and dwarf_linesrc.
+	* libdwP.h: Add more error codes.
+	(struct Dwarf): Remove mem_tail.next member.
+	(Dwarf_File): Define type.
+	(struct Dwarf_Line_s): Define type.
+	(struct Dwarf_CU): Add lines and nlines members.
+	(libdw_alloc): Define local variable _tail and use it.
+	Add some function attributes.
+	* libdw_alloc.c (__libdw_allocate): Don't initialize next member.
+	* libdw_findcu.c (__libdw_findcu): Initialize lines and nlines members.
+	* memory-access.h: Add unlikely for the endian conversion paths.
+	* Makefile.am (AM_CFLAGS): Add -std parameter.
+	(libdw_a_SOURCES): Add dwarf_getsrclines, dwarf_getsrc_die,
+	dwarf_lineno, and dwarf_linesrc.
+
+2003-08-11  Ulrich Drepper  <drepper@redhat.com>
+
+	* Moved to CVS archive.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
new file mode 100644
index 0000000..8545b5b
--- /dev/null
+++ b/libdw/Makefile.am
@@ -0,0 +1,145 @@
+## Process this file with automake to create Makefile.in
+##
+## Copyright (C) 2002-2010, 2012, 2014, 2016, 2018 Red Hat, Inc.
+## This file is part of elfutils.
+##
+## This file is free software; you can redistribute it and/or modify
+## it under the terms of either
+##
+##   * the GNU Lesser General Public License as published by the Free
+##     Software Foundation; either version 3 of the License, or (at
+##     your option) any later version
+##
+## or
+##
+##   * the GNU General Public License as published by the Free
+##     Software Foundation; either version 2 of the License, or (at
+##     your option) any later version
+##
+## or both in parallel, as here.
+##
+## 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 copies of the GNU General Public License and
+## the GNU Lesser General Public License along with this program.  If
+## not, see <http://www.gnu.org/licenses/>.
+##
+include $(top_srcdir)/config/eu.am
+if BUILD_STATIC
+AM_CFLAGS += $(fpic_CFLAGS)
+endif
+AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf
+VERSION = 1
+
+lib_LIBRARIES = libdw.a
+noinst_LIBRARIES = libdw_pic.a
+noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
+
+include_HEADERS = dwarf.h
+pkginclude_HEADERS = libdw.h known-dwarf.h
+
+libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
+		  dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \
+		  dwarf_error.c dwarf_nextcu.c dwarf_diename.c dwarf_offdie.c \
+		  dwarf_attr.c dwarf_formstring.c \
+		  dwarf_abbrev_hash.c dwarf_sig8_hash.c \
+		  dwarf_attr_integrate.c dwarf_hasattr_integrate.c \
+		  dwarf_child.c dwarf_haschildren.c dwarf_formaddr.c \
+		  dwarf_formudata.c dwarf_formsdata.c dwarf_lowpc.c \
+		  dwarf_entrypc.c dwarf_haspc.c dwarf_highpc.c dwarf_ranges.c \
+		  dwarf_formref.c dwarf_formref_die.c dwarf_siblingof.c \
+		  dwarf_dieoffset.c dwarf_cuoffset.c dwarf_diecu.c \
+		  dwarf_hasattr.c dwarf_hasform.c \
+		  dwarf_whatform.c dwarf_whatattr.c \
+		  dwarf_bytesize.c dwarf_arrayorder.c dwarf_bitsize.c \
+		  dwarf_bitoffset.c dwarf_srclang.c dwarf_getabbrevtag.c \
+		  dwarf_getabbrevcode.c dwarf_abbrevhaschildren.c \
+		  dwarf_getattrcnt.c dwarf_getabbrevattr.c \
+		  dwarf_getsrclines.c dwarf_getsrc_die.c \
+		  dwarf_getscopes.c dwarf_getscopes_die.c dwarf_getscopevar.c \
+		  dwarf_linesrc.c dwarf_lineno.c dwarf_lineaddr.c \
+		  dwarf_linecol.c dwarf_linebeginstatement.c \
+		  dwarf_lineendsequence.c dwarf_lineblock.c \
+		  dwarf_lineprologueend.c dwarf_lineepiloguebegin.c \
+		  dwarf_lineisa.c dwarf_linediscriminator.c \
+		  dwarf_lineop_index.c dwarf_line_file.c \
+		  dwarf_onesrcline.c dwarf_formblock.c \
+		  dwarf_getsrcfiles.c dwarf_filesrc.c dwarf_getsrcdirs.c \
+		  dwarf_getlocation.c dwarf_getstring.c dwarf_offabbrev.c \
+		  dwarf_getaranges.c dwarf_onearange.c dwarf_getarangeinfo.c \
+		  dwarf_getarange_addr.c dwarf_getattrs.c dwarf_formflag.c \
+		  dwarf_getmacros.c dwarf_macro_getparamcnt.c	\
+		  dwarf_macro_opcode.c dwarf_macro_param.c	\
+		  dwarf_macro_param1.c dwarf_macro_param2.c	\
+		  dwarf_macro_getsrcfiles.c			\
+		  dwarf_addrdie.c dwarf_getfuncs.c \
+		  dwarf_decl_file.c dwarf_decl_line.c dwarf_decl_column.c \
+		  dwarf_func_inline.c dwarf_getsrc_file.c \
+		  libdw_findcu.c libdw_form.c libdw_alloc.c \
+		  libdw_visit_scopes.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 \
+		  dwarf_aggregate_size.c dwarf_getlocation_implicit_pointer.c \
+		  dwarf_getlocation_die.c dwarf_getlocation_attr.c \
+		  dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \
+		  dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c
+
+if MAINTAINER_MODE
+BUILT_SOURCES = $(srcdir)/known-dwarf.h
+MAINTAINERCLEANFILES = $(srcdir)/known-dwarf.h
+$(srcdir)/known-dwarf.h: $(top_srcdir)/config/known-dwarf.awk $(srcdir)/dwarf.h
+	gawk -f $^ > $@.new
+	mv -f $@.new $@
+endif
+
+libdw_pic_a_SOURCES =
+am_libdw_pic_a_OBJECTS = $(libdw_a_SOURCES:.c=.os)
+
+libdw_so_LIBS = libdw_pic.a ../libdwelf/libdwelf_pic.a \
+	  ../libdwfl/libdwfl_pic.a ../libebl/libebl.a
+libdw_so_DEPS = ../lib/libeu.a ../libelf/libelf.so
+libdw_so_LDLIBS = $(libdw_so_DEPS) -ldl -lz $(argp_LDADD) $(zip_LIBS)
+libdw_so_SOURCES =
+libdw.so$(EXEEXT): $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS)
+# The rpath is necessary for libebl because its $ORIGIN use will
+# not fly in a setuid executable that links in libdw.
+	$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
+		-Wl,--soname,$@.$(VERSION) \
+		-Wl,--enable-new-dtags,-rpath,$(pkglibdir) \
+		-Wl,--version-script,$<,--no-undefined \
+		-Wl,--whole-archive $(libdw_so_LIBS) -Wl,--no-whole-archive \
+		$(libdw_so_LDLIBS)
+	@$(textrel_check)
+	$(AM_V_at)ln -fs $@ $@.$(VERSION)
+
+install: install-am libdw.so
+	$(mkinstalldirs) $(DESTDIR)$(libdir)
+	$(INSTALL_PROGRAM) libdw.so $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so
+	ln -fs libdw-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdw.so.$(VERSION)
+	ln -fs libdw.so.$(VERSION) $(DESTDIR)$(libdir)/libdw.so
+
+uninstall: uninstall-am
+	rm -f $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so
+	rm -f $(DESTDIR)$(libdir)/libdw.so.$(VERSION)
+	rm -f $(DESTDIR)$(libdir)/libdw.so
+	rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils
+
+libdwfl_objects = $(shell $(AR) t ../libdwfl/libdwfl.a)
+libdw_a_LIBADD = $(addprefix ../libdwfl/,$(libdwfl_objects))
+
+libdwelf_objects = $(shell $(AR) t ../libdwelf/libdwelf.a)
+libdw_a_LIBADD += $(addprefix ../libdwelf/,$(libdwelf_objects))
+
+noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \
+		 dwarf_sig8_hash.h cfi.h encoded-value.h
+
+EXTRA_DIST = libdw.map
+
+MOSTLYCLEANFILES = $(am_libdw_pic_a_OBJECTS) libdw.so.$(VERSION)
diff --git a/libdw/cfi.c b/libdw/cfi.c
new file mode 100644
index 0000000..341e055
--- /dev/null
+++ b/libdw/cfi.c
@@ -0,0 +1,518 @@
+/* CFI program execution.
+   Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#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 "system.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;
+}
+
+static inline bool
+enough_registers (Dwarf_Word reg, Dwarf_Frame **pfs, int *result)
+{
+  /* Don't allow insanely large register numbers.  268435456 registers
+     should be enough for anybody.  And very large values might overflow
+     the array size and offsetof calculations below.  */
+  if (unlikely (reg >= INT32_MAX / sizeof ((*pfs)->regs[0])))
+    {
+      *result = DWARF_E_INVALID_CFI;
+      return false;
+    }
+
+  if ((*pfs)->nregs <= reg)
+    {
+       size_t size = offsetof (Dwarf_Frame, regs[reg + 1]);
+       Dwarf_Frame *bigger = realloc (*pfs, size);
+       if (unlikely (bigger == NULL))
+         {
+           *result = DWARF_E_NOMEM;
+           return false;
+         }
+       else
+         {
+           eu_static_assert (reg_unspecified == 0);
+           memset (bigger->regs + bigger->nregs, 0,
+                   (reg + 1 - bigger->nregs) * sizeof bigger->regs[0]);
+           bigger->nregs = reg + 1;
+           *pfs = bigger;
+         }
+     }
+  return true;
+}
+
+static inline void
+require_cfa_offset (Dwarf_Frame *fs)
+{
+  if (unlikely (fs->cfa_rule != cfa_offset))
+    fs->cfa_rule = cfa_invalid;
+}
+
+/* Returns a DWARF_E_* error code, usually NOERROR or INVALID_CFI.
+   Frees *STATE on failure.  */
+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;
+
+#define register_rule(regno, r_rule, r_value) do {	\
+    if (unlikely (! enough_registers (regno, &fs, &result)))	\
+      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++;
+	  FALLTHROUGH;
+	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:
+	  cfi_assert (program + 2 <= end);
+	  operand = read_2ubyte_unaligned_inc (cache, program);
+	  goto advance_loc;
+	case DW_CFA_advance_loc4:
+	  cfi_assert (program + 4 <= end);
+	  operand = read_4ubyte_unaligned_inc (cache, program);
+	  goto advance_loc;
+	case DW_CFA_MIPS_advance_loc8:
+	  cfi_assert (program + 8 <= end);
+	  operand = read_8ubyte_unaligned_inc (cache, program);
+	  goto advance_loc;
+
+	case DW_CFA_set_loc:
+	  if (likely (!read_encoded_value (cache, cie->fde_encoding,
+					   &program, &loc)))
+	    break;
+	  result = INTUSE(dwarf_errno) ();
+	  goto out;
+
+	  /* 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, end);
+	  cfi_assert (program < end);
+	  get_uleb128 (offset, program, end);
+	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, end);
+	  require_cfa_offset (fs);
+	  fs->cfa_val_reg = regno;
+	  continue;
+
+	case DW_CFA_def_cfa_sf:
+	  get_uleb128 (operand, program, end);
+	  cfi_assert (program < end);
+	  get_sleb128 (sf_offset, program, end);
+	  offset = sf_offset * cie->data_alignment_factor;
+	  goto def_cfa;
+
+	case DW_CFA_def_cfa_offset:
+	  get_uleb128 (offset, program, end);
+	def_cfa_offset:
+	  require_cfa_offset (fs);
+	  fs->cfa_val_offset = offset;
+	  continue;
+
+	case DW_CFA_def_cfa_offset_sf:
+	  get_sleb128 (sf_offset, program, end);
+	  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, end);
+	  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, end);
+	  register_rule (regno, undefined, 0);
+	  continue;
+
+	case DW_CFA_same_value:
+	  get_uleb128 (regno, program, end);
+	  register_rule (regno, same_value, 0);
+	  continue;
+
+	case DW_CFA_offset_extended:
+	  get_uleb128 (operand, program, end);
+	  cfi_assert (program < end);
+	case DW_CFA_offset + 0 ... DW_CFA_offset + CFI_PRIMARY_MAX:
+	  get_uleb128 (offset, program, end);
+	  offset *= cie->data_alignment_factor;
+	offset_extended:
+	  register_rule (operand, offset, offset);
+	  continue;
+
+	case DW_CFA_offset_extended_sf:
+	  get_uleb128 (operand, program, end);
+	  get_sleb128 (sf_offset, program, end);
+	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, end);
+	  cfi_assert (program < end);
+	  get_uleb128 (offset, program, end);
+	  sf_offset = -offset;
+	  goto offset_extended_sf;
+
+	case DW_CFA_val_offset:
+	  get_uleb128 (operand, program, end);
+	  cfi_assert (program < end);
+	  get_uleb128 (offset, program, end);
+	  offset *= cie->data_alignment_factor;
+	val_offset:
+	  register_rule (operand, val_offset, offset);
+	  continue;
+
+	case DW_CFA_val_offset_sf:
+	  get_uleb128 (operand, program, end);
+	  cfi_assert (program < end);
+	  get_sleb128 (sf_offset, program, end);
+	  offset = sf_offset * cie->data_alignment_factor;
+	  goto val_offset;
+
+	case DW_CFA_register:
+	  get_uleb128 (regno, program, end);
+	  cfi_assert (program < end);
+	  get_uleb128 (operand, program, end);
+	  register_rule (regno, register, operand);
+	  continue;
+
+	case DW_CFA_expression:
+	  /* Expression rule relies on section data, abi_cfi cannot use it.  */
+	  assert (! abi_cfi);
+	  get_uleb128 (regno, program, end);
+	  offset = program - (const uint8_t *) cache->data->d.d_buf;
+	  /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
+	  cfi_assert (program < end);
+	  get_uleb128 (operand, program, end);
+	  cfi_assert (operand <= (Dwarf_Word) (end - program));
+	  program += operand;
+	  register_rule (regno, expression, offset);
+	  continue;
+
+	case DW_CFA_val_expression:
+	  /* Expression rule relies on section data, abi_cfi cannot use it.  */
+	  assert (! abi_cfi);
+	  get_uleb128 (regno, program, end);
+	  /* 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, end);
+	  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, end);
+	  FALLTHROUGH;
+	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, &fs, &result)))
+	    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, &fs, &result)))
+	    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, end);
+	  continue;
+
+	default:
+	  cfi_assert (false);
+	  continue;
+	}
+
+      /* We get here only for the cases that have just moved LOC.  */
+      cfi_assert (cie->initial_state != NULL);
+      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 (likely (result == DWARF_E_NOERROR))
+    *state = fs;
+  else
+    free (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 (likely (result == DWARF_E_NOERROR))
+    {
+      /* 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 (likely (result == DWARF_E_NOERROR))
+	*frame = fs;
+    }
+  return result;
+}
diff --git a/libdw/cfi.h b/libdw/cfi.h
new file mode 100644
index 0000000..1ebf2dc
--- /dev/null
+++ b/libdw/cfi.h
@@ -0,0 +1,236 @@
+/* Internal definitions for libdw CFI interpreter.
+   Copyright (C) 2009-2010, 2013, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWINDP_H
+#define _UNWINDP_H 1
+
+#include "libdwP.h"
+#include "libelfP.h"
+struct ebl;
+
+/* 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;
+  size_t search_table_len;
+  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 instructions for unwinding 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.
+     A bogon in the CFI can indicate an invalid/incalculable rule.
+     We store that as cfa_invalid rather than barfing when processing it,
+     so callers can ignore the bogon unless they really need that CFA.  */
+  enum { cfa_undefined, cfa_offset, cfa_expr, cfa_invalid } 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;
+
+/* Look for an FDE by its offset in the section.  */
+extern struct dwarf_fde *__libdw_fde_by_offset (Dwarf_CFI *cache,
+						Dwarf_Off offset)
+  __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/libdw/cie.c b/libdw/cie.c
new file mode 100644
index 0000000..1b0aae7
--- /dev/null
+++ b/libdw/cie.c
@@ -0,0 +1,196 @@
+/* CIE reading.
+   Copyright (C) 2009-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "cfi.h"
+#include "encoded-value.h"
+#include <assert.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;
+    }
+
+  if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr)
+    {
+      /* Canonicalize encoding to a specific size.  */
+      assert (DW_EH_PE_absptr == 0);
+
+      /* XXX should get from dwarf_next_cfi with v4 header.  */
+      uint_fast8_t address_size
+	= cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+      switch (address_size)
+	{
+	case 8:
+	  cie->fde_encoding |= DW_EH_PE_udata8;
+	  break;
+	case 4:
+	  cie->fde_encoding |= DW_EH_PE_udata4;
+	  break;
+	default:
+	  free (cie);
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	  return NULL;
+	}
+    }
+
+  /* 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/libdw/dwarf.h b/libdw/dwarf.h
new file mode 100644
index 0000000..8edf719
--- /dev/null
+++ b/libdw/dwarf.h
@@ -0,0 +1,911 @@
+/* This file defines standard DWARF types, structures, and macros.
+   Copyright (C) 2000-2011, 2014, 2016, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _DWARF_H
+#define	_DWARF_H 1
+
+/* DWARF tags.  */
+enum
+  {
+    DW_TAG_array_type = 0x01,
+    DW_TAG_class_type = 0x02,
+    DW_TAG_entry_point = 0x03,
+    DW_TAG_enumeration_type = 0x04,
+    DW_TAG_formal_parameter = 0x05,
+    /* 0x06 reserved.  */
+    /* 0x07 reserved.  */
+    DW_TAG_imported_declaration = 0x08,
+    /* 0x09 reserved.  */
+    DW_TAG_label = 0x0a,
+    DW_TAG_lexical_block = 0x0b,
+    /* 0x0c reserved.  */
+    DW_TAG_member = 0x0d,
+    /* 0x0e reserved.  */
+    DW_TAG_pointer_type = 0x0f,
+    DW_TAG_reference_type = 0x10,
+    DW_TAG_compile_unit = 0x11,
+    DW_TAG_string_type = 0x12,
+    DW_TAG_structure_type = 0x13,
+    /* 0x14 reserved.  */
+    DW_TAG_subroutine_type = 0x15,
+    DW_TAG_typedef = 0x16,
+    DW_TAG_union_type = 0x17,
+    DW_TAG_unspecified_parameters = 0x18,
+    DW_TAG_variant = 0x19,
+    DW_TAG_common_block = 0x1a,
+    DW_TAG_common_inclusion = 0x1b,
+    DW_TAG_inheritance = 0x1c,
+    DW_TAG_inlined_subroutine = 0x1d,
+    DW_TAG_module = 0x1e,
+    DW_TAG_ptr_to_member_type = 0x1f,
+    DW_TAG_set_type = 0x20,
+    DW_TAG_subrange_type = 0x21,
+    DW_TAG_with_stmt = 0x22,
+    DW_TAG_access_declaration = 0x23,
+    DW_TAG_base_type = 0x24,
+    DW_TAG_catch_block = 0x25,
+    DW_TAG_const_type = 0x26,
+    DW_TAG_constant = 0x27,
+    DW_TAG_enumerator = 0x28,
+    DW_TAG_file_type = 0x29,
+    DW_TAG_friend = 0x2a,
+    DW_TAG_namelist = 0x2b,
+    DW_TAG_namelist_item = 0x2c,
+    DW_TAG_packed_type = 0x2d,
+    DW_TAG_subprogram = 0x2e,
+    DW_TAG_template_type_parameter = 0x2f,
+    DW_TAG_template_value_parameter = 0x30,
+    DW_TAG_thrown_type = 0x31,
+    DW_TAG_try_block = 0x32,
+    DW_TAG_variant_part = 0x33,
+    DW_TAG_variable = 0x34,
+    DW_TAG_volatile_type = 0x35,
+    DW_TAG_dwarf_procedure = 0x36,
+    DW_TAG_restrict_type = 0x37,
+    DW_TAG_interface_type = 0x38,
+    DW_TAG_namespace = 0x39,
+    DW_TAG_imported_module = 0x3a,
+    DW_TAG_unspecified_type = 0x3b,
+    DW_TAG_partial_unit = 0x3c,
+    DW_TAG_imported_unit = 0x3d,
+    /* 0x3e reserved.  Was DW_TAG_mutable_type.  */
+    DW_TAG_condition = 0x3f,
+    DW_TAG_shared_type = 0x40,
+    DW_TAG_type_unit = 0x41,
+    DW_TAG_rvalue_reference_type = 0x42,
+    DW_TAG_template_alias = 0x43,
+    DW_TAG_coarray_type = 0x44,
+    DW_TAG_generic_subrange = 0x45,
+    DW_TAG_dynamic_type = 0x46,
+    DW_TAG_atomic_type = 0x47,
+    DW_TAG_call_site = 0x48,
+    DW_TAG_call_site_parameter = 0x49,
+    DW_TAG_skeleton_unit = 0x4a,
+    DW_TAG_immutable_type = 0x4b,
+
+    DW_TAG_lo_user = 0x4080,
+
+    DW_TAG_MIPS_loop = 0x4081,
+    DW_TAG_format_label = 0x4101,
+    DW_TAG_function_template = 0x4102,
+    DW_TAG_class_template = 0x4103,
+
+    DW_TAG_GNU_BINCL = 0x4104,
+    DW_TAG_GNU_EINCL = 0x4105,
+
+    DW_TAG_GNU_template_template_param = 0x4106,
+    DW_TAG_GNU_template_parameter_pack = 0x4107,
+    DW_TAG_GNU_formal_parameter_pack = 0x4108,
+    DW_TAG_GNU_call_site = 0x4109,
+    DW_TAG_GNU_call_site_parameter = 0x410a,
+
+    DW_TAG_hi_user = 0xffff
+  };
+
+
+/* Children determination encodings.  */
+enum
+  {
+    DW_CHILDREN_no = 0,
+    DW_CHILDREN_yes = 1
+  };
+
+
+/* DWARF attributes encodings.  */
+enum
+  {
+    DW_AT_sibling = 0x01,
+    DW_AT_location = 0x02,
+    DW_AT_name = 0x03,
+    /* 0x04 reserved.  */
+    /* 0x05 reserved.  */
+    /* 0x06 reserved.  */
+    /* 0x07 reserved.  */
+    /* 0x08 reserved.  */
+    DW_AT_ordering = 0x09,
+    /* 0x0a reserved.  */
+    DW_AT_byte_size = 0x0b,
+    DW_AT_bit_offset = 0x0c,  /* Deprecated in DWARF4.  */
+    DW_AT_bit_size = 0x0d,
+    /* 0x0e reserved.  */
+    /* 0x0f reserved.  */
+    DW_AT_stmt_list = 0x10,
+    DW_AT_low_pc = 0x11,
+    DW_AT_high_pc = 0x12,
+    DW_AT_language = 0x13,
+    /* 0x14 reserved.  */
+    DW_AT_discr = 0x15,
+    DW_AT_discr_value = 0x16,
+    DW_AT_visibility = 0x17,
+    DW_AT_import = 0x18,
+    DW_AT_string_length = 0x19,
+    DW_AT_common_reference = 0x1a,
+    DW_AT_comp_dir = 0x1b,
+    DW_AT_const_value = 0x1c,
+    DW_AT_containing_type = 0x1d,
+    DW_AT_default_value = 0x1e,
+    /* 0x1f reserved.  */
+    DW_AT_inline = 0x20,
+    DW_AT_is_optional = 0x21,
+    DW_AT_lower_bound = 0x22,
+    /* 0x23 reserved.  */
+    /* 0x24 reserved.  */
+    DW_AT_producer = 0x25,
+    /* 0x26 reserved.  */
+    DW_AT_prototyped = 0x27,
+    /* 0x28 reserved.  */
+    /* 0x29 reserved.  */
+    DW_AT_return_addr = 0x2a,
+    /* 0x2b reserved.  */
+    DW_AT_start_scope = 0x2c,
+    /* 0x2d reserved.  */
+    DW_AT_bit_stride = 0x2e,
+    DW_AT_upper_bound = 0x2f,
+    /* 0x30 reserved.  */
+    DW_AT_abstract_origin = 0x31,
+    DW_AT_accessibility = 0x32,
+    DW_AT_address_class = 0x33,
+    DW_AT_artificial = 0x34,
+    DW_AT_base_types = 0x35,
+    DW_AT_calling_convention = 0x36,
+    DW_AT_count = 0x37,
+    DW_AT_data_member_location = 0x38,
+    DW_AT_decl_column = 0x39,
+    DW_AT_decl_file = 0x3a,
+    DW_AT_decl_line = 0x3b,
+    DW_AT_declaration = 0x3c,
+    DW_AT_discr_list = 0x3d,
+    DW_AT_encoding = 0x3e,
+    DW_AT_external = 0x3f,
+    DW_AT_frame_base = 0x40,
+    DW_AT_friend = 0x41,
+    DW_AT_identifier_case = 0x42,
+    DW_AT_macro_info = 0x43, /* Deprecated in DWARF5.  */
+    DW_AT_namelist_item = 0x44,
+    DW_AT_priority = 0x45,
+    DW_AT_segment = 0x46,
+    DW_AT_specification = 0x47,
+    DW_AT_static_link = 0x48,
+    DW_AT_type = 0x49,
+    DW_AT_use_location = 0x4a,
+    DW_AT_variable_parameter = 0x4b,
+    DW_AT_virtuality = 0x4c,
+    DW_AT_vtable_elem_location = 0x4d,
+    DW_AT_allocated = 0x4e,
+    DW_AT_associated = 0x4f,
+    DW_AT_data_location = 0x50,
+    DW_AT_byte_stride = 0x51,
+    DW_AT_entry_pc = 0x52,
+    DW_AT_use_UTF8 = 0x53,
+    DW_AT_extension = 0x54,
+    DW_AT_ranges = 0x55,
+    DW_AT_trampoline = 0x56,
+    DW_AT_call_column = 0x57,
+    DW_AT_call_file = 0x58,
+    DW_AT_call_line = 0x59,
+    DW_AT_description = 0x5a,
+    DW_AT_binary_scale = 0x5b,
+    DW_AT_decimal_scale = 0x5c,
+    DW_AT_small = 0x5d,
+    DW_AT_decimal_sign = 0x5e,
+    DW_AT_digit_count = 0x5f,
+    DW_AT_picture_string = 0x60,
+    DW_AT_mutable = 0x61,
+    DW_AT_threads_scaled = 0x62,
+    DW_AT_explicit = 0x63,
+    DW_AT_object_pointer = 0x64,
+    DW_AT_endianity = 0x65,
+    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_enum_class = 0x6d,
+    DW_AT_linkage_name = 0x6e,
+    DW_AT_string_length_bit_size = 0x6f,
+    DW_AT_string_length_byte_size = 0x70,
+    DW_AT_rank = 0x71,
+    DW_AT_str_offsets_base = 0x72,
+    DW_AT_addr_base = 0x73,
+    DW_AT_rnglists_base = 0x74,
+    /* 0x75 reserved.  */
+    DW_AT_dwo_name = 0x76,
+    DW_AT_reference = 0x77,
+    DW_AT_rvalue_reference = 0x78,
+    DW_AT_macros = 0x79,
+    DW_AT_call_all_calls = 0x7a,
+    DW_AT_call_all_source_calls = 0x7b,
+    DW_AT_call_all_tail_calls = 0x7c,
+    DW_AT_call_return_pc = 0x7d,
+    DW_AT_call_value = 0x7e,
+    DW_AT_call_origin = 0x7f,
+    DW_AT_call_parameter = 0x80,
+    DW_AT_call_pc = 0x81,
+    DW_AT_call_tail_call = 0x82,
+    DW_AT_call_target = 0x83,
+    DW_AT_call_target_clobbered = 0x84,
+    DW_AT_call_data_location = 0x85,
+    DW_AT_call_data_value = 0x86,
+    DW_AT_noreturn = 0x87,
+    DW_AT_alignment = 0x88,
+    DW_AT_export_symbols = 0x89,
+    DW_AT_deleted = 0x8a,
+    DW_AT_defaulted = 0x8b,
+    DW_AT_loclists_base = 0x8c,
+
+    DW_AT_lo_user = 0x2000,
+
+    DW_AT_MIPS_fde = 0x2001,
+    DW_AT_MIPS_loop_begin = 0x2002,
+    DW_AT_MIPS_tail_loop_begin = 0x2003,
+    DW_AT_MIPS_epilog_begin = 0x2004,
+    DW_AT_MIPS_loop_unroll_factor = 0x2005,
+    DW_AT_MIPS_software_pipeline_depth = 0x2006,
+    DW_AT_MIPS_linkage_name = 0x2007,
+    DW_AT_MIPS_stride = 0x2008,
+    DW_AT_MIPS_abstract_name = 0x2009,
+    DW_AT_MIPS_clone_origin = 0x200a,
+    DW_AT_MIPS_has_inlines = 0x200b,
+    DW_AT_MIPS_stride_byte = 0x200c,
+    DW_AT_MIPS_stride_elem = 0x200d,
+    DW_AT_MIPS_ptr_dopetype = 0x200e,
+    DW_AT_MIPS_allocatable_dopetype = 0x200f,
+    DW_AT_MIPS_assumed_shape_dopetype = 0x2010,
+    DW_AT_MIPS_assumed_size = 0x2011,
+
+    /* GNU extensions.  */
+    DW_AT_sf_names = 0x2101,
+    DW_AT_src_info = 0x2102,
+    DW_AT_mac_info = 0x2103,
+    DW_AT_src_coords = 0x2104,
+    DW_AT_body_begin = 0x2105,
+    DW_AT_body_end = 0x2106,
+    DW_AT_GNU_vector = 0x2107,
+    DW_AT_GNU_guarded_by = 0x2108,
+    DW_AT_GNU_pt_guarded_by = 0x2109,
+    DW_AT_GNU_guarded = 0x210a,
+    DW_AT_GNU_pt_guarded = 0x210b,
+    DW_AT_GNU_locks_excluded = 0x210c,
+    DW_AT_GNU_exclusive_locks_required = 0x210d,
+    DW_AT_GNU_shared_locks_required = 0x210e,
+    DW_AT_GNU_odr_signature = 0x210f,
+    DW_AT_GNU_template_name = 0x2110,
+    DW_AT_GNU_call_site_value = 0x2111,
+    DW_AT_GNU_call_site_data_value = 0x2112,
+    DW_AT_GNU_call_site_target = 0x2113,
+    DW_AT_GNU_call_site_target_clobbered = 0x2114,
+    DW_AT_GNU_tail_call = 0x2115,
+    DW_AT_GNU_all_tail_call_sites = 0x2116,
+    DW_AT_GNU_all_call_sites = 0x2117,
+    DW_AT_GNU_all_source_call_sites = 0x2118,
+    DW_AT_GNU_macros = 0x2119,
+    DW_AT_GNU_deleted = 0x211a,
+
+    DW_AT_hi_user = 0x3fff
+  };
+
+/* Old unofficially attribute names.  Should not be used.
+   Will not appear in known-dwarf.h  */
+
+/* DWARF1 array subscripts and element data types.  */
+#define DW_AT_subscr_data	0x0a
+/* DWARF1 enumeration literals.  */
+#define DW_AT_element_list	0x0f
+/* DWARF1 reference for variable to member structure, class or union.  */
+#define DW_AT_member		0x14
+
+/* DWARF form encodings.  */
+enum
+  {
+    DW_FORM_addr = 0x01,
+    DW_FORM_block2 = 0x03,
+    DW_FORM_block4 = 0x04,
+    DW_FORM_data2 = 0x05,
+    DW_FORM_data4 = 0x06,
+    DW_FORM_data8 = 0x07,
+    DW_FORM_string = 0x08,
+    DW_FORM_block = 0x09,
+    DW_FORM_block1 = 0x0a,
+    DW_FORM_data1 = 0x0b,
+    DW_FORM_flag = 0x0c,
+    DW_FORM_sdata = 0x0d,
+    DW_FORM_strp = 0x0e,
+    DW_FORM_udata = 0x0f,
+    DW_FORM_ref_addr = 0x10,
+    DW_FORM_ref1 = 0x11,
+    DW_FORM_ref2 = 0x12,
+    DW_FORM_ref4 = 0x13,
+    DW_FORM_ref8 = 0x14,
+    DW_FORM_ref_udata = 0x15,
+    DW_FORM_indirect = 0x16,
+    DW_FORM_sec_offset = 0x17,
+    DW_FORM_exprloc = 0x18,
+    DW_FORM_flag_present = 0x19,
+    DW_FORM_ref_sig8 = 0x20,
+
+    DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo.  */
+    DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */
+  };
+
+
+/* DWARF location operation encodings.  */
+enum
+  {
+    DW_OP_addr = 0x03,		/* Constant address.  */
+    DW_OP_deref = 0x06,
+    DW_OP_const1u = 0x08,	/* Unsigned 1-byte constant.  */
+    DW_OP_const1s = 0x09,	/* Signed 1-byte constant.  */
+    DW_OP_const2u = 0x0a,	/* Unsigned 2-byte constant.  */
+    DW_OP_const2s = 0x0b,	/* Signed 2-byte constant.  */
+    DW_OP_const4u = 0x0c,	/* Unsigned 4-byte constant.  */
+    DW_OP_const4s = 0x0d,	/* Signed 4-byte constant.  */
+    DW_OP_const8u = 0x0e,	/* Unsigned 8-byte constant.  */
+    DW_OP_const8s = 0x0f,	/* Signed 8-byte constant.  */
+    DW_OP_constu = 0x10,	/* Unsigned LEB128 constant.  */
+    DW_OP_consts = 0x11,	/* Signed LEB128 constant.  */
+    DW_OP_dup = 0x12,
+    DW_OP_drop = 0x13,
+    DW_OP_over = 0x14,
+    DW_OP_pick = 0x15,		/* 1-byte stack index.  */
+    DW_OP_swap = 0x16,
+    DW_OP_rot = 0x17,
+    DW_OP_xderef = 0x18,
+    DW_OP_abs = 0x19,
+    DW_OP_and = 0x1a,
+    DW_OP_div = 0x1b,
+    DW_OP_minus = 0x1c,
+    DW_OP_mod = 0x1d,
+    DW_OP_mul = 0x1e,
+    DW_OP_neg = 0x1f,
+    DW_OP_not = 0x20,
+    DW_OP_or = 0x21,
+    DW_OP_plus = 0x22,
+    DW_OP_plus_uconst = 0x23,	/* Unsigned LEB128 addend.  */
+    DW_OP_shl = 0x24,
+    DW_OP_shr = 0x25,
+    DW_OP_shra = 0x26,
+    DW_OP_xor = 0x27,
+    DW_OP_bra = 0x28,		/* Signed 2-byte constant.  */
+    DW_OP_eq = 0x29,
+    DW_OP_ge = 0x2a,
+    DW_OP_gt = 0x2b,
+    DW_OP_le = 0x2c,
+    DW_OP_lt = 0x2d,
+    DW_OP_ne = 0x2e,
+    DW_OP_skip = 0x2f,		/* Signed 2-byte constant.  */
+    DW_OP_lit0 = 0x30,		/* Literal 0.  */
+    DW_OP_lit1 = 0x31,		/* Literal 1.  */
+    DW_OP_lit2 = 0x32,		/* Literal 2.  */
+    DW_OP_lit3 = 0x33,		/* Literal 3.  */
+    DW_OP_lit4 = 0x34,		/* Literal 4.  */
+    DW_OP_lit5 = 0x35,		/* Literal 5.  */
+    DW_OP_lit6 = 0x36,		/* Literal 6.  */
+    DW_OP_lit7 = 0x37,		/* Literal 7.  */
+    DW_OP_lit8 = 0x38,		/* Literal 8.  */
+    DW_OP_lit9 = 0x39,		/* Literal 9.  */
+    DW_OP_lit10 = 0x3a,		/* Literal 10.  */
+    DW_OP_lit11 = 0x3b,		/* Literal 11.  */
+    DW_OP_lit12 = 0x3c,		/* Literal 12.  */
+    DW_OP_lit13 = 0x3d,		/* Literal 13.  */
+    DW_OP_lit14 = 0x3e,		/* Literal 14.  */
+    DW_OP_lit15 = 0x3f,		/* Literal 15.  */
+    DW_OP_lit16 = 0x40,		/* Literal 16.  */
+    DW_OP_lit17 = 0x41,		/* Literal 17.  */
+    DW_OP_lit18 = 0x42,		/* Literal 18.  */
+    DW_OP_lit19 = 0x43,		/* Literal 19.  */
+    DW_OP_lit20 = 0x44,		/* Literal 20.  */
+    DW_OP_lit21 = 0x45,		/* Literal 21.  */
+    DW_OP_lit22 = 0x46,		/* Literal 22.  */
+    DW_OP_lit23 = 0x47,		/* Literal 23.  */
+    DW_OP_lit24 = 0x48,		/* Literal 24.  */
+    DW_OP_lit25 = 0x49,		/* Literal 25.  */
+    DW_OP_lit26 = 0x4a,		/* Literal 26.  */
+    DW_OP_lit27 = 0x4b,		/* Literal 27.  */
+    DW_OP_lit28 = 0x4c,		/* Literal 28.  */
+    DW_OP_lit29 = 0x4d,		/* Literal 29.  */
+    DW_OP_lit30 = 0x4e,		/* Literal 30.  */
+    DW_OP_lit31 = 0x4f,		/* Literal 31.  */
+    DW_OP_reg0 = 0x50,		/* Register 0.  */
+    DW_OP_reg1 = 0x51,		/* Register 1.  */
+    DW_OP_reg2 = 0x52,		/* Register 2.  */
+    DW_OP_reg3 = 0x53,		/* Register 3.  */
+    DW_OP_reg4 = 0x54,		/* Register 4.  */
+    DW_OP_reg5 = 0x55,		/* Register 5.  */
+    DW_OP_reg6 = 0x56,		/* Register 6.  */
+    DW_OP_reg7 = 0x57,		/* Register 7.  */
+    DW_OP_reg8 = 0x58,		/* Register 8.  */
+    DW_OP_reg9 = 0x59,		/* Register 9.  */
+    DW_OP_reg10 = 0x5a,		/* Register 10.  */
+    DW_OP_reg11 = 0x5b,		/* Register 11.  */
+    DW_OP_reg12 = 0x5c,		/* Register 12.  */
+    DW_OP_reg13 = 0x5d,		/* Register 13.  */
+    DW_OP_reg14 = 0x5e,		/* Register 14.  */
+    DW_OP_reg15 = 0x5f,		/* Register 15.  */
+    DW_OP_reg16 = 0x60,		/* Register 16.  */
+    DW_OP_reg17 = 0x61,		/* Register 17.  */
+    DW_OP_reg18 = 0x62,		/* Register 18.  */
+    DW_OP_reg19 = 0x63,		/* Register 19.  */
+    DW_OP_reg20 = 0x64,		/* Register 20.  */
+    DW_OP_reg21 = 0x65,		/* Register 21.  */
+    DW_OP_reg22 = 0x66,		/* Register 22.  */
+    DW_OP_reg23 = 0x67,		/* Register 24.  */
+    DW_OP_reg24 = 0x68,		/* Register 24.  */
+    DW_OP_reg25 = 0x69,		/* Register 25.  */
+    DW_OP_reg26 = 0x6a,		/* Register 26.  */
+    DW_OP_reg27 = 0x6b,		/* Register 27.  */
+    DW_OP_reg28 = 0x6c,		/* Register 28.  */
+    DW_OP_reg29 = 0x6d,		/* Register 29.  */
+    DW_OP_reg30 = 0x6e,		/* Register 30.  */
+    DW_OP_reg31 = 0x6f,		/* Register 31.  */
+    DW_OP_breg0 = 0x70,		/* Base register 0.  */
+    DW_OP_breg1 = 0x71,		/* Base register 1.  */
+    DW_OP_breg2 = 0x72,		/* Base register 2.  */
+    DW_OP_breg3 = 0x73,		/* Base register 3.  */
+    DW_OP_breg4 = 0x74,		/* Base register 4.  */
+    DW_OP_breg5 = 0x75,		/* Base register 5.  */
+    DW_OP_breg6 = 0x76,		/* Base register 6.  */
+    DW_OP_breg7 = 0x77,		/* Base register 7.  */
+    DW_OP_breg8 = 0x78,		/* Base register 8.  */
+    DW_OP_breg9 = 0x79,		/* Base register 9.  */
+    DW_OP_breg10 = 0x7a,	/* Base register 10.  */
+    DW_OP_breg11 = 0x7b,	/* Base register 11.  */
+    DW_OP_breg12 = 0x7c,	/* Base register 12.  */
+    DW_OP_breg13 = 0x7d,	/* Base register 13.  */
+    DW_OP_breg14 = 0x7e,	/* Base register 14.  */
+    DW_OP_breg15 = 0x7f,	/* Base register 15.  */
+    DW_OP_breg16 = 0x80,	/* Base register 16.  */
+    DW_OP_breg17 = 0x81,	/* Base register 17.  */
+    DW_OP_breg18 = 0x82,	/* Base register 18.  */
+    DW_OP_breg19 = 0x83,	/* Base register 19.  */
+    DW_OP_breg20 = 0x84,	/* Base register 20.  */
+    DW_OP_breg21 = 0x85,	/* Base register 21.  */
+    DW_OP_breg22 = 0x86,	/* Base register 22.  */
+    DW_OP_breg23 = 0x87,	/* Base register 23.  */
+    DW_OP_breg24 = 0x88,	/* Base register 24.  */
+    DW_OP_breg25 = 0x89,	/* Base register 25.  */
+    DW_OP_breg26 = 0x8a,	/* Base register 26.  */
+    DW_OP_breg27 = 0x8b,	/* Base register 27.  */
+    DW_OP_breg28 = 0x8c,	/* Base register 28.  */
+    DW_OP_breg29 = 0x8d,	/* Base register 29.  */
+    DW_OP_breg30 = 0x8e,	/* Base register 30.  */
+    DW_OP_breg31 = 0x8f,	/* Base register 31.  */
+    DW_OP_regx = 0x90,		/* Unsigned LEB128 register.  */
+    DW_OP_fbreg = 0x91,		/* Signed LEB128 offset.  */
+    DW_OP_bregx = 0x92,		/* ULEB128 register followed by SLEB128 off. */
+    DW_OP_piece = 0x93,		/* ULEB128 size of piece addressed. */
+    DW_OP_deref_size = 0x94,	/* 1-byte size of data retrieved.  */
+    DW_OP_xderef_size = 0x95,	/* 1-byte size of data retrieved.  */
+    DW_OP_nop = 0x96,
+    DW_OP_push_object_address = 0x97,
+    DW_OP_call2 = 0x98,
+    DW_OP_call4 = 0x99,
+    DW_OP_call_ref = 0x9a,
+    DW_OP_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,
+    DW_OP_GNU_uninit = 0xf0,
+    DW_OP_GNU_encoded_addr = 0xf1,
+    DW_OP_GNU_implicit_pointer = 0xf2,
+    DW_OP_GNU_entry_value = 0xf3,
+    DW_OP_GNU_const_type = 0xf4,
+    DW_OP_GNU_regval_type = 0xf5,
+    DW_OP_GNU_deref_type = 0xf6,
+    DW_OP_GNU_convert = 0xf7,
+    DW_OP_GNU_reinterpret = 0xf9,
+    DW_OP_GNU_parameter_ref = 0xfa,
+    DW_OP_GNU_variable_value = 0xfd,
+
+    DW_OP_lo_user = 0xe0,	/* Implementation-defined range start.  */
+    DW_OP_hi_user = 0xff	/* Implementation-defined range end.  */
+  };
+
+
+/* DWARF base type encodings.  */
+enum
+  {
+    DW_ATE_void = 0x0,
+    DW_ATE_address = 0x1,
+    DW_ATE_boolean = 0x2,
+    DW_ATE_complex_float = 0x3,
+    DW_ATE_float = 0x4,
+    DW_ATE_signed = 0x5,
+    DW_ATE_signed_char = 0x6,
+    DW_ATE_unsigned = 0x7,
+    DW_ATE_unsigned_char = 0x8,
+    DW_ATE_imaginary_float = 0x9,
+    DW_ATE_packed_decimal = 0xa,
+    DW_ATE_numeric_string = 0xb,
+    DW_ATE_edited = 0xc,
+    DW_ATE_signed_fixed = 0xd,
+    DW_ATE_unsigned_fixed = 0xe,
+    DW_ATE_decimal_float = 0xf,
+    DW_ATE_UTF = 0x10,
+    DW_ATE_UCS = 0x11,
+    DW_ATE_ASCII = 0x12,
+
+    DW_ATE_lo_user = 0x80,
+    DW_ATE_hi_user = 0xff
+  };
+
+
+/* DWARF decimal sign encodings.  */
+enum
+  {
+    DW_DS_unsigned = 1,
+    DW_DS_leading_overpunch = 2,
+    DW_DS_trailing_overpunch = 3,
+    DW_DS_leading_separate = 4,
+    DW_DS_trailing_separate = 5,
+  };
+
+
+/* DWARF endianity encodings.  */
+enum
+  {
+    DW_END_default = 0,
+    DW_END_big = 1,
+    DW_END_little = 2,
+
+    DW_END_lo_user = 0x40,
+    DW_END_hi_user = 0xff
+  };
+
+
+/* DWARF accessibility encodings.  */
+enum
+  {
+    DW_ACCESS_public = 1,
+    DW_ACCESS_protected = 2,
+    DW_ACCESS_private = 3
+  };
+
+
+/* DWARF visibility encodings.  */
+enum
+  {
+    DW_VIS_local = 1,
+    DW_VIS_exported = 2,
+    DW_VIS_qualified = 3
+  };
+
+
+/* DWARF virtuality encodings.  */
+enum
+  {
+    DW_VIRTUALITY_none = 0,
+    DW_VIRTUALITY_virtual = 1,
+    DW_VIRTUALITY_pure_virtual = 2
+  };
+
+
+/* DWARF language encodings.  */
+enum
+  {
+    DW_LANG_C89 = 0x0001,	     /* ISO C:1989 */
+    DW_LANG_C = 0x0002,		     /* C */
+    DW_LANG_Ada83 = 0x0003,	     /* ISO Ada:1983 */
+    DW_LANG_C_plus_plus	= 0x0004,    /* ISO C++:1998 */
+    DW_LANG_Cobol74 = 0x0005,	     /* ISO Cobol:1974 */
+    DW_LANG_Cobol85 = 0x0006,	     /* ISO Cobol:1985 */
+    DW_LANG_Fortran77 = 0x0007,	     /* ISO FORTRAN 77 */
+    DW_LANG_Fortran90 = 0x0008,	     /* ISO Fortran 90 */
+    DW_LANG_Pascal83 = 0x0009,	     /* ISO Pascal:1983 */
+    DW_LANG_Modula2 = 0x000a,	     /* ISO Modula-2:1996 */
+    DW_LANG_Java = 0x000b,	     /* Java */
+    DW_LANG_C99 = 0x000c,	     /* ISO C:1999 */
+    DW_LANG_Ada95 = 0x000d,	     /* ISO Ada:1995 */
+    DW_LANG_Fortran95 = 0x000e,	     /* ISO Fortran 95 */
+    DW_LANG_PLI = 0x000f,	     /* ISO PL/1:1976 */
+    DW_LANG_ObjC = 0x0010,	     /* Objective-C */
+    DW_LANG_ObjC_plus_plus = 0x0011, /* Objective-C++ */
+    DW_LANG_UPC = 0x0012,	     /* Unified Parallel C */
+    DW_LANG_D = 0x0013,		     /* D */
+    DW_LANG_Python = 0x0014,	     /* Python */
+    DW_LANG_OpenCL = 0x0015,	     /* OpenCL */
+    DW_LANG_Go = 0x0016,	     /* Go */
+    DW_LANG_Modula3 = 0x0017,	     /* Modula-3 */
+    DW_LANG_Haskell = 0x0018,	     /* Haskell */
+    DW_LANG_C_plus_plus_03 = 0x0019, /* ISO C++:2003 */
+    DW_LANG_C_plus_plus_11 = 0x001a, /* ISO C++:2011 */
+    DW_LANG_OCaml = 0x001b,	     /* OCaml */
+    DW_LANG_Rust = 0x001c,	     /* Rust */
+    DW_LANG_C11 = 0x001d,	     /* ISO C:2011 */
+    DW_LANG_Swift = 0x001e,	     /* Swift */
+    DW_LANG_Julia = 0x001f,	     /* Julia */
+    DW_LANG_Dylan = 0x0020,	     /* Dylan */
+    DW_LANG_C_plus_plus_14 = 0x0021, /* ISO C++:2014 */
+    DW_LANG_Fortran03 = 0x0022,	     /* ISO/IEC 1539-1:2004 */
+    DW_LANG_Fortran08 = 0x0023,	     /* ISO/IEC 1539-1:2010 */
+    DW_LANG_RenderScript = 0x0024,   /* RenderScript Kernal Language */
+    DW_LANG_BLISS = 0x0025,	     /* BLISS */
+
+    DW_LANG_lo_user = 0x8000,
+    DW_LANG_Mips_Assembler = 0x8001, /* Assembler */
+    DW_LANG_hi_user = 0xffff
+  };
+
+/* Old (typo) '1' != 'I'.  */
+#define DW_LANG_PL1 DW_LANG_PLI
+
+/* DWARF identifier case encodings.  */
+enum
+  {
+    DW_ID_case_sensitive = 0,
+    DW_ID_up_case = 1,
+    DW_ID_down_case = 2,
+    DW_ID_case_insensitive = 3
+  };
+
+
+/* DWARF calling conventions encodings.
+   Used as values of DW_AT_calling_convention for subroutines
+   (normal, program or nocall) or structures, unions and class types
+   (normal, reference or value).  */
+enum
+  {
+    DW_CC_normal = 0x1,
+    DW_CC_program = 0x2,
+    DW_CC_nocall = 0x3,
+    DW_CC_pass_by_reference = 0x4,
+    DW_CC_pass_by_value = 0x5,
+    DW_CC_lo_user = 0x40,
+    DW_CC_hi_user = 0xff
+  };
+
+
+/* DWARF inline encodings.  */
+enum
+  {
+    DW_INL_not_inlined = 0,
+    DW_INL_inlined = 1,
+    DW_INL_declared_not_inlined = 2,
+    DW_INL_declared_inlined = 3
+  };
+
+
+/* DWARF ordering encodings.  */
+enum
+  {
+    DW_ORD_row_major = 0,
+    DW_ORD_col_major = 1
+  };
+
+
+/* DWARF discriminant descriptor encodings.  */
+enum
+  {
+    DW_DSC_label = 0,
+    DW_DSC_range = 1
+  };
+
+/* DWARF defaulted member function encodings.  */
+enum
+  {
+    DW_DEFAULTED_no = 0,
+    DW_DEFAULTED_in_class = 1,
+    DW_DEFAULTED_out_of_class = 2
+  };
+
+
+/* DWARF standard opcode encodings.  */
+enum
+  {
+    DW_LNS_copy = 1,
+    DW_LNS_advance_pc = 2,
+    DW_LNS_advance_line = 3,
+    DW_LNS_set_file = 4,
+    DW_LNS_set_column = 5,
+    DW_LNS_negate_stmt = 6,
+    DW_LNS_set_basic_block = 7,
+    DW_LNS_const_add_pc = 8,
+    DW_LNS_fixed_advance_pc = 9,
+    DW_LNS_set_prologue_end = 10,
+    DW_LNS_set_epilogue_begin = 11,
+    DW_LNS_set_isa = 12
+  };
+
+
+/* DWARF extended opcode encodings.  */
+enum
+  {
+    DW_LNE_end_sequence = 1,
+    DW_LNE_set_address = 2,
+    DW_LNE_define_file = 3,
+    DW_LNE_set_discriminator = 4,
+
+    DW_LNE_lo_user = 128,
+    DW_LNE_hi_user = 255
+  };
+
+
+/* DWARF macinfo type encodings.  */
+enum
+  {
+    DW_MACINFO_define = 1,
+    DW_MACINFO_undef = 2,
+    DW_MACINFO_start_file = 3,
+    DW_MACINFO_end_file = 4,
+    DW_MACINFO_vendor_ext = 255
+  };
+
+
+/* DWARF debug_macro type encodings.  */
+enum
+  {
+    DW_MACRO_define = 0x01,
+    DW_MACRO_undef = 0x02,
+    DW_MACRO_start_file = 0x03,
+    DW_MACRO_end_file = 0x04,
+    DW_MACRO_define_strp = 0x05,
+    DW_MACRO_undef_strp = 0x06,
+    DW_MACRO_import = 0x07,
+    DW_MACRO_define_sup = 0x08,
+    DW_MACRO_undef_sup = 0x09,
+    DW_MACRO_import_sup = 0x0a,
+    DW_MACRO_define_strx = 0x0b,
+    DW_MACRO_undef_strx = 0x0c,
+    DW_MACRO_lo_user = 0xe0,
+    DW_MACRO_hi_user = 0xff
+  };
+
+/* Old GNU extension names for DWARF5 debug_macro type encodings.
+   There are no equivalents for the supplementary object file (sup)
+   and indirect string references (strx).  */
+#define DW_MACRO_GNU_define		 DW_MACRO_define
+#define DW_MACRO_GNU_undef		 DW_MACRO_undef
+#define DW_MACRO_GNU_start_file		 DW_MACRO_start_file
+#define DW_MACRO_GNU_end_file		 DW_MACRO_end_file
+#define DW_MACRO_GNU_define_indirect	 DW_MACRO_define_strp
+#define DW_MACRO_GNU_undef_indirect	 DW_MACRO_undef_strp
+#define DW_MACRO_GNU_transparent_include DW_MACRO_import
+#define DW_MACRO_GNU_lo_user		 DW_MACRO_lo_user
+#define DW_MACRO_GNU_hi_user		 DW_MACRO_hi_user
+
+
+/* DWARF call frame instruction encodings.  */
+enum
+  {
+    DW_CFA_advance_loc = 0x40,
+    DW_CFA_offset = 0x80,
+    DW_CFA_restore = 0xc0,
+    DW_CFA_extended = 0,
+
+    DW_CFA_nop = 0x00,
+    DW_CFA_set_loc = 0x01,
+    DW_CFA_advance_loc1 = 0x02,
+    DW_CFA_advance_loc2 = 0x03,
+    DW_CFA_advance_loc4 = 0x04,
+    DW_CFA_offset_extended = 0x05,
+    DW_CFA_restore_extended = 0x06,
+    DW_CFA_undefined = 0x07,
+    DW_CFA_same_value = 0x08,
+    DW_CFA_register = 0x09,
+    DW_CFA_remember_state = 0x0a,
+    DW_CFA_restore_state = 0x0b,
+    DW_CFA_def_cfa = 0x0c,
+    DW_CFA_def_cfa_register = 0x0d,
+    DW_CFA_def_cfa_offset = 0x0e,
+    DW_CFA_def_cfa_expression = 0x0f,
+    DW_CFA_expression = 0x10,
+    DW_CFA_offset_extended_sf = 0x11,
+    DW_CFA_def_cfa_sf = 0x12,
+    DW_CFA_def_cfa_offset_sf = 0x13,
+    DW_CFA_val_offset = 0x14,
+    DW_CFA_val_offset_sf = 0x15,
+    DW_CFA_val_expression = 0x16,
+
+    DW_CFA_low_user = 0x1c,
+    DW_CFA_MIPS_advance_loc8 = 0x1d,
+    DW_CFA_GNU_window_save = 0x2d,
+    DW_CFA_GNU_args_size = 0x2e,
+    DW_CFA_GNU_negative_offset_extended = 0x2f,
+    DW_CFA_high_user = 0x3f
+  };
+
+/* ID indicating CIE as opposed to FDE in .debug_frame.  */
+enum
+  {
+    DW_CIE_ID_32 = 0xffffffffU,		 /* In 32-bit format CIE header.  */
+    DW_CIE_ID_64 = 0xffffffffffffffffULL /* In 64-bit format CIE header.  */
+  };
+
+
+/* Information for GNU unwind information.  */
+enum
+  {
+    DW_EH_PE_absptr = 0x00,
+    DW_EH_PE_omit = 0xff,
+
+    /* FDE data encoding.  */
+    DW_EH_PE_uleb128 = 0x01,
+    DW_EH_PE_udata2 = 0x02,
+    DW_EH_PE_udata4 = 0x03,
+    DW_EH_PE_udata8 = 0x04,
+    DW_EH_PE_sleb128 = 0x09,
+    DW_EH_PE_sdata2 = 0x0a,
+    DW_EH_PE_sdata4 = 0x0b,
+    DW_EH_PE_sdata8 = 0x0c,
+    DW_EH_PE_signed = 0x08,
+
+    /* FDE flags.  */
+    DW_EH_PE_pcrel = 0x10,
+    DW_EH_PE_textrel = 0x20,
+    DW_EH_PE_datarel = 0x30,
+    DW_EH_PE_funcrel = 0x40,
+    DW_EH_PE_aligned = 0x50,
+
+    DW_EH_PE_indirect = 0x80
+  };
+
+
+/* DWARF XXX.  */
+#define DW_ADDR_none	0
+
+/* Section 7.2.2 of the DWARF3 specification defines a range of escape
+   codes that can appear in the length field of certain DWARF structures.
+
+   These defines enumerate the minium and maximum values of this range.
+   Currently only the maximum value is used (to indicate that 64-bit
+   values are going to be used in the dwarf data that accompanies the
+   structure).  The other values are reserved.
+
+   Note: There is a typo in DWARF3 spec (published Dec 20, 2005).  In
+   sections 7.4, 7.5.1, 7.19, 7.20 the minimum escape code is referred to
+   as 0xffffff00 whereas in fact it should be 0xfffffff0.  */
+#define DWARF3_LENGTH_MIN_ESCAPE_CODE 0xfffffff0u
+#define DWARF3_LENGTH_MAX_ESCAPE_CODE 0xffffffffu
+#define DWARF3_LENGTH_64_BIT          DWARF3_LENGTH_MAX_ESCAPE_CODE
+
+#endif	/* dwarf.h */
diff --git a/libdw/dwarf_abbrev_hash.c b/libdw/dwarf_abbrev_hash.c
new file mode 100644
index 0000000..f52f5ad
--- /dev/null
+++ b/libdw/dwarf_abbrev_hash.c
@@ -0,0 +1,45 @@
+/* Implementation of hash table for DWARF .debug_abbrev section content.
+   Copyright (C) 2000-2010 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "dwarf_sig8_hash.h"
+#define NO_UNDEF
+#include "libdwP.h"
+
+#define next_prime __libdwarf_next_prime
+extern size_t next_prime (size_t) attribute_hidden;
+
+#include <dynamicsizehash.c>
+
+#undef next_prime
+#define next_prime attribute_hidden __libdwarf_next_prime
+#include "../lib/next_prime.c"
diff --git a/libdw/dwarf_abbrev_hash.h b/libdw/dwarf_abbrev_hash.h
new file mode 100644
index 0000000..d2f02cc
--- /dev/null
+++ b/libdw/dwarf_abbrev_hash.h
@@ -0,0 +1,39 @@
+/* Hash table for DWARF .debug_abbrev section content.
+   Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _DWARF_ABBREV_HASH_H
+#define _DWARF_ABBREV_HASH_H	1
+
+#define NAME Dwarf_Abbrev_Hash
+#define TYPE Dwarf_Abbrev *
+#define COMPARE(a, b) (0)
+
+#include <dynamicsizehash.h>
+
+#endif	/* dwarf_abbrev_hash.h */
diff --git a/libdw/dwarf_abbrevhaschildren.c b/libdw/dwarf_abbrevhaschildren.c
new file mode 100644
index 0000000..0f17c7e
--- /dev/null
+++ b/libdw/dwarf_abbrevhaschildren.c
@@ -0,0 +1,43 @@
+/* Return true if abbreviation is children flag set.
+   Copyright (C) 2003 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_abbrevhaschildren (Dwarf_Abbrev *abbrev)
+{
+  return abbrev == NULL ? -1 : abbrev->has_children;
+}
diff --git a/libdw/dwarf_addrdie.c b/libdw/dwarf_addrdie.c
new file mode 100644
index 0000000..3a08ab7
--- /dev/null
+++ b/libdw/dwarf_addrdie.c
@@ -0,0 +1,51 @@
+/* Return CU DIE containing given address.
+   Copyright (C) 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+Dwarf_Die *
+dwarf_addrdie (Dwarf *dbg, Dwarf_Addr addr, Dwarf_Die *result)
+{
+  Dwarf_Aranges *aranges;
+  size_t naranges;
+  Dwarf_Off off;
+
+  if (INTUSE(dwarf_getaranges) (dbg, &aranges, &naranges) != 0
+      || INTUSE(dwarf_getarangeinfo) (INTUSE(dwarf_getarange_addr) (aranges,
+								    addr),
+				      NULL, NULL, &off) != 0)
+    return NULL;
+
+  return INTUSE(dwarf_offdie) (dbg, off, result);
+}
diff --git a/libdw/dwarf_aggregate_size.c b/libdw/dwarf_aggregate_size.c
new file mode 100644
index 0000000..6e50185
--- /dev/null
+++ b/libdw/dwarf_aggregate_size.c
@@ -0,0 +1,211 @@
+/* Compute size of an aggregate type from DWARF.
+   Copyright (C) 2010, 2014, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+static Dwarf_Die *
+get_type (Dwarf_Die *die, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
+{
+  Dwarf_Die *type = INTUSE(dwarf_formref_die)
+    (INTUSE(dwarf_attr_integrate) (die, DW_AT_type, attr_mem), type_mem);
+
+  if (INTUSE(dwarf_peel_type) (type, type) != 0)
+    return NULL;
+
+  return type;
+}
+
+static int
+array_size (Dwarf_Die *die, Dwarf_Word *size,
+	    Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
+{
+  Dwarf_Word eltsize;
+  if (INTUSE(dwarf_aggregate_size) (get_type (die, attr_mem, type_mem),
+				    &eltsize) != 0)
+      return -1;
+
+  /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type
+     children instead that give the size of each dimension.  */
+
+  Dwarf_Die child;
+  if (INTUSE(dwarf_child) (die, &child) != 0)
+    return -1;
+
+  bool any = false;
+  Dwarf_Word count_total = 1;
+  do
+    {
+      Dwarf_Word count;
+      switch (INTUSE(dwarf_tag) (&child))
+	{
+	case DW_TAG_subrange_type:
+	  /* This has either DW_AT_count or DW_AT_upper_bound.  */
+	  if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count,
+					    attr_mem) != NULL)
+	    {
+	      if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0)
+		return -1;
+	    }
+	  else
+	    {
+	      Dwarf_Sword upper;
+	      Dwarf_Sword lower;
+	      if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate)
+					   (&child, DW_AT_upper_bound,
+					    attr_mem), &upper) != 0)
+		return -1;
+
+	      /* Having DW_AT_lower_bound is optional.  */
+	      if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound,
+						attr_mem) != NULL)
+		{
+		  if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0)
+		    return -1;
+		}
+	      else
+		{
+		  Dwarf_Die cu = CUDIE (die->cu);
+		  int lang = INTUSE(dwarf_srclang) (&cu);
+		  if (lang == -1
+		      || INTUSE(dwarf_default_lower_bound) (lang, &lower) != 0)
+		    return -1;
+		}
+	      if (unlikely (lower > upper))
+		return -1;
+	      count = upper - lower + 1;
+	    }
+	  break;
+
+	case DW_TAG_enumeration_type:
+	  /* We have to find the DW_TAG_enumerator child with the
+	     highest value to know the array's element count.  */
+	  count = 0;
+	  Dwarf_Die enum_child;
+	  int has_children = INTUSE(dwarf_child) (die, &enum_child);
+	  if (has_children < 0)
+	    return -1;
+	  if (has_children > 0)
+	    do
+	      if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator)
+		{
+		  Dwarf_Word value;
+		  if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+					       (&enum_child, DW_AT_const_value,
+						attr_mem), &value) != 0)
+		    return -1;
+		  if (value >= count)
+		    count = value + 1;
+		}
+	    while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0);
+	  break;
+
+	default:
+	  continue;
+	}
+
+      count_total *= count;
+
+      any = true;
+    }
+  while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
+
+  if (!any)
+    return -1;
+
+  /* This is a subrange_type or enumeration_type and we've set COUNT.
+     Now determine the stride for this array.  */
+  Dwarf_Word stride = eltsize;
+  if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_stride,
+                                    attr_mem) != NULL)
+    {
+      if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
+        return -1;
+    }
+  else if (INTUSE(dwarf_attr_integrate) (die, DW_AT_bit_stride,
+                                         attr_mem) != NULL)
+    {
+      if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
+        return -1;
+      if (stride % 8) 	/* XXX maybe compute in bits? */
+        return -1;
+      stride /= 8;
+    }
+
+  *size = count_total * stride;
+  return 0;
+}
+
+static int
+aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem)
+{
+  Dwarf_Attribute attr_mem;
+
+  if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL)
+    return INTUSE(dwarf_formudata) (&attr_mem, size);
+
+  switch (INTUSE(dwarf_tag) (die))
+    {
+    case DW_TAG_subrange_type:
+      return aggregate_size (get_type (die, &attr_mem, type_mem),
+			     size, type_mem); /* Tail call.  */
+
+    case DW_TAG_array_type:
+      return array_size (die, size, &attr_mem, type_mem);
+
+    /* Assume references and pointers have pointer size if not given an
+       explicit DW_AT_byte_size.  */
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+    case DW_TAG_rvalue_reference_type:
+      *size = die->cu->address_size;
+      return 0;
+    }
+
+  /* Most types must give their size directly.  */
+  return -1;
+}
+
+int
+dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size)
+{
+  Dwarf_Die die_mem, type_mem;
+
+  if (INTUSE (dwarf_peel_type) (die, &die_mem) != 0)
+    return -1;
+
+  return aggregate_size (&die_mem, size, &type_mem);
+}
+INTDEF (dwarf_aggregate_size)
+OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
+NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161)
diff --git a/libdw/dwarf_arrayorder.c b/libdw/dwarf_arrayorder.c
new file mode 100644
index 0000000..da64f99
--- /dev/null
+++ b/libdw/dwarf_arrayorder.c
@@ -0,0 +1,49 @@
+/* Return array order attribute of DIE.
+   Copyright (C) 2003, 2005, 2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_arrayorder (Dwarf_Die *die)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word value;
+
+  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/libdw/dwarf_attr.c b/libdw/dwarf_attr.c
new file mode 100644
index 0000000..db8acfe
--- /dev/null
+++ b/libdw/dwarf_attr.c
@@ -0,0 +1,52 @@
+/* Return specific DWARF attribute of a DIE.
+   Copyright (C) 2003, 2005, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+Dwarf_Attribute *
+dwarf_attr (Dwarf_Die *die, unsigned int search_name, Dwarf_Attribute *result)
+{
+  if (die == NULL)
+    return NULL;
+
+  /* Search for the attribute with the given name.  */
+  result->valp = __libdw_find_attr (die, search_name, &result->code,
+				    &result->form);
+  /* Always fill in the CU information.  */
+  result->cu = die->cu;
+
+  return result->valp != NULL && result->code == search_name ? result : NULL;
+}
+INTDEF(dwarf_attr)
diff --git a/libdw/dwarf_attr_integrate.c b/libdw/dwarf_attr_integrate.c
new file mode 100644
index 0000000..812d74b
--- /dev/null
+++ b/libdw/dwarf_attr_integrate.c
@@ -0,0 +1,60 @@
+/* Return specific DWARF attribute of a DIE, integrating indirections.
+   Copyright (C) 2005 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+Dwarf_Attribute *
+dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name,
+		      Dwarf_Attribute *result)
+{
+  Dwarf_Die die_mem;
+
+  do
+    {
+      Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, search_name, result);
+      if (attr != NULL)
+	return attr;
+
+      attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, result);
+      if (attr == NULL)
+	attr = INTUSE(dwarf_attr) (die, DW_AT_specification, result);
+      if (attr == NULL)
+	break;
+
+      die = INTUSE(dwarf_formref_die) (attr, &die_mem);
+    }
+  while (die != NULL);
+
+  return NULL;
+}
+INTDEF (dwarf_attr_integrate)
diff --git a/libdw/dwarf_begin.c b/libdw/dwarf_begin.c
new file mode 100644
index 0000000..19d16e5
--- /dev/null
+++ b/libdw/dwarf_begin.c
@@ -0,0 +1,99 @@
+/* Create descriptor from file descriptor for processing file.
+   Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+#include <libdwP.h>
+
+
+Dwarf *
+dwarf_begin (int fd, Dwarf_Cmd cmd)
+{
+  Elf *elf;
+  Elf_Cmd elfcmd;
+  Dwarf *result = NULL;
+
+  switch (cmd)
+    {
+    case DWARF_C_READ:
+      elfcmd = ELF_C_READ_MMAP;
+      break;
+    case DWARF_C_WRITE:
+      elfcmd = ELF_C_WRITE;
+      break;
+    case DWARF_C_RDWR:
+      elfcmd = ELF_C_RDWR;
+      break;
+    default:
+      /* No valid mode.  */
+      __libdw_seterrno (DWARF_E_INVALID_CMD);
+      return NULL;
+    }
+
+  /* We have to call `elf_version' here since the user might have not
+     done it or initialized libelf with a different version.  This
+     would break libdwarf since we are using the ELF data structures
+     in a certain way.  */
+  elf_version (EV_CURRENT);
+
+  /* Get an ELF descriptor.  */
+  elf = elf_begin (fd, elfcmd, NULL);
+  if (elf == NULL)
+    {
+      /* Test why the `elf_begin" call failed.  */
+      struct stat st;
+
+      if (fstat (fd, &st) == 0 && ! S_ISREG (st.st_mode))
+	__libdw_seterrno (DWARF_E_NO_REGFILE);
+      else if (errno == EBADF)
+	__libdw_seterrno (DWARF_E_INVALID_FILE);
+      else
+	__libdw_seterrno (DWARF_E_IO_ERROR);
+    }
+  else
+    {
+      /* Do the real work now that we have an ELF descriptor.  */
+      result = INTUSE(dwarf_begin_elf) (elf, cmd, NULL);
+
+      /* If this failed, free the resources.  */
+      if (result == NULL)
+	elf_end (elf);
+      else
+	result->free_elf = true;
+    }
+
+  return result;
+}
+INTDEF(dwarf_begin)
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
new file mode 100644
index 0000000..6834ac5
--- /dev/null
+++ b/libdw/dwarf_begin_elf.c
@@ -0,0 +1,365 @@
+/* Create descriptor from ELF descriptor for processing file.
+   Copyright (C) 2002-2011, 2014, 2015, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <endian.h>
+
+#include "libdwP.h"
+
+
+/* Section names.  */
+static const char dwarf_scnnames[IDX_last][18] =
+{
+  [IDX_debug_info] = ".debug_info",
+  [IDX_debug_types] = ".debug_types",
+  [IDX_debug_abbrev] = ".debug_abbrev",
+  [IDX_debug_aranges] = ".debug_aranges",
+  [IDX_debug_line] = ".debug_line",
+  [IDX_debug_frame] = ".debug_frame",
+  [IDX_debug_loc] = ".debug_loc",
+  [IDX_debug_pubnames] = ".debug_pubnames",
+  [IDX_debug_str] = ".debug_str",
+  [IDX_debug_macinfo] = ".debug_macinfo",
+  [IDX_debug_macro] = ".debug_macro",
+  [IDX_debug_ranges] = ".debug_ranges",
+  [IDX_gnu_debugaltlink] = ".gnu_debugaltlink"
+};
+#define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0]))
+
+static Dwarf *
+check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
+{
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr;
+
+  /* Get the section header data.  */
+  shdr = gelf_getshdr (scn, &shdr_mem);
+  if (shdr == NULL)
+    /* We may read /proc/PID/mem with only program headers mapped and section
+       headers out of the mapped pages.  */
+    goto err;
+
+  /* Ignore any SHT_NOBITS sections.  Debugging sections should not
+     have been stripped, but in case of a corrupt file we won't try
+     to look at the missing data.  */
+  if (unlikely (shdr->sh_type == SHT_NOBITS))
+    return result;
+
+  /* Make sure the section is part of a section group only iff we
+     really need it.  If we are looking for the global (= non-section
+     group debug info) we have to ignore all the info in section
+     groups.  If we are looking into a section group we cannot look at
+     a section which isn't part of the section group.  */
+  if (! inscngrp && (shdr->sh_flags & SHF_GROUP) != 0)
+    /* Ignore the section.  */
+    return result;
+
+
+  /* We recognize the DWARF section by their names.  This is not very
+     safe and stable but the best we can do.  */
+  const char *scnname = elf_strptr (result->elf, ehdr->e_shstrndx,
+				    shdr->sh_name);
+  if (scnname == NULL)
+    {
+      /* The section name must be valid.  Otherwise is the ELF file
+	 invalid.  */
+    err:
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      __libdw_seterrno (DWARF_E_INVALID_ELF);
+      free (result);
+      return NULL;
+    }
+
+  /* Recognize the various sections.  Most names start with .debug_.  */
+  size_t cnt;
+  bool gnu_compressed = false;
+  for (cnt = 0; cnt < ndwarf_scnnames; ++cnt)
+    if (strcmp (scnname, dwarf_scnnames[cnt]) == 0)
+      break;
+    else if (scnname[0] == '.' && scnname[1] == 'z'
+	     && strcmp (&scnname[2], &dwarf_scnnames[cnt][1]) == 0)
+      {
+        gnu_compressed = true;
+        break;
+      }
+
+  if (cnt >= ndwarf_scnnames)
+    /* Not a debug section; ignore it. */
+    return result;
+
+  if (unlikely (result->sectiondata[cnt] != NULL))
+    /* A section appears twice.  That's bad.  We ignore the section.  */
+    return result;
+
+  /* We cannot know whether or not a GNU compressed section has already
+     been uncompressed or not, so ignore any errors.  */
+  if (gnu_compressed)
+    elf_compress_gnu (scn, 0, 0);
+
+  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+    {
+      if (elf_compress (scn, 0, 0) < 0)
+	{
+	  /* If we failed to decompress the section and it's the
+	     debug_info section, then fail with specific error rather
+	     than the generic NO_DWARF. Without debug_info we can't do
+	     anything (see also valid_p()). */
+	  if (cnt == IDX_debug_info)
+	    {
+	      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+	      __libdw_seterrno (DWARF_E_COMPRESSED_ERROR);
+	      free (result);
+	      return NULL;
+	    }
+	  return result;
+	}
+    }
+
+  /* Get the section data.  */
+  Elf_Data *data = elf_getdata (scn, NULL);
+  if (data == NULL)
+    goto err;
+
+  if (data->d_buf == NULL || data->d_size == 0)
+    /* No data actually available, ignore it. */
+    return result;
+
+  /* We can now read the section data into results. */
+  result->sectiondata[cnt] = data;
+
+  return result;
+}
+
+
+/* Check whether all the necessary DWARF information is available.  */
+static Dwarf *
+valid_p (Dwarf *result)
+{
+  /* We looked at all the sections.  Now determine whether all the
+     sections with debugging information we need are there.
+
+     XXX Which sections are absolutely necessary?  Add tests if
+     necessary.  For now we require only .debug_info.  Hopefully this
+     is correct.  */
+  if (likely (result != NULL)
+      && unlikely (result->sectiondata[IDX_debug_info] == NULL))
+    {
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      __libdw_seterrno (DWARF_E_NO_DWARF);
+      free (result);
+      result = NULL;
+    }
+
+  if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL)
+    {
+      result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+      if (unlikely (result->fake_loc_cu == NULL))
+	{
+	  Dwarf_Sig8_Hash_free (&result->sig8_hash);
+	  __libdw_seterrno (DWARF_E_NOMEM);
+	  free (result);
+	  result = NULL;
+	}
+      else
+	{
+	  result->fake_loc_cu->sec_idx = IDX_debug_loc;
+	  result->fake_loc_cu->dbg = result;
+	  result->fake_loc_cu->startp
+	    = result->sectiondata[IDX_debug_loc]->d_buf;
+	  result->fake_loc_cu->endp
+	    = (result->sectiondata[IDX_debug_loc]->d_buf
+	       + result->sectiondata[IDX_debug_loc]->d_size);
+	}
+    }
+
+  return result;
+}
+
+
+static Dwarf *
+global_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr)
+{
+  Elf_Scn *scn = NULL;
+
+  while (result != NULL && (scn = elf_nextscn (elf, scn)) != NULL)
+    result = check_section (result, ehdr, scn, false);
+
+  return valid_p (result);
+}
+
+
+static Dwarf *
+scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp)
+{
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr = gelf_getshdr (scngrp, &shdr_mem);
+  if (shdr == NULL)
+    {
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      __libdw_seterrno (DWARF_E_INVALID_ELF);
+      free (result);
+      return NULL;
+    }
+
+  if ((shdr->sh_flags & SHF_COMPRESSED) != 0
+      && elf_compress (scngrp, 0, 0) < 0)
+    {
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      __libdw_seterrno (DWARF_E_COMPRESSED_ERROR);
+      free (result);
+      return NULL;
+    }
+
+  /* SCNGRP is the section descriptor for a section group which might
+     contain debug sections.  */
+  Elf_Data *data = elf_getdata (scngrp, NULL);
+  if (data == NULL)
+    {
+      /* We cannot read the section content.  Fail!  */
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      free (result);
+      return NULL;
+    }
+
+  /* The content of the section is a number of 32-bit words which
+     represent section indices.  The first word is a flag word.  */
+  Elf32_Word *scnidx = (Elf32_Word *) data->d_buf;
+  size_t cnt;
+  for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt)
+    {
+      Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]);
+      if (scn == NULL)
+	{
+	  /* A section group refers to a non-existing section.  Should
+	     never happen.  */
+	  Dwarf_Sig8_Hash_free (&result->sig8_hash);
+	  __libdw_seterrno (DWARF_E_INVALID_ELF);
+	  free (result);
+	  return NULL;
+	}
+
+      result = check_section (result, ehdr, scn, true);
+      if (result == NULL)
+	break;
+    }
+
+  return valid_p (result);
+}
+
+
+Dwarf *
+dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
+{
+  GElf_Ehdr *ehdr;
+  GElf_Ehdr ehdr_mem;
+
+  /* Get the ELF header of the file.  We need various pieces of
+     information from it.  */
+  ehdr = gelf_getehdr (elf, &ehdr_mem);
+  if (ehdr == NULL)
+    {
+      if (elf_kind (elf) != ELF_K_ELF)
+	__libdw_seterrno (DWARF_E_NOELF);
+      else
+	__libdw_seterrno (DWARF_E_GETEHDR_ERROR);
+
+      return NULL;
+    }
+
+
+  /* Default memory allocation size.  */
+  size_t mem_default_size = sysconf (_SC_PAGESIZE) - 4 * sizeof (void *);
+  assert (sizeof (struct Dwarf) < mem_default_size);
+
+  /* Allocate the data structure.  */
+  Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size);
+  if (unlikely (result == NULL)
+      || unlikely (Dwarf_Sig8_Hash_init (&result->sig8_hash, 11) < 0))
+    {
+      free (result);
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  /* Fill in some values.  */
+  if ((BYTE_ORDER == LITTLE_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+      || (BYTE_ORDER == BIG_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2LSB))
+    result->other_byte_order = true;
+
+  result->elf = elf;
+  result->alt_fd = -1;
+
+  /* Initialize the memory handling.  */
+  result->mem_default_size = mem_default_size;
+  result->oom_handler = __libdw_oom;
+  result->mem_tail = (struct libdw_memblock *) (result + 1);
+  result->mem_tail->size = (result->mem_default_size
+			    - offsetof (struct libdw_memblock, mem));
+  result->mem_tail->remaining = result->mem_tail->size;
+  result->mem_tail->prev = NULL;
+
+  if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR)
+    {
+      /* If the caller provides a section group we get the DWARF
+	 sections only from this setion group.  Otherwise we search
+	 for the first section with the required name.  Further
+	 sections with the name are ignored.  The DWARF specification
+	 does not really say this is allowed.  */
+      if (scngrp == NULL)
+	return global_read (result, elf, ehdr);
+      else
+	return scngrp_read (result, elf, ehdr, scngrp);
+    }
+  else if (cmd == DWARF_C_WRITE)
+    {
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      __libdw_seterrno (DWARF_E_UNIMPL);
+      free (result);
+      return NULL;
+    }
+
+  Dwarf_Sig8_Hash_free (&result->sig8_hash);
+  __libdw_seterrno (DWARF_E_INVALID_CMD);
+  free (result);
+  return NULL;
+}
+INTDEF(dwarf_begin_elf)
diff --git a/libdw/dwarf_bitoffset.c b/libdw/dwarf_bitoffset.c
new file mode 100644
index 0000000..c1a3a34
--- /dev/null
+++ b/libdw/dwarf_bitoffset.c
@@ -0,0 +1,49 @@
+/* Return bit offset attribute of DIE.
+   Copyright (C) 2003, 2005, 2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_bitoffset (Dwarf_Die *die)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word value;
+
+  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/libdw/dwarf_bitsize.c b/libdw/dwarf_bitsize.c
new file mode 100644
index 0000000..0ed9b71
--- /dev/null
+++ b/libdw/dwarf_bitsize.c
@@ -0,0 +1,49 @@
+/* Return bit size attribute of DIE.
+   Copyright (C) 2003, 2005, 2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_bitsize (Dwarf_Die *die)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word value;
+
+  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/libdw/dwarf_bytesize.c b/libdw/dwarf_bytesize.c
new file mode 100644
index 0000000..116cd32
--- /dev/null
+++ b/libdw/dwarf_bytesize.c
@@ -0,0 +1,49 @@
+/* Return byte size attribute of DIE.
+   Copyright (C) 2003, 2005, 2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_bytesize (Dwarf_Die *die)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word value;
+
+  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/libdw/dwarf_cfi_addrframe.c b/libdw/dwarf_cfi_addrframe.c
new file mode 100644
index 0000000..4424027
--- /dev/null
+++ b/libdw/dwarf_cfi_addrframe.c
@@ -0,0 +1,54 @@
+/* Compute frame state at PC.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "cfi.h"
+
+int
+dwarf_cfi_addrframe (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/libdw/dwarf_cfi_end.c b/libdw/dwarf_cfi_end.c
new file mode 100644
index 0000000..d68e2db
--- /dev/null
+++ b/libdw/dwarf_cfi_end.c
@@ -0,0 +1,48 @@
+/* Clean up Dwarf_CFI structure.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include "cfi.h"
+#include <stdlib.h>
+
+int
+dwarf_cfi_end (Dwarf_CFI *cache)
+{
+  if (cache != NULL)
+    {
+      __libdw_destroy_frame_cache (cache);
+      free (cache);
+    }
+
+  return 0;
+}
+INTDEF (dwarf_cfi_end)
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
new file mode 100644
index 0000000..248338e
--- /dev/null
+++ b/libdw/dwarf_child.c
@@ -0,0 +1,165 @@
+/* Return child of current DIE.
+   Copyright (C) 2003-2011, 2014, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <string.h>
+
+/* Some arbitrary value not conflicting with any existing code.  */
+#define INVALID 0xffffe444
+
+
+unsigned char *
+internal_function
+__libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
+		   unsigned int *codep, unsigned int *formp)
+{
+  const unsigned char *readp;
+
+  /* Find the abbreviation entry.  */
+  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &readp);
+  if (unlikely (abbrevp == DWARF_END_ABBREV))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  /* Search the name attribute.  Attribute has been checked when
+     Dwarf_Abbrev was created, we can read unchecked.  */
+  const unsigned char *attrp = abbrevp->attrp;
+  while (1)
+    {
+      /* Get attribute name and form.  */
+      unsigned int attr_name;
+      get_uleb128_unchecked (attr_name, attrp);
+
+      unsigned int attr_form;
+      get_uleb128_unchecked (attr_form, attrp);
+
+      /* We can stop if we found the attribute with value zero.  */
+      if (attr_name == 0 && attr_form == 0)
+	break;
+
+      /* Is this the name attribute?  */
+      if (attr_name == search_name && search_name != INVALID)
+	{
+	  if (codep != NULL)
+	    *codep = attr_name;
+	  if (formp != NULL)
+	    *formp = attr_form;
+
+	  return (unsigned char *) readp;
+	}
+
+      /* Skip over the rest of this attribute (if there is any).  */
+      if (attr_form != 0)
+	{
+	  size_t len = __libdw_form_val_len (die->cu, attr_form, readp);
+	  if (unlikely (len == (size_t) -1l))
+	    {
+	      readp = NULL;
+	      break;
+	    }
+
+	  // __libdw_form_val_len will have done a bounds check.
+	  readp += len;
+	}
+    }
+
+  // XXX Do we need other values?
+  if (codep != NULL)
+    *codep = INVALID;
+  if (formp != NULL)
+    *formp = INVALID;
+
+  return (unsigned char *) readp;
+}
+
+
+int
+dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
+{
+  /* Ignore previous errors.  */
+  if (die == NULL)
+    return -1;
+
+  /* Find the abbreviation entry.  */
+  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
+  if (unlikely (abbrevp == DWARF_END_ABBREV))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  /* If there are no children, do not search.  */
+  if (! abbrevp->has_children)
+    return 1;
+
+  /* Skip past the last attribute.  */
+  void *addr = __libdw_find_attr (die, INVALID, NULL, NULL);
+
+  if (addr == NULL)
+    return -1;
+
+  /* RESULT can be the same as DIE.  So preserve what we need.  */
+  struct Dwarf_CU *cu = die->cu;
+
+  /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3).
+     So if this starts with ULEB128 of 0 (even with silly encoding of 0),
+     it is a kosher null entry and we do not really have any children.  */
+  const unsigned char *code = addr;
+  const unsigned char *endp = cu->endp;
+  while (1)
+    {
+      if (unlikely (code >= endp)) /* Truncated section.  */
+	return 1;
+      if (unlikely (*code == 0x80))
+	++code;
+      else
+	break;
+    }
+  if (unlikely (*code == '\0'))
+    return 1;
+
+  /* Clear the entire DIE structure.  This signals we have not yet
+     determined any of the information.  */
+  memset (result, '\0', sizeof (Dwarf_Die));
+
+  /* We have the address.  */
+  result->addr = addr;
+
+  /* Same CU as the parent.  */
+  result->cu = cu;
+
+  return 0;
+}
+INTDEF(dwarf_child)
diff --git a/libdw/dwarf_cu_die.c b/libdw/dwarf_cu_die.c
new file mode 100644
index 0000000..194da58
--- /dev/null
+++ b/libdw/dwarf_cu_die.c
@@ -0,0 +1,62 @@
+/* Internal definitions for libdwarf.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+#include "libdwP.h"
+
+
+Dwarf_Die *
+dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, Dwarf_Half *versionp,
+	      Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
+	      uint8_t *offset_sizep, uint64_t *type_signaturep,
+	      Dwarf_Off *type_offsetp)
+{
+  if (cu == NULL)
+    return NULL;
+
+  *result = CUDIE (cu);
+
+  if (versionp != NULL)
+    *versionp = cu->version;
+  if (abbrev_offsetp != NULL)
+    *abbrev_offsetp = cu->orig_abbrev_offset;
+  if (address_sizep != NULL)
+    *address_sizep = cu->address_size;
+  if (offset_sizep != NULL)
+    *offset_sizep = cu->offset_size;
+  if (type_signaturep != NULL)
+    *type_signaturep = cu->type_sig8;
+  if (type_offsetp != NULL)
+    *type_offsetp = cu->type_offset;
+
+  return result;
+}
diff --git a/libdw/dwarf_cu_getdwarf.c b/libdw/dwarf_cu_getdwarf.c
new file mode 100644
index 0000000..562460f
--- /dev/null
+++ b/libdw/dwarf_cu_getdwarf.c
@@ -0,0 +1,46 @@
+/* Retrieve Dwarf descriptor underlying a Dwarf_CU.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+
+#include "libdwP.h"
+
+
+Dwarf *
+dwarf_cu_getdwarf (Dwarf_CU *cu)
+{
+  if (cu == NULL)
+    /* Some error occurred before.  */
+    return NULL;
+
+  return cu->dbg;
+}
diff --git a/libdw/dwarf_cuoffset.c b/libdw/dwarf_cuoffset.c
new file mode 100644
index 0000000..ba37648
--- /dev/null
+++ b/libdw/dwarf_cuoffset.c
@@ -0,0 +1,44 @@
+/* Return offset of DIE in CU.
+   Copyright (C) 2003-2010, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+Dwarf_Off
+dwarf_cuoffset (Dwarf_Die *die)
+{
+  return (die == NULL
+	  ? (Dwarf_Off) -1l
+	  : (Dwarf_Off) (die->addr - die->cu->startp));
+}
diff --git a/libdw/dwarf_decl_column.c b/libdw/dwarf_decl_column.c
new file mode 100644
index 0000000..08d36b8
--- /dev/null
+++ b/libdw/dwarf_decl_column.c
@@ -0,0 +1,44 @@
+/* Get column number of beginning of given declaration.
+   Copyright (C) 2005-2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+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/libdw/dwarf_decl_file.c b/libdw/dwarf_decl_file.c
new file mode 100644
index 0000000..5657132
--- /dev/null
+++ b/libdw/dwarf_decl_file.c
@@ -0,0 +1,89 @@
+/* Return file name containing definition of the given function.
+   Copyright (C) 2005, 2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+const char *
+dwarf_decl_file (Dwarf_Die *die)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word idx = 0;
+
+  if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+			       (die, DW_AT_decl_file, &attr_mem),
+			       &idx) != 0)
+    return NULL;
+
+  /* Zero means no source file information available.  */
+  if (idx == 0)
+    {
+      __libdw_seterrno (DWARF_E_NO_ENTRY);
+      return NULL;
+    }
+
+  /* Get the array of source files for the CU.  */
+  struct Dwarf_CU *cu = die->cu;
+  if (cu->lines == NULL)
+    {
+      Dwarf_Lines *lines;
+      size_t nlines;
+
+      /* Let the more generic function do the work.  It'll create more
+	 data but that will be needed in an real program anyway.  */
+      (void) INTUSE(dwarf_getsrclines) (&CUDIE (cu), &lines, &nlines);
+      assert (cu->lines != NULL);
+    }
+
+  if (cu->lines == (void *) -1l)
+    {
+      /* If the file index is not zero, there must be file information
+	 available.  */
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  assert (cu->files != NULL && cu->files != (void *) -1l);
+
+  if (idx >= cu->files->nfiles)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  return cu->files->info[idx].name;
+}
+OLD_VERSION (dwarf_decl_file, ELFUTILS_0.122)
+NEW_VERSION (dwarf_decl_file, ELFUTILS_0.143)
diff --git a/libdw/dwarf_decl_line.c b/libdw/dwarf_decl_line.c
new file mode 100644
index 0000000..80fae6c
--- /dev/null
+++ b/libdw/dwarf_decl_line.c
@@ -0,0 +1,70 @@
+/* Get line number of beginning of given function.
+   Copyright (C) 2005, 2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include <limits.h>
+#include "libdwP.h"
+
+
+int
+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
+__libdw_attr_intval (Dwarf_Die *die, int *linep, int attval)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word line;
+
+  int res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+				     (die, attval, &attr_mem),
+				     &line);
+  if (res == 0)
+    {
+      if (line > INT_MAX)
+	{
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	  res = -1;
+	}
+      else
+	*linep = line;
+    }
+
+  return res;
+}
diff --git a/libdw/dwarf_default_lower_bound.c b/libdw/dwarf_default_lower_bound.c
new file mode 100644
index 0000000..a33a343
--- /dev/null
+++ b/libdw/dwarf_default_lower_bound.c
@@ -0,0 +1,91 @@
+/* Get the default subrange lower bound for a given language.
+   Copyright (C) 2016 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+/* Determine default lower bound from language, as per the DWARF5
+   "Subrange Type Entries" table.  */
+int
+dwarf_default_lower_bound (int lang, Dwarf_Sword *result)
+{
+  switch (lang)
+    {
+    case DW_LANG_C:
+    case DW_LANG_C89:
+    case DW_LANG_C99:
+    case DW_LANG_C11:
+    case DW_LANG_C_plus_plus:
+    case DW_LANG_C_plus_plus_03:
+    case DW_LANG_C_plus_plus_11:
+    case DW_LANG_C_plus_plus_14:
+    case DW_LANG_ObjC:
+    case DW_LANG_ObjC_plus_plus:
+    case DW_LANG_Java:
+    case DW_LANG_D:
+    case DW_LANG_Python:
+    case DW_LANG_UPC:
+    case DW_LANG_OpenCL:
+    case DW_LANG_Go:
+    case DW_LANG_Haskell:
+    case DW_LANG_OCaml:
+    case DW_LANG_Rust:
+    case DW_LANG_Swift:
+    case DW_LANG_Dylan:
+    case DW_LANG_RenderScript:
+    case DW_LANG_BLISS:
+      *result = 0;
+      return 0;
+
+    case DW_LANG_Ada83:
+    case DW_LANG_Ada95:
+    case DW_LANG_Cobol74:
+    case DW_LANG_Cobol85:
+    case DW_LANG_Fortran77:
+    case DW_LANG_Fortran90:
+    case DW_LANG_Fortran95:
+    case DW_LANG_Fortran03:
+    case DW_LANG_Fortran08:
+    case DW_LANG_Pascal83:
+    case DW_LANG_Modula2:
+    case DW_LANG_Modula3:
+    case DW_LANG_PLI:
+    case DW_LANG_Julia:
+      *result = 1;
+      return 0;
+
+    default:
+      __libdw_seterrno (DWARF_E_UNKNOWN_LANGUAGE);
+      return -1;
+    }
+}
+INTDEF (dwarf_default_lower_bound)
diff --git a/libdw/dwarf_diecu.c b/libdw/dwarf_diecu.c
new file mode 100644
index 0000000..5281c35
--- /dev/null
+++ b/libdw/dwarf_diecu.c
@@ -0,0 +1,52 @@
+/* Return CU DIE containing given DIE.
+   Copyright (C) 2005-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include "libdwP.h"
+
+
+Dwarf_Die *
+dwarf_diecu (Dwarf_Die *die, Dwarf_Die *result, uint8_t *address_sizep,
+	     uint8_t *offset_sizep)
+{
+  if (die == NULL)
+    return NULL;
+
+  *result = CUDIE (die->cu);
+
+  if (address_sizep != NULL)
+    *address_sizep = die->cu->address_size;
+  if (offset_sizep != NULL)
+    *offset_sizep = die->cu->offset_size;
+
+  return result;
+}
diff --git a/libdw/dwarf_diename.c b/libdw/dwarf_diename.c
new file mode 100644
index 0000000..96450c1
--- /dev/null
+++ b/libdw/dwarf_diename.c
@@ -0,0 +1,47 @@
+/* Return string in name attribute of DIE.
+   Copyright (C) 2002, 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+const char *
+dwarf_diename (Dwarf_Die *die)
+{
+  Dwarf_Attribute attr_mem;
+
+  return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr_integrate) (die,
+								 DW_AT_name,
+								 &attr_mem));
+}
+INTDEF (dwarf_diename)
diff --git a/libdw/dwarf_dieoffset.c b/libdw/dwarf_dieoffset.c
new file mode 100644
index 0000000..8028f6d
--- /dev/null
+++ b/libdw/dwarf_dieoffset.c
@@ -0,0 +1,45 @@
+/* Return offset of DIE.
+   Copyright (C) 2003-2010, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+Dwarf_Off
+dwarf_dieoffset (Dwarf_Die *die)
+{
+  return (die == NULL
+	  ? ~0ul
+	  : (Dwarf_Off) (die->addr - die->cu->startp + die->cu->start));
+}
+INTDEF(dwarf_dieoffset)
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
new file mode 100644
index 0000000..f6915ab
--- /dev/null
+++ b/libdw/dwarf_end.c
@@ -0,0 +1,120 @@
+/* Release debugging handling context.
+   Copyright (C) 2002-2011, 2014, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <search.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libdwP.h"
+#include "cfi.h"
+
+
+static void
+noop_free (void *arg __attribute__ ((unused)))
+{
+}
+
+
+static void
+cu_free (void *arg)
+{
+  struct Dwarf_CU *p = (struct Dwarf_CU *) arg;
+
+  Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
+
+  tdestroy (p->locs, noop_free);
+}
+
+
+int
+dwarf_end (Dwarf *dwarf)
+{
+  if (dwarf != NULL)
+    {
+      if (dwarf->cfi != NULL)
+	/* Clean up the CFI cache.  */
+	__libdw_destroy_frame_cache (dwarf->cfi);
+
+      Dwarf_Sig8_Hash_free (&dwarf->sig8_hash);
+
+      /* The search tree for the CUs.  NB: the CU data itself is
+	 allocated separately, but the abbreviation hash tables need
+	 to be handled.  */
+      tdestroy (dwarf->cu_tree, cu_free);
+      tdestroy (dwarf->tu_tree, cu_free);
+
+      /* Search tree for macro opcode tables.  */
+      tdestroy (dwarf->macro_ops, noop_free);
+
+      /* Search tree for decoded .debug_lines units.  */
+      tdestroy (dwarf->files_lines, noop_free);
+
+      struct libdw_memblock *memp = dwarf->mem_tail;
+      /* The first block is allocated together with the Dwarf object.  */
+      while (memp->prev != NULL)
+	{
+	  struct libdw_memblock *prevp = memp->prev;
+	  free (memp);
+	  memp = prevp;
+	}
+
+      /* Free the pubnames helper structure.  */
+      free (dwarf->pubnames_sets);
+
+      /* Free the ELF descriptor if necessary.  */
+      if (dwarf->free_elf)
+	elf_end (dwarf->elf);
+
+      /* Free the fake location list CU.  */
+      if (dwarf->fake_loc_cu != NULL)
+	{
+	  cu_free (dwarf->fake_loc_cu);
+	  free (dwarf->fake_loc_cu);
+	}
+
+      /* Did we find and allocate the alt Dwarf ourselves?  */
+      if (dwarf->alt_fd != -1)
+	{
+	  INTUSE(dwarf_end) (dwarf->alt_dwarf);
+	  close (dwarf->alt_fd);
+	}
+
+      /* Free the context descriptor.  */
+      free (dwarf);
+    }
+
+  return 0;
+}
+INTDEF(dwarf_end)
diff --git a/libdw/dwarf_entry_breakpoints.c b/libdw/dwarf_entry_breakpoints.c
new file mode 100644
index 0000000..c3c0f39
--- /dev/null
+++ b/libdw/dwarf_entry_breakpoints.c
@@ -0,0 +1,163 @@
+/* Find entry breakpoint locations for a function.
+   Copyright (C) 2005-2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "libdwP.h"
+#include <dwarf.h>
+#include <stdlib.h>
+
+
+/* Add one breakpoint location to the result vector.  */
+static inline int
+add_bkpt (Dwarf_Addr pc, Dwarf_Addr **bkpts, int *pnbkpts)
+{
+  Dwarf_Addr *newlist = realloc (*bkpts, ++(*pnbkpts) * sizeof newlist[0]);
+  if (newlist == NULL)
+    {
+      free (*bkpts);
+      *bkpts = NULL;
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return -1;
+    }
+  newlist[*pnbkpts - 1] = pc;
+  *bkpts = newlist;
+  return *pnbkpts;
+}
+
+/* Fallback result, break at the entrypc/lowpc value.  */
+static inline int
+entrypc_bkpt (Dwarf_Die *die, Dwarf_Addr **bkpts, int *pnbkpts)
+{
+  Dwarf_Addr pc;
+  return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc, bkpts, pnbkpts);
+}
+
+/* Search a contiguous PC range for prologue-end markers.
+   If DWARF, look for proper markers.
+   Failing that, if ADHOC, look for the ad hoc convention.  */
+static inline int
+search_range (Dwarf_Addr low, Dwarf_Addr high,
+	      bool dwarf, bool adhoc,
+              Dwarf_Lines *lines, size_t nlines,
+              Dwarf_Addr **bkpts, int *pnbkpts)
+{
+      size_t l = 0, u = nlines;
+      while (l < u)
+	{
+	  size_t idx = (l + u) / 2;
+	  if (lines->info[idx].addr < low)
+	    l = idx + 1;
+	  else if (lines->info[idx].addr > low)
+	    u = idx;
+	  else if (lines->info[idx].end_sequence)
+	    l = idx + 1;
+	  else
+	    {
+	      l = idx;
+	      break;
+	    }
+	}
+      if (l < u)
+	{
+	  if (dwarf)
+	    for (size_t i = l; i < u && lines->info[i].addr < high; ++i)
+	      if (lines->info[i].prologue_end
+		  && add_bkpt (lines->info[i].addr, bkpts, pnbkpts) < 0)
+		return -1;
+	  if (adhoc && *pnbkpts == 0)
+	    while (++l < nlines && lines->info[l].addr < high)
+	      if (!lines->info[l].end_sequence)
+		return add_bkpt (lines->info[l].addr, bkpts, pnbkpts);
+	  return *pnbkpts;
+	}
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+}
+
+int
+dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts)
+{
+  int nbkpts = 0;
+  *bkpts = NULL;
+
+  /* Fetch the CU's line records to look for this DIE's addresses.  */
+  Dwarf_Die cudie = CUDIE (die->cu);
+  Dwarf_Lines *lines;
+  size_t nlines;
+  if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
+    {
+      int error = INTUSE (dwarf_errno) ();
+      if (error == 0)		/* CU has no DW_AT_stmt_list.  */
+	return entrypc_bkpt (die, bkpts, &nbkpts);
+      __libdw_seterrno (error);
+      return -1;
+    }
+
+  /* Search each contiguous address range for DWARF prologue_end markers.  */
+
+  Dwarf_Addr base;
+  Dwarf_Addr begin;
+  Dwarf_Addr end;
+  ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end);
+  if (offset < 0)
+    return -1;
+
+  /* Most often there is a single contiguous PC range for the DIE.  */
+  if (offset == 1)
+    return search_range (begin, end, true, true, lines, nlines, bkpts, &nbkpts)
+        ?: entrypc_bkpt (die, bkpts, &nbkpts);
+
+  Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
+  Dwarf_Addr highpc = (Dwarf_Addr) -1l;
+  while (offset > 0)
+    {
+      /* We have an address range entry.  */
+      if (search_range (begin, end, true, false,
+                        lines, nlines, bkpts, &nbkpts) < 0)
+	return -1;
+
+      if (begin < lowpc)
+	{
+	  lowpc = begin;
+	  highpc = end;
+	}
+
+      offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end);
+    }
+
+  /* If we didn't find any proper DWARF markers, then look in the
+     lowest-addressed range for an ad hoc marker.  Failing that,
+     fall back to just using the entrypc value.  */
+  return (nbkpts
+	  ?: (lowpc == (Dwarf_Addr) -1l ? 0
+	      : search_range (lowpc, highpc, false, true,
+	                      lines, nlines, bkpts, &nbkpts))
+	  ?: entrypc_bkpt (die, bkpts, &nbkpts));
+}
diff --git a/libdw/dwarf_entrypc.c b/libdw/dwarf_entrypc.c
new file mode 100644
index 0000000..0ef3b0e
--- /dev/null
+++ b/libdw/dwarf_entrypc.c
@@ -0,0 +1,48 @@
+/* Return entry PC attribute of DIE.
+   Copyright (C) 2003, 2005 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_entrypc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+{
+  Dwarf_Attribute attr_mem;
+
+  return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_entry_pc,
+						     &attr_mem)
+				 ?: INTUSE(dwarf_attr) (die, DW_AT_low_pc,
+							&attr_mem),
+				 return_addr);
+}
+INTDEF(dwarf_entrypc)
diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c
new file mode 100644
index 0000000..939ec04
--- /dev/null
+++ b/libdw/dwarf_error.c
@@ -0,0 +1,124 @@
+/* Retrieve ELF descriptor used for DWARF access.
+   Copyright (C) 2002, 2003, 2004, 2005, 2009, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stddef.h>
+
+#include "libdwP.h"
+
+
+/* The error number.  */
+static __thread int global_error;
+
+
+int
+dwarf_errno (void)
+{
+  int result = global_error;
+  global_error = DWARF_E_NOERROR;
+  return result;
+}
+INTDEF(dwarf_errno)
+
+
+/* XXX For now we use string pointers.  Once the table stablelizes
+   make it more DSO-friendly.  */
+static const char *errmsgs[] =
+  {
+    [DWARF_E_NOERROR] = N_("no error"),
+    [DWARF_E_UNKNOWN_ERROR] = N_("unknown error"),
+    [DWARF_E_INVALID_ACCESS] = N_("invalid access"),
+    [DWARF_E_NO_REGFILE] = N_("no regular file"),
+    [DWARF_E_IO_ERROR] = N_("I/O error"),
+    [DWARF_E_INVALID_ELF] = N_("invalid ELF file"),
+    [DWARF_E_NO_DWARF] = N_("no DWARF information"),
+    [DWARF_E_COMPRESSED_ERROR] = N_("cannot decompress DWARF"),
+    [DWARF_E_NOELF] = N_("no ELF file"),
+    [DWARF_E_GETEHDR_ERROR] = N_("cannot get ELF header"),
+    [DWARF_E_NOMEM] = N_("out of memory"),
+    [DWARF_E_UNIMPL] = N_("not implemented"),
+    [DWARF_E_INVALID_CMD] = N_("invalid command"),
+    [DWARF_E_INVALID_VERSION] = N_("invalid version"),
+    [DWARF_E_INVALID_FILE] = N_("invalid file"),
+    [DWARF_E_NO_ENTRY] = N_("no entries found"),
+    [DWARF_E_INVALID_DWARF] = N_("invalid DWARF"),
+    [DWARF_E_NO_STRING] = N_("no string data"),
+    [DWARF_E_NO_ADDR] = N_("no address value"),
+    [DWARF_E_NO_CONSTANT] = N_("no constant value"),
+    [DWARF_E_NO_REFERENCE] = N_("no reference value"),
+    [DWARF_E_INVALID_REFERENCE] = N_("invalid reference value"),
+    [DWARF_E_NO_DEBUG_LINE] = N_(".debug_line section missing"),
+    [DWARF_E_INVALID_DEBUG_LINE] = N_("invalid .debug_line section"),
+    [DWARF_E_TOO_BIG] = N_("debug information too big"),
+    [DWARF_E_VERSION] = N_("invalid DWARF version"),
+    [DWARF_E_INVALID_DIR_IDX] = N_("invalid directory index"),
+    [DWARF_E_ADDR_OUTOFRANGE] = N_("address out of range"),
+    [DWARF_E_NO_LOCLIST] = N_("no location list value"),
+    [DWARF_E_NO_BLOCK] = N_("no block data"),
+    [DWARF_E_INVALID_LINE_IDX] = N_("invalid line index"),
+    [DWARF_E_INVALID_ARANGE_IDX] = N_("invalid address range index"),
+    [DWARF_E_NO_MATCH] = N_("no matching address range"),
+    [DWARF_E_NO_FLAG] = N_("no flag value"),
+    [DWARF_E_INVALID_OFFSET] = N_("invalid offset"),
+    [DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"),
+    [DWARF_E_INVALID_CFI] = N_("invalid CFI section"),
+    [DWARF_E_NO_ALT_DEBUGLINK] = N_("no alternative debug link found"),
+    [DWARF_E_INVALID_OPCODE] = N_("invalid opcode"),
+    [DWARF_E_NOT_CUDIE] = N_("not a CU (unit) DIE"),
+    [DWARF_E_UNKNOWN_LANGUAGE] = N_("unknown language code")
+  };
+#define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0]))
+
+
+void
+internal_function
+__libdw_seterrno (int value)
+{
+  global_error = (value >= 0 && value < (int) nerrmsgs
+		  ? value : DWARF_E_UNKNOWN_ERROR);
+}
+
+
+const char *
+dwarf_errmsg (int error)
+{
+  int last_error = global_error;
+
+  if (error == 0)
+    return last_error != 0 ? _(errmsgs[last_error]) : NULL;
+  else if (error < -1 || error >= (int) nerrmsgs)
+    return _(errmsgs[DWARF_E_UNKNOWN_ERROR]);
+
+  return _(errmsgs[error == -1 ? last_error : error]);
+}
+INTDEF(dwarf_errmsg)
diff --git a/libdw/dwarf_filesrc.c b/libdw/dwarf_filesrc.c
new file mode 100644
index 0000000..d866ce7
--- /dev/null
+++ b/libdw/dwarf_filesrc.c
@@ -0,0 +1,51 @@
+/* Find source file information.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+const char *
+dwarf_filesrc (Dwarf_Files *file, size_t idx, Dwarf_Word *mtime,
+	       Dwarf_Word *length)
+{
+  if (file == NULL || idx >= file->nfiles)
+    return NULL;
+
+  if (mtime != NULL)
+    *mtime = file->info[idx].mtime;
+
+  if (length != NULL)
+    *length = file->info[idx].length;
+
+  return file->info[idx].name;
+}
diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c
new file mode 100644
index 0000000..ddc4838
--- /dev/null
+++ b/libdw/dwarf_formaddr.c
@@ -0,0 +1,57 @@
+/* Return address represented by attribute.
+   Copyright (C) 2003-2010 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
+{
+  if (attr == NULL)
+    return -1;
+
+  if (unlikely (attr->form != DW_FORM_addr))
+    {
+      __libdw_seterrno (DWARF_E_NO_ADDR);
+      return -1;
+    }
+
+  if (__libdw_read_address (attr->cu->dbg,
+			    cu_sec_idx (attr->cu), attr->valp,
+			    attr->cu->address_size, return_addr))
+    return -1;
+
+  return 0;
+}
+INTDEF(dwarf_formaddr)
diff --git a/libdw/dwarf_formblock.c b/libdw/dwarf_formblock.c
new file mode 100644
index 0000000..13f9e72
--- /dev/null
+++ b/libdw/dwarf_formblock.c
@@ -0,0 +1,93 @@
+/* Return block represented by attribute.
+   Copyright (C) 2004-2010, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block)
+{
+  if (attr == NULL)
+    return -1;
+
+  const unsigned char *datap = attr->valp;
+  const unsigned char *endp = attr->cu->endp;
+
+  switch (attr->form)
+    {
+    case DW_FORM_block1:
+      if (unlikely (endp - datap < 1))
+	goto invalid;
+      return_block->length = *(uint8_t *) attr->valp;
+      return_block->data = attr->valp + 1;
+      break;
+
+    case DW_FORM_block2:
+      if (unlikely (endp - datap < 2))
+	goto invalid;
+      return_block->length = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
+      return_block->data = attr->valp + 2;
+      break;
+
+    case DW_FORM_block4:
+      if (unlikely (endp - datap < 4))
+	goto invalid;
+      return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+      return_block->data = attr->valp + 4;
+      break;
+
+    case DW_FORM_block:
+    case DW_FORM_exprloc:
+      if (unlikely (endp - datap < 1))
+	goto invalid;
+      get_uleb128 (return_block->length, datap, endp);
+      return_block->data = (unsigned char *) datap;
+      break;
+
+    default:
+      __libdw_seterrno (DWARF_E_NO_BLOCK);
+      return -1;
+    }
+
+  if (unlikely (return_block->length > (size_t) (endp - return_block->data)))
+    {
+      /* Block does not fit.  */
+    invalid:
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  return 0;
+}
+INTDEF(dwarf_formblock)
diff --git a/libdw/dwarf_formflag.c b/libdw/dwarf_formflag.c
new file mode 100644
index 0000000..b48ede4
--- /dev/null
+++ b/libdw/dwarf_formflag.c
@@ -0,0 +1,59 @@
+/* Return flag represented by attribute.
+   Copyright (C) 2004-2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_formflag (Dwarf_Attribute *attr, bool *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);
+      return -1;
+    }
+
+  *return_bool = *attr->valp != 0;
+
+  return 0;
+}
diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c
new file mode 100644
index 0000000..2240a25
--- /dev/null
+++ b/libdw/dwarf_formref.c
@@ -0,0 +1,110 @@
+/* Return reference offset represented by attribute.
+   Copyright (C) 2003-2010, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+int
+internal_function
+__libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
+{
+  const unsigned char *datap = attr->valp;
+  const unsigned char *endp = attr->cu->endp;
+
+  if (attr->valp == NULL)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_REFERENCE);
+      return -1;
+    }
+
+  switch (attr->form)
+    {
+    case DW_FORM_ref1:
+      if (datap + 1 > endp)
+	{
+	invalid:
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	  return -1;
+	}
+      *return_offset = *attr->valp;
+      break;
+
+    case DW_FORM_ref2:
+      if (datap + 2 > endp)
+	goto invalid;
+      *return_offset = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
+    case DW_FORM_ref4:
+      if (datap + 4 > endp)
+	goto invalid;
+      *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
+    case DW_FORM_ref8:
+      if (datap + 8 > endp)
+	goto invalid;
+      *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
+    case DW_FORM_ref_udata:
+      if (datap + 1 > endp)
+	goto invalid;
+      get_uleb128 (*return_offset, datap, endp);
+      break;
+
+    case DW_FORM_ref_addr:
+    case DW_FORM_ref_sig8:
+    case DW_FORM_GNU_ref_alt:
+      /* These aren't handled by dwarf_formref, only by dwarf_formref_die.  */
+      __libdw_seterrno (DWARF_E_INVALID_REFERENCE);
+      return -1;
+
+    default:
+      __libdw_seterrno (DWARF_E_NO_REFERENCE);
+      return -1;
+    }
+
+  return 0;
+}
+
+/* This is the old public entry point.
+   It is now deprecated in favor of dwarf_formref_die.  */
+int
+dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
+{
+  if (attr == NULL)
+    return -1;
+
+  return __libdw_formref (attr, return_offset);
+}
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
new file mode 100644
index 0000000..704816f
--- /dev/null
+++ b/libdw/dwarf_formref_die.c
@@ -0,0 +1,119 @@
+/* Look up the DIE in a reference-form attribute.
+   Copyright (C) 2005-2010, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include "libdwP.h"
+#include <dwarf.h>
+
+
+Dwarf_Die *
+dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *result)
+{
+  if (attr == NULL)
+    return NULL;
+
+  struct Dwarf_CU *cu = attr->cu;
+
+  Dwarf_Off offset;
+  if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt)
+    {
+      /* This has an absolute offset.  */
+
+      uint8_t ref_size = (cu->version == 2 && attr->form == DW_FORM_ref_addr
+			  ? cu->address_size
+			  : cu->offset_size);
+
+      Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt
+			? INTUSE(dwarf_getalt) (cu->dbg) : cu->dbg);
+
+      if (dbg_ret == NULL)
+	{
+	  __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK);
+	  return NULL;
+	}
+
+      if (__libdw_read_offset (cu->dbg, dbg_ret, IDX_debug_info, attr->valp,
+			       ref_size, &offset, IDX_debug_info, 0))
+	return NULL;
+
+      return INTUSE(dwarf_offdie) (dbg_ret, offset, result);
+    }
+
+  const unsigned char *datap;
+  size_t size;
+  if (attr->form == DW_FORM_ref_sig8)
+    {
+      /* This doesn't have an offset, but instead a value we
+	 have to match in the .debug_types type unit headers.  */
+
+      uint64_t sig = read_8ubyte_unaligned (cu->dbg, attr->valp);
+      cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig, NULL);
+      if (cu == NULL)
+	/* Not seen before.  We have to scan through the type units.  */
+	do
+	  {
+	    cu = __libdw_intern_next_unit (attr->cu->dbg, true);
+	    if (cu == NULL)
+	      {
+		__libdw_seterrno (INTUSE(dwarf_errno) ()
+				  ?: DWARF_E_INVALID_REFERENCE);
+		return NULL;
+	      }
+	  }
+	while (cu->type_sig8 != sig);
+
+      datap = cu->dbg->sectiondata[IDX_debug_types]->d_buf;
+      size = cu->dbg->sectiondata[IDX_debug_types]->d_size;
+      offset = cu->start + cu->type_offset;
+    }
+  else
+    {
+      /* Other forms produce an offset from the CU.  */
+      if (unlikely (__libdw_formref (attr, &offset) != 0))
+	return NULL;
+
+      datap = cu->startp;
+      size = cu->endp - cu->startp;
+    }
+
+  if (unlikely (offset >= size))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  memset (result, '\0', sizeof (Dwarf_Die));
+  result->addr = (char *) datap + offset;
+  result->cu = cu;
+  return result;
+}
+INTDEF (dwarf_formref_die)
diff --git a/libdw/dwarf_formsdata.c b/libdw/dwarf_formsdata.c
new file mode 100644
index 0000000..bc2b508
--- /dev/null
+++ b/libdw/dwarf_formsdata.c
@@ -0,0 +1,96 @@
+/* Return signed constant represented by attribute.
+   Copyright (C) 2003, 2005, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_sval)
+{
+  if (attr == NULL)
+    return -1;
+
+  const unsigned char *datap = attr->valp;
+  const unsigned char *endp = attr->cu->endp;
+
+  switch (attr->form)
+    {
+    case DW_FORM_data1:
+      if (datap + 1 > endp)
+	{
+	invalid:
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	  return -1;
+	}
+      *return_sval = (signed char) *attr->valp;
+      break;
+
+    case DW_FORM_data2:
+      if (datap + 2 > endp)
+	goto invalid;
+      *return_sval = read_2sbyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
+    case DW_FORM_data4:
+      if (datap + 4 > endp)
+	goto invalid;
+      *return_sval = read_4sbyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
+    case DW_FORM_data8:
+      if (datap + 8 > endp)
+	goto invalid;
+      *return_sval = read_8sbyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
+    case DW_FORM_sdata:
+      if (datap + 1 > endp)
+	goto invalid;
+      get_sleb128 (*return_sval, datap, endp);
+      break;
+
+    case DW_FORM_udata:
+      if (datap + 1 > endp)
+	goto invalid;
+      get_uleb128 (*return_sval, datap, endp);
+      break;
+
+    default:
+      __libdw_seterrno (DWARF_E_NO_CONSTANT);
+      return -1;
+    }
+
+  return 0;
+}
+INTDEF(dwarf_formsdata)
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
new file mode 100644
index 0000000..4eae0ed
--- /dev/null
+++ b/libdw/dwarf_formstring.c
@@ -0,0 +1,76 @@
+/* Return string associated with given attribute.
+   Copyright (C) 2003-2010, 2013, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+const char *
+dwarf_formstring (Dwarf_Attribute *attrp)
+{
+  /* Ignore earlier errors.  */
+  if (attrp == NULL)
+    return NULL;
+
+  /* We found it.  Now determine where the string is stored.  */
+  if (attrp->form == DW_FORM_string)
+    /* A simple inlined string.  */
+    return (const char *) attrp->valp;
+
+  Dwarf *dbg = attrp->cu->dbg;
+  Dwarf *dbg_ret = (attrp->form == DW_FORM_GNU_strp_alt
+		    ? INTUSE(dwarf_getalt) (dbg) : dbg);
+
+  if (unlikely (dbg_ret == NULL))
+    {
+      __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK);
+      return NULL;
+    }
+
+
+  if (unlikely (attrp->form != DW_FORM_strp
+		   && attrp->form != DW_FORM_GNU_strp_alt)
+      || dbg_ret->sectiondata[IDX_debug_str] == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NO_STRING);
+      return NULL;
+    }
+
+  uint64_t off;
+  if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp,
+			   attrp->cu->offset_size, &off, IDX_debug_str, 1))
+    return NULL;
+
+  return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off;
+}
+INTDEF(dwarf_formstring)
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
new file mode 100644
index 0000000..e41981a
--- /dev/null
+++ b/libdw/dwarf_formudata.c
@@ -0,0 +1,231 @@
+/* Return unsigned constant represented by attribute.
+   Copyright (C) 2003-2012, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#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, attr->cu->dbg,
+			       cu_sec_idx (attr->cu), attr->valp,
+			       attr->cu->offset_size, &offset, sec_index, 0))
+	return NULL;
+    }
+  else if (attr->cu->version > 3)
+    goto invalid;
+  else
+    switch (attr->form)
+      {
+      case DW_FORM_data4:
+      case DW_FORM_data8:
+	if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
+				 cu_sec_idx (attr->cu),
+				 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 (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
+{
+  if (attr == NULL)
+    return -1;
+
+  const unsigned char *datap = attr->valp;
+  const unsigned char *endp = attr->cu->endp;
+
+  switch (attr->form)
+    {
+    case DW_FORM_data1:
+      if (datap + 1 > endp)
+	{
+	invalid:
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	  return -1;
+	}
+      *return_uval = *attr->valp;
+      break;
+
+    case DW_FORM_data2:
+      if (datap + 2 > endp)
+	goto invalid;
+      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
+      break;
+
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+    case DW_FORM_sec_offset:
+      /* Before DWARF4 data4 and data8 are pure constants unless the
+	 attribute also allows offsets (*ptr classes), since DWARF4
+	 they are always just constants (start_scope is special though,
+	 since it only could express a rangelist since DWARF4).  */
+      if (attr->form == DW_FORM_sec_offset
+	  || (attr->cu->version < 4 && attr->code != DW_AT_start_scope))
+	{
+	  switch (attr->code)
+	    {
+	    case DW_AT_data_member_location:
+	    case DW_AT_frame_base:
+	    case DW_AT_location:
+	    case DW_AT_return_addr:
+	    case DW_AT_segment:
+	    case DW_AT_static_link:
+	    case DW_AT_string_length:
+	    case DW_AT_use_location:
+	    case DW_AT_vtable_elem_location:
+	      /* loclistptr */
+	      if (__libdw_formptr (attr, IDX_debug_loc,
+				   DWARF_E_NO_LOCLIST, NULL,
+				   return_uval) == NULL)
+		return -1;
+	      break;
+
+	    case DW_AT_macro_info:
+	      /* macptr into .debug_macinfo */
+	      if (__libdw_formptr (attr, IDX_debug_macinfo,
+				   DWARF_E_NO_ENTRY, NULL,
+				   return_uval) == NULL)
+		return -1;
+	      break;
+
+	    case DW_AT_GNU_macros:
+	      /* macptr into .debug_macro */
+	      if (__libdw_formptr (attr, IDX_debug_macro,
+				   DWARF_E_NO_ENTRY, NULL,
+				   return_uval) == NULL)
+		return -1;
+	      break;
+
+	    case DW_AT_ranges:
+	    case DW_AT_start_scope:
+	      /* rangelistptr */
+	      if (__libdw_formptr (attr, IDX_debug_ranges,
+				   DWARF_E_NO_DEBUG_RANGES, NULL,
+				   return_uval) == NULL)
+		return -1;
+	      break;
+
+	    case DW_AT_stmt_list:
+	      /* lineptr */
+	      if (__libdw_formptr (attr, IDX_debug_line,
+				   DWARF_E_NO_DEBUG_LINE, NULL,
+				   return_uval) == NULL)
+		return -1;
+	      break;
+
+	    default:
+	      /* sec_offset can only be used by one of the above attrs.  */
+	      if (attr->form == DW_FORM_sec_offset)
+		{
+		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+		  return -1;
+		}
+
+	      /* Not one of the special attributes, just a constant.  */
+	      if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
+					attr->valp,
+					attr->form == DW_FORM_data4 ? 4 : 8,
+					return_uval))
+		return -1;
+	      break;
+	    }
+	}
+      else
+	{
+	  /* We are dealing with a constant data4 or data8.  */
+	  if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
+				    attr->valp,
+				    attr->form == DW_FORM_data4 ? 4 : 8,
+				    return_uval))
+	    return -1;
+	}
+      break;
+
+    case DW_FORM_sdata:
+      if (datap + 1 > endp)
+	goto invalid;
+      get_sleb128 (*return_uval, datap, endp);
+      break;
+
+    case DW_FORM_udata:
+      if (datap + 1 > endp)
+	goto invalid;
+      get_uleb128 (*return_uval, datap, endp);
+      break;
+
+    default:
+      __libdw_seterrno (DWARF_E_NO_CONSTANT);
+      return -1;
+    }
+
+  return 0;
+}
+INTDEF(dwarf_formudata)
diff --git a/libdw/dwarf_frame_cfa.c b/libdw/dwarf_frame_cfa.c
new file mode 100644
index 0000000..07f998c
--- /dev/null
+++ b/libdw/dwarf_frame_cfa.c
@@ -0,0 +1,77 @@
+/* Get CFA expression for frame.
+   Copyright (C) 2009-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "cfi.h"
+#include <dwarf.h>
+#include <stdlib.h>
+
+int
+dwarf_frame_cfa (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, 4,
+	 &fs->cache->expr_tree, &fs->cfa_data.expr, false, false,
+	 ops, nops, IDX_debug_frame);
+      break;
+
+    case cfa_invalid:
+      __libdw_seterrno (DWARF_E_INVALID_CFI);
+      result = -1;
+      break;
+
+    default:
+      abort ();
+    }
+
+  return result;
+}
diff --git a/libdw/dwarf_frame_info.c b/libdw/dwarf_frame_info.c
new file mode 100644
index 0000000..9ba560f
--- /dev/null
+++ b/libdw/dwarf_frame_info.c
@@ -0,0 +1,50 @@
+/* Get return address register for frame.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "cfi.h"
+
+int
+dwarf_frame_info (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/libdw/dwarf_frame_register.c b/libdw/dwarf_frame_register.c
new file mode 100644
index 0000000..d0159fb
--- /dev/null
+++ b/libdw/dwarf_frame_register.c
@@ -0,0 +1,119 @@
+/* Get register location expression for frame.
+   Copyright (C) 2009-2010, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "cfi.h"
+#include <dwarf.h>
+
+int
+dwarf_frame_register (Dwarf_Frame *fs, int regno, Dwarf_Op *ops_mem,
+		      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;
+	const uint8_t *end = (fs->cache->data->d.d_buf
+			      + fs->cache->data->d.d_size);
+	get_uleb128 (block.length, p, end);
+	block.data = (void *) p;
+
+	/* Parse the expression into internal form.  */
+	if (__libdw_intern_expression (NULL,
+				       fs->cache->other_byte_order,
+				       address_size, 4,
+				       &fs->cache->expr_tree, &block,
+				       true, reg->rule == reg_val_expression,
+				       ops, nops, IDX_debug_frame) < 0)
+	  return -1;
+	break;
+      }
+    }
+
+  return 0;
+}
diff --git a/libdw/dwarf_func_inline.c b/libdw/dwarf_func_inline.c
new file mode 100644
index 0000000..1f04adf
--- /dev/null
+++ b/libdw/dwarf_func_inline.c
@@ -0,0 +1,101 @@
+/* Convenience functions for handling DWARF descriptions of inline functions.
+   Copyright (C) 2005,2006,2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+
+struct visitor_info
+{
+  void *die_addr;
+  int (*callback) (Dwarf_Die *, void *);
+  void *arg;
+};
+
+static int
+scope_visitor (unsigned int depth __attribute__ ((unused)),
+	       struct Dwarf_Die_Chain *die, void *arg)
+{
+  struct visitor_info *const v = arg;
+
+  if (INTUSE(dwarf_tag) (&die->die) != DW_TAG_inlined_subroutine)
+    return DWARF_CB_OK;
+
+  Dwarf_Attribute attr_mem;
+  Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&die->die, DW_AT_abstract_origin,
+					      &attr_mem);
+  if (attr == NULL)
+    return DWARF_CB_OK;
+
+  Dwarf_Die origin_mem;
+  Dwarf_Die *origin = INTUSE(dwarf_formref_die) (attr, &origin_mem);
+  if (origin == NULL)
+    return DWARF_CB_ABORT;
+
+  if (origin->addr != v->die_addr)
+    return DWARF_CB_OK;
+
+  return (*v->callback) (&die->die, v->arg);
+}
+
+int
+dwarf_func_inline (Dwarf_Die *func)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word val;
+  if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (func, DW_AT_inline,
+						   &attr_mem),
+			       &val) == 0)
+  switch (val)
+    {
+    case DW_INL_not_inlined:
+      return 0;
+
+    case DW_INL_declared_not_inlined:
+      return -1;
+
+    case DW_INL_inlined:
+    case DW_INL_declared_inlined:
+      return 1;
+    }
+
+  return 0;
+}
+
+int
+dwarf_func_inline_instances (Dwarf_Die *func,
+			     int (*callback) (Dwarf_Die *, void *),
+			     void *arg)
+{
+  struct visitor_info v = { func->addr, callback, arg };
+  struct Dwarf_Die_Chain cu = { .die = CUDIE (func->cu), .parent = NULL };
+  return __libdw_visit_scopes (0, &cu, NULL, &scope_visitor, NULL, &v);
+}
diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c
new file mode 100644
index 0000000..a3a68b3
--- /dev/null
+++ b/libdw/dwarf_getabbrev.c
@@ -0,0 +1,157 @@
+/* Get abbreviation at given offset.
+   Copyright (C) 2003, 2004, 2005, 2006, 2014, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+Dwarf_Abbrev *
+internal_function
+__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
+		   size_t *lengthp, Dwarf_Abbrev *result)
+{
+  /* Don't fail if there is not .debug_abbrev section.  */
+  if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
+    return NULL;
+
+  if (offset >= dbg->sectiondata[IDX_debug_abbrev]->d_size)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+      return NULL;
+    }
+
+  const unsigned char *abbrevp
+    = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset;
+
+  if (*abbrevp == '\0')
+    /* We are past the last entry.  */
+    return DWARF_END_ABBREV;
+
+  /* 7.5.3 Abbreviations Tables
+
+     [...] Each declaration begins with an unsigned LEB128 number
+     representing the abbreviation code itself.  [...]  The
+     abbreviation code is followed by another unsigned LEB128
+     number that encodes the entry's tag.  [...]
+
+     [...] Following the tag encoding is a 1-byte value that
+     determines whether a debugging information entry using this
+     abbreviation has child entries or not. [...]
+
+     [...] Finally, the child encoding is followed by a series of
+     attribute specifications. Each attribute specification
+     consists of two parts. The first part is an unsigned LEB128
+     number representing the attribute's name. The second part is
+     an unsigned LEB128 number representing the attribute's form.  */
+  const unsigned char *end = (dbg->sectiondata[IDX_debug_abbrev]->d_buf
+			      + dbg->sectiondata[IDX_debug_abbrev]->d_size);
+  const unsigned char *start_abbrevp = abbrevp;
+  unsigned int code;
+  get_uleb128 (code, abbrevp, end);
+
+  /* Check whether this code is already in the hash table.  */
+  bool foundit = false;
+  Dwarf_Abbrev *abb = NULL;
+  if (cu == NULL
+      || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL)
+    {
+      if (result == NULL)
+	abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
+      else
+	abb = result;
+    }
+  else
+    {
+      foundit = true;
+
+      if (unlikely (abb->offset != offset))
+	{
+	  /* A duplicate abbrev code at a different offset,
+	     that should never happen.  */
+	invalid:
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	  return NULL;
+	}
+
+      /* If the caller doesn't need the length we are done.  */
+      if (lengthp == NULL)
+	goto out;
+    }
+
+  /* If there is already a value in the hash table we are going to
+     overwrite its content.  This must not be a problem, since the
+     content better be the same.  */
+  abb->code = code;
+  if (abbrevp >= end)
+    goto invalid;
+  get_uleb128 (abb->tag, abbrevp, end);
+  if (abbrevp + 1 >= end)
+    goto invalid;
+  abb->has_children = *abbrevp++ == DW_CHILDREN_yes;
+  abb->attrp = (unsigned char *) abbrevp;
+  abb->offset = offset;
+
+  /* Skip over all the attributes and check rest of the abbrev is valid.  */
+  unsigned int attrname;
+  unsigned int attrform;
+  do
+    {
+      if (abbrevp >= end)
+	goto invalid;
+      get_uleb128 (attrname, abbrevp, end);
+      if (abbrevp >= end)
+	goto invalid;
+      get_uleb128 (attrform, abbrevp, end);
+    }
+  while (attrname != 0 && attrform != 0);
+
+  /* Return the length to the caller if she asked for it.  */
+  if (lengthp != NULL)
+    *lengthp = abbrevp - start_abbrevp;
+
+  /* Add the entry to the hash table.  */
+  if (cu != NULL && ! foundit)
+    (void) Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb);
+
+ out:
+  return abb;
+}
+
+
+Dwarf_Abbrev *
+dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
+{
+  return __libdw_getabbrev (die->cu->dbg, die->cu,
+			    die->cu->orig_abbrev_offset + offset, lengthp,
+			    NULL);
+}
diff --git a/libdw/dwarf_getabbrevattr.c b/libdw/dwarf_getabbrevattr.c
new file mode 100644
index 0000000..57fe363
--- /dev/null
+++ b/libdw/dwarf_getabbrevattr.c
@@ -0,0 +1,76 @@
+/* Get specific attribute of abbreviation.
+   Copyright (C) 2003, 2004, 2005, 2014, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
+		     unsigned int *formp, Dwarf_Off *offsetp)
+{
+  if (abbrev == NULL)
+    return -1;
+
+  size_t cnt = 0;
+  const unsigned char *attrp = abbrev->attrp;
+  const unsigned char *start_attrp;
+  unsigned int name;
+  unsigned int form;
+
+  do
+    {
+      start_attrp = attrp;
+
+      /* Attribute code and form are encoded as ULEB128 values.
+         Already checked when Dwarf_Abbrev was created, read unchecked.  */
+      get_uleb128_unchecked (name, attrp);
+      get_uleb128_unchecked (form, attrp);
+
+      /* If both values are zero the index is out of range.  */
+      if (name == 0 && form == 0)
+	return -1;
+    }
+  while (cnt++ < idx);
+
+  /* Store the result if requested.  */
+  if (namep != NULL)
+    *namep = name;
+  if (formp != NULL)
+    *formp = form;
+  if (offsetp != NULL)
+    *offsetp = (start_attrp - abbrev->attrp) + abbrev->offset;
+
+  return 0;
+}
diff --git a/libdw/dwarf_getabbrevcode.c b/libdw/dwarf_getabbrevcode.c
new file mode 100644
index 0000000..8691708
--- /dev/null
+++ b/libdw/dwarf_getabbrevcode.c
@@ -0,0 +1,43 @@
+/* Get abbreviation code.
+   Copyright (C) 2003 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+unsigned int
+dwarf_getabbrevcode (Dwarf_Abbrev *abbrev)
+{
+  return abbrev == NULL ? 0 : abbrev->code;
+}
diff --git a/libdw/dwarf_getabbrevtag.c b/libdw/dwarf_getabbrevtag.c
new file mode 100644
index 0000000..52aaa3f
--- /dev/null
+++ b/libdw/dwarf_getabbrevtag.c
@@ -0,0 +1,43 @@
+/* Get abbreviation tag.
+   Copyright (C) 2003 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+unsigned int
+dwarf_getabbrevtag (Dwarf_Abbrev *abbrev)
+{
+  return abbrev == NULL ? 0 : abbrev->tag;
+}
diff --git a/libdw/dwarf_getalt.c b/libdw/dwarf_getalt.c
new file mode 100644
index 0000000..3e5af15
--- /dev/null
+++ b/libdw/dwarf_getalt.c
@@ -0,0 +1,196 @@
+/* Retrieves the DWARF descriptor for debugaltlink data.
+   Copyright (C) 2014, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include "libelfP.h"
+#include "libdwelfP.h"
+#include "system.h"
+
+#include <inttypes.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+char *
+internal_function
+__libdw_filepath (int fd, const char *dir, const char *file)
+{
+  if (file == NULL)
+    return NULL;
+
+  if (file[0] == '/')
+    return strdup (file);
+
+  if (dir != NULL && dir[0] == '/')
+    {
+      size_t dirlen = strlen (dir);
+      size_t filelen = strlen (file);
+      size_t len = dirlen + 1 + filelen + 1;
+      char *path = malloc (len);
+      if (path != NULL)
+	{
+	  char *c = mempcpy (path, dir, dirlen);
+	  if (dir[dirlen - 1] != '/')
+	    *c++ = '/';
+	  mempcpy (c, file, filelen + 1);
+	}
+      return path;
+    }
+
+  if (fd >= 0)
+    {
+      /* strlen ("/proc/self/fd/") = 14 + strlen (<MAXINT>) = 10 + 1 = 25.  */
+      char devfdpath[25];
+      sprintf (devfdpath, "/proc/self/fd/%u", fd);
+      char *fdpath = realpath (devfdpath, NULL);
+      char *path = NULL;
+      char *fddir;
+      if (fdpath != NULL && fdpath[0] == '/'
+	  && (fddir = strrchr (fdpath, '/')) != NULL)
+	{
+	  *++fddir = '\0';
+	  size_t fdpathlen = strlen (fdpath);
+	  size_t dirlen = dir != NULL ? strlen (dir) : 0;
+	  size_t filelen = strlen (file);
+	  size_t len = fdpathlen + 1 + dirlen + 1 + filelen + 1;
+	  path = malloc (len);
+	  if (path != NULL)
+	    {
+	      char *c = mempcpy (path, fdpath, fdpathlen);
+	      if (dirlen > 0)
+		{
+		  c = mempcpy (c, dir, dirlen);
+		  if (dir[dirlen - 1] != '/')
+		    *c++ = '/';
+		}
+	      mempcpy (c, file, filelen + 1);
+	    }
+	}
+      free (fdpath);
+      return path;
+    }
+
+  return NULL;
+}
+
+static void
+find_debug_altlink (Dwarf *dbg)
+{
+  const char *altname;
+  const void *build_id;
+  ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
+							       &altname,
+							       &build_id);
+
+  /* Couldn't even get the debugaltlink.  It probably doesn't exist.  */
+  if (build_id_len <= 0)
+    return;
+
+  const uint8_t *id = (const uint8_t *) build_id;
+  size_t id_len = build_id_len;
+  int fd = -1;
+
+  /* We only look in the standard path.  And relative to the dbg file.  */
+#define DEBUGINFO_PATH "/usr/lib/debug"
+
+  /* We don't handle very short or really large build-ids.  We need at
+     at least 3 and allow for up to 64 (normally ids are 20 long).  */
+#define MIN_BUILD_ID_BYTES 3
+#define MAX_BUILD_ID_BYTES 64
+  if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES)
+    {
+      /* Note sizeof a string literal includes the trailing zero.  */
+      char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+		   + 2 + 1 + (MAX_BUILD_ID_BYTES - 2) * 2 + sizeof ".debug"];
+      sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/");
+      sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1],
+	       "%02" PRIx8 "/", (uint8_t) id[0]);
+      for (size_t i = 1; i < id_len; ++i)
+	sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+			  + 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]);
+      strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+		       + 3 + (id_len - 1) * 2], ".debug");
+
+      fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY));
+    }
+
+  /* Fall back on (possible relative) alt file path.  */
+  if (fd < 0)
+    {
+      char *altpath = __libdw_filepath (dbg->elf->fildes, NULL, altname);
+      if (altpath != NULL)
+	{
+	  fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
+	  free (altpath);
+	}
+    }
+
+  if (fd >= 0)
+    {
+      Dwarf *alt = dwarf_begin (fd, O_RDONLY);
+      if (alt != NULL)
+	{
+	  dbg->alt_dwarf = alt;
+	  dbg->alt_fd = fd;
+	}
+      else
+	close (fd);
+    }
+}
+
+Dwarf *
+dwarf_getalt (Dwarf *main)
+{
+  /* Only try once.  */
+  if (main == NULL || main->alt_dwarf == (void *) -1)
+    return NULL;
+
+  if (main->alt_dwarf != NULL)
+    return main->alt_dwarf;
+
+  find_debug_altlink (main);
+
+  /* If we found nothing, make sure we don't try again.  */
+  if (main->alt_dwarf == NULL)
+    {
+      main->alt_dwarf = (void *) -1;
+      return NULL;
+    }
+
+  return main->alt_dwarf;
+}
+INTDEF (dwarf_getalt)
diff --git a/libdw/dwarf_getarange_addr.c b/libdw/dwarf_getarange_addr.c
new file mode 100644
index 0000000..d383e22
--- /dev/null
+++ b/libdw/dwarf_getarange_addr.c
@@ -0,0 +1,60 @@
+/* Get address range which includes given address.
+   Copyright (C) 2004, 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libdwP.h>
+
+
+Dwarf_Arange *
+dwarf_getarange_addr (Dwarf_Aranges *aranges, Dwarf_Addr addr)
+{
+  if (aranges == NULL)
+    return NULL;
+
+  /* The ranges are sorted by address, so we can use binary search.  */
+  size_t l = 0, u = aranges->naranges;
+  while (l < u)
+    {
+      size_t idx = (l + u) / 2;
+      if (addr < aranges->info[idx].addr)
+	u = idx;
+      else if (addr > aranges->info[idx].addr
+	       && addr - aranges->info[idx].addr >= aranges->info[idx].length)
+	l = idx + 1;
+      else
+	return &aranges->info[idx];
+    }
+
+  __libdw_seterrno (DWARF_E_NO_MATCH);
+  return NULL;
+}
+INTDEF(dwarf_getarange_addr)
diff --git a/libdw/dwarf_getarangeinfo.c b/libdw/dwarf_getarangeinfo.c
new file mode 100644
index 0000000..67b6e67
--- /dev/null
+++ b/libdw/dwarf_getarangeinfo.c
@@ -0,0 +1,53 @@
+/* Return list address ranges.
+   Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libdwP.h>
+
+
+int
+dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp,
+		     Dwarf_Word *lengthp, Dwarf_Off *offsetp)
+{
+  if (arange == NULL)
+    return -1;
+
+  if (addrp != NULL)
+    *addrp = arange->addr;
+  if (lengthp != NULL)
+    *lengthp = arange->length;
+  if (offsetp != NULL)
+    *offsetp = arange->offset;
+
+  return 0;
+}
+INTDEF(dwarf_getarangeinfo)
diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c
new file mode 100644
index 0000000..4252746
--- /dev/null
+++ b/libdw/dwarf_getaranges.c
@@ -0,0 +1,274 @@
+/* Return list address ranges.
+   Copyright (C) 2000-2010 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include "libdwP.h"
+#include <dwarf.h>
+
+struct arangelist
+{
+  Dwarf_Arange arange;
+  struct arangelist *next;
+};
+
+/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers.  */
+static int
+compare_aranges (const void *a, const void *b)
+{
+  struct arangelist *const *p1 = a, *const *p2 = b;
+  struct arangelist *l1 = *p1, *l2 = *p2;
+  if (l1->arange.addr != l2->arange.addr)
+    return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
+  return 0;
+}
+
+int
+dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
+{
+  if (dbg == NULL)
+    return -1;
+
+  if (dbg->aranges != NULL)
+    {
+      *aranges = dbg->aranges;
+      if (naranges != NULL)
+	*naranges = dbg->aranges->naranges;
+      return 0;
+    }
+
+  if (dbg->sectiondata[IDX_debug_aranges] == NULL)
+    {
+      /* No such section.  */
+      *aranges = NULL;
+      if (naranges != NULL)
+	*naranges = 0;
+      return 0;
+    }
+
+  if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
+    return -1;
+
+  struct arangelist *arangelist = NULL;
+  unsigned int narangelist = 0;
+
+  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 unsigned char *hdrstart = readp;
+
+      /* Each entry starts with a header:
+
+	 1. A 4-byte or 12-byte length containing the length of the
+	 set of entries for this compilation unit, not including the
+	 length field itself. [...]
+
+	 2. A 2-byte version identifier containing the value 2 for
+	 DWARF Version 2.1.
+
+	 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
+
+	 4. A 1-byte unsigned integer containing the size in bytes of
+	 an address (or the offset portion of an address for segmented
+	 addressing) on the target system.
+
+	 5. A 1-byte unsigned integer containing the size in bytes of
+	 a segment descriptor on the target system.  */
+      if (unlikely (readp + 4 > readendp))
+	goto invalid;
+
+      Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
+      unsigned int length_bytes = 4;
+      if (length == DWARF3_LENGTH_64_BIT)
+	{
+	  if (unlikely (readp + 8 > readendp))
+	    goto invalid;
+
+	  length = read_8ubyte_unaligned_inc (dbg, readp);
+	  length_bytes = 8;
+	}
+      else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
+			 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
+	goto invalid;
+
+      if (unlikely (readp + 2 > readendp))
+	goto invalid;
+
+      unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
+      if (version != 2)
+	{
+	invalid:
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	fail:
+	  while (arangelist != NULL)
+	    {
+	      struct arangelist *next = arangelist->next;
+	      free (arangelist);
+	      arangelist = next;
+	    }
+	  return -1;
+	}
+
+      Dwarf_Word offset = 0;
+      if (__libdw_read_offset_inc (dbg,
+				   IDX_debug_aranges, &readp,
+				   length_bytes, &offset, IDX_debug_info, 4))
+	goto fail;
+
+      unsigned int address_size = *readp++;
+      if (unlikely (address_size != 4 && address_size != 8))
+	goto invalid;
+
+      /* We don't actually support segment selectors.  */
+      unsigned int segment_size = *readp++;
+      if (segment_size != 0)
+	goto invalid;
+
+      /* Round the address to the next multiple of 2*address_size.  */
+      readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
+		% (2 * address_size));
+
+      while (1)
+	{
+	  Dwarf_Word range_address;
+	  Dwarf_Word range_length;
+
+	  if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
+					address_size, &range_address))
+	    goto fail;
+
+	  if (readp + address_size > readendp)
+	    goto invalid;
+
+	  if (address_size == 4)
+	    range_length = read_4ubyte_unaligned_inc (dbg, readp);
+	  else
+	    range_length = read_8ubyte_unaligned_inc (dbg, readp);
+
+	  /* Two zero values mark the end.  */
+	  if (range_address == 0 && range_length == 0)
+	    break;
+
+	  /* We don't use alloca for these temporary structures because
+	     the total number of them can be quite large.  */
+	  struct arangelist *new_arange = malloc (sizeof *new_arange);
+	  if (unlikely (new_arange == NULL))
+	    {
+	      __libdw_seterrno (DWARF_E_NOMEM);
+	      goto fail;
+	    }
+
+	  new_arange->arange.addr = range_address;
+	  new_arange->arange.length = range_length;
+
+	  /* We store the actual CU DIE offset, not the CU header offset.  */
+	  const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
+				   + offset);
+	  unsigned int offset_size;
+	  if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT)
+	    offset_size = 8;
+	  else
+	    offset_size = 4;
+	  new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
+								 offset_size,
+								 false);
+
+	  new_arange->next = arangelist;
+	  arangelist = new_arange;
+	  ++narangelist;
+
+	  /* Sanity-check the data.  */
+	  if (unlikely (new_arange->arange.offset
+			>= dbg->sectiondata[IDX_debug_info]->d_size))
+	    goto invalid;
+	}
+    }
+
+  if (narangelist == 0)
+    {
+      assert (arangelist == NULL);
+      if (naranges != NULL)
+	*naranges = 0;
+      *aranges = NULL;
+      return 0;
+    }
+
+  /* Allocate the array for the result.  */
+  void *buf = libdw_alloc (dbg, Dwarf_Aranges,
+			   sizeof (Dwarf_Aranges)
+			   + narangelist * sizeof (Dwarf_Arange), 1);
+
+  /* First use the buffer for the pointers, and sort the entries.
+     We'll write the pointers in the end of the buffer, and then
+     copy into the buffer from the beginning so the overlap works.  */
+  assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
+  struct arangelist **sortaranges
+    = (buf + sizeof (Dwarf_Aranges)
+       + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
+
+  /* The list is in LIFO order and usually they come in clumps with
+     ascending addresses.  So fill from the back to probably start with
+     runs already in order before we sort.  */
+  unsigned int i = narangelist;
+  while (i-- > 0)
+    {
+      sortaranges[i] = arangelist;
+      arangelist = arangelist->next;
+    }
+  assert (arangelist == NULL);
+
+  /* Sort by ascending address.  */
+  qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
+
+  /* Now that they are sorted, put them in the final array.
+     The buffers overlap, so we've clobbered the early elements
+     of SORTARANGES by the time we're reading the later ones.  */
+  *aranges = buf;
+  (*aranges)->dbg = dbg;
+  (*aranges)->naranges = narangelist;
+  dbg->aranges = *aranges;
+  if (naranges != NULL)
+    *naranges = narangelist;
+  for (i = 0; i < narangelist; ++i)
+    {
+      struct arangelist *elt = sortaranges[i];
+      (*aranges)->info[i] = elt->arange;
+      free (elt);
+    }
+
+  return 0;
+}
+INTDEF(dwarf_getaranges)
diff --git a/libdw/dwarf_getattrcnt.c b/libdw/dwarf_getattrcnt.c
new file mode 100644
index 0000000..a05976d
--- /dev/null
+++ b/libdw/dwarf_getattrcnt.c
@@ -0,0 +1,61 @@
+/* Get number of attributes of abbreviation.
+   Copyright (C) 2003, 2004, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_getattrcnt (Dwarf_Abbrev *abbrev, size_t *attrcntp)
+{
+  if (abbrev == NULL)
+    return -1;
+
+  const unsigned char *abbrevp = abbrev->attrp;
+
+  /* Skip over all the attributes and count them while doing so.  */
+  int attrcnt = 0;
+  unsigned int attrname;
+  unsigned int attrform;
+  do
+    {
+      /* We can use unchecked since they were checked when the Dwrf_Abbrev
+	 was created.  */
+      get_uleb128_unchecked (attrname, abbrevp);
+      get_uleb128_unchecked (attrform, abbrevp);
+    }
+  while (attrname != 0 && attrform != 0 && ++attrcnt);
+
+  *attrcntp = attrcnt;
+
+  return 0;
+}
diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c
new file mode 100644
index 0000000..7f55faf
--- /dev/null
+++ b/libdw/dwarf_getattrs.c
@@ -0,0 +1,110 @@
+/* Get attributes of the DIE.
+   Copyright (C) 2004, 2005, 2008, 2009, 2014, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+ptrdiff_t
+dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
+		void *arg, ptrdiff_t offset)
+{
+  if (die == NULL)
+    return -1l;
+
+  if (unlikely (offset == 1))
+    return 1;
+
+  const unsigned char *die_addr;
+
+  /* Find the abbreviation entry.  */
+  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &die_addr);
+
+  if (unlikely (abbrevp == DWARF_END_ABBREV))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1l;
+    }
+
+  /* This is where the attributes start.  */
+  const unsigned char *attrp = abbrevp->attrp;
+  const unsigned char *const offset_attrp = abbrevp->attrp + offset;
+
+  /* Go over the list of attributes.  */
+  while (1)
+    {
+      /* Get attribute name and form.  Dwarf_Abbrev was checked when
+	 created, so we can read unchecked.  */
+      Dwarf_Attribute attr;
+      const unsigned char *remembered_attrp = attrp;
+
+      get_uleb128_unchecked (attr.code, attrp);
+      get_uleb128_unchecked (attr.form, attrp);
+
+      /* We can stop if we found the attribute with value zero.  */
+      if (attr.code == 0 && attr.form == 0)
+	/* Do not return 0 here - there would be no way to
+	   distinguish this value from the attribute at offset 0.
+	   Instead we return +1 which would never be a valid
+	   offset of an attribute.  */
+        return 1l;
+
+      /* If we are not to OFFSET_ATTRP yet, we just have to skip
+	 the values of the intervening attributes.  */
+      if (remembered_attrp >= offset_attrp)
+	{
+	  /* Fill in the rest.  */
+	  attr.valp = (unsigned char *) die_addr;
+	  attr.cu = die->cu;
+
+	  /* Now call the callback function.  */
+	  if (callback (&attr, arg) != DWARF_CB_OK)
+	    /* Return the offset of the start of the attribute, so that
+	       dwarf_getattrs() can be restarted from this point if the
+	       caller so desires.  */
+	    return remembered_attrp - abbrevp->attrp;
+	}
+
+      /* Skip over the rest of this attribute (if there is any).  */
+      if (attr.form != 0)
+	{
+	  size_t len = __libdw_form_val_len (die->cu, attr.form, die_addr);
+	  if (unlikely (len == (size_t) -1l))
+	    /* Something wrong with the file.  */
+	    return -1l;
+
+	  // __libdw_form_val_len will have done a bounds check.
+	  die_addr += len;
+	}
+    }
+  /* NOTREACHED */
+}
diff --git a/libdw/dwarf_getcfi.c b/libdw/dwarf_getcfi.c
new file mode 100644
index 0000000..9aed403
--- /dev/null
+++ b/libdw/dwarf_getcfi.c
@@ -0,0 +1,72 @@
+/* Get CFI from DWARF file.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include "cfi.h"
+#include <dwarf.h>
+
+Dwarf_CFI *
+dwarf_getcfi (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/libdw/dwarf_getcfi_elf.c b/libdw/dwarf_getcfi_elf.c
new file mode 100644
index 0000000..315cc02
--- /dev/null
+++ b/libdw/dwarf_getcfi_elf.c
@@ -0,0 +1,336 @@
+/* Get CFI from ELF file's exception-handling info.
+   Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#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 (hdr_size < 4 || *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)
+{
+  Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
+					 ELF_T_BYTE);
+  if (data == NULL || data->d_buf == NULL)
+    {
+    invalid_hdr:
+      /* XXX might be read error or corrupt phdr */
+      __libdw_seterrno (DWARF_E_INVALID_CFI);
+      return NULL;
+    }
+
+  size_t vsize, dmax;
+  Dwarf_Addr eh_frame_ptr;
+  size_t search_table_entries = 0;
+  uint8_t search_table_encoding = 0;
+  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);
+
+  /* Make sure there is enough room for the entries in the table,
+     each entry consists of 2 encoded values.  */
+  vsize = encoded_value_size (data, ehdr->e_ident, search_table_encoding,
+			      NULL);
+  dmax = phdr->p_filesz - (search_table - (const uint8_t *) data->d_buf);
+  if (unlikely (search_table == (void *) -1l
+		|| vsize == 0
+		|| search_table_entries > (dmax / vsize) / 2))
+    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_len = phdr->p_filesz;
+	  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)
+{
+  size_t phnum;
+  if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
+    return NULL;
+
+  for (size_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 || data->d_buf == 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 && hdr_data->d_buf != NULL)
+	    {
+	      size_t vsize, dmax;
+	      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);
+	      cfi->search_table_len = hdr_data->d_size;
+
+	      /* Make sure there is enough room for the entries in the table,
+		 each entry consists of 2 encoded values.  */
+	      vsize = encoded_value_size (hdr_data, ehdr->e_ident,
+					  cfi->search_table_encoding, NULL);
+	      dmax = hdr_data->d_size - (cfi->search_table
+					 - (const uint8_t *) hdr_data->d_buf);
+	      if (unlikely (cfi->search_table == (void *) -1l
+			    || vsize == 0
+			    || cfi->search_table_entries > (dmax / vsize) / 2))
+		{
+		  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"))
+	    {
+	      if (shdr->sh_type == SHT_PROGBITS)
+		return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
+					    hdr_scn, hdr_vaddr);
+	      else
+		return NULL;
+	    }
+	}
+    }
+
+  return (void *) -1l;
+}
+
+Dwarf_CFI *
+dwarf_getcfi_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/libdw/dwarf_getelf.c b/libdw/dwarf_getelf.c
new file mode 100644
index 0000000..2d6268e
--- /dev/null
+++ b/libdw/dwarf_getelf.c
@@ -0,0 +1,47 @@
+/* Retrieve ELF descriptor used for DWARF access.
+   Copyright (C) 2002, 2004, 2007 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+
+#include "libdwP.h"
+
+
+Elf *
+dwarf_getelf (Dwarf *dwarf)
+{
+  if (dwarf == NULL)
+    /* Some error occurred before.  */
+    return NULL;
+
+  return dwarf->elf;
+}
diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c
new file mode 100644
index 0000000..b95f06f
--- /dev/null
+++ b/libdw/dwarf_getfuncs.c
@@ -0,0 +1,118 @@
+/* Get function information.
+   Copyright (C) 2005, 2013, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+struct visitor_info
+{
+  /* The user callback of dwarf_getfuncs.  */
+  int (*callback) (Dwarf_Die *, void *);
+
+  /* The user arg value to dwarf_getfuncs.  */
+  void *arg;
+
+  /* Addr of the DIE offset where to (re)start the search.  Zero for all.  */
+  void *start_addr;
+
+  /* Last subprogram DIE addr seen.  */
+  void *last_addr;
+
+  /* The CU only contains C functions.  Allows pruning of most subtrees.  */
+  bool c_cu;
+};
+
+static int
+tree_visitor (unsigned int depth __attribute__ ((unused)),
+	      struct Dwarf_Die_Chain *chain, void *arg)
+{
+  struct visitor_info *const v = arg;
+  Dwarf_Die *die = &chain->die;
+  void *start_addr = v->start_addr;
+  void *die_addr = die->addr;
+
+  /* Pure C CUs can only contain defining subprogram DIEs as direct
+     children of the CU DIE or as nested function inside a normal C
+     code constructs.  */
+  int tag = INTUSE(dwarf_tag) (die);
+  if (v->c_cu
+      && tag != DW_TAG_subprogram
+      && tag != DW_TAG_lexical_block
+      && tag != DW_TAG_inlined_subroutine)
+    {
+      chain->prune = true;
+      return DWARF_CB_OK;
+    }
+
+  /* Skip all DIEs till we found the (re)start addr.  */
+  if (start_addr != NULL)
+    {
+      if (die_addr == start_addr)
+	v->start_addr = NULL;
+      return DWARF_CB_OK;
+    }
+
+  /* If this isn't a (defining) subprogram entity, skip DIE.  */
+  if (tag != DW_TAG_subprogram
+      || INTUSE(dwarf_hasattr) (die, DW_AT_declaration))
+    return DWARF_CB_OK;
+
+  v->last_addr = die_addr;
+  return (*v->callback) (die, v->arg);
+}
+
+ptrdiff_t
+dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
+		void *arg, ptrdiff_t offset)
+{
+  if (unlikely (cudie == NULL
+		|| INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
+    return -1;
+
+  int lang = INTUSE(dwarf_srclang) (cudie);
+  bool c_cu = (lang == DW_LANG_C89
+	       || lang == DW_LANG_C
+	       || lang == DW_LANG_C99
+	       || lang == DW_LANG_C11);
+
+  struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
+  struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
+				   .parent = NULL };
+  int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v);
+
+  if (res == DWARF_CB_ABORT)
+    return (ptrdiff_t) v.last_addr;
+  else
+    return res;
+}
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
new file mode 100644
index 0000000..86a9ae7
--- /dev/null
+++ b/libdw/dwarf_getlocation.c
@@ -0,0 +1,890 @@
+/* Return location expression list.
+   Copyright (C) 2000-2010, 2013-2015 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include <search.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <libdwP.h>
+
+
+static bool
+attr_ok (Dwarf_Attribute *attr)
+{
+  if (attr == NULL)
+    return false;
+
+  /* If it is an exprloc, it is obviously OK.  */
+  if (dwarf_whatform (attr) == DW_FORM_exprloc)
+    return true;
+
+  /* Otherwise must be one of the attributes listed below.  Older
+     DWARF versions might have encoded the exprloc as block, and we
+     cannot easily distinquish attributes in the loclist class because
+     the same forms are used for different classes.  */
+  switch (attr->code)
+    {
+    case DW_AT_location:
+    case DW_AT_byte_size:
+    case DW_AT_bit_offset:
+    case DW_AT_bit_size:
+    case DW_AT_lower_bound:
+    case DW_AT_bit_stride:
+    case DW_AT_upper_bound:
+    case DW_AT_count:
+    case DW_AT_allocated:
+    case DW_AT_associated:
+    case DW_AT_data_location:
+    case DW_AT_byte_stride:
+    case DW_AT_rank:
+    case DW_AT_call_value:
+    case DW_AT_call_target:
+    case DW_AT_call_target_clobbered:
+    case DW_AT_call_data_location:
+    case DW_AT_call_data_value:
+    case DW_AT_data_member_location:
+    case DW_AT_vtable_elem_location:
+    case DW_AT_string_length:
+    case DW_AT_use_location:
+    case DW_AT_frame_base:
+    case DW_AT_return_addr:
+    case DW_AT_static_link:
+    case DW_AT_segment:
+    case DW_AT_GNU_call_site_value:
+    case DW_AT_GNU_call_site_data_value:
+    case DW_AT_GNU_call_site_target:
+    case DW_AT_GNU_call_site_target_clobbered:
+      break;
+
+    default:
+      __libdw_seterrno (DWARF_E_NO_LOCLIST);
+      return false;
+    }
+
+  return true;
+}
+
+
+struct loclist
+{
+  uint8_t atom;
+  Dwarf_Word number;
+  Dwarf_Word number2;
+  Dwarf_Word offset;
+  struct loclist *next;
+};
+
+
+static int
+loc_compare (const void *p1, const void *p2)
+{
+  const struct loc_s *l1 = (const struct loc_s *) p1;
+  const struct loc_s *l2 = (const struct loc_s *) p2;
+
+  if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
+    return -1;
+  if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
+    return 1;
+
+  return 0;
+}
+
+/* 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)
+{
+  struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
+					   sizeof (struct loc_block_s), 1);
+  const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2;
+  // Ignored, equal to op->number.  And data length already checked.
+  (void) __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word));
+  block->addr = op;
+  block->data = (unsigned char *) data;
+  block->length = op->number;
+  (void) tsearch (block, cache, loc_compare);
+}
+
+int
+dwarf_getlocation_implicit_value (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
+check_constant_offset (Dwarf_Attribute *attr,
+		       Dwarf_Op **llbuf, size_t *listlen)
+{
+  if (attr->code != DW_AT_data_member_location)
+    return 1;
+
+  switch (attr->form)
+    {
+      /* Punt for any non-constant form.  */
+    default:
+      return 1;
+
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+    case DW_FORM_sdata:
+    case DW_FORM_udata:
+      break;
+    }
+
+  /* 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, unsigned int ref_size,
+			   void **cache, const Dwarf_Block *block,
+			   bool cfap, bool valuep,
+			   Dwarf_Op **llbuf, size_t *listlen, int sec_index)
+{
+  /* Empty location expressions don't have any ops to intern.  */
+  if (block->length == 0)
+    {
+      *listlen = 0;
+      return 0;
+    }
+
+  /* Check whether we already looked at this list.  */
+  struct loc_s fake = { .addr = block->data };
+  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;
+
+  /* Stack allocate at most this many locs.  */
+#define MAX_STACK_LOCS 256
+  struct loclist stack_locs[MAX_STACK_LOCS];
+#define NEW_LOC() ({ struct loclist *ll;			\
+		     ll = (likely (n < MAX_STACK_LOCS)		\
+			   ? &stack_locs[n]			\
+			   : malloc (sizeof (struct loclist)));	\
+		     if (unlikely (ll == NULL))			\
+		       goto nomem;				\
+		     n++;					\
+		     ll->next = loclist;			\
+		     loclist = ll;				\
+		     ll; })
+
+  if (cfap)
+    {
+      /* Synthesize the operation to push the CFA before the expression.  */
+      struct loclist *newloc = NEW_LOC ();
+      newloc->atom = DW_OP_call_frame_cfa;
+      newloc->number = 0;
+      newloc->number2 = 0;
+      newloc->offset = -1;
+    }
+
+  /* Decode the opcodes.  It is possible in some situations to have a
+     block of size zero.  */
+  while (data < end_data)
+    {
+      struct loclist *newloc;
+      newloc = NEW_LOC ();
+      newloc->number = 0;
+      newloc->number2 = 0;
+      newloc->offset = data - block->data;
+
+      switch ((newloc->atom = *data++))
+	{
+	case DW_OP_addr:
+	  /* Address, depends on address size of CU.  */
+	  if (dbg == NULL)
+	    {
+	      // XXX relocation?
+	      if (address_size == 4)
+		{
+		  if (unlikely (data + 4 > end_data))
+		    goto invalid;
+		  else
+		    newloc->number = read_4ubyte_unaligned_inc (&bo, data);
+		}
+	      else
+		{
+		  if (unlikely (data + 8 > end_data))
+		    goto invalid;
+		  else
+		    newloc->number = read_8ubyte_unaligned_inc (&bo, data);
+		}
+	    }
+	  else if (__libdw_read_address_inc (dbg, sec_index, &data,
+					     address_size, &newloc->number))
+	    goto invalid;
+	  break;
+
+	case DW_OP_call_ref:
+	case DW_OP_GNU_variable_value:
+	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
+	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
+						      ref_size,
+						      &newloc->number,
+						      IDX_debug_info, 0))
+	    goto invalid;
+	  break;
+
+	case DW_OP_deref:
+	case DW_OP_dup:
+	case DW_OP_drop:
+	case DW_OP_over:
+	case DW_OP_swap:
+	case DW_OP_rot:
+	case DW_OP_xderef:
+	case DW_OP_abs:
+	case DW_OP_and:
+	case DW_OP_div:
+	case DW_OP_minus:
+	case DW_OP_mod:
+	case DW_OP_mul:
+	case DW_OP_neg:
+	case DW_OP_not:
+	case DW_OP_or:
+	case DW_OP_plus:
+	case DW_OP_shl:
+	case DW_OP_shr:
+	case DW_OP_shra:
+	case DW_OP_xor:
+	case DW_OP_eq:
+	case DW_OP_ge:
+	case DW_OP_gt:
+	case DW_OP_le:
+	case DW_OP_lt:
+	case DW_OP_ne:
+	case DW_OP_lit0 ... DW_OP_lit31:
+	case DW_OP_reg0 ... DW_OP_reg31:
+	case DW_OP_nop:
+	case DW_OP_push_object_address:
+	case DW_OP_call_frame_cfa:
+	case DW_OP_form_tls_address:
+	case DW_OP_GNU_push_tls_address:
+	case DW_OP_stack_value:
+	  /* No operand.  */
+	  break;
+
+	case DW_OP_const1u:
+	case DW_OP_pick:
+	case DW_OP_deref_size:
+	case DW_OP_xderef_size:
+	  if (unlikely (data >= end_data))
+	    {
+	    invalid:
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	    returnmem:
+	      /* Free any dynamicly allocated loclists, if any.  */
+	      while (n > MAX_STACK_LOCS)
+		{
+		  struct loclist *loc = loclist;
+		  loclist = loc->next;
+		  free (loc);
+		  n--;
+		}
+	      return -1;
+	    }
+
+	  newloc->number = *data++;
+	  break;
+
+	case DW_OP_const1s:
+	  if (unlikely (data >= end_data))
+	    goto invalid;
+
+	  newloc->number = *((int8_t *) data);
+	  ++data;
+	  break;
+
+	case DW_OP_const2u:
+	  if (unlikely (data + 2 > end_data))
+	    goto invalid;
+
+	  newloc->number = read_2ubyte_unaligned_inc (&bo, data);
+	  break;
+
+	case DW_OP_const2s:
+	case DW_OP_skip:
+	case DW_OP_bra:
+	case DW_OP_call2:
+	  if (unlikely (data + 2 > end_data))
+	    goto invalid;
+
+	  newloc->number = read_2sbyte_unaligned_inc (&bo, data);
+	  break;
+
+	case DW_OP_const4u:
+	  if (unlikely (data + 4 > end_data))
+	    goto invalid;
+
+	  newloc->number = read_4ubyte_unaligned_inc (&bo, data);
+	  break;
+
+	case DW_OP_const4s:
+	case DW_OP_call4:
+	case DW_OP_GNU_parameter_ref:
+	  if (unlikely (data + 4 > end_data))
+	    goto invalid;
+
+	  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 (&bo, data);
+	  break;
+
+	case DW_OP_const8s:
+	  if (unlikely (data + 8 > end_data))
+	    goto invalid;
+
+	  newloc->number = read_8sbyte_unaligned_inc (&bo, data);
+	  break;
+
+	case DW_OP_constu:
+	case DW_OP_plus_uconst:
+	case DW_OP_regx:
+	case DW_OP_piece:
+	case DW_OP_GNU_convert:
+	case DW_OP_GNU_reinterpret:
+	  get_uleb128 (newloc->number, data, end_data);
+	  break;
+
+	case DW_OP_consts:
+	case DW_OP_breg0 ... DW_OP_breg31:
+	case DW_OP_fbreg:
+	  get_sleb128 (newloc->number, data, end_data);
+	  break;
+
+	case DW_OP_bregx:
+	  get_uleb128 (newloc->number, data, end_data);
+	  if (unlikely (data >= end_data))
+	    goto invalid;
+	  get_sleb128 (newloc->number2, data, end_data);
+	  break;
+
+	case DW_OP_bit_piece:
+	case DW_OP_GNU_regval_type:
+	  get_uleb128 (newloc->number, data, end_data);
+	  if (unlikely (data >= end_data))
+	    goto invalid;
+	  get_uleb128 (newloc->number2, data, end_data);
+	  break;
+
+	case DW_OP_implicit_value:
+	case DW_OP_GNU_entry_value:
+	  /* This cannot be used in a CFI expression.  */
+	  if (unlikely (dbg == NULL))
+	    goto invalid;
+
+	  /* start of block inc. len.  */
+	  newloc->number2 = (Dwarf_Word) (uintptr_t) data;
+	  get_uleb128 (newloc->number, data, end_data); /* Block length.  */
+	  if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
+	    goto invalid;
+	  data += newloc->number;		/* Skip the block.  */
+	  break;
+
+	case DW_OP_GNU_implicit_pointer:
+	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
+	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
+						      ref_size,
+						      &newloc->number,
+						      IDX_debug_info, 0))
+	    goto invalid;
+	  if (unlikely (data >= end_data))
+	    goto invalid;
+	  get_uleb128 (newloc->number2, data, end_data); /* Byte offset.  */
+	  break;
+
+	case DW_OP_GNU_deref_type:
+	  if (unlikely (data + 1 >= end_data))
+	    goto invalid;
+	  newloc->number = *data++;
+	  get_uleb128 (newloc->number2, data, end_data);
+	  break;
+
+	case DW_OP_GNU_const_type:
+	  {
+	    size_t size;
+	    get_uleb128 (newloc->number, data, end_data);
+	    if (unlikely (data >= end_data))
+	      goto invalid;
+
+	    /* start of block inc. len.  */
+	    newloc->number2 = (Dwarf_Word) (uintptr_t) data;
+	    size = *data++;
+	    if (unlikely ((Dwarf_Word) (end_data - data) < size))
+	      goto invalid;
+	    data += size;		/* Skip the block.  */
+	  }
+	  break;
+
+	default:
+	  goto invalid;
+	}
+    }
+
+  if (unlikely (n == 0))
+    {
+      /* This is not allowed.
+	 It would mean an empty location expression, which we handled
+	 already as a special case above.  */
+      goto invalid;
+    }
+
+  if (valuep)
+    {
+      struct loclist *newloc = NEW_LOC ();
+      newloc->atom = DW_OP_stack_value;
+      newloc->number = 0;
+      newloc->number2 = 0;
+      newloc->offset = data - block->data;
+    }
+
+  /* Allocate the array.  */
+  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);
+	  goto returnmem;
+	}
+    }
+
+  /* Store the result.  */
+  *llbuf = result;
+  *listlen = n;
+
+  do
+    {
+      /* We populate the array from the back since the list is backwards.  */
+      --n;
+      result[n].atom = loclist->atom;
+      result[n].number = loclist->number;
+      result[n].number2 = loclist->number2;
+      result[n].offset = loclist->offset;
+
+      if (result[n].atom == DW_OP_implicit_value)
+	store_implicit_value (dbg, cache, &result[n]);
+
+      struct loclist *loc = loclist;
+      loclist = loclist->next;
+      if (unlikely (n + 1 > MAX_STACK_LOCS))
+	free (loc);
+    }
+  while (n > 0);
+
+  /* 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, 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)
+{
+  /* Empty location expressions don't have any ops to intern.
+     Note that synthetic empty_cu doesn't have an associated DWARF dbg.  */
+  if (block->length == 0)
+    {
+      *listlen = 0;
+      return 0;
+    }
+
+  return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
+				    cu->address_size, (cu->version == 2
+						       ? cu->address_size
+						       : cu->offset_size),
+				    &cu->locs, block,
+				    false, false,
+				    llbuf, listlen, sec_index);
+}
+
+int
+dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
+{
+  if (! attr_ok (attr))
+    return -1;
+
+  int result = check_constant_offset (attr, llbuf, listlen);
+  if (result != 1)
+    return result;
+
+  /* If it has a block form, it's a single location expression.  */
+  Dwarf_Block block;
+  if (INTUSE(dwarf_formblock) (attr, &block) != 0)
+    return -1;
+
+  return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
+}
+
+static int
+attr_base_address (Dwarf_Attribute *attr, Dwarf_Addr *basep)
+{
+  /* Fetch the CU's base address.  */
+  Dwarf_Die cudie = CUDIE (attr->cu);
+
+  /* Find the base address of the compilation unit.  It will
+     normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
+     the base address could be overridden by DW_AT_entry_pc.  It's
+     been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
+     for compilation units with discontinuous ranges.  */
+  Dwarf_Attribute attr_mem;
+  if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
+      && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
+						     DW_AT_entry_pc,
+						     &attr_mem),
+				 basep) != 0)
+    {
+      if (INTUSE(dwarf_errno) () != 0)
+	return -1;
+
+      /* The compiler provided no base address when it should
+	 have.  Buggy GCC does this when it used absolute
+	 addresses in the location list and no DW_AT_ranges.  */
+      *basep = 0;
+    }
+  return 0;
+}
+
+static int
+initial_offset_base (Dwarf_Attribute *attr, ptrdiff_t *offset,
+		     Dwarf_Addr *basep)
+{
+  if (attr_base_address (attr, basep) != 0)
+    return -1;
+
+  Dwarf_Word start_offset;
+  if (__libdw_formptr (attr, IDX_debug_loc,
+		       DWARF_E_NO_LOCLIST,
+		       NULL, &start_offset) == NULL)
+    return -1;
+
+  *offset = start_offset;
+  return 0;
+}
+
+static ptrdiff_t
+getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
+		   Dwarf_Addr *basep, Dwarf_Addr *startp, Dwarf_Addr *endp,
+		   Dwarf_Addr address, const Elf_Data *locs, Dwarf_Op **expr,
+		   size_t *exprlen)
+{
+  unsigned char *readp = locs->d_buf + offset;
+  unsigned char *readendp = locs->d_buf + locs->d_size;
+
+ next:
+  if (readendp - readp < attr->cu->address_size * 2)
+    {
+    invalid:
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  Dwarf_Addr begin;
+  Dwarf_Addr end;
+
+  switch (__libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
+					   &readp, attr->cu->address_size,
+					   &begin, &end, basep))
+    {
+    case 0: /* got location range. */
+      break;
+    case 1: /* base address setup. */
+      goto next;
+    case 2: /* end of loclist */
+      return 0;
+    default: /* error */
+      return -1;
+    }
+
+  if (readendp - readp < 2)
+    goto invalid;
+
+  /* We have a location expression.  */
+  Dwarf_Block block;
+  block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
+  block.data = readp;
+  if (readendp - readp < (ptrdiff_t) block.length)
+    goto invalid;
+  readp += block.length;
+
+  *startp = *basep + begin;
+  *endp = *basep + end;
+
+  /* If address is minus one we want them all, otherwise only matching.  */
+  if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp))
+    goto next;
+
+  if (getlocation (attr->cu, &block, expr, exprlen, IDX_debug_loc) != 0)
+    return -1;
+
+  return readp - (unsigned char *) locs->d_buf;
+}
+
+int
+dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
+			Dwarf_Op **llbufs, size_t *listlens, size_t maxlocs)
+{
+  if (! attr_ok (attr))
+    return -1;
+
+  if (llbufs == NULL)
+    maxlocs = SIZE_MAX;
+
+  /* If it has a block form, it's a single location expression.  */
+  Dwarf_Block block;
+  if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+    {
+      if (maxlocs == 0)
+	return 0;
+      if (llbufs != NULL &&
+	  getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
+		       cu_sec_idx (attr->cu)) != 0)
+	return -1;
+      return listlens[0] == 0 ? 0 : 1;
+    }
+
+  int error = INTUSE(dwarf_errno) ();
+  if (unlikely (error != DWARF_E_NO_BLOCK))
+    {
+      __libdw_seterrno (error);
+      return -1;
+    }
+
+  int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
+  if (result != 1)
+    return result ?: 1;
+
+  Dwarf_Addr base, start, end;
+  Dwarf_Op *expr;
+  size_t expr_len;
+  ptrdiff_t off = 0;
+  size_t got = 0;
+
+  /* This is a true loclistptr, fetch the initial base address and offset.  */
+  if (initial_offset_base (attr, &off, &base) != 0)
+    return -1;
+
+  const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
+  if (d == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NO_LOCLIST);
+      return -1;
+    }
+
+  while (got < maxlocs
+         && (off = getlocations_addr (attr, off, &base, &start, &end,
+				   address, d, &expr, &expr_len)) > 0)
+    {
+      /* This one matches the address.  */
+      if (llbufs != NULL)
+	{
+	  llbufs[got] = expr;
+	  listlens[got] = expr_len;
+	}
+      ++got;
+    }
+
+  /* We might stop early, so off can be zero or positive on success.  */
+  if (off < 0)
+    return -1;
+
+  return got;
+}
+
+ptrdiff_t
+dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
+		    Dwarf_Addr *startp, Dwarf_Addr *endp, Dwarf_Op **expr,
+		    size_t *exprlen)
+{
+  if (! attr_ok (attr))
+    return -1;
+
+  /* 1 is an invalid offset, meaning no more locations. */
+  if (offset == 1)
+    return 0;
+
+  if (offset == 0)
+    {
+      /* If it has a block form, it's a single location expression.  */
+      Dwarf_Block block;
+      if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+	{
+	  if (getlocation (attr->cu, &block, expr, exprlen,
+			   cu_sec_idx (attr->cu)) != 0)
+	    return -1;
+
+	  /* This is the one and only location covering everything. */
+	  *startp = 0;
+	  *endp = -1;
+	  return 1;
+	}
+
+      int error = INTUSE(dwarf_errno) ();
+      if (unlikely (error != DWARF_E_NO_BLOCK))
+	{
+	  __libdw_seterrno (error);
+	  return -1;
+	}
+
+      int result = check_constant_offset (attr, expr, exprlen);
+      if (result != 1)
+	{
+	  if (result == 0)
+	    {
+	      /* This is the one and only location covering everything. */
+	      *startp = 0;
+	      *endp = -1;
+	      return 1;
+	    }
+	  return result;
+	}
+
+      /* We must be looking at a true loclistptr, fetch the initial
+	 base address and offset.  */
+      if (initial_offset_base (attr, &offset, basep) != 0)
+	return -1;
+    }
+
+  const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
+  if (d == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NO_LOCLIST);
+      return -1;
+    }
+
+  return getlocations_addr (attr, offset, basep, startp, endp,
+			    (Dwarf_Word) -1, d, expr, exprlen);
+}
diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c
new file mode 100644
index 0000000..e4dd708
--- /dev/null
+++ b/libdw/dwarf_getlocation_attr.c
@@ -0,0 +1,120 @@
+/* Return DWARF attribute associated with a location expression op.
+   Copyright (C) 2013, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include <libdwP.h>
+
+static Dwarf_CU *
+attr_form_cu (Dwarf_Attribute *attr)
+{
+  /* If the attribute has block/expr form the data comes from the
+     .debug_info from the same cu as the attr.  Otherwise it comes from
+     the .debug_loc data section.  */
+  switch (attr->form)
+    {
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+    case DW_FORM_block:
+    case DW_FORM_exprloc:
+      return attr->cu;
+    default:
+      return attr->cu->dbg->fake_loc_cu;
+    }
+}
+
+int
+dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribute *result)
+{
+  if (attr == NULL)
+    return -1;
+
+  switch (op->atom)
+    {
+      case DW_OP_implicit_value:
+	result->code = DW_AT_const_value;
+	result->form = DW_FORM_block;
+	result->valp = (unsigned char *) (uintptr_t) op->number2;
+	result->cu = attr_form_cu (attr);
+	break;
+
+      case DW_OP_GNU_entry_value:
+	result->code = DW_AT_location;
+	result->form = DW_FORM_exprloc;
+	result->valp = (unsigned char *) (uintptr_t) op->number2;
+	result->cu = attr_form_cu (attr);
+	break;
+
+      case DW_OP_GNU_const_type:
+	result->code = DW_AT_const_value;
+	result->form = DW_FORM_block1;
+	result->valp = (unsigned char *) (uintptr_t) op->number2;
+	result->cu = attr_form_cu (attr);
+	break;
+
+      case DW_OP_call2:
+      case DW_OP_call4:
+      case DW_OP_call_ref:
+	{
+	  Dwarf_Die die;
+	  if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0)
+	    return -1;
+	  if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL)
+	    {
+	      __libdw_empty_loc_attr (result);
+	      return 0;
+	    }
+	}
+	break;
+
+      case DW_OP_GNU_implicit_pointer:
+      case DW_OP_GNU_variable_value:
+	{
+	  Dwarf_Die die;
+	  if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0)
+	    return -1;
+	  if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL
+	      && INTUSE(dwarf_attr) (&die, DW_AT_const_value, result) == NULL)
+	    {
+	      __libdw_empty_loc_attr (result);
+	      return 0;
+	    }
+	}
+	break;
+
+      default:
+	__libdw_seterrno (DWARF_E_INVALID_ACCESS);
+	return -1;
+    }
+
+  return 0;
+}
diff --git a/libdw/dwarf_getlocation_die.c b/libdw/dwarf_getlocation_die.c
new file mode 100644
index 0000000..21b4365
--- /dev/null
+++ b/libdw/dwarf_getlocation_die.c
@@ -0,0 +1,77 @@
+/* Return DIE associated with a location expression op.
+   Copyright (C) 2013 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include <libdwP.h>
+
+int
+dwarf_getlocation_die (Dwarf_Attribute *attr, const Dwarf_Op *op,
+		       Dwarf_Die *result)
+{
+  if (attr == NULL)
+    return -1;
+
+  Dwarf_Off dieoff;
+  switch (op->atom)
+    {
+    case DW_OP_GNU_implicit_pointer:
+    case DW_OP_call_ref:
+    case DW_OP_GNU_variable_value:
+      dieoff = op->number;
+      break;
+
+    case DW_OP_GNU_parameter_ref:
+    case DW_OP_GNU_convert:
+    case DW_OP_GNU_reinterpret:
+    case DW_OP_GNU_const_type:
+    case DW_OP_call2:
+    case DW_OP_call4:
+      dieoff = attr->cu->start + op->number;
+      break;
+
+    case DW_OP_GNU_regval_type:
+    case DW_OP_GNU_deref_type:
+      dieoff = attr->cu->start + op->number2;
+      break;
+
+    default:
+      __libdw_seterrno (DWARF_E_INVALID_ACCESS);
+      return -1;
+    }
+
+  if (__libdw_offdie (attr->cu->dbg, dieoff, result,
+                     attr->cu->type_offset != 0) == NULL)
+    return -1;
+
+  return 0;
+}
+INTDEF(dwarf_getlocation_die);
diff --git a/libdw/dwarf_getlocation_implicit_pointer.c b/libdw/dwarf_getlocation_implicit_pointer.c
new file mode 100644
index 0000000..9505382
--- /dev/null
+++ b/libdw/dwarf_getlocation_implicit_pointer.c
@@ -0,0 +1,77 @@
+/* Return associated attribute for DW_OP_GNU_implicit_pointer.
+   Copyright (C) 2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+
+
+static unsigned char empty_exprloc = 0;
+static Dwarf_CU empty_cu = { .startp = &empty_exprloc,
+			     .endp = &empty_exprloc + 1 };
+
+void
+internal_function
+__libdw_empty_loc_attr (Dwarf_Attribute *attr)
+{
+  attr->code = DW_AT_location;
+  attr->form = DW_FORM_exprloc;
+  attr->valp = &empty_exprloc;
+  attr->cu = &empty_cu;
+}
+
+int
+dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr, const Dwarf_Op *op,
+				    Dwarf_Attribute *result)
+{
+  if (attr == NULL)
+    return -1;
+
+  if (unlikely (op->atom != DW_OP_GNU_implicit_pointer))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_ACCESS);
+      return -1;
+    }
+
+  Dwarf_Die die;
+  if (__libdw_offdie (attr->cu->dbg, op->number, &die,
+		      attr->cu->type_offset != 0) == NULL)
+    return -1;
+
+  if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL
+      && INTUSE(dwarf_attr) (&die, DW_AT_const_value, result) == NULL)
+    {
+      __libdw_empty_loc_attr (result);
+      return 0;
+    }
+
+  return 0;
+}
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
new file mode 100644
index 0000000..c456051
--- /dev/null
+++ b/libdw/dwarf_getmacros.c
@@ -0,0 +1,573 @@
+/* Get macro information.
+   Copyright (C) 2002-2009, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libdwP.h>
+
+static int
+get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
+{
+  /* Get the appropriate attribute.  */
+  Dwarf_Attribute attr;
+  if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
+    return -1;
+
+  /* Offset into the corresponding section.  */
+  return INTUSE(dwarf_formudata) (&attr, retp);
+}
+
+static int
+macro_op_compare (const void *p1, const void *p2)
+{
+  const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
+  const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
+
+  if (t1->offset < t2->offset)
+    return -1;
+  if (t1->offset > t2->offset)
+    return 1;
+
+  if (t1->sec_index < t2->sec_index)
+    return -1;
+  if (t1->sec_index > t2->sec_index)
+    return 1;
+
+  return 0;
+}
+
+static void
+build_table (Dwarf_Macro_Op_Table *table,
+	     Dwarf_Macro_Op_Proto op_protos[static 255])
+{
+  unsigned ct = 0;
+  for (unsigned i = 1; i < 256; ++i)
+    if (op_protos[i - 1].forms != NULL)
+      table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
+    else
+      table->opcodes[i - 1] = 0xff;
+}
+
+#define MACRO_PROTO(NAME, ...)					\
+  Dwarf_Macro_Op_Proto NAME = ({				\
+      static const uint8_t proto[] = {__VA_ARGS__};		\
+      (Dwarf_Macro_Op_Proto) {sizeof proto, proto};		\
+    })
+
+enum { macinfo_data_size = offsetof (Dwarf_Macro_Op_Table, table[5]) };
+static unsigned char macinfo_data[macinfo_data_size]
+	__attribute__ ((aligned (__alignof (Dwarf_Macro_Op_Table))));
+
+static __attribute__ ((constructor)) void
+init_macinfo_table (void)
+{
+  MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
+  MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
+  MACRO_PROTO (p_none);
+
+  Dwarf_Macro_Op_Proto op_protos[255] =
+    {
+      [DW_MACINFO_define - 1] = p_udata_str,
+      [DW_MACINFO_undef - 1] = p_udata_str,
+      [DW_MACINFO_vendor_ext - 1] = p_udata_str,
+      [DW_MACINFO_start_file - 1] = p_udata_udata,
+      [DW_MACINFO_end_file - 1] = p_none,
+      /* If you are adding more elements to this array, increase
+	 MACINFO_DATA_SIZE above.  */
+    };
+
+  Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data;
+  memset (macinfo_table, 0, sizeof macinfo_data);
+  build_table (macinfo_table, op_protos);
+  macinfo_table->sec_index = IDX_debug_macinfo;
+}
+
+static Dwarf_Macro_Op_Table *
+get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie)
+{
+  assert (cudie != NULL);
+
+  Dwarf_Attribute attr_mem, *attr
+    = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
+  Dwarf_Off line_offset = (Dwarf_Off) -1;
+  if (attr != NULL)
+    if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
+      return NULL;
+
+  Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
+					     macinfo_data_size, 1);
+  memcpy (table, macinfo_data, macinfo_data_size);
+
+  table->offset = macoff;
+  table->sec_index = IDX_debug_macinfo;
+  table->line_offset = line_offset;
+  table->is_64bit = cudie->cu->address_size == 8;
+  table->comp_dir = __libdw_getcompdir (cudie);
+
+  return table;
+}
+
+static Dwarf_Macro_Op_Table *
+get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
+		      const unsigned char *readp,
+		      const unsigned char *const endp,
+		      Dwarf_Die *cudie)
+{
+  const unsigned char *startp = readp;
+
+  /* Request at least 3 bytes for header.  */
+  if (readp + 3 > endp)
+    {
+    invalid_dwarf:
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+  if (version != 4 && version != 5)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_VERSION);
+      return NULL;
+    }
+
+  uint8_t flags = *readp++;
+  bool is_64bit = (flags & 0x1) != 0;
+
+  Dwarf_Off line_offset = (Dwarf_Off) -1;
+  if ((flags & 0x2) != 0)
+    {
+      line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp);
+      if (readp > endp)
+	goto invalid_dwarf;
+    }
+  else if (cudie != NULL)
+    {
+      Dwarf_Attribute attr_mem, *attr
+	= INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
+      if (attr != NULL)
+	if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
+	  return NULL;
+    }
+
+  /* """The macinfo entry types defined in this standard may, but
+     might not, be described in the table""".
+
+     I.e. these may be present.  It's tempting to simply skip them,
+     but it's probably more correct to tolerate that a producer tweaks
+     the way certain opcodes are encoded, for whatever reasons.  */
+
+  MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
+  MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
+  MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
+  MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
+  MACRO_PROTO (p_none);
+
+  Dwarf_Macro_Op_Proto op_protos[255] =
+    {
+      [DW_MACRO_define - 1] = p_udata_str,
+      [DW_MACRO_undef - 1] = p_udata_str,
+      [DW_MACRO_define_strp - 1] = p_udata_strp,
+      [DW_MACRO_undef_strp - 1] = p_udata_strp,
+      [DW_MACRO_start_file - 1] = p_udata_udata,
+      [DW_MACRO_end_file - 1] = p_none,
+      [DW_MACRO_import - 1] = p_secoffset,
+      /* When adding support for DWARF5 supplementary object files and
+	 indirect string tables also add support for DW_MACRO_define_sup,
+	 DW_MACRO_undef_sup, DW_MACRO_import_sup, DW_MACRO_define_strx
+	 and DW_MACRO_undef_strx.  */
+    };
+
+  if ((flags & 0x4) != 0)
+    {
+      unsigned count = *readp++;
+      for (unsigned i = 0; i < count; ++i)
+	{
+	  unsigned opcode = *readp++;
+
+	  Dwarf_Macro_Op_Proto e;
+	  if (readp >= endp)
+	    goto invalid;
+	  get_uleb128 (e.nforms, readp, endp);
+	  e.forms = readp;
+	  op_protos[opcode - 1] = e;
+
+	  readp += e.nforms;
+	  if (readp > endp)
+	    {
+	    invalid:
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return NULL;
+	    }
+	}
+    }
+
+  size_t ct = 0;
+  for (unsigned i = 1; i < 256; ++i)
+    if (op_protos[i - 1].forms != NULL)
+      ++ct;
+
+  /* We support at most 0xfe opcodes defined in the table, as 0xff is
+     a value that means that given opcode is not stored at all.  But
+     that should be fine, as opcode 0 is not allocated.  */
+  assert (ct < 0xff);
+
+  size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
+
+  Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
+					     macop_table_size, 1);
+
+  *table = (Dwarf_Macro_Op_Table) {
+    .offset = macoff,
+    .sec_index = IDX_debug_macro,
+    .line_offset = line_offset,
+    .header_len = readp - startp,
+    .version = version,
+    .is_64bit = is_64bit,
+
+    /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent.  */
+    .comp_dir = __libdw_getcompdir (cudie),
+  };
+  build_table (table, op_protos);
+
+  return table;
+}
+
+static Dwarf_Macro_Op_Table *
+cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
+		const unsigned char *startp,
+		const unsigned char *const endp,
+		Dwarf_Die *cudie)
+{
+  Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
+  Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops,
+					macro_op_compare);
+  if (found != NULL)
+    return *found;
+
+  Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro
+    ? get_table_for_offset (dbg, macoff, startp, endp, cudie)
+    : get_macinfo_table (dbg, macoff, cudie);
+
+  if (table == NULL)
+    return NULL;
+
+  Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops,
+					macro_op_compare);
+  if (unlikely (ret == NULL))
+    {
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  return *ret;
+}
+
+static ptrdiff_t
+read_macros (Dwarf *dbg, int sec_index,
+	     Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *),
+	     void *arg, ptrdiff_t offset, bool accept_0xff,
+	     Dwarf_Die *cudie)
+{
+  Elf_Data *d = dbg->sectiondata[sec_index];
+  if (unlikely (d == NULL || d->d_buf == NULL))
+    {
+      __libdw_seterrno (DWARF_E_NO_ENTRY);
+      return -1;
+    }
+
+  if (unlikely (macoff >= d->d_size))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  const unsigned char *const startp = d->d_buf + macoff;
+  const unsigned char *const endp = d->d_buf + d->d_size;
+
+  Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff,
+						startp, endp, cudie);
+  if (table == NULL)
+    return -1;
+
+  if (offset == 0)
+    offset = table->header_len;
+
+  assert (offset >= 0);
+  assert (offset < endp - startp);
+  const unsigned char *readp = startp + offset;
+
+  while (readp < endp)
+    {
+      unsigned int opcode = *readp++;
+      if (opcode == 0)
+	/* Nothing more to do.  */
+	return 0;
+
+      if (unlikely (opcode == 0xff && ! accept_0xff))
+	{
+	  /* See comment below at dwarf_getmacros for explanation of
+	     why we are doing this.  */
+	  __libdw_seterrno (DWARF_E_INVALID_OPCODE);
+	  return -1;
+	}
+
+      unsigned int idx = table->opcodes[opcode - 1];
+      if (idx == 0xff)
+	{
+	  __libdw_seterrno (DWARF_E_INVALID_OPCODE);
+	  return -1;
+	}
+
+      Dwarf_Macro_Op_Proto *proto = &table->table[idx];
+
+      /* A fake CU with bare minimum data to fool dwarf_formX into
+	 doing the right thing with the attributes that we put out.
+	 We pretend it is the same version as the actual table.
+	 Version 4 for the old GNU extension, version 5 for DWARF5.  */
+      Dwarf_CU fake_cu = {
+	.dbg = dbg,
+	.sec_idx = sec_index,
+	.version = table->version,
+	.offset_size = table->is_64bit ? 8 : 4,
+	.startp = (void *) startp + offset,
+	.endp = (void *) endp,
+      };
+
+      Dwarf_Attribute *attributes;
+      Dwarf_Attribute *attributesp = NULL;
+      Dwarf_Attribute nattributes[8];
+      if (unlikely (proto->nforms > 8))
+	{
+	  attributesp = malloc (sizeof (Dwarf_Attribute) * proto->nforms);
+	  if (attributesp == NULL)
+	    {
+	      __libdw_seterrno (DWARF_E_NOMEM);
+	      return -1;
+	    }
+	  attributes = attributesp;
+	}
+      else
+	attributes = &nattributes[0];
+
+      for (Dwarf_Word i = 0; i < proto->nforms; ++i)
+	{
+	  /* We pretend this is a DW_AT_GNU_macros attribute so that
+	     DW_FORM_sec_offset forms get correctly interpreted as
+	     offset into .debug_macro.  */
+	  attributes[i].code = DW_AT_GNU_macros;
+	  attributes[i].form = proto->forms[i];
+	  attributes[i].valp = (void *) readp;
+	  attributes[i].cu = &fake_cu;
+
+	  size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
+	  if (unlikely (len == (size_t) -1))
+	    {
+	      free (attributesp);
+	      return -1;
+	    }
+
+	  readp += len;
+	}
+
+      Dwarf_Macro macro = {
+	.table = table,
+	.opcode = opcode,
+	.attributes = attributes,
+      };
+
+      int res = callback (&macro, arg);
+      if (unlikely (attributesp != NULL))
+	free (attributesp);
+
+      if (res != DWARF_CB_OK)
+	return readp - startp;
+    }
+
+  return 0;
+}
+
+/* Token layout:
+
+   - The highest bit is used for distinguishing between callers that
+     know that opcode 0xff may have one of two incompatible meanings.
+     The mask that we use for selecting this bit is
+     DWARF_GETMACROS_START.
+
+   - The rest of the token (31 or 63 bits) encodes address inside the
+     macro unit.
+
+   Besides, token value of 0 signals end of iteration and -1 is
+   reserved for signaling errors.  That means it's impossible to
+   represent maximum offset of a .debug_macro unit to new-style
+   callers (which in practice decreases the permissible macro unit
+   size by another 1 byte).  */
+
+static ptrdiff_t
+token_from_offset (ptrdiff_t offset, bool accept_0xff)
+{
+  if (offset == -1 || offset == 0)
+    return offset;
+
+  /* Make sure the offset didn't overflow into the flag bit.  */
+  if ((offset & DWARF_GETMACROS_START) != 0)
+    {
+      __libdw_seterrno (DWARF_E_TOO_BIG);
+      return -1;
+    }
+
+  if (accept_0xff)
+    offset |= DWARF_GETMACROS_START;
+
+  return offset;
+}
+
+static ptrdiff_t
+offset_from_token (ptrdiff_t token, bool *accept_0xffp)
+{
+  *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
+  token &= ~DWARF_GETMACROS_START;
+
+  return token;
+}
+
+static ptrdiff_t
+gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+			  int (*callback) (Dwarf_Macro *, void *),
+			  void *arg, ptrdiff_t offset, bool accept_0xff,
+			  Dwarf_Die *cudie)
+{
+  assert (offset >= 0);
+
+  if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+      return -1;
+    }
+
+  return read_macros (dbg, IDX_debug_macro, macoff,
+		      callback, arg, offset, accept_0xff, cudie);
+}
+
+static ptrdiff_t
+macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+			  int (*callback) (Dwarf_Macro *, void *),
+			  void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
+{
+  assert (offset >= 0);
+
+  return read_macros (dbg, IDX_debug_macinfo, macoff,
+		      callback, arg, offset, true, cudie);
+}
+
+ptrdiff_t
+dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+		     int (*callback) (Dwarf_Macro *, void *),
+		     void *arg, ptrdiff_t token)
+{
+  if (dbg == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NO_DWARF);
+      return -1;
+    }
+
+  bool accept_0xff;
+  ptrdiff_t offset = offset_from_token (token, &accept_0xff);
+  assert (accept_0xff);
+
+  offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
+				     accept_0xff, NULL);
+
+  return token_from_offset (offset, accept_0xff);
+}
+
+ptrdiff_t
+dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
+		 void *arg, ptrdiff_t token)
+{
+  if (cudie == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NO_DWARF);
+      return -1;
+    }
+
+  /* This function might be called from a code that expects to see
+     DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones.  It is fine to
+     serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
+     whose values are the same as DW_MACINFO_* ones also have the same
+     behavior.  It is not very likely that a .debug_macro section
+     would only use the part of opcode space that it shares with
+     .debug_macinfo, but it is possible.  Serving the opcodes that are
+     only valid in DW_MACRO_{GNU_,}* domain is OK as well, because
+     clients in general need to be ready that newer standards define
+     more opcodes, and have coping mechanisms for unfamiliar opcodes.
+
+     The one exception to the above rule is opcode 0xff, which has
+     concrete semantics in .debug_macinfo, but falls into vendor block
+     in .debug_macro, and can be assigned to do whatever.  There is
+     some small probability that the two opcodes would look
+     superficially similar enough that a client would be confused and
+     misbehave as a result.  For this reason, we refuse to serve
+     through this interface 0xff's originating from .debug_macro
+     unless the TOKEN that we obtained indicates the call originates
+     from a new-style caller.  See above for details on what
+     information is encoded into tokens.  */
+
+  bool accept_0xff;
+  ptrdiff_t offset = offset_from_token (token, &accept_0xff);
+
+  /* DW_AT_macro_info */
+  if (dwarf_hasattr (cudie, DW_AT_macro_info))
+    {
+      Dwarf_Word macoff;
+      if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
+	return -1;
+      offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
+					 callback, arg, offset, cudie);
+    }
+  else
+    {
+      /* DW_AT_GNU_macros, DW_AT_macros */
+      Dwarf_Word macoff;
+      if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0)
+	return -1;
+      offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
+					 callback, arg, offset, accept_0xff,
+					 cudie);
+    }
+
+  return token_from_offset (offset, accept_0xff);
+}
diff --git a/libdw/dwarf_getpubnames.c b/libdw/dwarf_getpubnames.c
new file mode 100644
index 0000000..25600f3
--- /dev/null
+++ b/libdw/dwarf_getpubnames.c
@@ -0,0 +1,244 @@
+/* Get public symbol information.
+   Copyright (C) 2002, 2003, 2004, 2005, 2008 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libdwP.h>
+#include <dwarf.h>
+#include <system.h>
+
+
+static int
+get_offsets (Dwarf *dbg)
+{
+  size_t allocated = 0;
+  size_t cnt = 0;
+  struct pubnames_s *mem = NULL;
+  const size_t entsize = sizeof (struct pubnames_s);
+  unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf;
+  unsigned char *readp = startp;
+  unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
+
+  while (readp + 14 < endp)
+    {
+      /* If necessary, allocate more entries.  */
+      if (cnt >= allocated)
+	{
+	  allocated = MAX (10, 2 * allocated);
+	  struct pubnames_s *newmem
+	    = (struct pubnames_s *) realloc (mem, allocated * entsize);
+	  if (newmem == NULL)
+	    {
+	      __libdw_seterrno (DWARF_E_NOMEM);
+	    err_return:
+	      free (mem);
+	      return -1;
+	    }
+
+	  mem = newmem;
+	}
+
+      /* Read the set header.  */
+      int len_bytes = 4;
+      Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp);
+      if (len == DWARF3_LENGTH_64_BIT)
+	{
+	  len = read_8ubyte_unaligned_inc (dbg, readp);
+	  len_bytes = 8;
+	}
+      else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE
+			 && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
+	{
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	  goto err_return;
+	}
+
+      /* Now we know the offset of the first offset/name pair.  */
+      mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp;
+      mem[cnt].address_len = len_bytes;
+      size_t max_size = dbg->sectiondata[IDX_debug_pubnames]->d_size;
+      if (mem[cnt].set_start >= max_size
+	  || len - (2 + 2 * len_bytes) > max_size - mem[cnt].set_start)
+	/* Something wrong, the first entry is beyond the end of
+	   the section.  Or the length of the whole unit is too big.  */
+	break;
+
+      /* Read the version.  It better be two for now.  */
+      uint16_t version = read_2ubyte_unaligned (dbg, readp);
+      if (unlikely (version != 2))
+	{
+	  __libdw_seterrno (DWARF_E_INVALID_VERSION);
+	  goto err_return;
+	}
+
+      /* Get the CU offset.  */
+      if (__libdw_read_offset (dbg, 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.  */
+      unsigned char *infop
+	= ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
+	   + mem[cnt].cu_offset);
+      if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT)
+	mem[cnt].cu_header_size = 23;
+      else
+	mem[cnt].cu_header_size = 11;
+
+      ++cnt;
+
+      /* Advance to the next set.  */
+      readp += len;
+    }
+
+  if (mem == NULL || cnt == 0)
+    {
+      free (mem);
+      __libdw_seterrno (DWARF_E_NO_ENTRY);
+      return -1;
+    }
+
+  dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize);
+  dbg->pubnames_nsets = cnt;
+
+  return 0;
+}
+
+
+ptrdiff_t
+dwarf_getpubnames (Dwarf *dbg,
+		   int (*callback) (Dwarf *, Dwarf_Global *, void *),
+		   void *arg, ptrdiff_t offset)
+{
+  if (dbg == NULL)
+    return -1l;
+
+  if (unlikely (offset < 0))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+      return -1l;
+    }
+
+  /* Make sure it is a valid offset.  */
+  if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL
+		|| ((size_t) offset
+		    >= dbg->sectiondata[IDX_debug_pubnames]->d_size)))
+    /* No (more) entry.  */
+    return 0;
+
+  /* If necessary read the set information.  */
+  if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0))
+    return -1l;
+
+  /* Find the place where to start.  */
+  size_t cnt;
+  if (offset == 0)
+    {
+      cnt = 0;
+      offset = dbg->pubnames_sets[0].set_start;
+    }
+  else
+    {
+      for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt)
+	if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start)
+	  {
+	    assert ((Dwarf_Off) offset
+		    < dbg->pubnames_sets[cnt + 1].set_start);
+	    break;
+	  }
+      assert (cnt + 1 < dbg->pubnames_nsets);
+    }
+
+  unsigned char *startp
+    = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
+  unsigned char *endp
+    = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
+  unsigned char *readp = startp + offset;
+  while (1)
+    {
+      Dwarf_Global gl;
+
+      gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset
+		      + dbg->pubnames_sets[cnt].cu_header_size);
+
+      while (1)
+	{
+	  /* READP points to the next offset/name pair.  */
+	  if (readp + dbg->pubnames_sets[cnt].address_len > endp)
+	    goto invalid_dwarf;
+	  if (dbg->pubnames_sets[cnt].address_len == 4)
+	    gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp);
+	  else
+	    gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp);
+
+	  /* If the offset is zero we reached the end of the set.  */
+	  if (gl.die_offset == 0)
+	    break;
+
+	  /* Add the CU offset.  */
+	  gl.die_offset += dbg->pubnames_sets[cnt].cu_offset;
+
+	  gl.name = (char *) readp;
+	  readp = (unsigned char *) memchr (gl.name, '\0', endp - readp);
+	  if (unlikely (readp == NULL))
+	    {
+	    invalid_dwarf:
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return -1l;
+	    }
+	  readp++;
+
+	  /* We found name and DIE offset.  Report it.  */
+	  if (callback (dbg, &gl, arg) != DWARF_CB_OK)
+	    {
+	      /* The user wants us to stop.  Return the offset of the
+		 next entry.  */
+	      return readp - startp;
+	    }
+	}
+
+      if (++cnt == dbg->pubnames_nsets)
+	/* This was the last set.  */
+	break;
+
+      startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
+      readp = startp + dbg->pubnames_sets[cnt].set_start;
+    }
+
+  /* We are done.  No more entries.  */
+  return 0;
+}
diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c
new file mode 100644
index 0000000..df480d3
--- /dev/null
+++ b/libdw/dwarf_getscopes.c
@@ -0,0 +1,201 @@
+/* Return scope DIEs containing PC address.
+   Copyright (C) 2005, 2007, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include "libdwP.h"
+#include <dwarf.h>
+
+
+struct args
+{
+  Dwarf_Addr pc;
+  Dwarf_Die *scopes;
+  unsigned int inlined, nscopes;
+  Dwarf_Die inlined_origin;
+};
+
+/* Preorder visitor: prune the traversal if this DIE does not contain PC.  */
+static int
+pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
+{
+  struct args *a = arg;
+
+  if (a->scopes != NULL)
+    die->prune = true;
+  else
+    {
+      /* dwarf_haspc returns an error if there are no appropriate attributes.
+	 But we use it indiscriminantly instead of presuming which tags can
+	 have PC attributes.  So when it fails for that reason, treat it just
+	 as a nonmatching return.  */
+      int result = INTUSE(dwarf_haspc) (&die->die, a->pc);
+      if (result < 0)
+	{
+	  int error = INTUSE(dwarf_errno) ();
+	  if (error != DWARF_E_NOERROR && error != DWARF_E_NO_DEBUG_RANGES)
+	    {
+	      __libdw_seterrno (error);
+	      return -1;
+	    }
+	  result = 0;
+	}
+      if (result == 0)
+    	die->prune = true;
+
+      if (!die->prune
+	  && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
+	a->inlined = depth;
+    }
+
+  return 0;
+}
+
+/* Preorder visitor for second partial traversal after finding a
+   concrete inlined instance.  */
+static int
+origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
+{
+  struct args *a = arg;
+
+  if (die->die.addr != a->inlined_origin.addr)
+    return 0;
+
+  /* We have a winner!  This is the abstract definition of the inline
+     function of which A->scopes[A->nscopes - 1] is a concrete instance.
+  */
+
+  unsigned int nscopes = a->nscopes + depth;
+  Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]);
+  if (scopes == NULL)
+    {
+      free (a->scopes);
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return -1;
+    }
+
+  a->scopes = scopes;
+  do
+    {
+      die = die->parent;
+      scopes[a->nscopes++] = die->die;
+    }
+  while (a->nscopes < nscopes);
+  assert (die->parent == NULL);
+  return a->nscopes;
+}
+
+/* Postorder visitor: first (innermost) call wins.  */
+static int
+pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
+{
+  struct args *a = arg;
+
+  if (die->prune)
+    return 0;
+
+  if (a->scopes == NULL)
+    {
+      /* We have hit the innermost DIE that contains the target PC.  */
+
+      a->nscopes = depth + 1 - a->inlined;
+      a->scopes = malloc (a->nscopes * sizeof a->scopes[0]);
+      if (a->scopes == NULL)
+	{
+	  __libdw_seterrno (DWARF_E_NOMEM);
+	  return -1;
+	}
+
+      for (unsigned int i = 0; i < a->nscopes; ++i)
+	{
+	  a->scopes[i] = die->die;
+	  die = die->parent;
+	}
+
+      if (a->inlined == 0)
+	{
+	  assert (die == NULL);
+	  return a->nscopes;
+	}
+
+      /* This is the concrete inlined instance itself.
+	 Record its abstract_origin pointer.  */
+      Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
+
+      assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
+      Dwarf_Attribute attr_mem;
+      Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
+						   DW_AT_abstract_origin,
+						   &attr_mem);
+      if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
+	return -1;
+      return 0;
+    }
+
+
+  /* We've recorded the scopes back to one that is a concrete inlined
+     instance.  Now return out of the traversal back to the scope
+     containing that instance.  */
+
+  assert (a->inlined);
+  if (depth >= a->inlined)
+    /* Not there yet.  */
+    return 0;
+
+  /* Now we are in a scope that contains the concrete inlined instance.
+     Search it for the inline function's abstract definition.
+     If we don't find it, return to search the containing scope.
+     If we do find it, the nonzero return value will bail us out
+     of the postorder traversal.  */
+  return __libdw_visit_scopes (depth, die, NULL, &origin_match, NULL, a);
+}
+
+
+int
+dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
+{
+  if (cudie == NULL)
+    return -1;
+
+  struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
+  struct args a = { .pc = pc };
+
+  int result = __libdw_visit_scopes (0, &cu, NULL, &pc_match, &pc_record, &a);
+
+  if (result == 0 && a.scopes != NULL)
+    result = __libdw_visit_scopes (0, &cu, NULL, &origin_match, NULL, &a);
+
+  if (result > 0)
+    *scopes = a.scopes;
+
+  return result;
+}
diff --git a/libdw/dwarf_getscopes_die.c b/libdw/dwarf_getscopes_die.c
new file mode 100644
index 0000000..8e2e41d
--- /dev/null
+++ b/libdw/dwarf_getscopes_die.c
@@ -0,0 +1,74 @@
+/* Return scope DIEs containing given DIE.
+   Copyright (C) 2005, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "libdwP.h"
+#include <assert.h>
+#include <stdlib.h>
+
+static int
+scope_visitor (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
+{
+  if (die->die.addr != *(void **) arg)
+    return 0;
+
+  Dwarf_Die *scopes = malloc (depth * sizeof scopes[0]);
+  if (scopes == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return -1;
+    }
+
+  unsigned int i = 0;
+  do
+    {
+      scopes[i++] = die->die;
+      die = die->parent;
+    }
+  while (die != NULL);
+  assert (i == depth);
+
+  *(void **) arg = scopes;
+  return depth;
+}
+
+int
+dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes)
+{
+  if (die == NULL)
+    return -1;
+
+  struct Dwarf_Die_Chain cu = { .die = CUDIE (die->cu), .parent = NULL };
+  void *info = die->addr;
+  int result = __libdw_visit_scopes (1, &cu, NULL, &scope_visitor, NULL, &info);
+  if (result > 0)
+    *scopes = info;
+  return result;
+}
diff --git a/libdw/dwarf_getscopevar.c b/libdw/dwarf_getscopevar.c
new file mode 100644
index 0000000..7b1416f
--- /dev/null
+++ b/libdw/dwarf_getscopevar.c
@@ -0,0 +1,159 @@
+/* Find a named variable or parameter within given scopes.
+   Copyright (C) 2005-2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <string.h>
+#include "libdwP.h"
+#include <dwarf.h>
+
+
+/* Find the containing CU's files.  */
+static int
+getfiles (Dwarf_Die *die, Dwarf_Files **files)
+{
+  return INTUSE(dwarf_getsrcfiles) (&CUDIE (die->cu), files, NULL);
+}
+
+/* Fetch an attribute that should have a constant integer form.  */
+static int
+getattr (Dwarf_Die *die, int search_name, Dwarf_Word *value)
+{
+  Dwarf_Attribute attr_mem;
+  return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, search_name,
+						      &attr_mem), value);
+}
+
+static inline int
+file_matches (const char *lastfile,
+              size_t match_file_len, const char *match_file,
+              Dwarf_Files *files, size_t idx,
+              bool *lastfile_matches)
+{
+  if (idx >= files->nfiles)
+    return false;
+  const char *file = files->info[idx].name;
+  if (file != lastfile)
+    {
+      size_t len = strlen (file);
+      *lastfile_matches = (len >= match_file_len
+                          && !memcmp (match_file, file, match_file_len)
+                          && (len == match_file_len
+                              || file[len - match_file_len - 1] == '/'));
+    }
+  return *lastfile_matches;
+}
+
+/* Search SCOPES[0..NSCOPES-1] for a variable called NAME.
+   Ignore the first SKIP_SHADOWS scopes that match the name.
+   If MATCH_FILE is not null, accept only declaration in that source file;
+   if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration
+   at that line and column.
+
+   If successful, fill in *RESULT with the DIE of the variable found,
+   and return N where SCOPES[N] is the scope defining the variable.
+   Return -1 for errors or -2 for no matching variable found.  */
+
+int
+dwarf_getscopevar (Dwarf_Die *scopes, int nscopes,
+		   const char *name, int skip_shadows,
+		   const char *match_file, int match_lineno, int match_linecol,
+		   Dwarf_Die *result)
+{
+  /* Match against the given file name.  */
+  size_t match_file_len = match_file == NULL ? 0 : strlen (match_file);
+  bool lastfile_matches = false;
+  const char *lastfile = NULL;
+
+  /* Start with the innermost scope and move out.  */
+  for (int out = 0; out < nscopes; ++out)
+    if (INTUSE(dwarf_haschildren) (&scopes[out]))
+      {
+	if (INTUSE(dwarf_child) (&scopes[out], result) != 0)
+	  return -1;
+	do
+	  {
+	    switch (INTUSE(dwarf_tag) (result))
+	      {
+	      case DW_TAG_variable:
+	      case DW_TAG_formal_parameter:
+		break;
+
+	      default:
+		continue;
+	      }
+
+	    /* Only get here for a variable or parameter.  Check the name.  */
+	    const char *diename = INTUSE(dwarf_diename) (result);
+	    if (diename != NULL && !strcmp (name, diename))
+	      {
+		/* We have a matching name.  */
+
+		if (skip_shadows > 0)
+		  {
+		    /* Punt this scope for the one it shadows.  */
+		    --skip_shadows;
+		    break;
+		  }
+
+		if (match_file != NULL)
+		  {
+		    /* Check its decl_file.  */
+
+		    Dwarf_Word i;
+		    Dwarf_Files *files;
+		    if (getattr (result, DW_AT_decl_file, &i) != 0
+			|| getfiles (&scopes[out], &files) != 0)
+		      break;
+
+		    if (!file_matches (lastfile, match_file_len, match_file,
+		                       files, i, &lastfile_matches))
+		      break;
+
+		    if (match_lineno > 0
+			&& (getattr (result, DW_AT_decl_line, &i) != 0
+			    || (int) i != match_lineno))
+		      break;
+		    if (match_linecol > 0
+			&& (getattr (result, DW_AT_decl_column, &i) != 0
+			    || (int) i != match_linecol))
+		      break;
+		  }
+
+		/* We have a winner!  */
+		return out;
+	      }
+	  }
+	while (INTUSE(dwarf_siblingof) (result, result) == 0);
+      }
+
+  return -2;
+}
diff --git a/libdw/dwarf_getsrc_die.c b/libdw/dwarf_getsrc_die.c
new file mode 100644
index 0000000..a95179f
--- /dev/null
+++ b/libdw/dwarf_getsrc_die.c
@@ -0,0 +1,74 @@
+/* Find line information for address.
+   Copyright (C) 2004, 2005, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <assert.h>
+
+
+Dwarf_Line *
+dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr)
+{
+  Dwarf_Lines *lines;
+  size_t nlines;
+
+  if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0)
+    return NULL;
+
+  /* The lines are sorted by address, so we can use binary search.  */
+  if (nlines > 0)
+    {
+      size_t l = 0, u = nlines - 1;
+      while (l < u)
+	{
+	  size_t idx = u - (u - l) / 2;
+	  Dwarf_Line *line = &lines->info[idx];
+	  if (addr < line->addr)
+	    u = idx - 1;
+	  else
+	    l = idx;
+	}
+
+      /* This is guaranteed for us by libdw read_srclines.  */
+      assert (lines->info[nlines - 1].end_sequence);
+
+      /* The last line which is less than or equal to addr is what we
+	 want, unless it is the end_sequence which is after the
+	 current line sequence.  */
+      Dwarf_Line *line = &lines->info[l];
+      if (! line->end_sequence && line->addr <= addr)
+	return &lines->info[l];
+    }
+
+  __libdw_seterrno (DWARF_E_ADDR_OUTOFRANGE);
+  return NULL;
+}
diff --git a/libdw/dwarf_getsrc_file.c b/libdw/dwarf_getsrc_file.c
new file mode 100644
index 0000000..5289c7d
--- /dev/null
+++ b/libdw/dwarf_getsrc_file.c
@@ -0,0 +1,178 @@
+/* Find line information for given file/line/column triple.
+   Copyright (C) 2005-2009 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libdwP.h"
+
+
+int
+dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,
+		   Dwarf_Line ***srcsp, size_t *nsrcs)
+{
+  if (dbg == NULL)
+    return -1;
+
+  bool is_basename = strchr (fname, '/') == NULL;
+
+  size_t max_match = *nsrcs ?: ~0u;
+  size_t act_match = *nsrcs;
+  size_t cur_match = 0;
+  Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp;
+
+  size_t cuhl;
+  Dwarf_Off noff;
+  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);
+      if (cudie == NULL)
+	continue;
+
+      /* Get the line number information for this file.  */
+      Dwarf_Lines *lines;
+      size_t nlines;
+      if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0)
+	{
+	  /* 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,
+	 no match is performed.  */
+      unsigned int lastfile = UINT_MAX;
+      bool lastmatch = false;
+      for (size_t cnt = 0; cnt < nlines; ++cnt)
+	{
+	  Dwarf_Line *line = &lines->info[cnt];
+
+	  if (lastfile != line->file)
+	    {
+	      lastfile = line->file;
+	      if (lastfile >= line->files->nfiles)
+		{
+		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+		  return -1;
+		}
+
+	      /* Match the name with the name the user provided.  */
+	      const char *fname2 = line->files->info[lastfile].name;
+	      if (is_basename)
+		lastmatch = strcmp (basename (fname2), fname) == 0;
+	      else
+		lastmatch = strcmp (fname2, fname) == 0;
+	    }
+	  if (!lastmatch)
+	    continue;
+
+	  /* See whether line and possibly column match.  */
+	  if (lineno != 0
+	      && (lineno > line->line
+		  || (column != 0 && column > line->column)))
+	    /* Cannot match.  */
+	    continue;
+
+	  /* Determine whether this is the best match so far.  */
+	  size_t inner;
+	  for (inner = 0; inner < cur_match; ++inner)
+	    if (match[inner]->files == line->files
+		&& match[inner]->file == line->file)
+	      break;
+	  if (inner < cur_match
+	      && (match[inner]->line != line->line
+		  || match[inner]->line != lineno
+		  || (column != 0
+		      && (match[inner]->column != line->column
+			  || match[inner]->column != column))))
+	    {
+	      /* We know about this file already.  If this is a better
+		 match for the line number, use it.  */
+	      if (match[inner]->line >= line->line
+		  && (match[inner]->line != line->line
+		      || match[inner]->column >= line->column))
+		/*  Use the new line.  Otherwise the old one.  */
+		match[inner] = line;
+	      continue;
+	    }
+
+	  if (cur_match < max_match)
+	    {
+	      if (cur_match == act_match)
+		{
+		  /* Enlarge the array for the results.  */
+		  act_match += 10;
+		  Dwarf_Line **newp = realloc (match,
+					       act_match
+					       * sizeof (Dwarf_Line *));
+		  if (newp == NULL)
+		    {
+		      free (match);
+		      __libdw_seterrno (DWARF_E_NOMEM);
+		      return -1;
+		    }
+		  match = newp;
+		}
+
+	      match[cur_match++] = line;
+	    }
+	}
+
+      /* If we managed to find as many matches as the user requested
+	 already, there is no need to go on to the next CU.  */
+      if (cur_match == max_match)
+	break;
+    }
+
+  if (cur_match > 0)
+    {
+      assert (*nsrcs == 0 || *srcsp == match);
+
+      *nsrcs = cur_match;
+      *srcsp = match;
+
+      return 0;
+    }
+
+  __libdw_seterrno (DWARF_E_NO_MATCH);
+  return -1;
+}
diff --git a/libdw/dwarf_getsrcdirs.c b/libdw/dwarf_getsrcdirs.c
new file mode 100644
index 0000000..8160ed3
--- /dev/null
+++ b/libdw/dwarf_getsrcdirs.c
@@ -0,0 +1,45 @@
+/* Find include directories in source file information.
+   Copyright (C) 2007 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_getsrcdirs (Dwarf_Files *files, const char *const **result, size_t *ndirs)
+{
+  if (files == NULL)
+    return -1;
+
+  *result = (void *) &files->info[files->nfiles];
+  *ndirs = files->ndirs;
+  return 0;
+}
diff --git a/libdw/dwarf_getsrcfiles.c b/libdw/dwarf_getsrcfiles.c
new file mode 100644
index 0000000..5af6f68
--- /dev/null
+++ b/libdw/dwarf_getsrcfiles.c
@@ -0,0 +1,79 @@
+/* Return source file information of CU.
+   Copyright (C) 2004, 2005, 2013, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles)
+{
+  if (cudie == NULL)
+    return -1;
+  if (! is_cudie (cudie))
+    {
+      __libdw_seterrno (DWARF_E_NOT_CUDIE);
+      return -1;
+    }
+
+  int res = -1;
+
+  /* Get the information if it is not already known.  */
+  struct Dwarf_CU *const cu = cudie->cu;
+  if (cu->lines == NULL)
+    {
+      Dwarf_Lines *lines;
+      size_t nlines;
+
+      /* Let the more generic function do the work.  It'll create more
+	 data but that will be needed in an real program anyway.  */
+      res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines);
+    }
+  else if (cu->files != (void *) -1l)
+    /* We already have the information.  */
+    res = 0;
+
+  if (likely (res == 0))
+    {
+      assert (cu->files != NULL && cu->files != (void *) -1l);
+      *files = cu->files;
+      if (nfiles != NULL)
+	*nfiles = cu->files->nfiles;
+    }
+
+  // XXX Eventually: unlocking here.
+
+  return res;
+}
+INTDEF (dwarf_getsrcfiles)
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
new file mode 100644
index 0000000..d02c38d
--- /dev/null
+++ b/libdw/dwarf_getsrclines.c
@@ -0,0 +1,952 @@
+/* Return line number information of CU.
+   Copyright (C) 2004-2010, 2013, 2014, 2015, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+
+#include "dwarf.h"
+#include "libdwP.h"
+
+
+struct filelist
+{
+  Dwarf_Fileinfo info;
+  struct filelist *next;
+};
+
+struct linelist
+{
+  Dwarf_Line line;
+  struct linelist *next;
+  size_t sequence;
+};
+
+
+/* Compare by Dwarf_Line.addr, given pointers into an array of pointers.  */
+static int
+compare_lines (const void *a, const void *b)
+{
+  struct linelist *const *p1 = a;
+  struct linelist *const *p2 = b;
+  struct linelist *list1 = *p1;
+  struct linelist *list2 = *p2;
+  Dwarf_Line *line1 = &list1->line;
+  Dwarf_Line *line2 = &list2->line;
+
+  if (line1->addr != line2->addr)
+    return (line1->addr < line2->addr) ? -1 : 1;
+
+  /* An end_sequence marker precedes a normal record at the same address.  */
+  if (line1->end_sequence != line2->end_sequence)
+    return line2->end_sequence - line1->end_sequence;
+
+  /* Otherwise, the linelist sequence maintains a stable sort.  */
+  return (list1->sequence < list2->sequence) ? -1
+    : (list1->sequence > list2->sequence) ? 1
+    : 0;
+}
+
+struct line_state
+{
+  Dwarf_Word addr;
+  unsigned int op_index;
+  unsigned int file;
+  int64_t line;
+  unsigned int column;
+  uint_fast8_t is_stmt;
+  bool basic_block;
+  bool prologue_end;
+  bool epilogue_begin;
+  unsigned int isa;
+  unsigned int discriminator;
+  struct linelist *linelist;
+  size_t nlinelist;
+  unsigned int end_sequence;
+};
+
+static inline void
+run_advance_pc (struct line_state *state, unsigned int op_advance,
+                uint_fast8_t minimum_instr_len, uint_fast8_t max_ops_per_instr)
+{
+  state->addr += minimum_instr_len * ((state->op_index + op_advance)
+				      / max_ops_per_instr);
+  state->op_index = (state->op_index + op_advance) % max_ops_per_instr;
+}
+
+static inline bool
+add_new_line (struct line_state *state, struct linelist *new_line)
+{
+  /* Set the line information.  For some fields we use bitfields,
+     so we would lose information if the encoded values are too large.
+     Check just for paranoia, and call the data "invalid" if it
+     violates our assumptions on reasonable limits for the values.  */
+  new_line->next = state->linelist;
+  new_line->sequence = state->nlinelist;
+  state->linelist = new_line;
+  ++(state->nlinelist);
+
+  /* Set the line information.  For some fields we use bitfields,
+     so we would lose information if the encoded values are too large.
+     Check just for paranoia, and call the data "invalid" if it
+     violates our assumptions on reasonable limits for the values.  */
+#define SET(field)						      \
+  do {								      \
+     new_line->line.field = state->field;			      \
+     if (unlikely (new_line->line.field != state->field))	      \
+       return true;						      \
+   } while (0)
+
+  SET (addr);
+  SET (op_index);
+  SET (file);
+  SET (line);
+  SET (column);
+  SET (is_stmt);
+  SET (basic_block);
+  SET (end_sequence);
+  SET (prologue_end);
+  SET (epilogue_begin);
+  SET (isa);
+  SET (discriminator);
+
+#undef SET
+
+  return false;
+}
+
+static int
+read_srclines (Dwarf *dbg,
+	       const unsigned char *linep, const unsigned char *lineendp,
+	       const char *comp_dir, unsigned address_size,
+	       Dwarf_Lines **linesp, Dwarf_Files **filesp)
+{
+  int res = -1;
+
+  size_t nfilelist = 0;
+  unsigned int ndirlist = 0;
+
+  struct filelist null_file =
+    {
+      .info =
+      {
+	.name = "???",
+	.mtime = 0,
+	.length = 0
+      },
+      .next = NULL
+    };
+  struct filelist *filelist = &null_file;
+
+  /* If there are a large number of lines, files or dirs don't blow up
+     the stack.  Stack allocate some entries, only dynamically malloc
+     when more than MAX.  */
+#define MAX_STACK_ALLOC 4096
+#define MAX_STACK_LINES MAX_STACK_ALLOC
+#define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
+#define MAX_STACK_DIRS  (MAX_STACK_ALLOC / 16)
+
+  struct dirlist
+  {
+    const char *dir;
+    size_t len;
+  };
+  struct dirlist dirstack[MAX_STACK_DIRS];
+  struct dirlist *dirarray = dirstack;
+
+  /* We are about to process the statement program.  Initialize the
+     state machine registers (see 6.2.2 in the v2.1 specification).  */
+  struct line_state state =
+    {
+      .linelist = NULL,
+      .nlinelist = 0,
+      .addr = 0,
+      .op_index = 0,
+      .file = 1,
+      /* We only store int but want to check for overflow (see SET above).  */
+      .line = 1,
+      .column = 0,
+      .basic_block = false,
+      .prologue_end = false,
+      .epilogue_begin = false,
+      .isa = 0,
+      .discriminator = 0
+    };
+
+  if (unlikely (linep + 4 > lineendp))
+    {
+    invalid_data:
+      __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+      goto out;
+    }
+
+  Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
+  unsigned int length = 4;
+  if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
+    {
+      if (unlikely (linep + 8 > lineendp))
+	goto invalid_data;
+      unit_length = read_8ubyte_unaligned_inc (dbg, linep);
+      length = 8;
+    }
+
+  /* Check whether we have enough room in the section.  */
+  if (unlikely (unit_length > (size_t) (lineendp - linep)
+      || unit_length < 2 + length + 5 * 1))
+    goto invalid_data;
+  lineendp = linep + unit_length;
+
+  /* The next element of the header is the version identifier.  */
+  uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
+  if (unlikely (version < 2) || unlikely (version > 4))
+    {
+      __libdw_seterrno (DWARF_E_VERSION);
+      goto out;
+    }
+
+  /* Next comes the header length.  */
+  Dwarf_Word header_length;
+  if (length == 4)
+    header_length = read_4ubyte_unaligned_inc (dbg, linep);
+  else
+    header_length = read_8ubyte_unaligned_inc (dbg, linep);
+  const unsigned char *header_start = linep;
+
+  /* Next the minimum instruction length.  */
+  uint_fast8_t minimum_instr_len = *linep++;
+
+  /* Next the maximum operations per instruction, in version 4 format.  */
+  uint_fast8_t max_ops_per_instr = 1;
+  if (version >= 4)
+    {
+      if (unlikely (lineendp - linep < 5))
+	goto invalid_data;
+      max_ops_per_instr = *linep++;
+      if (unlikely (max_ops_per_instr == 0))
+	goto invalid_data;
+    }
+
+  /* Then the flag determining the default value of the is_stmt
+     register.  */
+  uint_fast8_t default_is_stmt = *linep++;
+
+  /* Now the line base.  */
+  int_fast8_t line_base = (int8_t) *linep++;
+
+  /* And the line range.  */
+  uint_fast8_t line_range = *linep++;
+
+  /* The opcode base.  */
+  uint_fast8_t opcode_base = *linep++;
+
+  /* Remember array with the standard opcode length (-1 to account for
+     the opcode with value zero not being mentioned).  */
+  const uint8_t *standard_opcode_lengths = linep - 1;
+  if (unlikely (lineendp - linep < opcode_base - 1))
+    goto invalid_data;
+  linep += opcode_base - 1;
+
+  /* First comes the list of directories.  Add the compilation
+     directory first since the index zero is used for it.  */
+  struct dirlist comp_dir_elem =
+    {
+      .dir = comp_dir,
+      .len = comp_dir ? strlen (comp_dir) : 0,
+    };
+  ndirlist = 1;
+
+  /* First count the entries.  */
+  const unsigned char *dirp = linep;
+  unsigned int ndirs = 0;
+  while (*dirp != 0)
+    {
+      uint8_t *endp = memchr (dirp, '\0', lineendp - dirp);
+      if (endp == NULL)
+	goto invalid_data;
+      ++ndirs;
+      dirp = endp + 1;
+    }
+  ndirlist += ndirs;
+
+  /* Arrange the list in array form.  */
+  if (ndirlist >= MAX_STACK_DIRS)
+    {
+      dirarray = (struct dirlist *) malloc (ndirlist * sizeof (*dirarray));
+      if (unlikely (dirarray == NULL))
+	{
+	no_mem:
+	  __libdw_seterrno (DWARF_E_NOMEM);
+	  goto out;
+	}
+    }
+  dirarray[0] = comp_dir_elem;
+  for (unsigned int n = 1; n < ndirlist; n++)
+    {
+      dirarray[n].dir = (char *) linep;
+      uint8_t *endp = memchr (linep, '\0', lineendp - linep);
+      assert (endp != NULL);
+      dirarray[n].len = endp - linep;
+      linep = endp + 1;
+    }
+  /* Skip the final NUL byte.  */
+  ++linep;
+
+  /* Allocate memory for a new file.  For the first MAX_STACK_FILES
+     entries just return a slot in the preallocated stack array.  */
+  struct filelist flstack[MAX_STACK_FILES];
+#define NEW_FILE() ({							\
+  struct filelist *fl = (nfilelist < MAX_STACK_FILES			\
+			   ? &flstack[nfilelist]			\
+			   : malloc (sizeof (struct filelist)));	\
+  if (unlikely (fl == NULL))						\
+    goto no_mem;							\
+  ++nfilelist;								\
+  fl->next = filelist;							\
+  filelist = fl;							\
+  fl; })
+
+  /* Now read the files.  */
+  nfilelist = 1;
+
+  if (unlikely (linep >= lineendp))
+    goto invalid_data;
+  while (*linep != 0)
+    {
+      struct filelist *new_file = NEW_FILE ();
+
+      /* First comes the file name.  */
+      char *fname = (char *) linep;
+      uint8_t *endp = memchr (fname, '\0', lineendp - linep);
+      if (endp == NULL)
+	goto invalid_data;
+      size_t fnamelen = endp - (uint8_t *) fname;
+      linep = endp + 1;
+
+      /* Then the index.  */
+      Dwarf_Word diridx;
+      if (unlikely (linep >= lineendp))
+	goto invalid_data;
+      get_uleb128 (diridx, linep, lineendp);
+      if (unlikely (diridx >= ndirlist))
+	{
+	  __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+	  goto out;
+	}
+
+      if (*fname == '/')
+	/* It's an absolute path.  */
+	new_file->info.name = fname;
+      else
+	{
+	  new_file->info.name = libdw_alloc (dbg, char, 1,
+					     dirarray[diridx].len + 1
+					     + fnamelen + 1);
+	  char *cp = new_file->info.name;
+
+	  if (dirarray[diridx].dir != NULL)
+	    {
+	      /* This value could be NULL in case the DW_AT_comp_dir
+		 was not present.  We cannot do much in this case.
+		 The easiest thing is to convert the path in an
+		 absolute path.  */
+	      cp = stpcpy (cp, dirarray[diridx].dir);
+	    }
+	  *cp++ = '/';
+	  strcpy (cp, fname);
+	  assert (strlen (new_file->info.name)
+		  < dirarray[diridx].len + 1 + fnamelen + 1);
+	}
+
+      /* Next comes the modification time.  */
+      if (unlikely (linep >= lineendp))
+	goto invalid_data;
+      get_uleb128 (new_file->info.mtime, linep, lineendp);
+
+      /* Finally the length of the file.  */
+      if (unlikely (linep >= lineendp))
+	goto invalid_data;
+      get_uleb128 (new_file->info.length, linep, lineendp);
+    }
+  /* Skip the final NUL byte.  */
+  ++linep;
+
+  /* Consistency check.  */
+  if (unlikely (linep != header_start + header_length))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      goto out;
+    }
+
+  state.is_stmt = default_is_stmt;
+
+  /* Apply the "operation advance" from a special opcode or
+     DW_LNS_advance_pc (as per DWARF4 6.2.5.1).  */
+#define advance_pc(op_advance) \
+  run_advance_pc (&state, op_advance, minimum_instr_len, max_ops_per_instr)
+
+  /* Process the instructions.  */
+
+  /* Adds a new line to the matrix.  For the first MAX_STACK_LINES
+     entries just return a slot in the preallocated stack array.  */
+  struct linelist llstack[MAX_STACK_LINES];
+#define NEW_LINE(end_seq)						\
+  do {								\
+    struct linelist *ll = (state.nlinelist < MAX_STACK_LINES	\
+			   ? &llstack[state.nlinelist]		\
+			   : malloc (sizeof (struct linelist)));	\
+    if (unlikely (ll == NULL))					\
+      goto no_mem;						\
+    state.end_sequence = end_seq;				\
+    if (unlikely (add_new_line (&state, ll)))			\
+      goto invalid_data;						\
+  } while (0)
+
+  while (linep < lineendp)
+    {
+      unsigned int opcode;
+      unsigned int u128;
+      int s128;
+
+      /* Read the opcode.  */
+      opcode = *linep++;
+
+      /* Is this a special opcode?  */
+      if (likely (opcode >= opcode_base))
+	{
+	  if (unlikely (line_range == 0))
+	    goto invalid_data;
+
+	  /* Yes.  Handling this is quite easy since the opcode value
+	     is computed with
+
+	     opcode = (desired line increment - line_base)
+		       + (line_range * address advance) + opcode_base
+	  */
+	  int line_increment = (line_base
+				+ (opcode - opcode_base) % line_range);
+
+	  /* Perform the increments.  */
+	  state.line += line_increment;
+	  advance_pc ((opcode - opcode_base) / line_range);
+
+	  /* Add a new line with the current state machine values.  */
+	  NEW_LINE (0);
+
+	  /* Reset the flags.  */
+	  state.basic_block = false;
+	  state.prologue_end = false;
+	  state.epilogue_begin = false;
+	  state.discriminator = 0;
+	}
+      else if (opcode == 0)
+	{
+	  /* This an extended opcode.  */
+	  if (unlikely (lineendp - linep < 2))
+	    goto invalid_data;
+
+	  /* The length.  */
+	  uint_fast8_t len = *linep++;
+
+	  if (unlikely ((size_t) (lineendp - linep) < len))
+	    goto invalid_data;
+
+	  /* The sub-opcode.  */
+	  opcode = *linep++;
+
+	  switch (opcode)
+	    {
+	    case DW_LNE_end_sequence:
+	      /* Add a new line with the current state machine values.
+		 The is the end of the sequence.  */
+	      NEW_LINE (1);
+
+	      /* Reset the registers.  */
+	      state.addr = 0;
+	      state.op_index = 0;
+	      state.file = 1;
+	      state.line = 1;
+	      state.column = 0;
+	      state.is_stmt = default_is_stmt;
+	      state.basic_block = false;
+	      state.prologue_end = false;
+	      state.epilogue_begin = false;
+	      state.isa = 0;
+	      state.discriminator = 0;
+	      break;
+
+	    case DW_LNE_set_address:
+	      /* The value is an address.  The size is defined as
+		 apporiate for the target machine.  We use the
+		 address size field from the CU header.  */
+	      state.op_index = 0;
+	      if (unlikely (lineendp - linep < (uint8_t) address_size))
+		goto invalid_data;
+	      if (__libdw_read_address_inc (dbg, IDX_debug_line, &linep,
+					    address_size, &state.addr))
+		goto out;
+	      break;
+
+	    case DW_LNE_define_file:
+	      {
+		char *fname = (char *) linep;
+		uint8_t *endp = memchr (linep, '\0', lineendp - linep);
+		if (endp == NULL)
+		  goto invalid_data;
+		size_t fnamelen = endp - linep;
+		linep = endp + 1;
+
+		unsigned int diridx;
+		if (unlikely (linep >= lineendp))
+		  goto invalid_data;
+		get_uleb128 (diridx, linep, lineendp);
+		if (unlikely (diridx >= ndirlist))
+		  {
+		    __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+		    goto invalid_data;
+		  }
+		Dwarf_Word mtime;
+		if (unlikely (linep >= lineendp))
+		  goto invalid_data;
+		get_uleb128 (mtime, linep, lineendp);
+		Dwarf_Word filelength;
+		if (unlikely (linep >= lineendp))
+		  goto invalid_data;
+		get_uleb128 (filelength, linep, lineendp);
+
+		struct filelist *new_file = NEW_FILE ();
+		if (fname[0] == '/')
+		  new_file->info.name = fname;
+		else
+		  {
+		    new_file->info.name =
+		      libdw_alloc (dbg, char, 1, (dirarray[diridx].len + 1
+						  + fnamelen + 1));
+		    char *cp = new_file->info.name;
+
+		    if (dirarray[diridx].dir != NULL)
+		      /* This value could be NULL in case the
+			 DW_AT_comp_dir was not present.  We
+			 cannot do much in this case.  The easiest
+			 thing is to convert the path in an
+			 absolute path.  */
+		      cp = stpcpy (cp, dirarray[diridx].dir);
+		    *cp++ = '/';
+		    strcpy (cp, fname);
+		  }
+
+		new_file->info.mtime = mtime;
+		new_file->info.length = filelength;
+	      }
+	      break;
+
+	    case DW_LNE_set_discriminator:
+	      /* Takes one ULEB128 parameter, the discriminator.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 1))
+		goto invalid_data;
+
+	      if (unlikely (linep >= lineendp))
+		goto invalid_data;
+	      get_uleb128 (state.discriminator, linep, lineendp);
+	      break;
+
+	    default:
+	      /* Unknown, ignore it.  */
+	      if (unlikely ((size_t) (lineendp - (linep - 1)) < len))
+		goto invalid_data;
+	      linep += len - 1;
+	      break;
+	    }
+	}
+      else if (opcode <= DW_LNS_set_isa)
+	{
+	  /* This is a known standard opcode.  */
+	  switch (opcode)
+	    {
+	    case DW_LNS_copy:
+	      /* Takes no argument.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 0))
+		goto invalid_data;
+
+	      /* Add a new line with the current state machine values.  */
+	      NEW_LINE (0);
+
+	      /* Reset the flags.  */
+	      state.basic_block = false;
+	      state.prologue_end = false;
+	      state.epilogue_begin = false;
+	      state.discriminator = 0;
+	      break;
+
+	    case DW_LNS_advance_pc:
+	      /* Takes one uleb128 parameter which is added to the
+		 address.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 1))
+		goto invalid_data;
+
+	      if (unlikely (linep >= lineendp))
+		goto invalid_data;
+	      get_uleb128 (u128, linep, lineendp);
+	      advance_pc (u128);
+	      break;
+
+	    case DW_LNS_advance_line:
+	      /* Takes one sleb128 parameter which is added to the
+		 line.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 1))
+		goto invalid_data;
+
+	      if (unlikely (linep >= lineendp))
+		goto invalid_data;
+	      get_sleb128 (s128, linep, lineendp);
+	      state.line += s128;
+	      break;
+
+	    case DW_LNS_set_file:
+	      /* Takes one uleb128 parameter which is stored in file.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 1))
+		goto invalid_data;
+
+	      if (unlikely (linep >= lineendp))
+		goto invalid_data;
+	      get_uleb128 (u128, linep, lineendp);
+	      state.file = u128;
+	      break;
+
+	    case DW_LNS_set_column:
+	      /* Takes one uleb128 parameter which is stored in column.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 1))
+		goto invalid_data;
+
+	      if (unlikely (linep >= lineendp))
+		goto invalid_data;
+	      get_uleb128 (u128, linep, lineendp);
+	      state.column = u128;
+	      break;
+
+	    case DW_LNS_negate_stmt:
+	      /* Takes no argument.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 0))
+		goto invalid_data;
+
+	      state.is_stmt = 1 - state.is_stmt;
+	      break;
+
+	    case DW_LNS_set_basic_block:
+	      /* Takes no argument.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 0))
+		goto invalid_data;
+
+	      state.basic_block = true;
+	      break;
+
+	    case DW_LNS_const_add_pc:
+	      /* Takes no argument.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 0))
+		goto invalid_data;
+
+	      if (unlikely (line_range == 0))
+		goto invalid_data;
+
+	      advance_pc ((255 - opcode_base) / line_range);
+	      break;
+
+	    case DW_LNS_fixed_advance_pc:
+	      /* Takes one 16 bit parameter which is added to the
+		 address.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 1)
+		  || unlikely (lineendp - linep < 2))
+		goto invalid_data;
+
+	      state.addr += read_2ubyte_unaligned_inc (dbg, linep);
+	      state.op_index = 0;
+	      break;
+
+	    case DW_LNS_set_prologue_end:
+	      /* Takes no argument.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 0))
+		goto invalid_data;
+
+	      state.prologue_end = true;
+	      break;
+
+	    case DW_LNS_set_epilogue_begin:
+	      /* Takes no argument.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 0))
+		goto invalid_data;
+
+	      state.epilogue_begin = true;
+	      break;
+
+	    case DW_LNS_set_isa:
+	      /* Takes one uleb128 parameter which is stored in isa.  */
+	      if (unlikely (standard_opcode_lengths[opcode] != 1))
+		goto invalid_data;
+
+	      if (unlikely (linep >= lineendp))
+		goto invalid_data;
+	      get_uleb128 (state.isa, linep, lineendp);
+	      break;
+	    }
+	}
+      else
+	{
+	  /* This is a new opcode the generator but not we know about.
+	     Read the parameters associated with it but then discard
+	     everything.  Read all the parameters for this opcode.  */
+	  for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
+	    {
+	      if (unlikely (linep >= lineendp))
+		goto invalid_data;
+	      get_uleb128 (u128, linep, lineendp);
+	    }
+
+	  /* Next round, ignore this opcode.  */
+	  continue;
+	}
+    }
+
+  /* Put all the files in an array.  */
+  Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
+				    sizeof (Dwarf_Files)
+				    + nfilelist * sizeof (Dwarf_Fileinfo)
+				    + (ndirlist + 1) * sizeof (char *),
+				    1);
+  const char **dirs = (void *) &files->info[nfilelist];
+
+  struct filelist *fileslist = filelist;
+  files->nfiles = nfilelist;
+  for (size_t n = nfilelist; n > 0; n--)
+    {
+      files->info[n - 1] = fileslist->info;
+      fileslist = fileslist->next;
+    }
+  assert (fileslist == NULL);
+
+  /* Put all the directory strings in an array.  */
+  files->ndirs = ndirlist;
+  for (unsigned int i = 0; i < ndirlist; ++i)
+    dirs[i] = dirarray[i].dir;
+  dirs[ndirlist] = NULL;
+
+  /* Pass the file data structure to the caller.  */
+  if (filesp != NULL)
+    *filesp = files;
+
+  size_t buf_size = (sizeof (Dwarf_Lines)
+		     + (sizeof (Dwarf_Line) * state.nlinelist));
+  void *buf = libdw_alloc (dbg, Dwarf_Lines, buf_size, 1);
+
+  /* First use the buffer for the pointers, and sort the entries.
+     We'll write the pointers in the end of the buffer, and then
+     copy into the buffer from the beginning so the overlap works.  */
+  assert (sizeof (Dwarf_Line) >= sizeof (struct linelist *));
+  struct linelist **sortlines = (buf + buf_size
+				 - sizeof (struct linelist **) * state.nlinelist);
+
+  /* The list is in LIFO order and usually they come in clumps with
+     ascending addresses.  So fill from the back to probably start with
+     runs already in order before we sort.  */
+  struct linelist *lineslist = state.linelist;
+  for (size_t i = state.nlinelist; i-- > 0; )
+    {
+      sortlines[i] = lineslist;
+      lineslist = lineslist->next;
+    }
+  assert (lineslist == NULL);
+
+  /* Sort by ascending address.  */
+  qsort (sortlines, state.nlinelist, sizeof sortlines[0], &compare_lines);
+
+  /* Now that they are sorted, put them in the final array.
+     The buffers overlap, so we've clobbered the early elements
+     of SORTLINES by the time we're reading the later ones.  */
+  Dwarf_Lines *lines = buf;
+  lines->nlines = state.nlinelist;
+  for (size_t i = 0; i < state.nlinelist; ++i)
+    {
+      lines->info[i] = sortlines[i]->line;
+      lines->info[i].files = files;
+    }
+
+  /* Make sure the highest address for the CU is marked as end_sequence.
+     This is required by the DWARF spec, but some compilers forget and
+     dwfl_module_getsrc depends on it.  */
+  if (state.nlinelist > 0)
+    lines->info[state.nlinelist - 1].end_sequence = 1;
+
+  /* Pass the line structure back to the caller.  */
+  if (linesp != NULL)
+    *linesp = lines;
+
+  /* Success.  */
+  res = 0;
+
+ out:
+  /* Free malloced line records, if any.  */
+  for (size_t i = MAX_STACK_LINES; i < state.nlinelist; i++)
+    {
+      struct linelist *ll = state.linelist->next;
+      free (state.linelist);
+      state.linelist = ll;
+    }
+  if (ndirlist >= MAX_STACK_DIRS)
+    free (dirarray);
+  for (size_t i = MAX_STACK_FILES; i < nfilelist; i++)
+    {
+      struct filelist *fl = filelist->next;
+      free (filelist);
+      filelist = fl;
+    }
+
+  return res;
+}
+
+static int
+files_lines_compare (const void *p1, const void *p2)
+{
+  const struct files_lines_s *t1 = p1;
+  const struct files_lines_s *t2 = p2;
+
+  if (t1->debug_line_offset < t2->debug_line_offset)
+    return -1;
+  if (t1->debug_line_offset > t2->debug_line_offset)
+    return 1;
+
+  return 0;
+}
+
+int
+internal_function
+__libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
+		     const char *comp_dir, unsigned address_size,
+		     Dwarf_Lines **linesp, Dwarf_Files **filesp)
+{
+  struct files_lines_s fake = { .debug_line_offset = debug_line_offset };
+  struct files_lines_s **found = tfind (&fake, &dbg->files_lines,
+					files_lines_compare);
+  if (found == NULL)
+    {
+      Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line);
+      if (data == NULL
+	  || __libdw_offset_in_section (dbg, IDX_debug_line,
+					debug_line_offset, 1) != 0)
+	return -1;
+
+      const unsigned char *linep = data->d_buf + debug_line_offset;
+      const unsigned char *lineendp = data->d_buf + data->d_size;
+
+      struct files_lines_s *node = libdw_alloc (dbg, struct files_lines_s,
+						sizeof *node, 1);
+
+      if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
+			 &node->lines, &node->files) != 0)
+	return -1;
+
+      node->debug_line_offset = debug_line_offset;
+
+      found = tsearch (node, &dbg->files_lines, files_lines_compare);
+      if (found == NULL)
+	{
+	  __libdw_seterrno (DWARF_E_NOMEM);
+	  return -1;
+	}
+    }
+
+  if (linesp != NULL)
+    *linesp = (*found)->lines;
+
+  if (filesp != NULL)
+    *filesp = (*found)->files;
+
+  return 0;
+}
+
+/* Get the compilation directory, if any is set.  */
+const char *
+__libdw_getcompdir (Dwarf_Die *cudie)
+{
+  Dwarf_Attribute compdir_attr_mem;
+  Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie,
+						      DW_AT_comp_dir,
+						      &compdir_attr_mem);
+  return INTUSE(dwarf_formstring) (compdir_attr);
+}
+
+int
+dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
+{
+  if (cudie == NULL)
+    return -1;
+  if (! is_cudie (cudie))
+    {
+      __libdw_seterrno (DWARF_E_NOT_CUDIE);
+      return -1;
+    }
+
+  /* Get the information if it is not already known.  */
+  struct Dwarf_CU *const cu = cudie->cu;
+  if (cu->lines == NULL)
+    {
+      /* Failsafe mode: no data found.  */
+      cu->lines = (void *) -1l;
+      cu->files = (void *) -1l;
+
+      /* The die must have a statement list associated.  */
+      Dwarf_Attribute stmt_list_mem;
+      Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list,
+						       &stmt_list_mem);
+
+      /* Get the offset into the .debug_line section.  NB: this call
+	 also checks whether the previous dwarf_attr call failed.  */
+      Dwarf_Off debug_line_offset;
+      if (__libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE,
+			   NULL, &debug_line_offset) == NULL)
+	return -1;
+
+      if (__libdw_getsrclines (cu->dbg, debug_line_offset,
+			       __libdw_getcompdir (cudie),
+			       cu->address_size, &cu->lines, &cu->files) < 0)
+	return -1;
+    }
+  else if (cu->lines == (void *) -1l)
+    return -1;
+
+  *lines = cu->lines;
+  *nlines = cu->lines->nlines;
+
+  // XXX Eventually: unlocking here.
+
+  return 0;
+}
+INTDEF(dwarf_getsrclines)
diff --git a/libdw/dwarf_getstring.c b/libdw/dwarf_getstring.c
new file mode 100644
index 0000000..5620cb0
--- /dev/null
+++ b/libdw/dwarf_getstring.c
@@ -0,0 +1,63 @@
+/* Get string.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include "libdwP.h"
+
+
+const char *
+dwarf_getstring (Dwarf *dbg, Dwarf_Off offset, size_t *lenp)
+{
+  if (dbg == NULL)
+    return NULL;
+
+  if (dbg->sectiondata[IDX_debug_str] == NULL
+      || offset >= dbg->sectiondata[IDX_debug_str]->d_size)
+    {
+    no_string:
+      __libdw_seterrno (DWARF_E_NO_STRING);
+      return NULL;
+    }
+
+  const char *result = ((const char *) dbg->sectiondata[IDX_debug_str]->d_buf
+			+ offset);
+  const char *endp = memchr (result, '\0',
+			     dbg->sectiondata[IDX_debug_str]->d_size - offset);
+  if (endp == NULL)
+    goto no_string;
+
+  if (lenp != NULL)
+    *lenp = endp - result;
+
+  return result;
+}
diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c
new file mode 100644
index 0000000..90b333e
--- /dev/null
+++ b/libdw/dwarf_hasattr.c
@@ -0,0 +1,71 @@
+/* Check whether given DIE has specific attribute.
+   Copyright (C) 2003, 2005, 2014, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_hasattr (Dwarf_Die *die, unsigned int search_name)
+{
+  if (die == NULL)
+    return 0;
+
+  /* Find the abbreviation entry.  */
+  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
+  if (unlikely (abbrevp == DWARF_END_ABBREV))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return 0;
+    }
+
+  /* Search the name attribute.  Dwarf_Abbrev was checked when created,
+     so we can read unchecked here.  */
+  const unsigned char *attrp = abbrevp->attrp;
+  while (1)
+    {
+      /* Get attribute name and form.  */
+      unsigned int attr_name;
+      get_uleb128_unchecked (attr_name, attrp);
+      unsigned int attr_form;
+      get_uleb128_unchecked (attr_form, attrp);
+
+      /* We can stop if we found the attribute with value zero.  */
+      if (attr_name == 0 || attr_form == 0)
+	return 0;
+
+      if (attr_name == search_name)
+	return 1;
+    }
+}
+INTDEF (dwarf_hasattr)
diff --git a/libdw/dwarf_hasattr_integrate.c b/libdw/dwarf_hasattr_integrate.c
new file mode 100644
index 0000000..2d5348c
--- /dev/null
+++ b/libdw/dwarf_hasattr_integrate.c
@@ -0,0 +1,59 @@
+/* Check whether DIE has specific attribute, integrating DW_AT_abstract_origin.
+   Copyright (C) 2005 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+int
+dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name)
+{
+  Dwarf_Die die_mem;
+
+  do
+    {
+      if (INTUSE(dwarf_hasattr) (die, search_name))
+	return 1;
+
+      Dwarf_Attribute attr_mem;
+      Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin,
+						  &attr_mem);
+      if (attr == NULL)
+	attr = INTUSE(dwarf_attr) (die, DW_AT_specification, &attr_mem);
+      if (attr == NULL)
+	break;
+
+      die = INTUSE(dwarf_formref_die) (attr, &die_mem);
+    }
+  while (die != NULL);
+
+  return 0;
+}
diff --git a/libdw/dwarf_haschildren.c b/libdw/dwarf_haschildren.c
new file mode 100644
index 0000000..03a8173
--- /dev/null
+++ b/libdw/dwarf_haschildren.c
@@ -0,0 +1,51 @@
+/* Return string associated with given attribute.
+   Copyright (C) 2003, 2005, 2008, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <string.h>
+
+
+int
+dwarf_haschildren (Dwarf_Die *die)
+{
+  /* Find the abbreviation entry.  */
+  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
+  if (unlikely (abbrevp == DWARF_END_ABBREV))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  return abbrevp->has_children;
+}
+INTDEF (dwarf_haschildren)
diff --git a/libdw/dwarf_hasform.c b/libdw/dwarf_hasform.c
new file mode 100644
index 0000000..a0c3229
--- /dev/null
+++ b/libdw/dwarf_hasform.c
@@ -0,0 +1,45 @@
+/* Check whether given attribute has specific form.
+   Copyright (C) 2003 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_hasform (Dwarf_Attribute *attr, unsigned int search_form)
+{
+  if (attr == NULL)
+    return 0;
+
+  return attr->form == search_form;
+}
diff --git a/libdw/dwarf_haspc.c b/libdw/dwarf_haspc.c
new file mode 100644
index 0000000..47e2b05
--- /dev/null
+++ b/libdw/dwarf_haspc.c
@@ -0,0 +1,54 @@
+/* Determine whether a DIE covers a PC address.
+   Copyright (C) 2005 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+
+
+int
+dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc)
+{
+  if (die == NULL)
+    return -1;
+
+  Dwarf_Addr base;
+  Dwarf_Addr begin;
+  Dwarf_Addr end;
+  ptrdiff_t offset = 0;
+  while ((offset = INTUSE(dwarf_ranges) (die, offset, &base,
+					 &begin, &end)) > 0)
+    if (pc >= begin && pc < end)
+      return 1;
+
+  return offset;
+}
+INTDEF (dwarf_haspc)
diff --git a/libdw/dwarf_highpc.c b/libdw/dwarf_highpc.c
new file mode 100644
index 0000000..2070254
--- /dev/null
+++ b/libdw/dwarf_highpc.c
@@ -0,0 +1,66 @@
+/* Return high PC attribute of DIE.
+   Copyright (C) 2003, 2005, 2012 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+{
+  Dwarf_Attribute attr_high_mem;
+  Dwarf_Attribute *attr_high = INTUSE(dwarf_attr) (die, DW_AT_high_pc,
+						   &attr_high_mem);
+  if (attr_high == NULL)
+    return -1;
+
+  if (attr_high->form == DW_FORM_addr)
+    return INTUSE(dwarf_formaddr) (attr_high, return_addr);
+
+  /* DWARF 4 allows high_pc to be a constant offset from low_pc. */
+  Dwarf_Attribute attr_low_mem;
+  if (INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
+						  &attr_low_mem),
+			      return_addr) == 0)
+    {
+      Dwarf_Word uval;
+      if (INTUSE(dwarf_formudata) (attr_high, &uval) == 0)
+	{
+	  *return_addr += uval;
+	  return 0;
+	}
+      __libdw_seterrno (DWARF_E_NO_ADDR);
+    }
+  return -1;
+}
+INTDEF(dwarf_highpc)
diff --git a/libdw/dwarf_line_file.c b/libdw/dwarf_line_file.c
new file mode 100644
index 0000000..e2df642
--- /dev/null
+++ b/libdw/dwarf_line_file.c
@@ -0,0 +1,52 @@
+/* Find line information for address.
+   Copyright (C) 2017 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_line_file (Dwarf_Line *line, Dwarf_Files **files, size_t *idx)
+{
+  if (line == NULL)
+    return -1;
+
+  if (line->file >= line->files->nfiles)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  *files = line->files;
+  *idx = line->file;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineaddr.c b/libdw/dwarf_lineaddr.c
new file mode 100644
index 0000000..4e1952d
--- /dev/null
+++ b/libdw/dwarf_lineaddr.c
@@ -0,0 +1,46 @@
+/* Return line address.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp)
+{
+  if (line == NULL)
+    return -1;
+
+  *addrp =  line->addr;
+
+  return 0;
+}
diff --git a/libdw/dwarf_linebeginstatement.c b/libdw/dwarf_linebeginstatement.c
new file mode 100644
index 0000000..4854c56
--- /dev/null
+++ b/libdw/dwarf_linebeginstatement.c
@@ -0,0 +1,46 @@
+/* Return true if record is for beginning of a statement.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp)
+{
+  if (line == NULL)
+    return -1;
+
+  *flagp =  line->is_stmt;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineblock.c b/libdw/dwarf_lineblock.c
new file mode 100644
index 0000000..e3c7f41
--- /dev/null
+++ b/libdw/dwarf_lineblock.c
@@ -0,0 +1,46 @@
+/* Return true if record is for beginning of a basic block.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineblock (Dwarf_Line *line, bool *flagp)
+{
+  if (line == NULL)
+    return -1;
+
+  *flagp =  line->basic_block;
+
+  return 0;
+}
diff --git a/libdw/dwarf_linecol.c b/libdw/dwarf_linecol.c
new file mode 100644
index 0000000..c667b1b
--- /dev/null
+++ b/libdw/dwarf_linecol.c
@@ -0,0 +1,46 @@
+/* Return column in line.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_linecol (Dwarf_Line *line, int *colp)
+{
+  if (line == NULL)
+    return -1;
+
+  *colp =  line->column;
+
+  return 0;
+}
diff --git a/libdw/dwarf_linediscriminator.c b/libdw/dwarf_linediscriminator.c
new file mode 100644
index 0000000..552205a
--- /dev/null
+++ b/libdw/dwarf_linediscriminator.c
@@ -0,0 +1,45 @@
+/* Return code path discriminator in line record.
+   Copyright (C) 2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_linediscriminator (Dwarf_Line *line, unsigned int *discp)
+{
+  if (line == NULL)
+    return -1;
+
+  *discp = line->discriminator;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineendsequence.c b/libdw/dwarf_lineendsequence.c
new file mode 100644
index 0000000..61bde93
--- /dev/null
+++ b/libdw/dwarf_lineendsequence.c
@@ -0,0 +1,46 @@
+/* Return true if record is for end of sequence.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineendsequence (Dwarf_Line *line, bool *flagp)
+{
+  if (line == NULL)
+    return -1;
+
+  *flagp =  line->end_sequence;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineepiloguebegin.c b/libdw/dwarf_lineepiloguebegin.c
new file mode 100644
index 0000000..b914787
--- /dev/null
+++ b/libdw/dwarf_lineepiloguebegin.c
@@ -0,0 +1,46 @@
+/* Return true if record is for beginning of epilogue.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp)
+{
+  if (line == NULL)
+    return -1;
+
+  *flagp =  line->epilogue_begin;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineisa.c b/libdw/dwarf_lineisa.c
new file mode 100644
index 0000000..30181fc
--- /dev/null
+++ b/libdw/dwarf_lineisa.c
@@ -0,0 +1,45 @@
+/* Return ISA in line.
+   Copyright (C) 2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineisa (Dwarf_Line *line, unsigned int *isap)
+{
+  if (line == NULL)
+    return -1;
+
+  *isap = line->isa;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineno.c b/libdw/dwarf_lineno.c
new file mode 100644
index 0000000..009999c
--- /dev/null
+++ b/libdw/dwarf_lineno.c
@@ -0,0 +1,46 @@
+/* Return line number.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineno (Dwarf_Line *line, int *linep)
+{
+  if (line == NULL)
+    return -1;
+
+  *linep =  line->line;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineop_index.c b/libdw/dwarf_lineop_index.c
new file mode 100644
index 0000000..9ea4ef4
--- /dev/null
+++ b/libdw/dwarf_lineop_index.c
@@ -0,0 +1,45 @@
+/* Return line VLIW operation index.
+   Copyright (C) 2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineop_index (Dwarf_Line *line, unsigned int *idxp)
+{
+  if (line == NULL)
+    return -1;
+
+  *idxp = line->op_index;
+
+  return 0;
+}
diff --git a/libdw/dwarf_lineprologueend.c b/libdw/dwarf_lineprologueend.c
new file mode 100644
index 0000000..6ba8be2
--- /dev/null
+++ b/libdw/dwarf_lineprologueend.c
@@ -0,0 +1,46 @@
+/* Return true if record is for end of prologue.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_lineprologueend (Dwarf_Line *line, bool *flagp)
+{
+  if (line == NULL)
+    return -1;
+
+  *flagp =  line->prologue_end;
+
+  return 0;
+}
diff --git a/libdw/dwarf_linesrc.c b/libdw/dwarf_linesrc.c
new file mode 100644
index 0000000..27b5990
--- /dev/null
+++ b/libdw/dwarf_linesrc.c
@@ -0,0 +1,56 @@
+/* Find line information for address.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+const char *
+dwarf_linesrc (Dwarf_Line *line, Dwarf_Word *mtime, Dwarf_Word *length)
+{
+  if (line == NULL)
+    return NULL;
+
+  if (line->file >= line->files->nfiles)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  if (mtime != NULL)
+    *mtime = line->files->info[line->file].mtime;
+
+  if (length != NULL)
+    *length = line->files->info[line->file].length;
+
+  return line->files->info[line->file].name;
+}
diff --git a/libdw/dwarf_lowpc.c b/libdw/dwarf_lowpc.c
new file mode 100644
index 0000000..b3be2b0
--- /dev/null
+++ b/libdw/dwarf_lowpc.c
@@ -0,0 +1,47 @@
+/* Return low PC attribute of DIE.
+   Copyright (C) 2003, 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+{
+  Dwarf_Attribute attr_mem;
+
+  return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
+						     &attr_mem),
+				 return_addr);
+}
+INTDEF(dwarf_lowpc)
diff --git a/libdw/dwarf_macro_getparamcnt.c b/libdw/dwarf_macro_getparamcnt.c
new file mode 100644
index 0000000..e218eb1
--- /dev/null
+++ b/libdw/dwarf_macro_getparamcnt.c
@@ -0,0 +1,43 @@
+/* Return number of parameters of a macro.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+int
+dwarf_macro_getparamcnt (Dwarf_Macro *macro, size_t *paramcntp)
+{
+  if (macro == NULL)
+    return -1;
+
+  *paramcntp = libdw_macro_nforms (macro);
+  return 0;
+}
diff --git a/libdw/dwarf_macro_getsrcfiles.c b/libdw/dwarf_macro_getsrcfiles.c
new file mode 100644
index 0000000..3b1794b
--- /dev/null
+++ b/libdw/dwarf_macro_getsrcfiles.c
@@ -0,0 +1,86 @@
+/* Find line information for a given macro.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+int
+dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
+			 Dwarf_Files **files, size_t *nfiles)
+{
+  /* macro is declared NN */
+  Dwarf_Macro_Op_Table *const table = macro->table;
+  if (table->files == NULL)
+    {
+      Dwarf_Off line_offset = table->line_offset;
+      if (line_offset == (Dwarf_Off) -1)
+	{
+	  *files = NULL;
+	  *nfiles = 0;
+	  return 0;
+	}
+
+      /* If TABLE->comp_dir is NULL that could mean any of the
+	 following:
+
+	 - The macro unit is not bound to a CU.  It's an auxiliary
+           unit used purely for import from other units.  In that case
+           there's actually no COMP_DIR value that we could use.
+
+	 - The macro unit is bound to a CU, but there's no
+           DW_AT_comp_dir attribute at the CU DIE.
+
+	 - The macro unit is bound to a CU, but we don't know that,
+           likely because its iteration was requested through
+           dwarf_getmacros_off interface.  This might be legitimate if
+           one macro unit imports another CU's macro unit, but that is
+           unlikely to happen in practice.  Most probably this is not
+           legitimate use of the interfaces.
+
+	 So when the interfaces are used correctly, COMP_DIR value is
+	 always right.  That means that we can cache the parsed
+	 .debug_line unit without fear that later on someone requests
+	 the same unit through dwarf_getsrcfiles, and the file names
+	 will be broken.  */
+
+      if (__libdw_getsrclines (dbg, line_offset, table->comp_dir,
+			       table->is_64bit ? 8 : 4,
+			       NULL, &table->files) < 0)
+	table->files = (void *) -1;
+    }
+
+  if (table->files == (void *) -1)
+    return -1;
+
+  *files = table->files;
+  *nfiles = table->files->nfiles;
+  return 0;
+}
diff --git a/libdw/dwarf_macro_opcode.c b/libdw/dwarf_macro_opcode.c
new file mode 100644
index 0000000..8607777
--- /dev/null
+++ b/libdw/dwarf_macro_opcode.c
@@ -0,0 +1,46 @@
+/* Return macro opcode.
+   Copyright (C) 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep)
+{
+  if (macro == NULL)
+    return -1;
+
+  *opcodep = macro->opcode;
+
+  return 0;
+}
diff --git a/libdw/dwarf_macro_param.c b/libdw/dwarf_macro_param.c
new file mode 100644
index 0000000..bd846a7
--- /dev/null
+++ b/libdw/dwarf_macro_param.c
@@ -0,0 +1,46 @@
+/* Return a given parameter of a macro.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+int
+dwarf_macro_param (Dwarf_Macro *macro, size_t idx, Dwarf_Attribute *ret)
+{
+  if (macro == NULL)
+    return -1;
+
+  if (idx >= libdw_macro_nforms (macro))
+    return -1;
+
+  *ret = macro->attributes[idx];
+  return 0;
+}
diff --git a/libdw/dwarf_macro_param1.c b/libdw/dwarf_macro_param1.c
new file mode 100644
index 0000000..87ce003
--- /dev/null
+++ b/libdw/dwarf_macro_param1.c
@@ -0,0 +1,48 @@
+/* Return first macro parameter.
+   Copyright (C) 2005, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp)
+{
+  if (macro == NULL)
+    return -1;
+
+  Dwarf_Attribute param;
+  if (dwarf_macro_param (macro, 0, &param) != 0)
+    return -1;
+
+  return dwarf_formudata (&param, paramp);
+}
diff --git a/libdw/dwarf_macro_param2.c b/libdw/dwarf_macro_param2.c
new file mode 100644
index 0000000..cc902c9
--- /dev/null
+++ b/libdw/dwarf_macro_param2.c
@@ -0,0 +1,55 @@
+/* Return second macro parameter.
+   Copyright (C) 2005, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, const char **strp)
+{
+  if (macro == NULL)
+    return -1;
+
+  Dwarf_Attribute param;
+  if (dwarf_macro_param (macro, 1, &param) != 0)
+    return -1;
+
+  if (param.form == DW_FORM_string
+      || param.form == DW_FORM_strp)
+    {
+      *strp = dwarf_formstring (&param);
+      return 0;
+    }
+  else
+    return dwarf_formudata (&param, paramp);
+}
diff --git a/libdw/dwarf_next_cfi.c b/libdw/dwarf_next_cfi.c
new file mode 100644
index 0000000..53fc369
--- /dev/null
+++ b/libdw/dwarf_next_cfi.c
@@ -0,0 +1,245 @@
+/* Advance to next CFI entry.
+   Copyright (C) 2009-2010, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "cfi.h"
+#include "encoded-value.h"
+
+#include <string.h>
+
+
+int
+dwarf_next_cfi (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 && (unlikely (version < 3) || unlikely (version > 4)))
+	goto invalid;
+
+      entry->cie.augmentation = (const char *) bytes;
+
+      bytes = memchr (bytes, '\0', limit - bytes);
+      if (unlikely (bytes == NULL))
+	goto invalid;
+      ++bytes;
+
+      /* The address size for CFI is implicit in the ELF class.  */
+      uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+      uint_fast8_t segment_size = 0;
+      if (version >= 4)
+	{
+	  if (unlikely (limit - bytes < 5))
+	    goto invalid;
+	  /* XXX We don't actually support address_size not matching the class.
+	     To do so, we'd have to return it here so that intern_new_cie
+	     could use it choose a specific fde_encoding.  */
+	  if (unlikely (*bytes != address_size))
+	    {
+	      __libdw_seterrno (DWARF_E_VERSION);
+	      return -1;
+	    }
+	  address_size = *bytes++;
+	  segment_size = *bytes++;
+	  /* We don't actually support segment selectors.  We'd have to
+	     roll this into the fde_encoding bits or something.  */
+	  if (unlikely (segment_size != 0))
+	    {
+	      __libdw_seterrno (DWARF_E_VERSION);
+	      return -1;
+	    }
+	}
+
+      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'))
+	{
+	  ap += 2;
+	  bytes += address_size;
+	}
+
+      if (bytes >= limit)
+	goto invalid;
+      get_uleb128 (entry->cie.code_alignment_factor, bytes, limit);
+
+      if (bytes >= limit)
+	goto invalid;
+      get_sleb128 (entry->cie.data_alignment_factor, bytes, limit);
+
+      if (bytes >= limit)
+	goto invalid;
+
+      if (version >= 3)		/* DWARF 3+ */
+	get_uleb128 (entry->cie.return_address_register, bytes, limit);
+      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)
+	{
+	  if (bytes >= limit)
+	    goto invalid;
+	  get_uleb128 (entry->cie.augmentation_data_size, bytes, limit);
+	  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/libdw/dwarf_nextcu.c b/libdw/dwarf_nextcu.c
new file mode 100644
index 0000000..fa9b0af
--- /dev/null
+++ b/libdw/dwarf_nextcu.c
@@ -0,0 +1,186 @@
+/* Advance to next CU header.
+   Copyright (C) 2002-2010 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libdwP.h>
+#include <dwarf.h>
+
+
+int
+dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
+		 size_t *header_sizep, Dwarf_Half *versionp,
+		 Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
+		 uint8_t *offset_sizep, uint64_t *type_signaturep,
+		 Dwarf_Off *type_offsetp)
+{
+  const bool debug_types = type_signaturep != NULL;
+  const size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
+
+  /* Maybe there has been an error before.  */
+  if (dwarf == NULL)
+    return -1;
+
+  /* If we reached the end before don't do anything.  */
+  if (off == (Dwarf_Off) -1l
+      || unlikely (dwarf->sectiondata[sec_idx] == NULL)
+      /* Make sure there is enough space in the .debug_info section
+	 for at least the initial word.  We cannot test the rest since
+	 we don't know yet whether this is a 64-bit object or not.  */
+      || unlikely (off + 4 >= dwarf->sectiondata[sec_idx]->d_size))
+    {
+      *next_off = (Dwarf_Off) -1l;
+      return 1;
+    }
+
+  /* This points into the .debug_info section to the beginning of the
+     CU entry.  */
+  const unsigned char *data = dwarf->sectiondata[sec_idx]->d_buf;
+  const unsigned char *bytes = data + off;
+
+  /* The format of the CU header is described in dwarf2p1 7.5.1:
+
+     1.  A 4-byte or 12-byte unsigned integer representing the length
+	 of the .debug_info contribution for that compilation unit, not
+	 including the length field itself. In the 32-bit DWARF format,
+	 this is a 4-byte unsigned integer (which must be less than
+	 0xfffffff0); in the 64-bit DWARF format, this consists of the
+	 4-byte value 0xffffffff followed by an 8-byte unsigned integer
+	 that gives the actual length (see Section 7.2.2).
+
+      2. A 2-byte unsigned integer representing the version of the
+	 DWARF information for that compilation unit. For DWARF Version
+	 2.1, the value in this field is 2.
+
+      3. A 4-byte or 8-byte unsigned offset into the .debug_abbrev
+	 section. This offset associates the compilation unit with a
+	 particular set of debugging information entry abbreviations. In
+	 the 32-bit DWARF format, this is a 4-byte unsigned length; in
+	 the 64-bit DWARF format, this is an 8-byte unsigned length (see
+	 Section 7.4).
+
+      4. A 1-byte unsigned integer representing the size in bytes of
+	 an address on the target architecture. If the system uses
+	 segmented addressing, this value represents the size of the
+	 offset portion of an address.  */
+  uint64_t length = read_4ubyte_unaligned_inc (dwarf, bytes);
+  size_t offset_size = 4;
+  /* Lengths of 0xfffffff0 - 0xffffffff are escape codes.  Oxffffffff is
+     used to indicate that 64-bit dwarf information is being used, the
+     other values are currently reserved.  */
+  if (length == DWARF3_LENGTH_64_BIT)
+    offset_size = 8;
+  else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
+		     && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
+    {
+    invalid:
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  /* Now we know how large the header is.  */
+  if (unlikely (DIE_OFFSET_FROM_CU_OFFSET (off, offset_size, debug_types)
+		>= dwarf->sectiondata[sec_idx]->d_size))
+    {
+      *next_off = -1;
+      return 1;
+    }
+
+  if (length == DWARF3_LENGTH_64_BIT)
+    /* This is a 64-bit DWARF format.  */
+    length = read_8ubyte_unaligned_inc (dwarf, bytes);
+
+  /* Read the version stamp.  Always a 16-bit value.  */
+  uint_fast16_t version = read_2ubyte_unaligned_inc (dwarf, bytes);
+
+  /* Get offset in .debug_abbrev.  Note that the size of the entry
+     depends on whether this is a 32-bit or 64-bit DWARF definition.  */
+  uint64_t abbrev_offset;
+  if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
+			       &abbrev_offset, IDX_debug_abbrev, 0))
+    return -1;
+
+  /* The address size.  Always an 8-bit value.  */
+  uint8_t address_size = *bytes++;
+
+  if (debug_types)
+    {
+      uint64_t type_sig8 = read_8ubyte_unaligned_inc (dwarf, bytes);
+
+      Dwarf_Off type_offset;
+      if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
+				   &type_offset, sec_idx, 0))
+	return -1;
+
+      /* Validate that the TYPE_OFFSET points past the header.  */
+      if (unlikely (type_offset < (size_t) (bytes - (data + off))))
+	goto invalid;
+
+      *type_signaturep = type_sig8;
+      if (type_offsetp != NULL)
+	*type_offsetp = type_offset;
+    }
+
+  /* Store the header length.  */
+  if (header_sizep != NULL)
+    *header_sizep = bytes - (data + off);
+
+  if (versionp != NULL)
+    *versionp = version;
+
+  if (abbrev_offsetp != NULL)
+    *abbrev_offsetp = abbrev_offset;
+
+  if (address_sizep != NULL)
+    *address_sizep = address_size;
+
+  /* Store the offset size.  */
+  if (offset_sizep != NULL)
+    *offset_sizep = offset_size;
+
+  /* See definition of DIE_OFFSET_FROM_CU_OFFSET macro
+     for an explanation of the trick in this expression.  */
+  *next_off = off + 2 * offset_size - 4 + length;
+
+  return 0;
+}
+INTDEF(dwarf_next_unit)
+
+int
+dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
+	      size_t *header_sizep, Dwarf_Off *abbrev_offsetp,
+	      uint8_t *address_sizep, uint8_t *offset_sizep)
+{
+  return INTUSE(dwarf_next_unit) (dwarf, off, next_off, header_sizep, NULL,
+				  abbrev_offsetp, address_sizep, offset_sizep,
+				  NULL, NULL);
+}
+INTDEF(dwarf_nextcu)
diff --git a/libdw/dwarf_offabbrev.c b/libdw/dwarf_offabbrev.c
new file mode 100644
index 0000000..27cdad6
--- /dev/null
+++ b/libdw/dwarf_offabbrev.c
@@ -0,0 +1,51 @@
+/* Get abbreviation at given offset.
+   Copyright (C) 2004, 2005 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+int
+dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp,
+		 Dwarf_Abbrev *abbrevp)
+{
+  if (dbg == NULL)
+    return -1;
+
+  Dwarf_Abbrev *abbrev = __libdw_getabbrev (dbg, NULL, offset, lengthp,
+					    abbrevp);
+
+  if (abbrev == NULL)
+    return -1;
+
+  return abbrev == DWARF_END_ABBREV ? 1 : 0;
+}
diff --git a/libdw/dwarf_offdie.c b/libdw/dwarf_offdie.c
new file mode 100644
index 0000000..883720d
--- /dev/null
+++ b/libdw/dwarf_offdie.c
@@ -0,0 +1,84 @@
+/* Return DIE at given offset.
+   Copyright (C) 2002-2010, 2017 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include "libdwP.h"
+
+
+Dwarf_Die *
+internal_function
+__libdw_offdie (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result,
+		bool debug_types)
+{
+  if (dbg == NULL)
+    return NULL;
+
+  Elf_Data *const data = dbg->sectiondata[debug_types ? IDX_debug_types
+					  : IDX_debug_info];
+  if (data == NULL || offset >= data->d_size)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  /* Clear the entire DIE structure.  This signals we have not yet
+     determined any of the information.  */
+  memset (result, '\0', sizeof (Dwarf_Die));
+
+  result->addr = (char *) data->d_buf + offset;
+
+  /* Get the CU.  */
+  result->cu = __libdw_findcu (dbg, offset, debug_types);
+  if (result->cu == NULL)
+    {
+      /* This should never happen.  The input file is malformed.  */
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      result = NULL;
+    }
+
+  return result;
+}
+
+
+Dwarf_Die *
+dwarf_offdie (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result)
+{
+  return __libdw_offdie (dbg, offset, result, false);
+}
+INTDEF(dwarf_offdie)
+
+Dwarf_Die *
+dwarf_offdie_types (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result)
+{
+  return __libdw_offdie (dbg, offset, result, true);
+}
diff --git a/libdw/dwarf_onearange.c b/libdw/dwarf_onearange.c
new file mode 100644
index 0000000..de49f6c
--- /dev/null
+++ b/libdw/dwarf_onearange.c
@@ -0,0 +1,50 @@
+/* Return one of the address range entries.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+Dwarf_Arange *
+dwarf_onearange (Dwarf_Aranges *aranges, size_t idx)
+{
+  if (aranges == NULL)
+    return NULL;
+
+  if (idx >= aranges->naranges)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_ARANGE_IDX);
+      return NULL;
+    }
+
+  return &aranges->info[idx];
+}
diff --git a/libdw/dwarf_onesrcline.c b/libdw/dwarf_onesrcline.c
new file mode 100644
index 0000000..5d3c3de
--- /dev/null
+++ b/libdw/dwarf_onesrcline.c
@@ -0,0 +1,50 @@
+/* Return one of the sources lines of a CU.
+   Copyright (C) 2004 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+Dwarf_Line *
+dwarf_onesrcline (Dwarf_Lines *lines, size_t idx)
+{
+  if (lines == NULL)
+    return NULL;
+
+  if (idx >= lines->nlines)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_LINE_IDX);
+      return NULL;
+    }
+
+  return &lines->info[idx];
+}
diff --git a/libdw/dwarf_peel_type.c b/libdw/dwarf_peel_type.c
new file mode 100644
index 0000000..6bbfd42
--- /dev/null
+++ b/libdw/dwarf_peel_type.c
@@ -0,0 +1,75 @@
+/* Peel type aliases and qualifier tags from a type DIE.
+   Copyright (C) 2014, 2015, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+#include <string.h>
+
+
+int
+dwarf_peel_type (Dwarf_Die *die, Dwarf_Die *result)
+{
+  int tag;
+
+  /* Ignore previous errors.  */
+  if (die == NULL)
+    return -1;
+
+  *result = *die;
+  tag = INTUSE (dwarf_tag) (result);
+  while (tag == DW_TAG_typedef
+	 || tag == DW_TAG_const_type
+	 || tag == DW_TAG_volatile_type
+	 || tag == DW_TAG_restrict_type
+	 || tag == DW_TAG_atomic_type
+	 || tag == DW_TAG_immutable_type
+	 || tag == DW_TAG_packed_type
+	 || tag == DW_TAG_shared_type)
+    {
+      Dwarf_Attribute attr_mem;
+      Dwarf_Attribute *attr = INTUSE (dwarf_attr_integrate) (result, DW_AT_type,
+							     &attr_mem);
+      if (attr == NULL)
+	return 1;
+
+      if (INTUSE (dwarf_formref_die) (attr, result) == NULL)
+	return -1;
+
+      tag = INTUSE (dwarf_tag) (result);
+    }
+
+  if (tag == DW_TAG_invalid)
+    return -1;
+
+  return 0;
+}
+INTDEF(dwarf_peel_type)
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
new file mode 100644
index 0000000..4b6853d
--- /dev/null
+++ b/libdw/dwarf_ranges.c
@@ -0,0 +1,193 @@
+/* Enumerate the PC ranges covered by a DIE.
+   Copyright (C) 2005, 2007, 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#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,
+	      Dwarf_Addr *startp, Dwarf_Addr *endp)
+{
+  if (die == NULL)
+    return -1;
+
+  if (offset == 0
+      /* Usually there is a single contiguous range.  */
+      && INTUSE(dwarf_highpc) (die, endp) == 0
+      && INTUSE(dwarf_lowpc) (die, startp) == 0)
+    /* A offset into .debug_ranges will never be 1, it must be at least a
+       multiple of 4.  So we can return 1 as a special case value to mark
+       there are no ranges to look for on the next call.  */
+    return 1;
+
+  if (offset == 1)
+    return 0;
+
+  /* We have to look for a noncontiguous range.  */
+
+  const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
+  if (d == NULL && offset != 0)
+    {
+      __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
+      return -1;
+    }
+
+  unsigned char *readp;
+  unsigned char *readendp;
+  if (offset == 0)
+    {
+      Dwarf_Attribute attr_mem;
+      Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
+						  &attr_mem);
+      if (attr == NULL)
+	/* No PC attributes in this DIE at all, so an empty range list.  */
+	return 0;
+
+      Dwarf_Word start_offset;
+      if ((readp = __libdw_formptr (attr, IDX_debug_ranges,
+				    DWARF_E_NO_DEBUG_RANGES,
+				    &readendp, &start_offset)) == NULL)
+	return -1;
+
+      offset = start_offset;
+      assert ((Dwarf_Word) offset == start_offset);
+
+      /* Fetch the CU's base address.  */
+      Dwarf_Die cudie = CUDIE (attr->cu);
+
+      /* Find the base address of the compilation unit.  It will
+	 normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
+	 the base address could be overridden by DW_AT_entry_pc.  It's
+	 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
+	 for compilation units with discontinuous ranges.  */
+      if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
+	  && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
+							 DW_AT_entry_pc,
+							 &attr_mem),
+				     basep) != 0)
+	*basep = (Dwarf_Addr) -1;
+    }
+  else
+    {
+      if (__libdw_offset_in_section (die->cu->dbg,
+				     IDX_debug_ranges, offset, 1))
+	return -1l;
+
+      readp = d->d_buf + offset;
+      readendp = d->d_buf + d->d_size;
+    }
+
+ next:
+  if (readendp - readp < die->cu->address_size * 2)
+    goto invalid;
+
+  Dwarf_Addr begin;
+  Dwarf_Addr end;
+
+  switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
+					   &readp, die->cu->address_size,
+					   &begin, &end, basep))
+    {
+    case 0:
+      break;
+    case 1:
+      goto next;
+    case 2:
+      return 0;
+    default:
+      return -1l;
+    }
+
+  /* We have an address range entry.  Check that we have a base.  */
+  if (*basep == (Dwarf_Addr) -1)
+    {
+      if (INTUSE(dwarf_errno) () == 0)
+	{
+	invalid:
+	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	}
+      return -1;
+    }
+
+  *startp = *basep + begin;
+  *endp = *basep + end;
+  return readp - (unsigned char *) d->d_buf;
+}
+INTDEF (dwarf_ranges)
diff --git a/libdw/dwarf_setalt.c b/libdw/dwarf_setalt.c
new file mode 100644
index 0000000..9051b8e
--- /dev/null
+++ b/libdw/dwarf_setalt.c
@@ -0,0 +1,49 @@
+/* Provides the data referenced by the .gnu_debugaltlink section.
+   Copyright (C) 2014, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+#include <unistd.h>
+
+void
+dwarf_setalt (Dwarf *main, Dwarf *alt)
+{
+  if (main->alt_fd != -1)
+    {
+      INTUSE(dwarf_end) (main->alt_dwarf);
+      close (main->alt_fd);
+      main->alt_fd = -1;
+    }
+
+  main->alt_dwarf = alt;
+}
+INTDEF (dwarf_setalt)
diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c
new file mode 100644
index 0000000..df39c1c
--- /dev/null
+++ b/libdw/dwarf_siblingof.c
@@ -0,0 +1,143 @@
+/* Return sibling of given DIE.
+   Copyright (C) 2003-2010, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+#include <string.h>
+
+
+int
+dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
+{
+  /* Ignore previous errors.  */
+  if (die == NULL)
+    return -1;
+
+  /* result is declared NN */
+
+  if (result != die)
+    result->addr = NULL;
+
+  unsigned int level = 0;
+
+  /* Copy of the current DIE.  */
+  Dwarf_Die this_die = *die;
+  /* Temporary attributes we create.  */
+  Dwarf_Attribute sibattr;
+  /* Copy of the CU in the request.  */
+  sibattr.cu = this_die.cu;
+  /* That's the address we start looking.  */
+  unsigned char *addr = this_die.addr;
+  /* End of the buffer.  */
+  unsigned char *endp = sibattr.cu->endp;
+
+  /* Search for the beginning of the next die on this level.  We
+     must not return the dies for children of the given die.  */
+  do
+    {
+      /* Find the end of the DIE or the sibling attribute.  */
+      addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code,
+				&sibattr.form);
+      if (addr != NULL && sibattr.code == DW_AT_sibling)
+	{
+	  Dwarf_Off offset;
+	  sibattr.valp = addr;
+	  if (unlikely (__libdw_formref (&sibattr, &offset) != 0))
+	    /* Something went wrong.  */
+	    return -1;
+
+	  /* The sibling attribute should point after this DIE in the CU.
+	     But not after the end of the CU.  */
+	  size_t size = sibattr.cu->endp - sibattr.cu->startp;
+	  size_t die_off = this_die.addr - this_die.cu->startp;
+	  if (unlikely (offset >= size || offset <= die_off))
+	    {
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return -1;
+	    }
+
+	  /* Compute the next address.  */
+	  addr = sibattr.cu->startp + offset;
+	}
+      else if (unlikely (addr == NULL)
+	       || unlikely (this_die.abbrev == DWARF_END_ABBREV))
+	return -1;
+      else if (this_die.abbrev->has_children)
+	/* This abbreviation has children.  */
+	++level;
+
+
+      while (1)
+	{
+	  /* Make sure we are still in range.  Some producers might skip
+	     the trailing NUL bytes.  */
+	  if (addr >= endp)
+	    return 1;
+
+	  if (*addr != '\0')
+	    break;
+
+	  if (level-- == 0)
+	    {
+	      if (result != die)
+		result->addr = addr;
+	      /* No more sibling at all.  */
+	      return 1;
+	    }
+
+	  ++addr;
+	}
+
+      /* Initialize the 'current DIE'.  */
+      this_die.addr = addr;
+      this_die.abbrev = NULL;
+    }
+  while (level > 0);
+
+  /* Maybe we reached the end of the CU.  */
+  if (addr >= endp)
+    return 1;
+
+  /* Clear the entire DIE structure.  This signals we have not yet
+     determined any of the information.  */
+  memset (result, '\0', sizeof (Dwarf_Die));
+
+  /* We have the address.  */
+  result->addr = addr;
+
+  /* Same CU as the parent.  */
+  result->cu = sibattr.cu;
+
+  return 0;
+}
+INTDEF(dwarf_siblingof)
diff --git a/libdw/dwarf_sig8_hash.c b/libdw/dwarf_sig8_hash.c
new file mode 100644
index 0000000..043cac7
--- /dev/null
+++ b/libdw/dwarf_sig8_hash.c
@@ -0,0 +1,41 @@
+/* Implementation of hash table for DWARF .debug_types section content.
+   Copyright (C) 2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define NO_UNDEF
+#include "dwarf_sig8_hash.h"
+#undef NO_UNDEF
+
+/* This is defined in dwarf_abbrev_hash.c, we can just use it here.  */
+#define next_prime __libdwarf_next_prime
+extern size_t next_prime (size_t) attribute_hidden;
+
+#include <dynamicsizehash.c>
diff --git a/libdw/dwarf_sig8_hash.h b/libdw/dwarf_sig8_hash.h
new file mode 100644
index 0000000..705ffbc
--- /dev/null
+++ b/libdw/dwarf_sig8_hash.h
@@ -0,0 +1,38 @@
+/* Hash table for DWARF .debug_types section content.
+   Copyright (C) 2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _DWARF_SIG8_HASH_H
+#define _DWARF_SIG8_HASH_H	1
+
+#define NAME Dwarf_Sig8_Hash
+#define TYPE struct Dwarf_CU *
+#define COMPARE(a, b) (0)
+
+#include <dynamicsizehash.h>
+
+#endif	/* dwarf_sig8_hash.h */
diff --git a/libdw/dwarf_srclang.c b/libdw/dwarf_srclang.c
new file mode 100644
index 0000000..f10e764
--- /dev/null
+++ b/libdw/dwarf_srclang.c
@@ -0,0 +1,50 @@
+/* Return source language attribute of DIE.
+   Copyright (C) 2003-2010 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_srclang (Dwarf_Die *die)
+{
+  Dwarf_Attribute attr_mem;
+  Dwarf_Word value;
+
+  return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+				  (die, DW_AT_language, &attr_mem),
+				  &value) == 0 ? (int) value : -1;
+}
+INTDEF (dwarf_srclang)
+OLD_VERSION (dwarf_srclang, ELFUTILS_0.122)
+NEW_VERSION (dwarf_srclang, ELFUTILS_0.143)
diff --git a/libdw/dwarf_tag.c b/libdw/dwarf_tag.c
new file mode 100644
index 0000000..331eaa0
--- /dev/null
+++ b/libdw/dwarf_tag.c
@@ -0,0 +1,94 @@
+/* Return tag of given DIE.
+   Copyright (C) 2003-2011, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+
+
+Dwarf_Abbrev *
+internal_function
+__libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code)
+{
+  Dwarf_Abbrev *abb;
+
+  /* Abbreviation code can never have a value of 0.  */
+  if (unlikely (code == 0))
+    return DWARF_END_ABBREV;
+
+  /* See whether the entry is already in the hash table.  */
+  abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL);
+  if (abb == NULL)
+    while (cu->last_abbrev_offset != (size_t) -1l)
+      {
+	size_t length;
+
+	/* Find the next entry.  It gets automatically added to the
+	   hash table.  */
+	abb = __libdw_getabbrev (cu->dbg, cu, cu->last_abbrev_offset, &length,
+				 NULL);
+	if (abb == NULL || abb == DWARF_END_ABBREV)
+	  {
+	    /* Make sure we do not try to search for it again.  */
+	    cu->last_abbrev_offset = (size_t) -1l;
+	    return DWARF_END_ABBREV;
+	  }
+
+	cu->last_abbrev_offset += length;
+
+	/* Is this the code we are looking for?  */
+	if (abb->code == code)
+	  break;
+      }
+
+  /* This is our second (or third, etc.) call to __libdw_findabbrev
+     and the code is invalid.  */
+  if (unlikely (abb == NULL))
+    abb = DWARF_END_ABBREV;
+
+  return abb;
+}
+
+
+int
+dwarf_tag (Dwarf_Die *die)
+{
+  /* Find the abbreviation entry.  */
+  Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
+  if (unlikely (abbrevp == DWARF_END_ABBREV))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return DW_TAG_invalid;
+    }
+
+  return abbrevp->tag;
+}
+INTDEF(dwarf_tag)
diff --git a/libdw/dwarf_whatattr.c b/libdw/dwarf_whatattr.c
new file mode 100644
index 0000000..d664b02
--- /dev/null
+++ b/libdw/dwarf_whatattr.c
@@ -0,0 +1,42 @@
+/* Return attribute code of given attribute.
+   Copyright (C) 2003 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+unsigned int
+dwarf_whatattr (Dwarf_Attribute *attr)
+{
+  return attr == NULL ? 0 : attr->code;
+}
diff --git a/libdw/dwarf_whatform.c b/libdw/dwarf_whatform.c
new file mode 100644
index 0000000..dee29a9
--- /dev/null
+++ b/libdw/dwarf_whatform.c
@@ -0,0 +1,42 @@
+/* Return form code of given attribute.
+   Copyright (C) 2003 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+unsigned int
+dwarf_whatform (Dwarf_Attribute *attr)
+{
+  return attr == NULL ? 0 : attr->form;
+}
diff --git a/libdw/encoded-value.h b/libdw/encoded-value.h
new file mode 100644
index 0000000..f0df4ce
--- /dev/null
+++ b/libdw/encoded-value.h
@@ -0,0 +1,232 @@
+/* DW_EH_PE_* support for libdw unwinder.
+   Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ENCODED_VALUE_H
+#define _ENCODED_VALUE_H 1
+
+#include <dwarf.h>
+#include <stdlib.h>
+#include "libdwP.h"
+#include "../libelf/common.h"
+
+
+/* Returns zero if the value is omitted, the encoding is unknown or
+   the (leb128) size cannot be determined.  */
+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;
+	}
+      return 0;
+
+    default:
+      return 0;
+    }
+}
+
+/* Returns zero when value was read successfully, minus one otherwise.  */
+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.  */
+
+  const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
+  Dwarf eh_dbg = { .other_byte_order = MY_ELFDATA != cache->e_ident[EI_DATA] };
+
+  if (width == 4)
+    {
+      if (unlikely (*addrp + 4 > endp))
+	{
+	invalid_data:
+	  __libdw_seterrno (DWARF_E_INVALID_CFI);
+	  return -1;
+	}
+      *ret = read_4ubyte_unaligned_inc (&eh_dbg, *addrp);
+    }
+  else
+    {
+      if (unlikely (*addrp + 8 > endp))
+	goto invalid_data;
+      *ret = read_8ubyte_unaligned_inc (&eh_dbg, *addrp);
+    }
+  return 0;
+}
+
+/* Returns true on error, false otherwise. */
+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 size = encoded_value_size (&cache->data->d,
+						cache->e_ident,
+						encoding, *p);
+	if (unlikely (size == 0))
+	  return true;
+	size_t align = ((cache->frame_vaddr
+			 + (*p - (const uint8_t *) cache->data->d.d_buf))
+			& (size - 1));
+	if (align != 0)
+	  *p += size - align;
+	break;
+      }
+
+    default:
+      __libdw_seterrno (DWARF_E_INVALID_CFI);
+      return true;
+    }
+
+  Dwarf_Addr value = 0;
+  const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
+  switch (encoding & 0x0f)
+    {
+    case DW_EH_PE_udata2:
+      if (unlikely (*p + 2 > endp))
+	{
+	invalid_data:
+	  __libdw_seterrno (DWARF_E_INVALID_CFI);
+	  return true;
+	}
+      value = read_2ubyte_unaligned_inc (cache, *p);
+      break;
+
+    case DW_EH_PE_sdata2:
+      if (unlikely (*p + 2 > endp))
+	goto invalid_data;
+      value = read_2sbyte_unaligned_inc (cache, *p);
+      break;
+
+    case DW_EH_PE_udata4:
+      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
+	return true;
+      break;
+
+    case DW_EH_PE_sdata4:
+      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
+	return true;
+      value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend.  */
+      break;
+
+    case DW_EH_PE_udata8:
+    case DW_EH_PE_sdata8:
+      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 8, &value) != 0))
+	return true;
+      break;
+
+    case DW_EH_PE_absptr:
+      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 0, &value) != 0))
+	return true;
+      break;
+
+    case DW_EH_PE_uleb128:
+      get_uleb128 (value, *p, endp);
+      break;
+
+    case DW_EH_PE_sleb128:
+      get_sleb128 (value, *p, endp);
+      break;
+
+    default:
+      __libdw_seterrno (DWARF_E_INVALID_CFI);
+      return true;
+    }
+
+  *result += value;
+
+  if (encoding & DW_EH_PE_indirect)
+    {
+      if (unlikely (*result < cache->frame_vaddr))
+	return true;
+      *result -= cache->frame_vaddr;
+      size_t ptrsize = encoded_value_size (NULL, cache->e_ident,
+					   DW_EH_PE_absptr, NULL);
+      if (unlikely (cache->data->d.d_size < ptrsize
+		    || *result > (cache->data->d.d_size - ptrsize)))
+	return true;
+      const uint8_t *ptr = cache->data->d.d_buf + *result;
+      if (unlikely (__libdw_cfi_read_address_inc (cache, &ptr, 0, result)
+		    != 0))
+	return true;
+    }
+
+  return false;
+}
+
+#endif	/* encoded-value.h */
diff --git a/libdw/fde.c b/libdw/fde.c
new file mode 100644
index 0000000..f5f6fbe
--- /dev/null
+++ b/libdw/fde.c
@@ -0,0 +1,324 @@
+/* FDE reading.
+   Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#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)))
+    {
+      free (fde);
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+  fde->end += fde->start;
+
+  /* Make sure the fde actually covers a real code range.  */
+  if (fde->start >= fde->end)
+    {
+      free (fde);
+      return (void *) -1;
+    }
+
+  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, fde->instructions_end);
+      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.  */
+  struct dwarf_fde **tres = tsearch (fde, &cache->fde_tree, &compare_fde);
+  if (tres == NULL)
+    {
+      free (fde);
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+  else if (*tres != fde)
+    {
+      /* There is already an FDE in the cache that covers the same
+	 address range.  That is odd.  Ignore this FDE.  And just use
+	 the one in the cache for consistency.  */
+      free (fde);
+      return *tres;
+    }
+
+  return fde;
+}
+
+struct dwarf_fde *
+internal_function
+__libdw_fde_by_offset (Dwarf_CFI *cache, 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;
+
+  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);
+  if (unlikely (size == 0))
+    return (Dwarf_Off) -1l;
+
+  /* Dummy used by read_encoded_value.  */
+  Elf_Data_Scn dummy_cfi_hdr_data =
+    {
+      .d = { .d_buf = (void *) cache->search_table,
+	     .d_size = cache->search_table_len }
+    };
+
+  Dwarf_CFI dummy_cfi =
+    {
+      .e_ident = cache->e_ident,
+      .datarel = cache->search_table_vaddr,
+      .frame_vaddr = cache->search_table_vaddr,
+      .data = &dummy_cfi_hdr_data
+    };
+
+  size_t l = 0, u = cache->search_table_entries;
+  while (l < u)
+    {
+      size_t idx = (l + u) / 2;
+
+      /* Max idx * size is checked against search_table len when
+	 loading eh_frame_hdr.  */
+      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
+	{
+	  l = idx + 1;
+
+	  Dwarf_Addr fde;
+	  if (unlikely (read_encoded_value (&dummy_cfi,
+					    cache->search_table_encoding, &p,
+					    &fde)))
+	    break;
+
+	  /* 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;
+      struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
+      if (likely (fde != NULL))
+	{
+	  /* Sanity check the address range.  */
+	  if (unlikely (address < fde->start))
+	    {
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return NULL;
+	    }
+	  /* .eh_frame_hdr does not indicate length covered by FDE.  */
+	  if (unlikely (address >= fde->end))
+	    goto no_match;
+	}
+      return fde;
+    }
+
+  /* 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/libdw/frame-cache.c b/libdw/frame-cache.c
new file mode 100644
index 0000000..5b6afb5
--- /dev/null
+++ b/libdw/frame-cache.c
@@ -0,0 +1,70 @@
+/* Frame cache handling.
+   Copyright (C) 2009, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "../libebl/libebl.h"
+#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);
+
+  if (cache->ebl != NULL && cache->ebl != (void *) -1l)
+    ebl_closebackend (cache->ebl);
+}
diff --git a/libdw/libdw.h b/libdw/libdw.h
new file mode 100644
index 0000000..1dcc815
--- /dev/null
+++ b/libdw/libdw.h
@@ -0,0 +1,1031 @@
+/* Interfaces for libdw.
+   Copyright (C) 2002-2010, 2013, 2014, 2016, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBDW_H
+#define _LIBDW_H	1
+
+#include <gelf.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Mode for the session.  */
+typedef enum
+  {
+    DWARF_C_READ,		/* Read .. */
+    DWARF_C_RDWR,		/* Read and write .. */
+    DWARF_C_WRITE,		/* Write .. */
+  }
+Dwarf_Cmd;
+
+
+/* Callback results.  */
+enum
+{
+  DWARF_CB_OK = 0,
+  DWARF_CB_ABORT
+};
+
+
+/* Error values.  */
+enum
+  {
+    DW_TAG_invalid = 0
+#define DW_TAG_invalid	DW_TAG_invalid
+  };
+
+
+/* Type for offset in DWARF file.  */
+typedef GElf_Off Dwarf_Off;
+
+/* Type for address in DWARF file.  */
+typedef GElf_Addr Dwarf_Addr;
+
+/* Integer types.  Big enough to hold any numeric value.  */
+typedef GElf_Xword Dwarf_Word;
+typedef GElf_Sxword Dwarf_Sword;
+/* For the times we know we do not need that much.  */
+typedef GElf_Half Dwarf_Half;
+
+
+/* DWARF abbreviation record.  */
+typedef struct Dwarf_Abbrev Dwarf_Abbrev;
+
+/* Returned to show the last DIE has be returned.  */
+#define DWARF_END_ABBREV ((Dwarf_Abbrev *) -1l)
+
+/* Source code line information for CU.  */
+typedef struct Dwarf_Lines_s Dwarf_Lines;
+
+/* One source code line information.  */
+typedef struct Dwarf_Line_s Dwarf_Line;
+
+/* Source file information.  */
+typedef struct Dwarf_Files_s Dwarf_Files;
+
+/* One address range record.  */
+typedef struct Dwarf_Arange_s Dwarf_Arange;
+
+/* Address ranges of a file.  */
+typedef struct Dwarf_Aranges_s Dwarf_Aranges;
+
+/* CU representation.  */
+struct Dwarf_CU;
+typedef struct Dwarf_CU Dwarf_CU;
+
+/* Macro information.  */
+typedef struct Dwarf_Macro_s Dwarf_Macro;
+
+/* Attribute representation.  */
+typedef struct
+{
+  unsigned int code;
+  unsigned int form;
+  unsigned char *valp;
+  struct Dwarf_CU *cu;
+} Dwarf_Attribute;
+
+
+/* Data block representation.  */
+typedef struct
+{
+  Dwarf_Word length;
+  unsigned char *data;
+} Dwarf_Block;
+
+
+/* DIE information.  */
+typedef struct
+{
+  /* The offset can be computed from the address.  */
+  void *addr;
+  struct Dwarf_CU *cu;
+  Dwarf_Abbrev *abbrev;
+  // XXX We'll see what other information will be needed.
+  long int padding__;
+} Dwarf_Die;
+
+/* Returned to show the last DIE has be returned.  */
+#define DWARF_END_DIE ((Dwarf_Die *) -1l)
+
+
+/* Global symbol information.  */
+typedef struct
+{
+  Dwarf_Off cu_offset;
+  Dwarf_Off die_offset;
+  const char *name;
+} Dwarf_Global;
+
+
+/* One operation in a DWARF location expression.
+   A location expression is an array of these.  */
+typedef struct
+{
+  uint8_t atom;			/* Operation */
+  Dwarf_Word number;		/* Operand */
+  Dwarf_Word number2;		/* Possible second operand */
+  Dwarf_Word offset;		/* Offset in location expression */
+} 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;
+
+/* Same as DW_CIE_ID_64 from dwarf.h to keep libdw.h independent.  */
+#define LIBDW_CIE_ID 0xffffffffffffffffULL
+#define dwarf_cfi_cie_p(entry)	((entry)->cie.CIE_id == LIBDW_CIE_ID)
+
+/* 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;
+
+
+/* Out-Of-Memory handler.  */
+typedef void (*__noreturn_attribute__ Dwarf_OOM) (void);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Create a handle for a new debug session.  */
+extern Dwarf *dwarf_begin (int fildes, Dwarf_Cmd cmd);
+
+/* Create a handle for a new debug session for an ELF file.  */
+extern Dwarf *dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp);
+
+/* Retrieve ELF descriptor used for DWARF access.  */
+extern Elf *dwarf_getelf (Dwarf *dwarf);
+
+/* Retieve DWARF descriptor used for a Dwarf_Die or Dwarf_Attribute.
+   A Dwarf_Die or a Dwarf_Attribute is associated with a particular
+   Dwarf_CU handle.  This function returns the DWARF descriptor for
+   that Dwarf_CU.  */
+extern Dwarf *dwarf_cu_getdwarf (Dwarf_CU *cu);
+
+/* Retrieves the DWARF descriptor for debugaltlink data.  Returns NULL
+   if no alternate debug data has been supplied yet.  libdw will try
+   to set the alt file on first use of an alt FORM if not yet explicitly
+   provided by dwarf_setalt.  */
+extern Dwarf *dwarf_getalt (Dwarf *main);
+
+/* Provides the data referenced by the .gnu_debugaltlink section.  The
+   caller should check that MAIN and ALT match (i.e., they have the
+   same build ID).  It is the responsibility of the caller to ensure
+   that the data referenced by ALT stays valid while it is used by
+   MAIN, until dwarf_setalt is called on MAIN with a different
+   descriptor, or dwarf_end.  Must be called before inspecting DIEs
+   that might have alt FORMs.  Otherwise libdw will try to set the
+   alt file itself on first use.  */
+extern void dwarf_setalt (Dwarf *main, Dwarf *alt);
+
+/* Release debugging handling context.  */
+extern int dwarf_end (Dwarf *dwarf);
+
+
+/* Get the data block for the .debug_info section.  */
+extern Elf_Data *dwarf_getscn_info (Dwarf *dwarf);
+
+/* Read the header for the DWARF CU.  */
+extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
+			 size_t *header_sizep, Dwarf_Off *abbrev_offsetp,
+			 uint8_t *address_sizep, uint8_t *offset_sizep)
+     __nonnull_attribute__ (3);
+
+/* Read the header of a DWARF CU or type unit.  If TYPE_SIGNATUREP is not
+   null, this reads a type unit from the .debug_types section; otherwise
+   this reads a CU from the .debug_info section.  */
+extern int dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
+			    size_t *header_sizep, Dwarf_Half *versionp,
+			    Dwarf_Off *abbrev_offsetp,
+			    uint8_t *address_sizep, uint8_t *offset_sizep,
+			    uint64_t *type_signaturep, Dwarf_Off *type_offsetp)
+     __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 in .debug_info section.  */
+extern Dwarf_Die *dwarf_offdie (Dwarf *dbg, Dwarf_Off offset,
+				Dwarf_Die *result) __nonnull_attribute__ (3);
+
+/* Return DIE at given offset in .debug_types section.  */
+extern Dwarf_Die *dwarf_offdie_types (Dwarf *dbg, Dwarf_Off offset,
+				      Dwarf_Die *result)
+     __nonnull_attribute__ (3);
+
+/* Return offset of DIE.  */
+extern Dwarf_Off dwarf_dieoffset (Dwarf_Die *die);
+
+/* Return offset of DIE in CU.  */
+extern Dwarf_Off dwarf_cuoffset (Dwarf_Die *die);
+
+/* Return CU DIE containing given DIE.  */
+extern Dwarf_Die *dwarf_diecu (Dwarf_Die *die, Dwarf_Die *result,
+			       uint8_t *address_sizep, uint8_t *offset_sizep)
+     __nonnull_attribute__ (2);
+
+/* Return the CU DIE and the header info associated with a Dwarf_Die
+   or Dwarf_Attribute.  A Dwarf_Die or a Dwarf_Attribute is associated
+   with a particular Dwarf_CU handle.  This function returns the CU or
+   type unit DIE and header information for that Dwarf_CU.  The
+   returned DIE is either a compile_unit, partial_unit or type_unit.
+   If it is a type_unit, then the type signature and type offset are
+   also provided, otherwise type_offset will be set to zero.  See also
+   dwarf_diecu and dwarf_next_unit.  */
+extern Dwarf_Die *dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result,
+				Dwarf_Half *versionp,
+				Dwarf_Off *abbrev_offsetp,
+				uint8_t *address_sizep,
+				uint8_t *offset_sizep,
+				uint64_t *type_signaturep,
+				Dwarf_Off *type_offsetp)
+     __nonnull_attribute__ (2);
+
+/* Return CU DIE containing given address.  */
+extern Dwarf_Die *dwarf_addrdie (Dwarf *dbg, Dwarf_Addr addr,
+				 Dwarf_Die *result) __nonnull_attribute__ (3);
+
+/* Return child of current DIE.  */
+extern int dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
+     __nonnull_attribute__ (2);
+
+/* Locates the first sibling of DIE and places it in RESULT.
+   Returns 0 if a sibling was found, -1 if something went wrong.
+   Returns 1 if no sibling could be found and, if RESULT is not
+   the same as DIE, it sets RESULT->addr to the address of the
+   (non-sibling) DIE that follows this one, or NULL if this DIE
+   was the last one in the compilation unit.  */
+extern int dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
+     __nonnull_attribute__ (2);
+
+/* For type aliases and qualifier type DIEs, which don't modify or
+   change the structural layout of the underlying type, follow the
+   DW_AT_type attribute (recursively) and return the underlying type
+   Dwarf_Die.
+
+   Returns 0 when RESULT contains a Dwarf_Die (possibly equal to the
+   given DIE) that isn't a type alias or qualifier type.  Returns 1
+   when RESULT contains a type alias or qualifier Dwarf_Die that
+   couldn't be peeled further (it doesn't have a DW_TAG_type
+   attribute).  Returns -1 when an error occured.
+
+   The current DWARF specification defines one type alias tag
+   (DW_TAG_typedef) and seven modifier/qualifier type tags
+   (DW_TAG_const_type, DW_TAG_volatile_type, DW_TAG_restrict_type,
+   DW_TAG_atomic_type, DW_TAG_immutable_type, DW_TAG_packed_type and
+   DW_TAG_shared_type).  This function won't peel modifier type
+   tags that change the way the underlying type is accessed such
+   as the pointer or reference type tags (DW_TAG_pointer_type,
+   DW_TAG_reference_type or DW_TAG_rvalue_reference_type).
+
+   A future version of this function might peel other alias or
+   qualifier type tags if a future DWARF version or GNU extension
+   defines other type aliases or qualifier type tags that don't modify,
+   change the structural layout or the way to access the underlying type.  */
+extern int dwarf_peel_type (Dwarf_Die *die, Dwarf_Die *result)
+    __nonnull_attribute__ (2);
+
+/* Check whether the DIE has children.  */
+extern int dwarf_haschildren (Dwarf_Die *die) __nonnull_attribute__ (1);
+
+/* Walks the attributes of DIE, starting at the one OFFSET bytes in,
+   calling the CALLBACK function for each one.  Stops if the callback
+   function ever returns a value other than DWARF_CB_OK and returns the
+   offset of the offending attribute.  If the end of the attributes
+   is reached 1 is returned.  If something goes wrong -1 is returned and
+   the dwarf error number is set.  */
+extern ptrdiff_t dwarf_getattrs (Dwarf_Die *die,
+				 int (*callback) (Dwarf_Attribute *, void *),
+				 void *arg, ptrdiff_t offset)
+     __nonnull_attribute__ (2);
+
+/* Return tag of given DIE.  */
+extern int dwarf_tag (Dwarf_Die *die) __nonnull_attribute__ (1);
+
+
+/* Return specific attribute of DIE.  */
+extern Dwarf_Attribute *dwarf_attr (Dwarf_Die *die, unsigned int search_name,
+				    Dwarf_Attribute *result)
+     __nonnull_attribute__ (3);
+
+/* Check whether given DIE has specific attribute.  */
+extern int dwarf_hasattr (Dwarf_Die *die, unsigned int search_name);
+
+/* These are the same as dwarf_attr and dwarf_hasattr, respectively,
+   but they resolve an indirect attribute through DW_AT_abstract_origin.  */
+extern Dwarf_Attribute *dwarf_attr_integrate (Dwarf_Die *die,
+					      unsigned int search_name,
+					      Dwarf_Attribute *result)
+     __nonnull_attribute__ (3);
+extern int dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name);
+
+
+
+
+/* Check whether given attribute has specific form.  */
+extern int dwarf_hasform (Dwarf_Attribute *attr, unsigned int search_form);
+
+/* Return attribute code of given attribute.  */
+extern unsigned int dwarf_whatattr (Dwarf_Attribute *attr);
+
+/* Return form code of given attribute.  */
+extern unsigned int dwarf_whatform (Dwarf_Attribute *attr);
+
+
+/* Return string associated with given attribute.  */
+extern const char *dwarf_formstring (Dwarf_Attribute *attrp);
+
+/* Return unsigned constant represented by attribute.  */
+extern int dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
+     __nonnull_attribute__ (2);
+
+/* Return signed constant represented by attribute.  */
+extern int dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_uval)
+     __nonnull_attribute__ (2);
+
+/* Return address represented by attribute.  */
+extern int dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
+     __nonnull_attribute__ (2);
+
+/* This function is deprecated.  Always use dwarf_formref_die instead.
+   Return reference offset represented by attribute.  */
+extern int dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
+     __nonnull_attribute__ (2) __deprecated_attribute__;
+
+/* Look up the DIE in a reference-form attribute.  */
+extern Dwarf_Die *dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem)
+     __nonnull_attribute__ (2);
+
+/* Return block represented by attribute.  */
+extern int dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block)
+     __nonnull_attribute__ (2);
+
+/* Return flag represented by attribute.  */
+extern int dwarf_formflag (Dwarf_Attribute *attr, bool *return_bool)
+     __nonnull_attribute__ (2);
+
+
+/* Simplified attribute value access functions.  */
+
+/* Return string in name attribute of DIE.  */
+extern const char *dwarf_diename (Dwarf_Die *die);
+
+/* Return high PC attribute of DIE.  */
+extern int dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+     __nonnull_attribute__ (2);
+
+/* Return low PC attribute of DIE.  */
+extern int dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+     __nonnull_attribute__ (2);
+
+/* Return entry_pc or low_pc attribute of DIE.  */
+extern int dwarf_entrypc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+     __nonnull_attribute__ (2);
+
+/* Return 1 if DIE's lowpc/highpc or ranges attributes match the PC address,
+   0 if not, or -1 for errors.  */
+extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc);
+
+/* Enumerate the PC address ranges covered by this DIE, covering all
+   addresses where dwarf_haspc returns true.  In the first call OFFSET
+   should be zero and *BASEP need not be initialized.  Returns -1 for
+   errors, zero when there are no more address ranges to report, or a
+   nonzero OFFSET value to pass to the next call.  Each subsequent call
+   must preserve *BASEP from the prior call.  Successful calls fill in
+   *STARTP and *ENDP with a contiguous address range.  */
+extern ptrdiff_t dwarf_ranges (Dwarf_Die *die,
+			       ptrdiff_t offset, Dwarf_Addr *basep,
+			       Dwarf_Addr *startp, Dwarf_Addr *endp);
+
+
+/* Return byte size attribute of DIE.  */
+extern int dwarf_bytesize (Dwarf_Die *die);
+
+/* Return bit size attribute of DIE.  */
+extern int dwarf_bitsize (Dwarf_Die *die);
+
+/* Return bit offset attribute of DIE.  */
+extern int dwarf_bitoffset (Dwarf_Die *die);
+
+/* Return array order attribute of DIE.  */
+extern int dwarf_arrayorder (Dwarf_Die *die);
+
+/* Return source language attribute of DIE.  */
+extern int dwarf_srclang (Dwarf_Die *die);
+
+
+/* Get abbreviation at given offset for given DIE.  */
+extern Dwarf_Abbrev *dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset,
+				      size_t *lengthp);
+
+/* Get abbreviation at given offset in .debug_abbrev section.  */
+extern int dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp,
+			    Dwarf_Abbrev *abbrevp)
+     __nonnull_attribute__ (4);
+
+/* Get abbreviation code.  */
+extern unsigned int dwarf_getabbrevcode (Dwarf_Abbrev *abbrev);
+
+/* Get abbreviation tag.  */
+extern unsigned int dwarf_getabbrevtag (Dwarf_Abbrev *abbrev);
+
+/* Return true if abbreviation is children flag set.  */
+extern int dwarf_abbrevhaschildren (Dwarf_Abbrev *abbrev);
+
+/* Get number of attributes of abbreviation.  */
+extern int dwarf_getattrcnt (Dwarf_Abbrev *abbrev, size_t *attrcntp)
+     __nonnull_attribute__ (2);
+
+/* Get specific attribute of abbreviation.  */
+extern int dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx,
+				unsigned int *namep, unsigned int *formp,
+				Dwarf_Off *offset);
+
+
+/* Get string from-debug_str section.  */
+extern const char *dwarf_getstring (Dwarf *dbg, Dwarf_Off offset,
+				    size_t *lenp);
+
+
+/* Get public symbol information.  */
+extern ptrdiff_t dwarf_getpubnames (Dwarf *dbg,
+				    int (*callback) (Dwarf *, Dwarf_Global *,
+						     void *),
+				    void *arg, ptrdiff_t offset)
+     __nonnull_attribute__ (2);
+
+
+/* Get source file information for CU.  */
+extern int dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines,
+			      size_t *nlines) __nonnull_attribute__ (2, 3);
+
+/* Return one of the source lines of the CU.  */
+extern Dwarf_Line *dwarf_onesrcline (Dwarf_Lines *lines, size_t idx);
+
+/* Get the file source files used in the CU.  */
+extern int dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files,
+			      size_t *nfiles)
+     __nonnull_attribute__ (2);
+
+
+/* Get source for address in CU.  */
+extern Dwarf_Line *dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr);
+
+/* Get source for file and line number.  */
+extern int dwarf_getsrc_file (Dwarf *dbg, const char *fname, int line, int col,
+			      Dwarf_Line ***srcsp, size_t *nsrcs)
+     __nonnull_attribute__ (2, 5, 6);
+
+
+/* Return line address.  */
+extern int dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp);
+
+/* Return line VLIW operation index.  */
+extern int dwarf_lineop_index (Dwarf_Line *line, unsigned int *op_indexp);
+
+/* Return line number.  */
+extern int dwarf_lineno (Dwarf_Line *line, int *linep)
+     __nonnull_attribute__ (2);
+
+/* Return column in line.  */
+extern int dwarf_linecol (Dwarf_Line *line, int *colp)
+     __nonnull_attribute__ (2);
+
+/* Return true if record is for beginning of a statement.  */
+extern int dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp)
+     __nonnull_attribute__ (2);
+
+/* Return true if record is for end of sequence.  */
+extern int dwarf_lineendsequence (Dwarf_Line *line, bool *flagp)
+     __nonnull_attribute__ (2);
+
+/* Return true if record is for beginning of a basic block.  */
+extern int dwarf_lineblock (Dwarf_Line *line, bool *flagp)
+     __nonnull_attribute__ (2);
+
+/* Return true if record is for end of prologue.  */
+extern int dwarf_lineprologueend (Dwarf_Line *line, bool *flagp)
+     __nonnull_attribute__ (2);
+
+/* Return true if record is for beginning of epilogue.  */
+extern int dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp)
+     __nonnull_attribute__ (2);
+
+/* Return instruction-set architecture in this record.  */
+extern int dwarf_lineisa (Dwarf_Line *line, unsigned int *isap)
+     __nonnull_attribute__ (2);
+
+/* Return code path discriminator in this record.  */
+extern int dwarf_linediscriminator (Dwarf_Line *line, unsigned int *discp)
+     __nonnull_attribute__ (2);
+
+
+/* Find line information for address.  */
+extern const char *dwarf_linesrc (Dwarf_Line *line,
+				  Dwarf_Word *mtime, Dwarf_Word *length);
+
+/* Return file information.  */
+extern const char *dwarf_filesrc (Dwarf_Files *file, size_t idx,
+				  Dwarf_Word *mtime, Dwarf_Word *length);
+
+/* Return the Dwarf_Files and index associated with the given Dwarf_Line.  */
+extern int dwarf_line_file (Dwarf_Line *line,
+			    Dwarf_Files **files, size_t *idx)
+    __nonnull_attribute__ (2, 3);
+
+/* Return the directory list used in the file information extracted.
+   (*RESULT)[0] is the CU's DW_AT_comp_dir value, and may be null.
+   (*RESULT)[0..*NDIRS-1] are the compile-time include directory path
+   encoded by the compiler.  */
+extern int dwarf_getsrcdirs (Dwarf_Files *files,
+			     const char *const **result, size_t *ndirs)
+  __nonnull_attribute__ (2, 3);
+
+
+/* Return location expression, decoded as a list of operations.  */
+extern int dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **expr,
+			      size_t *exprlen) __nonnull_attribute__ (2, 3);
+
+/* Return location expressions.  If the attribute uses a location list,
+   ADDRESS selects the relevant location expressions from the list.
+   There can be multiple matches, resulting in multiple expressions to
+   return.  EXPRS and EXPRLENS are parallel arrays of NLOCS slots to
+   fill in.  Returns the number of locations filled in, or -1 for
+   errors.  If EXPRS is a null pointer, stores nothing and returns the
+   total number of locations.  A return value of zero means that the
+   location list indicated no value is accessible.  */
+extern int dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
+				   Dwarf_Op **exprs, size_t *exprlens,
+				   size_t nlocs);
+
+/* Enumerate the locations ranges and descriptions covered by the
+   given attribute.  In the first call OFFSET should be zero and
+   *BASEP need not be initialized.  Returns -1 for errors, zero when
+   there are no more locations to report, or a nonzero OFFSET
+   value to pass to the next call.  Each subsequent call must preserve
+   *BASEP from the prior call.  Successful calls fill in *STARTP and
+   *ENDP with a contiguous address range and *EXPR with a pointer to
+   an array of operations with length *EXPRLEN.  If the attribute
+   describes a single location description and not a location list the
+   first call (with OFFSET zero) will return the location description
+   in *EXPR with *STARTP set to zero and *ENDP set to minus one.  */
+extern ptrdiff_t dwarf_getlocations (Dwarf_Attribute *attr,
+				     ptrdiff_t offset, Dwarf_Addr *basep,
+				     Dwarf_Addr *startp, Dwarf_Addr *endp,
+				     Dwarf_Op **expr, size_t *exprlen);
+
+/* 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 the attribute indicated by a DW_OP_GNU_implicit_pointer operation.
+   The OP pointer must point into an expression that dwarf_getlocation
+   or dwarf_getlocation_addr has returned given the same ATTR.
+   The result is the DW_AT_location or DW_AT_const_value attribute
+   of the OP->number DIE.  */
+extern int dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr,
+					       const Dwarf_Op *op,
+					       Dwarf_Attribute *result)
+  __nonnull_attribute__ (2, 3);
+
+/* Return the DIE associated with an operation such as
+   DW_OP_GNU_implicit_pointer, DW_OP_GNU_parameter_ref, DW_OP_GNU_convert,
+   DW_OP_GNU_reinterpret, DW_OP_GNU_const_type, DW_OP_GNU_regval_type or
+   DW_OP_GNU_deref_type.  The OP pointer must point into an expression that
+   dwarf_getlocation or dwarf_getlocation_addr has returned given the same
+   ATTR.  The RESULT is a DIE that expresses a type or value needed by the
+   given OP.  */
+extern int dwarf_getlocation_die (Dwarf_Attribute *attr,
+				  const Dwarf_Op *op,
+				  Dwarf_Die *result)
+  __nonnull_attribute__ (2, 3);
+
+/* Return the attribute expressing a value associated with an operation such
+   as DW_OP_implicit_value, DW_OP_GNU_entry_value or DW_OP_GNU_const_type.
+   The OP pointer must point into an expression that dwarf_getlocation
+   or dwarf_getlocation_addr has returned given the same ATTR.
+   The RESULT is a value expressed by an attribute such as DW_AT_location
+   or DW_AT_const_value.  */
+extern int dwarf_getlocation_attr (Dwarf_Attribute *attr,
+				   const Dwarf_Op *op,
+				   Dwarf_Attribute *result)
+  __nonnull_attribute__ (2, 3);
+
+
+/* Compute the byte-size of a type DIE according to DWARF rules.
+   For most types, this is just DW_AT_byte_size.
+   For DW_TAG_array_type it can apply much more complex rules.  */
+extern int dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size);
+
+/* Given a language code, as returned by dwarf_srclan, get the default
+   lower bound for a subrange type without a lower bound attribute.
+   Returns zero on success or -1 on failure when the given language
+   wasn't recognized.  */
+extern int dwarf_default_lower_bound (int lang, Dwarf_Sword *result)
+  __nonnull_attribute__ (2);
+
+/* Return scope DIEs containing PC address.
+   Sets *SCOPES to a malloc'd array of Dwarf_Die structures,
+   and returns the number of elements in the array.
+   (*SCOPES)[0] is the DIE for the innermost scope containing PC,
+   (*SCOPES)[1] is the DIE for the scope containing that scope, and so on.
+   Returns -1 for errors or 0 if no scopes match PC.  */
+extern int dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc,
+			    Dwarf_Die **scopes);
+
+/* Return scope DIEs containing the given DIE.
+   Sets *SCOPES to a malloc'd array of Dwarf_Die structures,
+   and returns the number of elements in the array.
+   (*SCOPES)[0] is a copy of DIE.
+   (*SCOPES)[1] is the DIE for the scope containing that scope, and so on.
+   Returns -1 for errors or 0 if DIE is not found in any scope entry.  */
+extern int dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes);
+
+
+/* Search SCOPES[0..NSCOPES-1] for a variable called NAME.
+   Ignore the first SKIP_SHADOWS scopes that match the name.
+   If MATCH_FILE is not null, accept only declaration in that source file;
+   if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration
+   at that line and column.
+
+   If successful, fill in *RESULT with the DIE of the variable found,
+   and return N where SCOPES[N] is the scope defining the variable.
+   Return -1 for errors or -2 for no matching variable found.  */
+extern int dwarf_getscopevar (Dwarf_Die *scopes, int nscopes,
+			      const char *name, int skip_shadows,
+			      const char *match_file,
+			      int match_lineno, int match_linecol,
+			      Dwarf_Die *result);
+
+
+
+/* Return list address ranges.  */
+extern int dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges,
+			     size_t *naranges)
+     __nonnull_attribute__ (2);
+
+/* Return one of the address range entries.  */
+extern Dwarf_Arange *dwarf_onearange (Dwarf_Aranges *aranges, size_t idx);
+
+/* Return information in address range record.  */
+extern int dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp,
+				Dwarf_Word *lengthp, Dwarf_Off *offsetp);
+
+/* Get address range which includes given address.  */
+extern Dwarf_Arange *dwarf_getarange_addr (Dwarf_Aranges *aranges,
+					   Dwarf_Addr addr);
+
+
+
+/* Get functions in CUDIE.  The given callback will be called for all
+   defining DW_TAG_subprograms in the CU DIE tree.  If the callback
+   returns DWARF_CB_ABORT the return value can be used as offset argument
+   to resume the function to find all remaining functions (this is not
+   really recommended, since it needs to rewalk the CU DIE tree first till
+   that offset is found again).  If the callback returns DWARF_CB_OK
+   dwarf_getfuncs will not return but keep calling the callback for each
+   function DIE it finds.  Pass zero for offset on the first call to walk
+   the full CU DIE tree.  If no more functions can be found and the callback
+   returned DWARF_CB_OK then the function returns zero.  */
+extern ptrdiff_t dwarf_getfuncs (Dwarf_Die *cudie,
+				 int (*callback) (Dwarf_Die *, void *),
+				 void *arg, ptrdiff_t offset);
+
+
+/* Return file name containing definition of the given declaration.  */
+extern const char *dwarf_decl_file (Dwarf_Die *decl);
+
+/* Get line number of beginning of given declaration.  */
+extern int dwarf_decl_line (Dwarf_Die *decl, int *linep)
+     __nonnull_attribute__ (2);
+
+/* Get column number of beginning of given declaration.  */
+extern int dwarf_decl_column (Dwarf_Die *decl, int *colp)
+     __nonnull_attribute__ (2);
+
+
+/* Return nonzero if given function is an abstract inline definition.  */
+extern int dwarf_func_inline (Dwarf_Die *func);
+
+/* Find each concrete inlined instance of the abstract inline definition.  */
+extern int dwarf_func_inline_instances (Dwarf_Die *func,
+					int (*callback) (Dwarf_Die *, void *),
+					void *arg);
+
+
+/* Find the appropriate PC location or locations for function entry
+   breakpoints for the given DW_TAG_subprogram DIE.  Returns -1 for errors.
+   On success, returns the number of breakpoint locations (never zero)
+   and sets *BKPTS to a malloc'd vector of addresses.  */
+extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts);
+
+
+/* Iterate through the macro unit referenced by CUDIE and call
+   CALLBACK for each macro information entry.  To start the iteration,
+   one would pass DWARF_GETMACROS_START for TOKEN.
+
+   The iteration continues while CALLBACK returns DWARF_CB_OK.  If the
+   callback returns DWARF_CB_ABORT, the iteration stops and a
+   continuation token is returned, which can be used to restart the
+   iteration at the point where it ended.  Returns -1 for errors or 0
+   if there are no more macro entries.
+
+   Note that the Dwarf_Macro pointer passed to the callback is only
+   valid for the duration of the callback invocation.
+
+   For backward compatibility, a token of 0 is accepted for starting
+   the iteration as well, but in that case this interface will refuse
+   to serve opcode 0xff from .debug_macro sections.  Such opcode would
+   be considered invalid and would cause dwarf_getmacros to return
+   with error.  */
+#define DWARF_GETMACROS_START PTRDIFF_MIN
+extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie,
+				  int (*callback) (Dwarf_Macro *, void *),
+				  void *arg, ptrdiff_t token)
+     __nonnull_attribute__ (2);
+
+/* This is similar in operation to dwarf_getmacros, but selects the
+   unit to iterate through by offset instead of by CU, and always
+   iterates .debug_macro.  This can be used for handling
+   DW_MACRO_GNU_transparent_include's or similar opcodes.
+
+   TOKEN value of DWARF_GETMACROS_START can be used to start the
+   iteration.
+
+   It is not appropriate to obtain macro unit offset by hand from a CU
+   DIE and then request iteration through this interface.  The reason
+   for this is that if a dwarf_macro_getsrcfiles is later called,
+   there would be no way to figure out what DW_AT_comp_dir was present
+   on the CU DIE, and file names referenced in either the macro unit
+   itself, or the .debug_line unit that it references, might be wrong.
+   Use dwarf_getmacros.  */
+extern ptrdiff_t dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
+				      int (*callback) (Dwarf_Macro *, void *),
+				      void *arg, ptrdiff_t token)
+  __nonnull_attribute__ (3);
+
+/* Get the source files used by the macro entry.  You shouldn't assume
+   that Dwarf_Files references will remain valid after MACRO becomes
+   invalid.  (Which is to say it's only valid within the
+   dwarf_getmacros* callback.)  Returns 0 for success or a negative
+   value in case of an error.  */
+extern int dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
+				    Dwarf_Files **files, size_t *nfiles)
+  __nonnull_attribute__ (2, 3, 4);
+
+/* Return macro opcode.  That's a constant that can be either from
+   DW_MACINFO_* domain or DW_MACRO_GNU_* domain.  The two domains have
+   compatible values, so it's OK to use either of them for
+   comparisons.  The only differences is 0xff, which could be either
+   DW_MACINFO_vendor_ext or a vendor-defined DW_MACRO_* constant.  One
+   would need to look if the CU DIE which the iteration was requested
+   for has attribute DW_AT_macro_info, or either of DW_AT_GNU_macros
+   or DW_AT_macros to differentiate the two interpretations.  */
+extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep)
+     __nonnull_attribute__ (2);
+
+/* Get number of parameters of MACRO and store it to *PARAMCNTP.  */
+extern int dwarf_macro_getparamcnt (Dwarf_Macro *macro, size_t *paramcntp);
+
+/* Get IDX-th parameter of MACRO (numbered from zero), and stores it
+   to *ATTRIBUTE.  Returns 0 on success or -1 for errors.
+
+   After a successful call, you can query ATTRIBUTE by dwarf_whatform
+   to determine which of the dwarf_formX calls to make to get actual
+   value out of ATTRIBUTE.  Note that calling dwarf_whatattr is not
+   meaningful for pseudo-attributes formed this way.  */
+extern int dwarf_macro_param (Dwarf_Macro *macro, size_t idx,
+			      Dwarf_Attribute *attribute);
+
+/* Return macro parameter with index 0.  This will return -1 if the
+   parameter is not an integral value.  Use dwarf_macro_param for more
+   general access.  */
+extern int dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp)
+     __nonnull_attribute__ (2);
+
+/* Return macro parameter with index 1.  This will return -1 if the
+   parameter is not an integral or string value.  Use
+   dwarf_macro_param for more general access.  */
+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);
+
+/* Return error string for ERROR.  If ERROR is zero, return error string
+   for most recent error or NULL is none occurred.  If ERROR is -1 the
+   behaviour is similar to the last case except that not NULL but a legal
+   string is returned.  */
+extern const char *dwarf_errmsg (int err);
+
+
+/* Register new Out-Of-Memory handler.  The old handler is returned.  */
+extern Dwarf_OOM dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler);
+
+
+/* Inline optimizations.  */
+#ifdef __OPTIMIZE__
+/* Return attribute code of given attribute.  */
+__libdw_extern_inline unsigned int
+dwarf_whatattr (Dwarf_Attribute *attr)
+{
+  return attr == NULL ? 0 : attr->code;
+}
+
+/* Return attribute code of given attribute.  */
+__libdw_extern_inline unsigned int
+dwarf_whatform (Dwarf_Attribute *attr)
+{
+  return attr == NULL ? 0 : attr->form;
+}
+#endif	/* Optimize.  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* libdw.h */
diff --git a/libdw/libdw.map b/libdw/libdw.map
new file mode 100644
index 0000000..1430705
--- /dev/null
+++ b/libdw/libdw.map
@@ -0,0 +1,346 @@
+ELFUTILS_0 { };
+ELFUTILS_0.122 {
+  global:
+    dwarf_abbrevhaschildren;
+    dwarf_addrdie;
+    dwarf_arrayorder;
+    dwarf_attr;
+    dwarf_attr_integrate;
+    dwarf_begin;
+    dwarf_begin_elf;
+    dwarf_bitoffset;
+    dwarf_bitsize;
+    dwarf_bytesize;
+    dwarf_child;
+    dwarf_cuoffset;
+    dwarf_decl_column;
+    dwarf_decl_file;
+    dwarf_decl_line;
+    dwarf_diecu;
+    dwarf_diename;
+    dwarf_dieoffset;
+    dwarf_end;
+    dwarf_entry_breakpoints;
+    dwarf_entrypc;
+    dwarf_errmsg;
+    dwarf_errno;
+    dwarf_filesrc;
+    dwarf_formaddr;
+    dwarf_formblock;
+    dwarf_formflag;
+    dwarf_formref;
+    dwarf_formref_die;
+    dwarf_formsdata;
+    dwarf_formstring;
+    dwarf_formudata;
+    dwarf_func_inline;
+    dwarf_func_inline_instances;
+    dwarf_getabbrev;
+    dwarf_getabbrevattr;
+    dwarf_getabbrevcode;
+    dwarf_getabbrevtag;
+    dwarf_getarange_addr;
+    dwarf_getarangeinfo;
+    dwarf_getaranges;
+    dwarf_getattrcnt;
+    dwarf_getattrs;
+    dwarf_getfuncs;
+    dwarf_getlocation;
+    dwarf_getlocation_addr;
+    dwarf_getmacros;
+    dwarf_getpubnames;
+    dwarf_getscn_info;
+    dwarf_getscopes;
+    dwarf_getscopes_die;
+    dwarf_getscopevar;
+    dwarf_getsrc_die;
+    dwarf_getsrc_file;
+    dwarf_getsrcfiles;
+    dwarf_getsrclines;
+    dwarf_getstring;
+    dwarf_hasattr;
+    dwarf_hasattr_integrate;
+    dwarf_haschildren;
+    dwarf_hasform;
+    dwarf_haspc;
+    dwarf_highpc;
+    dwarf_lineaddr;
+    dwarf_linebeginstatement;
+    dwarf_lineblock;
+    dwarf_linecol;
+    dwarf_lineendsequence;
+    dwarf_lineepiloguebegin;
+    dwarf_lineno;
+    dwarf_lineprologueend;
+    dwarf_linesrc;
+    dwarf_lowpc;
+    dwarf_macro_opcode;
+    dwarf_macro_param1;
+    dwarf_macro_param2;
+    dwarf_new_oom_handler;
+    dwarf_nextcu;
+    dwarf_offabbrev;
+    dwarf_offdie;
+    dwarf_onearange;
+    dwarf_onesrcline;
+    dwarf_ranges;
+    dwarf_siblingof;
+    dwarf_srclang;
+    dwarf_tag;
+    dwarf_whatattr;
+    dwarf_whatform;
+
+    # libdwfl_pic.a contributes these symbols.
+    dwfl_addrdie;
+    dwfl_addrdwarf;
+    dwfl_addrmodule;
+    dwfl_begin;
+    dwfl_cumodule;
+    dwfl_end;
+    dwfl_errmsg;
+    dwfl_errno;
+    dwfl_getdwarf;
+    dwfl_getmodules;
+    dwfl_getsrc;
+    dwfl_getsrclines;
+    dwfl_line_comp_dir;
+    dwfl_linecu;
+    dwfl_lineinfo;
+    dwfl_linemodule;
+    dwfl_linux_kernel_find_elf;
+    dwfl_linux_kernel_module_section_address;
+    dwfl_linux_kernel_report_kernel;
+    dwfl_linux_kernel_report_modules;
+    dwfl_linux_kernel_report_offline;
+    dwfl_linux_proc_find_elf;
+    dwfl_linux_proc_maps_report;
+    dwfl_linux_proc_report;
+    dwfl_module_addrdie;
+    dwfl_module_addrname;
+    dwfl_module_getdwarf;
+    dwfl_module_getelf;
+    dwfl_module_getsrc;
+    dwfl_module_getsrc_file;
+    dwfl_module_getsym;
+    dwfl_module_getsymtab;
+    dwfl_module_info;
+    dwfl_module_nextcu;
+    dwfl_module_register_names;
+    dwfl_module_relocate_address;
+    dwfl_module_relocation_info;
+    dwfl_module_relocations;
+    dwfl_module_return_value_location;
+    dwfl_nextcu;
+    dwfl_offline_section_address;
+    dwfl_onesrcline;
+    dwfl_report_begin;
+    dwfl_report_elf;
+    dwfl_report_end;
+    dwfl_report_module;
+    dwfl_report_offline;
+    dwfl_standard_argp;
+    dwfl_standard_find_debuginfo;
+    dwfl_version;
+
+  local:
+    *;
+} ELFUTILS_0;
+
+ELFUTILS_0.126 {
+  global:
+    dwarf_getelf;
+
+  local:
+    *;
+} ELFUTILS_0.122;
+
+ELFUTILS_0.127 {
+  global:
+    dwarf_getsrcdirs;
+
+    dwfl_module_addrsym;
+    dwfl_report_begin_add;
+    dwfl_module_address_section;
+
+  local:
+    *;
+} ELFUTILS_0.126;
+
+ELFUTILS_0.130 {
+  global:
+    dwfl_build_id_find_elf;
+    dwfl_build_id_find_debuginfo;
+    dwfl_module_build_id;
+    dwfl_module_report_build_id;
+
+  local:
+    *;
+} ELFUTILS_0.127;
+
+ELFUTILS_0.136 {
+  global:
+    dwfl_addrsegment;
+    dwfl_report_segment;
+
+  local:
+    *;
+} ELFUTILS_0.130;
+
+ELFUTILS_0.138 {
+  global:
+    # Replaced ELFUTILS_0.130 version, which has bug-compatibility wrapper.
+    dwfl_module_build_id;
+
+  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;
+
+ELFUTILS_0.144 {
+  global:
+    dwarf_aggregate_size;
+} ELFUTILS_0.143;
+
+ELFUTILS_0.146 {
+  global:
+    dwfl_core_file_report;
+} ELFUTILS_0.144;
+
+ELFUTILS_0.148 {
+  global:
+    dwarf_lineisa;
+    dwarf_linediscriminator;
+    dwarf_lineop_index;
+
+    dwarf_next_unit;
+    dwarf_offdie_types;
+} ELFUTILS_0.146;
+
+ELFUTILS_0.149 {
+  global:
+    dwarf_getlocation_implicit_pointer;
+
+    dwfl_dwarf_line;
+} ELFUTILS_0.148;
+
+ELFUTILS_0.156 {
+  global:
+    # Replaced ELFUTILS_0.122 version, which has a wrapper without add_p_vaddr.
+    dwfl_report_elf;
+} ELFUTILS_0.149;
+
+ELFUTILS_0.157 {
+  global:
+    dwarf_getlocations;
+    dwarf_getlocation_die;
+    dwarf_getlocation_attr;
+} ELFUTILS_0.156;
+
+ELFUTILS_0.158 {
+  global:
+    # Replaced ELFUTILS_0.146 version, which has a wrapper without executable.
+    dwfl_core_file_report;
+
+    dwfl_attach_state;
+    dwfl_pid;
+    dwfl_thread_dwfl;
+    dwfl_thread_tid;
+    dwfl_frame_thread;
+    dwfl_thread_state_registers;
+    dwfl_thread_state_register_pc;
+    dwfl_getthread_frames;
+    dwfl_getthreads;
+    dwfl_thread_getframes;
+    dwfl_frame_pc;
+
+    dwfl_module_getsymtab_first_global;
+    dwfl_module_addrinfo;
+    dwfl_module_getsym_info;
+
+    dwfl_core_file_attach;
+    dwfl_linux_proc_attach;
+} ELFUTILS_0.157;
+
+ELFUTILS_0.159 {
+  global:
+    dwarf_getalt;
+    dwarf_setalt;
+    dwelf_dwarf_gnu_debugaltlink;
+    dwelf_elf_gnu_debuglink;
+    dwelf_elf_gnu_build_id;
+} ELFUTILS_0.158;
+
+ELFUTILS_0.160 {
+  global:
+    dwarf_cu_getdwarf;
+    dwarf_cu_die;
+} ELFUTILS_0.159;
+
+ELFUTILS_0.161 {
+  global:
+    dwarf_peel_type;
+
+    # Replaced ELFUTILS_0.144 version.  Both versions point to the
+    # same implementation, but users of the new symbol version can
+    # presume that it uses dwarf_peel_type.
+    dwarf_aggregate_size;
+
+    dwarf_getmacros_off;
+    dwarf_macro_getsrcfiles;
+    dwarf_macro_getparamcnt;
+    dwarf_macro_param;
+} ELFUTILS_0.160;
+
+ELFUTILS_0.165 {
+  global:
+    dwelf_scn_gnu_compressed_size;
+} ELFUTILS_0.161;
+
+ELFUTILS_0.167 {
+  global:
+    dwelf_strtab_init;
+    dwelf_strtab_add;
+    dwelf_strtab_add_len;
+    dwelf_strtab_finalize;
+    dwelf_strent_off;
+    dwelf_strent_str;
+    dwelf_strtab_free;
+} ELFUTILS_0.165;
+
+ELFUTILS_0.170 {
+  global:
+    dwarf_default_lower_bound;
+    dwarf_line_file;
+} ELFUTILS_0.167;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
new file mode 100644
index 0000000..0681aa1
--- /dev/null
+++ b/libdw/libdwP.h
@@ -0,0 +1,825 @@
+/* Internal definitions for libdwarf.
+   Copyright (C) 2002-2011, 2013-2018 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBDWP_H
+#define _LIBDWP_H 1
+
+#include <libintl.h>
+#include <stdbool.h>
+
+#include <libdw.h>
+#include <dwarf.h>
+
+
+/* gettext helper macros.  */
+#define _(Str) dgettext ("elfutils", Str)
+
+
+/* Known location expressions already decoded.  */
+struct loc_s
+{
+  void *addr;
+  Dwarf_Op *loc;
+  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;
+};
+
+/* Already decoded .debug_line units.  */
+struct files_lines_s
+{
+  Dwarf_Off debug_line_offset;
+  Dwarf_Files *files;
+  Dwarf_Lines *lines;
+};
+
+/* Valid indeces for the section data.  */
+enum
+  {
+    IDX_debug_info = 0,
+    IDX_debug_types,
+    IDX_debug_abbrev,
+    IDX_debug_aranges,
+    IDX_debug_line,
+    IDX_debug_frame,
+    IDX_debug_loc,
+    IDX_debug_pubnames,
+    IDX_debug_str,
+    IDX_debug_macinfo,
+    IDX_debug_macro,
+    IDX_debug_ranges,
+    IDX_gnu_debugaltlink,
+    IDX_last
+  };
+
+
+/* Error values.  */
+enum
+{
+  DWARF_E_NOERROR = 0,
+  DWARF_E_UNKNOWN_ERROR,
+  DWARF_E_INVALID_ACCESS,
+  DWARF_E_NO_REGFILE,
+  DWARF_E_IO_ERROR,
+  DWARF_E_INVALID_ELF,
+  DWARF_E_NO_DWARF,
+  DWARF_E_COMPRESSED_ERROR,
+  DWARF_E_NOELF,
+  DWARF_E_GETEHDR_ERROR,
+  DWARF_E_NOMEM,
+  DWARF_E_UNIMPL,
+  DWARF_E_INVALID_CMD,
+  DWARF_E_INVALID_VERSION,
+  DWARF_E_INVALID_FILE,
+  DWARF_E_NO_ENTRY,
+  DWARF_E_INVALID_DWARF,
+  DWARF_E_NO_STRING,
+  DWARF_E_NO_ADDR,
+  DWARF_E_NO_CONSTANT,
+  DWARF_E_NO_REFERENCE,
+  DWARF_E_INVALID_REFERENCE,
+  DWARF_E_NO_DEBUG_LINE,
+  DWARF_E_INVALID_DEBUG_LINE,
+  DWARF_E_TOO_BIG,
+  DWARF_E_VERSION,
+  DWARF_E_INVALID_DIR_IDX,
+  DWARF_E_ADDR_OUTOFRANGE,
+  DWARF_E_NO_LOCLIST,
+  DWARF_E_NO_BLOCK,
+  DWARF_E_INVALID_LINE_IDX,
+  DWARF_E_INVALID_ARANGE_IDX,
+  DWARF_E_NO_MATCH,
+  DWARF_E_NO_FLAG,
+  DWARF_E_INVALID_OFFSET,
+  DWARF_E_NO_DEBUG_RANGES,
+  DWARF_E_INVALID_CFI,
+  DWARF_E_NO_ALT_DEBUGLINK,
+  DWARF_E_INVALID_OPCODE,
+  DWARF_E_NOT_CUDIE,
+  DWARF_E_UNKNOWN_LANGUAGE,
+};
+
+
+#include "dwarf_sig8_hash.h"
+
+/* This is the structure representing the debugging state.  */
+struct Dwarf
+{
+  /* The underlying ELF file.  */
+  Elf *elf;
+
+  /* dwz alternate DWARF file.  */
+  Dwarf *alt_dwarf;
+
+  /* The section data.  */
+  Elf_Data *sectiondata[IDX_last];
+
+  /* True if the file has a byte order different from the host.  */
+  bool other_byte_order;
+
+  /* If true, we allocated the ELF descriptor ourselves.  */
+  bool free_elf;
+
+  /* If >= 0, we allocated the alt_dwarf ourselves and must end it and
+     close this file descriptor.  */
+  int alt_fd;
+
+  /* Information for traversing the .debug_pubnames section.  This is
+     an array and separately allocated with malloc.  */
+  struct pubnames_s
+  {
+    Dwarf_Off cu_offset;
+    Dwarf_Off set_start;
+    unsigned int cu_header_size;
+    int address_len;
+  } *pubnames_sets;
+  size_t pubnames_nsets;
+
+  /* Search tree for the CUs.  */
+  void *cu_tree;
+  Dwarf_Off next_cu_offset;
+
+  /* Search tree and sig8 hash table for .debug_types type units.  */
+  void *tu_tree;
+  Dwarf_Off next_tu_offset;
+  Dwarf_Sig8_Hash sig8_hash;
+
+  /* Search tree for .debug_macro operator tables.  */
+  void *macro_ops;
+
+  /* Search tree for decoded .debug_line units.  */
+  void *files_lines;
+
+  /* Address ranges.  */
+  Dwarf_Aranges *aranges;
+
+  /* Cached info from the CFI section.  */
+  struct Dwarf_CFI_s *cfi;
+
+  /* Fake loc CU.  Used when synthesizing attributes for Dwarf_Ops that
+     came from a location list entry in dwarf_getlocation_attr.  */
+  struct Dwarf_CU *fake_loc_cu;
+
+  /* Internal memory handling.  This is basically a simplified
+     reimplementation of obstacks.  Unfortunately the standard obstack
+     implementation is not usable in libraries.  */
+  struct libdw_memblock
+  {
+    size_t size;
+    size_t remaining;
+    struct libdw_memblock *prev;
+    char mem[0];
+  } *mem_tail;
+
+  /* Default size of allocated memory blocks.  */
+  size_t mem_default_size;
+
+  /* Registered OOM handler.  */
+  Dwarf_OOM oom_handler;
+};
+
+
+/* Abbreviation representation.  */
+struct Dwarf_Abbrev
+{
+  Dwarf_Off offset;	  /* Offset to start of abbrev into .debug_abbrev.  */
+  unsigned char *attrp;   /* Pointer to start of attribute name/form pairs. */
+  bool has_children : 1;  /* Whether or not the DIE has children. */
+  unsigned int code : 31; /* The (unique) abbrev code.  */
+  unsigned int tag;	  /* The tag of the DIE. */
+} attribute_packed;
+
+#include "dwarf_abbrev_hash.h"
+
+
+/* Files in line information records.  */
+struct Dwarf_Files_s
+  {
+    unsigned int ndirs;
+    unsigned int nfiles;
+    struct Dwarf_Fileinfo_s
+    {
+      char *name;
+      Dwarf_Word mtime;
+      Dwarf_Word length;
+    } info[0];
+    /* nfiles of those, followed by char *[ndirs].  */
+  };
+typedef struct Dwarf_Fileinfo_s Dwarf_Fileinfo;
+
+
+/* Representation of a row in the line table.  */
+
+struct Dwarf_Line_s
+{
+  Dwarf_Files *files;
+
+  Dwarf_Addr addr;
+  unsigned int file;
+  int line;
+  unsigned short int column;
+  unsigned int is_stmt:1;
+  unsigned int basic_block:1;
+  unsigned int end_sequence:1;
+  unsigned int prologue_end:1;
+  unsigned int epilogue_begin:1;
+  /* The remaining bit fields are not flags, but hold values presumed to be
+     small.  All the flags and other bit fields should add up to 48 bits
+     to give the whole struct a nice round size.  */
+  unsigned int op_index:8;
+  unsigned int isa:8;
+  unsigned int discriminator:24;
+};
+
+struct Dwarf_Lines_s
+{
+  size_t nlines;
+  struct Dwarf_Line_s info[0];
+};
+
+/* Representation of address ranges.  */
+struct Dwarf_Aranges_s
+{
+  Dwarf *dbg;
+  size_t naranges;
+
+  struct Dwarf_Arange_s
+  {
+    Dwarf_Addr addr;
+    Dwarf_Word length;
+    Dwarf_Off offset;
+  } info[0];
+};
+
+
+/* CU representation.  */
+struct Dwarf_CU
+{
+  Dwarf *dbg;
+  Dwarf_Off start;
+  Dwarf_Off end;
+  uint8_t address_size;
+  uint8_t offset_size;
+  uint16_t version;
+
+  size_t sec_idx; /* Normally .debug_info, could be .debug_type or "fake". */
+
+  /* Zero if this is a normal CU.  Nonzero if it is a type unit.  */
+  size_t type_offset;
+  uint64_t type_sig8;
+
+  /* Hash table for the abbreviations.  */
+  Dwarf_Abbrev_Hash abbrev_hash;
+  /* Offset of the first abbreviation.  */
+  size_t orig_abbrev_offset;
+  /* Offset past last read abbreviation.  */
+  size_t last_abbrev_offset;
+
+  /* The srcline information.  */
+  Dwarf_Lines *lines;
+
+  /* The source file information.  */
+  Dwarf_Files *files;
+
+  /* Known location lists.  */
+  void *locs;
+
+  /* Memory boundaries of this CU.  */
+  void *startp;
+  void *endp;
+};
+
+/* Compute the offset of a CU's first DIE from its offset.  This
+   is either:
+        LEN       VER     OFFSET    ADDR
+      4-bytes + 2-bytes + 4-bytes + 1-byte  for 32-bit dwarf
+     12-bytes + 2-bytes + 8-bytes + 1-byte  for 64-bit dwarf
+   or in .debug_types, 			     SIGNATURE TYPE-OFFSET
+      4-bytes + 2-bytes + 4-bytes + 1-byte + 8-bytes + 4-bytes  for 32-bit
+     12-bytes + 2-bytes + 8-bytes + 1-byte + 8-bytes + 8-bytes  for 64-bit
+
+   Note the trick in the computation.  If the offset_size is 4
+   the '- 4' term changes the '3 *' into a '2 *'.  If the
+   offset_size is 8 it accounts for the 4-byte escape value
+   used at the start of the length.  */
+#define DIE_OFFSET_FROM_CU_OFFSET(cu_offset, offset_size, type_unit)	\
+  ((type_unit) ? ((cu_offset) + 4 * (offset_size) - 4 + 3 + 8)		\
+   : ((cu_offset) + 3 * (offset_size) - 4 + 3))
+
+#define CUDIE(fromcu)							      \
+  ((Dwarf_Die)								      \
+   {									      \
+     .cu = (fromcu),							      \
+     .addr = ((char *) fromcu->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf   \
+	      + DIE_OFFSET_FROM_CU_OFFSET ((fromcu)->start,		      \
+					   (fromcu)->offset_size,	      \
+					   (fromcu)->type_offset != 0))	      \
+   })									      \
+
+
+/* Prototype of a single .debug_macro operator.  */
+typedef struct
+{
+  Dwarf_Word nforms;
+  unsigned char const *forms;
+} Dwarf_Macro_Op_Proto;
+
+/* Prototype table.  */
+typedef struct
+{
+  /* Offset of .debug_macro section.  */
+  Dwarf_Off offset;
+
+  /* Offset of associated .debug_line section.  */
+  Dwarf_Off line_offset;
+
+  /* The source file information.  */
+  Dwarf_Files *files;
+
+  /* If this macro unit was opened through dwarf_getmacros or
+     dwarf_getmacros_die, this caches value of DW_AT_comp_dir, if
+     present.  */
+  const char *comp_dir;
+
+  /* Header length.  */
+  Dwarf_Half header_len;
+
+  uint16_t version;
+  bool is_64bit;
+  uint8_t sec_index;	/* IDX_debug_macro or IDX_debug_macinfo.  */
+
+  /* Shows where in TABLE each opcode is defined.  Since opcode 0 is
+     never used, it stores index of opcode X in X-1'th element.  The
+     value of 0xff means not stored at all.  */
+  unsigned char opcodes[255];
+
+  /* Individual opcode prototypes.  */
+  Dwarf_Macro_Op_Proto table[];
+} Dwarf_Macro_Op_Table;
+
+struct Dwarf_Macro_s
+{
+  Dwarf_Macro_Op_Table *table;
+  Dwarf_Attribute *attributes;
+  uint8_t opcode;
+};
+
+static inline Dwarf_Word
+libdw_macro_nforms (Dwarf_Macro *macro)
+{
+  return macro->table->table[macro->table->opcodes[macro->opcode - 1]].nforms;
+}
+
+/* We have to include the file at this point because the inline
+   functions access internals of the Dwarf structure.  */
+#include "memory-access.h"
+
+
+/* Set error value.  */
+extern void __libdw_seterrno (int value) internal_function;
+
+
+/* Memory handling, the easy parts.  This macro does not do any locking.  */
+#define libdw_alloc(dbg, type, tsize, cnt) \
+  ({ struct libdw_memblock *_tail = (dbg)->mem_tail;			      \
+     size_t _required = (tsize) * (cnt);				      \
+     type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\
+     size_t _padding = ((__alignof (type)				      \
+			 - ((uintptr_t) _result & (__alignof (type) - 1)))    \
+			& (__alignof (type) - 1));			      \
+     if (unlikely (_tail->remaining < _required + _padding))		      \
+       _result = (type *) __libdw_allocate (dbg, _required, __alignof (type));\
+     else								      \
+       {								      \
+	 _required += _padding;						      \
+	 _result = (type *) ((char *) _result + _padding);		      \
+	 _tail->remaining -= _required;					      \
+       }								      \
+     _result; })
+
+#define libdw_typed_alloc(dbg, type) \
+  libdw_alloc (dbg, type, sizeof (type), 1)
+
+/* Callback to allocate more.  */
+extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
+     __attribute__ ((__malloc__)) __nonnull_attribute__ (1);
+
+/* Default OOM handler.  */
+extern void __libdw_oom (void) __attribute ((noreturn)) attribute_hidden;
+
+/* Allocate the internal data for a unit not seen before.  */
+extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
+     __nonnull_attribute__ (1) internal_function;
+
+/* Find CU for given offset.  */
+extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset, bool tu)
+     __nonnull_attribute__ (1) internal_function;
+
+/* Get abbreviation with given code.  */
+extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
+					 unsigned int code)
+     __nonnull_attribute__ (1) internal_function;
+
+/* Get abbreviation at given offset.  */
+extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
+					Dwarf_Off offset, size_t *lengthp,
+					Dwarf_Abbrev *result)
+     __nonnull_attribute__ (1) internal_function;
+
+/* Get abbreviation of given DIE, and optionally set *READP to the DIE memory
+   just past the abbreviation code.  */
+static inline Dwarf_Abbrev *
+__nonnull_attribute__ (1)
+__libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp)
+{
+  /* Do we need to get the abbreviation, or need to read after the code?  */
+  if (die->abbrev == NULL || readp != NULL)
+    {
+      /* Get the abbreviation code.  */
+      unsigned int code;
+      const unsigned char *addr = die->addr;
+      get_uleb128 (code, addr, die->cu->endp);
+      if (readp != NULL)
+	*readp = addr;
+
+      /* Find the abbreviation.  */
+      if (die->abbrev == NULL)
+	die->abbrev = __libdw_findabbrev (die->cu, code);
+    }
+  return die->abbrev;
+}
+
+/* Helper functions for form handling.  */
+extern size_t __libdw_form_val_compute_len (struct Dwarf_CU *cu,
+					    unsigned int form,
+					    const unsigned char *valp)
+     __nonnull_attribute__ (1, 3) internal_function;
+
+/* Find the length of a form attribute.  */
+static inline size_t
+__nonnull_attribute__ (1, 3)
+__libdw_form_val_len (struct Dwarf_CU *cu, unsigned int form,
+		      const unsigned char *valp)
+{
+  /* Small lookup table of forms with fixed lengths.  Absent indexes are
+     initialized 0, so any truly desired 0 is set to 0x80 and masked.  */
+  static const uint8_t form_lengths[] =
+    {
+      [DW_FORM_flag_present] = 0x80,
+      [DW_FORM_data1] = 1, [DW_FORM_ref1] = 1, [DW_FORM_flag] = 1,
+      [DW_FORM_data2] = 2, [DW_FORM_ref2] = 2,
+      [DW_FORM_data4] = 4, [DW_FORM_ref4] = 4,
+      [DW_FORM_data8] = 8, [DW_FORM_ref8] = 8, [DW_FORM_ref_sig8] = 8,
+    };
+
+  /* Return immediately for forms with fixed lengths.  */
+  if (form < sizeof form_lengths / sizeof form_lengths[0])
+    {
+      uint8_t len = form_lengths[form];
+      if (len != 0)
+	{
+	  const unsigned char *endp = cu->endp;
+	  len &= 0x7f; /* Mask to allow 0x80 -> 0.  */
+	  if (unlikely (len > (size_t) (endp - valp)))
+	    {
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return -1;
+	    }
+	  return len;
+	}
+    }
+
+  /* Other forms require some computation.  */
+  return __libdw_form_val_compute_len (cu, form, valp);
+}
+
+/* Helper function for DW_FORM_ref* handling.  */
+extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
+     __nonnull_attribute__ (1, 2) internal_function;
+
+
+/* Helper function to locate attribute.  */
+extern unsigned char *__libdw_find_attr (Dwarf_Die *die,
+					 unsigned int search_name,
+					 unsigned int *codep,
+					 unsigned int *formp)
+     __nonnull_attribute__ (1) internal_function;
+
+/* Helper function to access integer attribute.  */
+extern int __libdw_attr_intval (Dwarf_Die *die, int *valp, int attval)
+     __nonnull_attribute__ (1, 2) internal_function;
+
+/* Helper function to walk scopes.  */
+struct Dwarf_Die_Chain
+{
+  Dwarf_Die die;
+  struct Dwarf_Die_Chain *parent;
+  bool prune;			/* The PREVISIT function can set this.  */
+};
+extern int __libdw_visit_scopes (unsigned int depth,
+				 struct Dwarf_Die_Chain *root,
+				 struct Dwarf_Die_Chain *imports,
+				 int (*previsit) (unsigned int depth,
+						  struct Dwarf_Die_Chain *,
+						  void *arg),
+				 int (*postvisit) (unsigned int depth,
+						   struct Dwarf_Die_Chain *,
+						   void *arg),
+				 void *arg)
+  __nonnull_attribute__ (2, 4) 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,
+				      unsigned int ref_size,
+				      void **cache, const Dwarf_Block *block,
+				      bool cfap, bool valuep,
+				      Dwarf_Op **llbuf, size_t *listlen,
+				      int sec_index)
+  __nonnull_attribute__ (5, 6, 9, 10) internal_function;
+
+extern Dwarf_Die *__libdw_offdie (Dwarf *dbg, Dwarf_Off offset,
+				  Dwarf_Die *result, bool debug_types)
+  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 < size)
+      || unlikely (offset > data->d_size - 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 < size)
+      || unlikely ((size_t)(addr - data->d_buf) > data->d_size - 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, Dwarf *dbg_ret,
+		     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_ret, sec_ret, *ret, size);
+}
+
+static inline size_t
+cu_sec_idx (struct Dwarf_CU *cu)
+{
+  return cu->sec_idx;
+}
+
+static inline bool
+is_cudie (Dwarf_Die *cudie)
+{
+  return CUDIE (cudie->cu).addr == cudie->addr;
+}
+
+/* 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;
+
+/* Fills in the given attribute to point at an empty location expression.  */
+void __libdw_empty_loc_attr (Dwarf_Attribute *attr)
+  internal_function;
+
+/* Load .debug_line unit at DEBUG_LINE_OFFSET.  COMP_DIR is a value of
+   DW_AT_comp_dir or NULL if that attribute is not available.  Caches
+   the loaded unit and optionally set *LINESP and/or *FILESP (if not
+   NULL) with loaded information.  Returns 0 for success or a negative
+   value for failure.  */
+int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
+			 const char *comp_dir, unsigned address_size,
+			 Dwarf_Lines **linesp, Dwarf_Files **filesp)
+  internal_function
+  __nonnull_attribute__ (1);
+
+/* Load and return value of DW_AT_comp_dir from CUDIE.  */
+const char *__libdw_getcompdir (Dwarf_Die *cudie);
+
+/* Given a file descriptor, dir and file returns a full path.  If the
+   file is absolute (starts with a /) a copy of file is returned.  If
+   the file isn't absolute, but dir is absolute, then a path that is
+   the concatenation of dir and file is returned.  If neither file,
+   nor dir is absolute, the path will be constructed using dir (if not
+   NULL) and file relative to the path of the given file descriptor
+   (if valid).
+
+   The file descriptor may be -1 and the dir may be NULL (in which
+   case they aren't used). If file is NULL, or no full path can be
+   constructed NULL is returned.
+
+   The caller is responsible for freeing the result if not NULL.  */
+char * filepath (int fd, const char *dir, const char *file)
+  internal_function;
+
+
+/* Aliases to avoid PLTs.  */
+INTDECL (dwarf_aggregate_size)
+INTDECL (dwarf_attr)
+INTDECL (dwarf_attr_integrate)
+INTDECL (dwarf_begin)
+INTDECL (dwarf_begin_elf)
+INTDECL (dwarf_child)
+INTDECL (dwarf_default_lower_bound)
+INTDECL (dwarf_dieoffset)
+INTDECL (dwarf_diename)
+INTDECL (dwarf_end)
+INTDECL (dwarf_entrypc)
+INTDECL (dwarf_errmsg)
+INTDECL (dwarf_formaddr)
+INTDECL (dwarf_formblock)
+INTDECL (dwarf_formref_die)
+INTDECL (dwarf_formsdata)
+INTDECL (dwarf_formstring)
+INTDECL (dwarf_formudata)
+INTDECL (dwarf_getalt)
+INTDECL (dwarf_getarange_addr)
+INTDECL (dwarf_getarangeinfo)
+INTDECL (dwarf_getaranges)
+INTDECL (dwarf_getlocation_die)
+INTDECL (dwarf_getsrcfiles)
+INTDECL (dwarf_getsrclines)
+INTDECL (dwarf_hasattr)
+INTDECL (dwarf_haschildren)
+INTDECL (dwarf_haspc)
+INTDECL (dwarf_highpc)
+INTDECL (dwarf_lowpc)
+INTDECL (dwarf_nextcu)
+INTDECL (dwarf_next_unit)
+INTDECL (dwarf_offdie)
+INTDECL (dwarf_peel_type)
+INTDECL (dwarf_ranges)
+INTDECL (dwarf_setalt)
+INTDECL (dwarf_siblingof)
+INTDECL (dwarf_srclang)
+INTDECL (dwarf_tag)
+
+#endif	/* libdwP.h */
diff --git a/libdw/libdw_alloc.c b/libdw/libdw_alloc.c
new file mode 100644
index 0000000..d6af23a
--- /dev/null
+++ b/libdw/libdw_alloc.c
@@ -0,0 +1,78 @@
+/* Memory handling for libdw.
+   Copyright (C) 2003, 2004, 2006 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <error.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "libdwP.h"
+#include "system.h"
+
+
+void *
+__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
+{
+  size_t size = MAX (dbg->mem_default_size,
+		     (align - 1 +
+		      2 * minsize + offsetof (struct libdw_memblock, mem)));
+  struct libdw_memblock *newp = malloc (size);
+  if (newp == NULL)
+    dbg->oom_handler ();
+
+  uintptr_t result = ((uintptr_t) newp->mem + align - 1) & ~(align - 1);
+
+  newp->size = size - offsetof (struct libdw_memblock, mem);
+  newp->remaining = (uintptr_t) newp + size - (result + minsize);
+
+  newp->prev = dbg->mem_tail;
+  dbg->mem_tail = newp;
+
+  return (void *) result;
+}
+
+
+Dwarf_OOM
+dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler)
+{
+  Dwarf_OOM old = dbg->oom_handler;
+  dbg->oom_handler = handler;
+  return old;
+}
+
+
+void
+__attribute ((noreturn)) attribute_hidden
+__libdw_oom (void)
+{
+  while (1)
+    error (EXIT_FAILURE, ENOMEM, "libdw");
+}
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
new file mode 100644
index 0000000..4e025e2
--- /dev/null
+++ b/libdw/libdw_findcu.c
@@ -0,0 +1,169 @@
+/* Find CU for given offset.
+   Copyright (C) 2003-2010, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <search.h>
+#include "libdwP.h"
+
+static int
+findcu_cb (const void *arg1, const void *arg2)
+{
+  struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
+  struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
+
+  /* Find out which of the two arguments is the search value.  It has
+     end offset 0.  */
+  if (cu1->end == 0)
+    {
+      if (cu1->start < cu2->start)
+	return -1;
+      if (cu1->start >= cu2->end)
+	return 1;
+    }
+  else
+    {
+      if (cu2->start < cu1->start)
+	return 1;
+      if (cu2->start >= cu1->end)
+	return -1;
+    }
+
+  return 0;
+}
+
+struct Dwarf_CU *
+internal_function
+__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
+{
+  Dwarf_Off *const offsetp
+    = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
+  void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
+
+  Dwarf_Off oldoff = *offsetp;
+  uint16_t version;
+  uint8_t address_size;
+  uint8_t offset_size;
+  Dwarf_Off abbrev_offset;
+  uint64_t type_sig8 = 0;
+  Dwarf_Off type_offset = 0;
+
+  if (INTUSE(dwarf_next_unit) (dbg, oldoff, offsetp, NULL,
+			       &version, &abbrev_offset,
+			       &address_size, &offset_size,
+			       debug_types ? &type_sig8 : NULL,
+			       debug_types ? &type_offset : NULL) != 0)
+    /* No more entries.  */
+    return NULL;
+
+  /* We only know how to handle the DWARF version 2 through 4 formats.  */
+  if (unlikely (version < 2) || unlikely (version > 4))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  /* Invalid or truncated debug section data?  */
+  size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
+  Elf_Data *data = dbg->sectiondata[sec_idx];
+  if (unlikely (*offsetp > data->d_size))
+    *offsetp = data->d_size;
+
+  /* Create an entry for this CU.  */
+  struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
+
+  newp->dbg = dbg;
+  newp->sec_idx = sec_idx;
+  newp->start = oldoff;
+  newp->end = *offsetp;
+  newp->address_size = address_size;
+  newp->offset_size = offset_size;
+  newp->version = version;
+  newp->type_sig8 = type_sig8;
+  newp->type_offset = type_offset;
+  Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
+  newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
+  newp->lines = NULL;
+  newp->locs = NULL;
+
+  if (debug_types)
+    Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, type_sig8, newp);
+
+  newp->startp = data->d_buf + newp->start;
+  newp->endp = data->d_buf + newp->end;
+
+  /* Add the new entry to the search tree.  */
+  if (tsearch (newp, tree, findcu_cb) == NULL)
+    {
+      /* Something went wrong.  Undo the operation.  */
+      *offsetp = oldoff;
+      __libdw_seterrno (DWARF_E_NOMEM);
+      return NULL;
+    }
+
+  return newp;
+}
+
+struct Dwarf_CU *
+internal_function
+__libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool debug_types)
+{
+  void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
+  Dwarf_Off *next_offset
+    = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
+
+  /* Maybe we already know that CU.  */
+  struct Dwarf_CU fake = { .start = start, .end = 0 };
+  struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
+  if (found != NULL)
+    return *found;
+
+  if (start < *next_offset)
+    {
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
+
+  /* No.  Then read more CUs.  */
+  while (1)
+    {
+      struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, debug_types);
+      if (newp == NULL)
+	return NULL;
+
+      /* Is this the one we are looking for?  */
+      if (start < *next_offset)
+	// XXX Match exact offset.
+	return newp;
+    }
+  /* NOTREACHED */
+}
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
new file mode 100644
index 0000000..72e2390
--- /dev/null
+++ b/libdw/libdw_form.c
@@ -0,0 +1,132 @@
+/* Helper functions for form handling.
+   Copyright (C) 2003-2009, 2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include <string.h>
+
+#include "libdwP.h"
+
+
+size_t
+internal_function
+__libdw_form_val_compute_len (struct Dwarf_CU *cu, unsigned int form,
+			      const unsigned char *valp)
+{
+  const unsigned char *startp = valp;
+  const unsigned char *endp = cu->endp;
+  Dwarf_Word u128;
+  size_t result;
+
+  /* NB: This doesn't cover constant form lengths, which are
+     already handled by the inlined __libdw_form_val_len.  */
+  switch (form)
+    {
+    case DW_FORM_addr:
+      result = cu->address_size;
+      break;
+
+    case DW_FORM_ref_addr:
+      result = cu->version == 2 ? cu->address_size : cu->offset_size;
+      break;
+
+    case DW_FORM_strp:
+    case DW_FORM_sec_offset:
+    case DW_FORM_GNU_ref_alt:
+    case DW_FORM_GNU_strp_alt:
+      result = cu->offset_size;
+      break;
+
+    case DW_FORM_block1:
+      if (unlikely ((size_t) (endp - startp) < 1))
+	goto invalid;
+      result = *valp + 1;
+      break;
+
+    case DW_FORM_block2:
+      if (unlikely ((size_t) (endp - startp) < 2))
+	goto invalid;
+      result = read_2ubyte_unaligned (cu->dbg, valp) + 2;
+      break;
+
+    case DW_FORM_block4:
+      if (unlikely ((size_t) (endp - startp) < 4))
+	goto invalid;
+      result = read_4ubyte_unaligned (cu->dbg, valp) + 4;
+      break;
+
+    case DW_FORM_block:
+    case DW_FORM_exprloc:
+      get_uleb128 (u128, valp, endp);
+      result = u128 + (valp - startp);
+      break;
+
+    case DW_FORM_string:
+      {
+	const unsigned char *endstrp = memchr (valp, '\0',
+					       (size_t) (endp - startp));
+	if (unlikely (endstrp == NULL))
+	  goto invalid;
+	result = (size_t) (endstrp - startp) + 1;
+	break;
+      }
+
+    case DW_FORM_sdata:
+    case DW_FORM_udata:
+    case DW_FORM_ref_udata:
+      get_uleb128 (u128, valp, endp);
+      result = valp - startp;
+      break;
+
+    case DW_FORM_indirect:
+      get_uleb128 (u128, valp, endp);
+      // XXX Is this really correct?
+      result = __libdw_form_val_len (cu, u128, valp);
+      if (result != (size_t) -1)
+	result += valp - startp;
+      else
+        return (size_t) -1;
+      break;
+
+    default:
+      goto invalid;
+    }
+
+  if (unlikely (result > (size_t) (endp - startp)))
+    {
+    invalid:
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      result = (size_t) -1;
+    }
+
+  return result;
+}
diff --git a/libdw/libdw_visit_scopes.c b/libdw/libdw_visit_scopes.c
new file mode 100644
index 0000000..eb892e1
--- /dev/null
+++ b/libdw/libdw_visit_scopes.c
@@ -0,0 +1,188 @@
+/* Helper functions to descend DWARF scope trees.
+   Copyright (C) 2005,2006,2007,2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+
+
+static bool
+may_have_scopes (Dwarf_Die *die)
+{
+  switch (INTUSE(dwarf_tag) (die))
+    {
+      /* DIEs with addresses we can try to match.  */
+    case DW_TAG_compile_unit:
+    case DW_TAG_module:
+    case DW_TAG_lexical_block:
+    case DW_TAG_with_stmt:
+    case DW_TAG_catch_block:
+    case DW_TAG_try_block:
+    case DW_TAG_entry_point:
+    case DW_TAG_inlined_subroutine:
+    case DW_TAG_subprogram:
+      return true;
+
+      /* DIEs without addresses that can own DIEs with addresses.  */
+    case DW_TAG_namespace:
+    case DW_TAG_class_type:
+    case DW_TAG_structure_type:
+      return true;
+
+      /* Other DIEs we have no reason to descend.  */
+    default:
+      break;
+    }
+  return false;
+}
+
+struct walk_children_state
+{
+  /* Parameters of __libdw_visit_scopes. */
+  unsigned int depth;
+  struct Dwarf_Die_Chain *imports;
+  int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
+  int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
+  void *arg;
+  /* Extra local variables for the walker. */
+  struct Dwarf_Die_Chain child;
+};
+
+static inline int
+walk_children (struct walk_children_state *state);
+
+int
+internal_function
+__libdw_visit_scopes (unsigned int depth, struct Dwarf_Die_Chain *root,
+		      struct Dwarf_Die_Chain *imports,
+		      int (*previsit) (unsigned int,
+				       struct Dwarf_Die_Chain *,
+				       void *),
+		      int (*postvisit) (unsigned int,
+					struct Dwarf_Die_Chain *,
+					void *),
+		      void *arg)
+{
+  struct walk_children_state state =
+    {
+      .depth = depth,
+      .imports = imports,
+      .previsit = previsit,
+      .postvisit = postvisit,
+      .arg = arg
+    };
+
+  state.child.parent = root;
+  int ret;
+  if ((ret = INTUSE(dwarf_child) (&root->die, &state.child.die)) != 0)
+    return ret < 0 ? -1 : 0; // Having zero children is legal.
+
+  return walk_children (&state);
+}
+
+static inline int
+walk_children (struct walk_children_state *state)
+{
+  int ret;
+  do
+    {
+      /* For an imported unit, it is logically as if the children of
+	 that unit are siblings of the other children.  So don't do
+	 a full recursion into the imported unit, but just walk the
+	 children in place before moving to the next real child.  */
+      while (INTUSE(dwarf_tag) (&state->child.die) == DW_TAG_imported_unit)
+	{
+	  Dwarf_Die orig_child_die = state->child.die;
+	  Dwarf_Attribute attr_mem;
+	  Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&state->child.die,
+						      DW_AT_import,
+						      &attr_mem);
+	  if (INTUSE(dwarf_formref_die) (attr, &state->child.die) != NULL
+	      && INTUSE(dwarf_child) (&state->child.die, &state->child.die) == 0)
+	    {
+	      /* Checks the given DIE hasn't been imported yet
+	         to prevent cycles.  */
+	      bool imported = false;
+	      for (struct Dwarf_Die_Chain *import = state->imports; import != NULL;
+	        import = import->parent)
+	        if (import->die.addr == orig_child_die.addr)
+	          {
+	            imported = true;
+	            break;
+	          }
+	      if (imported)
+		{
+		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+		  return -1;
+		}
+	      struct Dwarf_Die_Chain *orig_imports = state->imports;
+	      struct Dwarf_Die_Chain import = { .die = orig_child_die,
+					        .parent = orig_imports };
+	      state->imports = &import;
+	      int result = walk_children (state);
+	      state->imports = orig_imports;
+	      if (result != DWARF_CB_OK)
+		return result;
+	    }
+
+	  /* Any "real" children left?  */
+	  if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die,
+					      &state->child.die)) != 0)
+	    return ret < 0 ? -1 : 0;
+	};
+
+	state->child.prune = false;
+
+	/* previsit is declared NN */
+	int result = (*state->previsit) (state->depth + 1, &state->child, state->arg);
+	if (result != DWARF_CB_OK)
+	  return result;
+
+	if (!state->child.prune && may_have_scopes (&state->child.die)
+	    && INTUSE(dwarf_haschildren) (&state->child.die))
+	  {
+	    result = __libdw_visit_scopes (state->depth + 1, &state->child, state->imports,
+				           state->previsit, state->postvisit, state->arg);
+	    if (result != DWARF_CB_OK)
+	      return result;
+	  }
+
+	if (state->postvisit != NULL)
+	  {
+	    result = (*state->postvisit) (state->depth + 1, &state->child, state->arg);
+	    if (result != DWARF_CB_OK)
+	      return result;
+	  }
+    }
+  while ((ret = INTUSE(dwarf_siblingof) (&state->child.die, &state->child.die)) == 0);
+
+  return ret < 0 ? -1 : 0;
+}
diff --git a/libdw/memory-access.h b/libdw/memory-access.h
new file mode 100644
index 0000000..ed68bdb
--- /dev/null
+++ b/libdw/memory-access.h
@@ -0,0 +1,305 @@
+/* Unaligned memory access functionality.
+   Copyright (C) 2000-2014 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _MEMORY_ACCESS_H
+#define _MEMORY_ACCESS_H 1
+
+#include <byteswap.h>
+#include <limits.h>
+#include <stdint.h>
+
+
+/* Number decoding macros.  See 7.6 Variable Length Data.  */
+
+#define len_leb128(var) ((8 * sizeof (var) + 6) / 7)
+
+static inline size_t
+__libdw_max_len_leb128 (const size_t type_len,
+			const unsigned char *addr, const unsigned char *end)
+{
+  const size_t pointer_len = likely (addr < end) ? end - addr : 0;
+  return likely (type_len <= pointer_len) ? type_len : pointer_len;
+}
+
+static inline size_t
+__libdw_max_len_uleb128 (const unsigned char *addr, const unsigned char *end)
+{
+  const size_t type_len = len_leb128 (uint64_t);
+  return __libdw_max_len_leb128 (type_len, addr, end);
+}
+
+static inline size_t
+__libdw_max_len_sleb128 (const unsigned char *addr, const unsigned char *end)
+{
+  /* Subtract one step, so we don't shift into sign bit.  */
+  const size_t type_len = len_leb128 (int64_t) - 1;
+  return __libdw_max_len_leb128 (type_len, addr, end);
+}
+
+#define get_uleb128_step(var, addr, nth)				      \
+  do {									      \
+    unsigned char __b = *(addr)++;					      \
+    (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7);		      \
+    if (likely ((__b & 0x80) == 0))					      \
+      return (var);							      \
+  } while (0)
+
+static inline uint64_t
+__libdw_get_uleb128 (const unsigned char **addrp, const unsigned char *end)
+{
+  uint64_t acc = 0;
+
+  /* Unroll the first step to help the compiler optimize
+     for the common single-byte case.  */
+  get_uleb128_step (acc, *addrp, 0);
+
+  const size_t max = __libdw_max_len_uleb128 (*addrp - 1, end);
+  for (size_t i = 1; i < max; ++i)
+    get_uleb128_step (acc, *addrp, i);
+  /* Other implementations set VALUE to UINT_MAX in this
+     case.  So we better do this as well.  */
+  return UINT64_MAX;
+}
+
+static inline uint64_t
+__libdw_get_uleb128_unchecked (const unsigned char **addrp)
+{
+  uint64_t acc = 0;
+
+  /* Unroll the first step to help the compiler optimize
+     for the common single-byte case.  */
+  get_uleb128_step (acc, *addrp, 0);
+
+  const size_t max = len_leb128 (uint64_t);
+  for (size_t i = 1; i < max; ++i)
+    get_uleb128_step (acc, *addrp, i);
+  /* Other implementations set VALUE to UINT_MAX in this
+     case.  So we better do this as well.  */
+  return UINT64_MAX;
+}
+
+/* Note, addr needs to me smaller than end. */
+#define get_uleb128(var, addr, end) ((var) = __libdw_get_uleb128 (&(addr), end))
+#define get_uleb128_unchecked(var, addr) ((var) = __libdw_get_uleb128_unchecked (&(addr)))
+
+/* The signed case is similar, but we sign-extend the result.  */
+
+#define get_sleb128_step(var, addr, nth)				      \
+  do {									      \
+    unsigned char __b = *(addr)++;					      \
+    if (likely ((__b & 0x80) == 0))					      \
+      {									      \
+	struct { signed int i:7; } __s = { .i = __b };			      \
+	(var) |= (typeof (var)) __s.i * ((typeof (var)) 1 << ((nth) * 7));    \
+	return (var);							      \
+      }									      \
+    (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7);		      \
+  } while (0)
+
+static inline int64_t
+__libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end)
+{
+  int64_t acc = 0;
+
+  /* Unroll the first step to help the compiler optimize
+     for the common single-byte case.  */
+  get_sleb128_step (acc, *addrp, 0);
+
+  const size_t max = __libdw_max_len_sleb128 (*addrp - 1, end);
+  for (size_t i = 1; i < max; ++i)
+    get_sleb128_step (acc, *addrp, i);
+  /* Other implementations set VALUE to INT_MAX in this
+     case.  So we better do this as well.  */
+  return INT64_MAX;
+}
+
+#define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end))
+
+
+/* We use simple memory access functions in case the hardware allows it.
+   The caller has to make sure we don't have alias problems.  */
+#if ALLOW_UNALIGNED
+
+# define read_2ubyte_unaligned(Dbg, Addr) \
+  (unlikely ((Dbg)->other_byte_order)					      \
+   ? bswap_16 (*((const uint16_t *) (Addr)))				      \
+   : *((const uint16_t *) (Addr)))
+# define read_2sbyte_unaligned(Dbg, Addr) \
+  (unlikely ((Dbg)->other_byte_order)					      \
+   ? (int16_t) bswap_16 (*((const int16_t *) (Addr)))			      \
+   : *((const int16_t *) (Addr)))
+
+# define read_4ubyte_unaligned_noncvt(Addr) \
+   *((const uint32_t *) (Addr))
+# define read_4ubyte_unaligned(Dbg, Addr) \
+  (unlikely ((Dbg)->other_byte_order)					      \
+   ? bswap_32 (*((const uint32_t *) (Addr)))				      \
+   : *((const uint32_t *) (Addr)))
+# define read_4sbyte_unaligned(Dbg, Addr) \
+  (unlikely ((Dbg)->other_byte_order)					      \
+   ? (int32_t) bswap_32 (*((const int32_t *) (Addr)))			      \
+   : *((const int32_t *) (Addr)))
+
+# define read_8ubyte_unaligned_noncvt(Addr) \
+   *((const uint64_t *) (Addr))
+# define read_8ubyte_unaligned(Dbg, Addr) \
+  (unlikely ((Dbg)->other_byte_order)					      \
+   ? bswap_64 (*((const uint64_t *) (Addr)))				      \
+   : *((const uint64_t *) (Addr)))
+# define read_8sbyte_unaligned(Dbg, Addr) \
+  (unlikely ((Dbg)->other_byte_order)					      \
+   ? (int64_t) bswap_64 (*((const int64_t *) (Addr)))			      \
+   : *((const int64_t *) (Addr)))
+
+#else
+
+union unaligned
+  {
+    void *p;
+    uint16_t u2;
+    uint32_t u4;
+    uint64_t u8;
+    int16_t s2;
+    int32_t s4;
+    int64_t s8;
+  } attribute_packed;
+
+# 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_1 (bool other_byte_order, const void *p)
+{
+  const union unaligned *up = p;
+  if (unlikely (other_byte_order))
+    return bswap_16 (up->u2);
+  return up->u2;
+}
+static inline int16_t
+read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
+{
+  const union unaligned *up = p;
+  if (unlikely (other_byte_order))
+    return (int16_t) bswap_16 (up->u2);
+  return up->s2;
+}
+
+static inline uint32_t
+read_4ubyte_unaligned_noncvt (const void *p)
+{
+  const union unaligned *up = p;
+  return up->u4;
+}
+static inline uint32_t
+read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
+{
+  const union unaligned *up = p;
+  if (unlikely (other_byte_order))
+    return bswap_32 (up->u4);
+  return up->u4;
+}
+static inline int32_t
+read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
+{
+  const union unaligned *up = p;
+  if (unlikely (other_byte_order))
+    return (int32_t) bswap_32 (up->u4);
+  return up->s4;
+}
+
+static inline uint64_t
+read_8ubyte_unaligned_noncvt (const void *p)
+{
+  const union unaligned *up = p;
+  return up->u8;
+}
+static inline uint64_t
+read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
+{
+  const union unaligned *up = p;
+  if (unlikely (other_byte_order))
+    return bswap_64 (up->u8);
+  return up->u8;
+}
+static inline int64_t
+read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
+{
+  const union unaligned *up = p;
+  if (unlikely (other_byte_order))
+    return (int64_t) bswap_64 (up->u8);
+  return up->s8;
+}
+
+#endif	/* allow unaligned */
+
+
+#define read_2ubyte_unaligned_inc(Dbg, Addr) \
+  ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr);			      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);		      \
+     t_; })
+#define read_2sbyte_unaligned_inc(Dbg, Addr) \
+  ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr);			      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);		      \
+     t_; })
+
+#define read_4ubyte_unaligned_inc(Dbg, Addr) \
+  ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr);			      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);		      \
+     t_; })
+#define read_4sbyte_unaligned_inc(Dbg, Addr) \
+  ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr);			      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);		      \
+     t_; })
+
+#define read_8ubyte_unaligned_inc(Dbg, Addr) \
+  ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr);			      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);		      \
+     t_; })
+#define read_8sbyte_unaligned_inc(Dbg, Addr) \
+  ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr);			      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);		      \
+     t_; })
+
+
+#define read_addr_unaligned_inc(Nbytes, Dbg, Addr)			\
+  (assert ((Nbytes) == 4 || (Nbytes) == 8),				\
+    ((Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr)		\
+     : read_8ubyte_unaligned_inc (Dbg, Addr)))
+
+#endif	/* memory-access.h */