summaryrefslogtreecommitdiffstats
path: root/src/libdwfl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdwfl')
-rwxr-xr-xsrc/libdwfl/Android.mk116
-rw-r--r--src/libdwfl/ChangeLog1418
-rw-r--r--src/libdwfl/Makefile.am99
-rw-r--r--src/libdwfl/Makefile.in680
-rw-r--r--src/libdwfl/argp-std.c334
-rw-r--r--src/libdwfl/bzip2.c4
-rw-r--r--src/libdwfl/core-file.c484
-rw-r--r--src/libdwfl/cu.c324
-rw-r--r--src/libdwfl/derelocate.c411
-rw-r--r--src/libdwfl/dwfl_addrdie.c57
-rw-r--r--src/libdwfl/dwfl_addrdwarf.c58
-rw-r--r--src/libdwfl/dwfl_addrmodule.c59
-rw-r--r--src/libdwfl/dwfl_begin.c72
-rw-r--r--src/libdwfl/dwfl_build_id_find_debuginfo.c98
-rw-r--r--src/libdwfl/dwfl_build_id_find_elf.c180
-rw-r--r--src/libdwfl/dwfl_cumodule.c57
-rw-r--r--src/libdwfl/dwfl_dwarf_line.c64
-rw-r--r--src/libdwfl/dwfl_end.c71
-rw-r--r--src/libdwfl/dwfl_error.c189
-rw-r--r--src/libdwfl/dwfl_getdwarf.c80
-rw-r--r--src/libdwfl/dwfl_getmodules.c113
-rw-r--r--src/libdwfl/dwfl_getsrc.c57
-rw-r--r--src/libdwfl/dwfl_getsrclines.c69
-rw-r--r--src/libdwfl/dwfl_line_comp_dir.c64
-rw-r--r--src/libdwfl/dwfl_linecu.c62
-rw-r--r--src/libdwfl/dwfl_lineinfo.c76
-rw-r--r--src/libdwfl/dwfl_linemodule.c59
-rw-r--r--src/libdwfl/dwfl_module.c226
-rw-r--r--src/libdwfl/dwfl_module_addrdie.c66
-rw-r--r--src/libdwfl/dwfl_module_addrname.c57
-rw-r--r--src/libdwfl/dwfl_module_addrsym.c200
-rw-r--r--src/libdwfl/dwfl_module_build_id.c195
-rw-r--r--src/libdwfl/dwfl_module_dwarf_cfi.c92
-rw-r--r--src/libdwfl/dwfl_module_eh_cfi.c78
-rw-r--r--src/libdwfl/dwfl_module_getdwarf.c1093
-rw-r--r--src/libdwfl/dwfl_module_getelf.c88
-rw-r--r--src/libdwfl/dwfl_module_getsrc.c99
-rw-r--r--src/libdwfl/dwfl_module_getsrc_file.c188
-rw-r--r--src/libdwfl/dwfl_module_getsym.c128
-rw-r--r--src/libdwfl/dwfl_module_info.c82
-rw-r--r--src/libdwfl/dwfl_module_nextcu.c65
-rw-r--r--src/libdwfl/dwfl_module_register_names.c100
-rw-r--r--src/libdwfl/dwfl_module_report_build_id.c101
-rw-r--r--src/libdwfl/dwfl_module_return_value_location.c85
-rw-r--r--src/libdwfl/dwfl_nextcu.c103
-rw-r--r--src/libdwfl/dwfl_onesrcline.c77
-rw-r--r--src/libdwfl/dwfl_report_elf.c306
-rw-r--r--src/libdwfl/dwfl_segment_report_module.c673
-rw-r--r--src/libdwfl/dwfl_validate_address.c82
-rw-r--r--src/libdwfl/dwfl_version.c57
-rw-r--r--src/libdwfl/elf-from-memory.c368
-rw-r--r--src/libdwfl/find-debuginfo.c315
-rw-r--r--src/libdwfl/gzip.c316
-rw-r--r--src/libdwfl/image-header.c122
-rw-r--r--src/libdwfl/libdwfl.h585
-rw-r--r--src/libdwfl/libdwflP.h512
-rw-r--r--src/libdwfl/libdwfl_crc32.c56
-rw-r--r--src/libdwfl/libdwfl_crc32_file.c57
-rw-r--r--src/libdwfl/lines.c73
-rw-r--r--src/libdwfl/link_map.c888
-rw-r--r--src/libdwfl/linux-kernel-modules.c943
-rw-r--r--src/libdwfl/linux-proc-maps.c348
-rw-r--r--src/libdwfl/lzma.c4
-rw-r--r--src/libdwfl/offline.c329
-rw-r--r--src/libdwfl/open.c203
-rw-r--r--src/libdwfl/relocate.c655
-rw-r--r--src/libdwfl/segment.c350
67 files changed, 15720 insertions, 0 deletions
diff --git a/src/libdwfl/Android.mk b/src/libdwfl/Android.mk
new file mode 100755
index 00000000..dc6a14ad
--- /dev/null
+++ b/src/libdwfl/Android.mk
@@ -0,0 +1,116 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+LIBDWFL_SRC_FILES := \
+ dwfl_addrdwarf.c \
+ dwfl_addrmodule.c \
+ dwfl_begin.c \
+ dwfl_build_id_find_elf.c \
+ dwfl_build_id_find_debuginfo.c \
+ dwfl_end.c \
+ dwfl_error.c \
+ dwfl_module.c \
+ dwfl_module_addrdie.c \
+ dwfl_module_addrsym.c \
+ dwfl_module_build_id.c \
+ dwfl_report_elf.c \
+ dwfl_module_getdwarf.c \
+ dwfl_module_getsym.c \
+ dwfl_module_report_build_id.c \
+ find-debuginfo.c \
+ image-header.c \
+ libdwfl_crc32.c \
+ libdwfl_crc32_file.c \
+ linux-kernel-modules.c \
+ offline.c \
+ open.c \
+ relocate.c \
+ segment.c \
+
+ifeq ($(HOST_OS),linux)
+
+#
+# host libdwfl
+#
+
+include $(CLEAR_VARS)
+
+# Clang has no nested functions.
+LOCAL_CLANG := false
+
+LOCAL_SRC_FILES := $(LIBDWFL_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/.. \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../libdwfl \
+ $(LOCAL_PATH)/../libebl \
+ $(LOCAL_PATH)/../libdw \
+ $(LOCAL_PATH)/../libelf
+
+LOCAL_CFLAGS += -DHAVE_CONFIG_H -std=gnu99 -D_GNU_SOURCE
+
+# to suppress the "pointer of type ‘void *’ used in arithmetic" warning
+LOCAL_CFLAGS += -Wno-pointer-arith
+
+# Asserts are not compiled, so some debug variables appear unused. Rather than
+# fix, we prefer to turn off the warning locally.
+LOCAL_CFLAGS += -Wno-unused-but-set-variable
+
+LOCAL_MODULE:= libdwfl
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+endif # linux
+
+#
+# target libdwfl
+#
+
+include $(CLEAR_VARS)
+
+# Clang has no nested functions.
+LOCAL_CLANG := false
+
+LOCAL_SRC_FILES := $(LIBDWFL_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/.. \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../libdwfl \
+ $(LOCAL_PATH)/../libebl \
+ $(LOCAL_PATH)/../libdw \
+ $(LOCAL_PATH)/../libelf
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../bionic-fixup
+
+LOCAL_CFLAGS += -include $(LOCAL_PATH)/../bionic-fixup/AndroidFixup.h
+
+LOCAL_CFLAGS += -DHAVE_CONFIG_H -std=gnu99 -Werror
+
+# to suppress the "pointer of type ‘void *’ used in arithmetic" warning
+LOCAL_CFLAGS += -Wno-pointer-arith
+
+# See above.
+LOCAL_CFLAGS += -Wno-unused-but-set-variable
+
+LOCAL_MODULE:= libdwfl
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/libdwfl/ChangeLog b/src/libdwfl/ChangeLog
new file mode 100644
index 00000000..87a05550
--- /dev/null
+++ b/src/libdwfl/ChangeLog
@@ -0,0 +1,1418 @@
+2011-12-02 Roland McGrath <roland@hack.frob.com>
+
+ * elf-from-memory.c (elf_from_remote_memory): Fix ELFCLASS64 case
+ to use elf64_xlatetom and PHDRS.p64.
+ Reported by Serge Pavlov <serge.pavlov.at.gnu@gmail.com>.
+
+2011-11-31 Mark Wielaard <mjw@redhat.com>
+
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): First search all
+ global symbols. Then only when that doesn't provide a match search
+ all local symbols too.
+ * dwfl_module_getdwarf.c (load_symtab): Take first_global int arg
+ and fill it in.
+ (find_symtab): Initialize mod->first_global and pass it to load_symtab.
+ * libdwfl/libdwflP.h (Dwfl_Module): Add first_global field.
+
+2011-11-31 Mark Wielaard <mjw@redhat.com>
+
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Only update
+ sizeless_sym if needed and closer to desired addr.
+
+2011-10-20 Mark Wielaard <mjw@redhat.com>
+
+ * derelocate.c (cache_sections): Intern mod->reloc_info check.
+ (dwfl_module_relocations): Don't check mod->reloc_info.
+ (dwfl_module_relocation_info): Likewise.
+ (find_section): Likewise.
+
+2011-07-09 Roland McGrath <roland@hack.frob.com>
+
+ * image-header.c (LE32): Macro removed (now in lib/system.h).
+
+2011-04-11 Mark Wielaard <mjw@redhat.com>
+
+ * linux-kernel-modules.c (vmlinux_suffixes): Guard definition
+ by check for zlib, bzlib or lzma defines to check it isn't empty.
+ (try_kernel_name): Use same guard for use of vmlinux_suffixes.
+
+2011-03-08 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (open_elf): Clear errno before CBFAIL.
+ Reported by Kurt Roeckx <kurt@roeckx.be>.
+
+2011-02-11 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (try_kernel_name): Try .gz, .bz2, .xz
+ suffixes if corresponding decompression support is enabled.
+
+2011-02-01 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (find_prelink_address_sync): Use the
+ section-end address as the synchronization point, rather than sh_addr.
+
+ * dwfl_module_getdwarf.c (find_prelink_address_sync): Discover
+ PT_INTERP p_vaddr separately from main phdrs and undo phdrs.
+
+ * dwfl_module_getdwarf.c (find_prelink_address_sync): Fix pasto in
+ last change, so we recognize PT_INTERP in ELFCLASS64 correctly.
+
+2011-01-11 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (open_elf): Remove section-based
+ address_sync fixup from here.
+ (find_prelink_address_sync): New function.
+ (find_debuginfo): Call it.
+ * libdwflP.h (DWFL_ERRORS): Add BAD_PRELINK error.
+
+2011-01-04 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (open_elf): Enhance address_sync calculation
+ logic to consider section addresses, the better to survive all the
+ possible prelink machinations.
+ * libdwflP.h (struct dwfl_file): Comment change.
+
+2010-11-30 Roland McGrath <roland@redhat.com>
+
+ * derelocate.c (dwfl_module_relocations): Remove over-eager assert.
+
+2010-11-12 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (struct Dwfl_Module): New member main_bias.
+ (dwfl_adjusted_address, dwfl_deadjust_address): Use it.
+ * dwfl_module_getdwarf.c (__libdwfl_getelf): Initialize it.
+
+ * libdwflP.h (dwfl_deadjust_address): New function.
+ (dwfl_deadjust_dwarf_addr, dwfl_deadjust_st_value): New functions.
+ * cu.c (addrarange): Use dwfl_deadjust_dwarf_addr.
+ * dwfl_module_addrsym.c: Use dwfl_deadjust_st_value.
+
+2010-11-11 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (struct dwfl_file): Remove bias member.
+ Add vaddr and address_sync members instead.
+ (dwfl_adjusted_address): Calculate using vaddr.
+ (dwfl_adjusted_dwarf_addr): Calculate using address_sync and call that.
+ (dwfl_adjusted_st_value): Use one of those calls.
+ * dwfl_module_getdwarf.c (open_elf): Initialize vaddr and address_sync.
+ * dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise.
+ * derelocate.c (dwfl_module_relocations): Update ET_EXEC assertions.
+ * link_map.c (consider_executable): Adjust only MOD->low_addr for
+ detected PIE bias change.
+
+ * libdwflP.h (dwfl_adjusted_dwarf_addr): New function.
+ * dwfl_module_info.c: Use it.
+ * cu.c (addrarange): Likewise.
+ * dwfl_dwarf_line.c: Likewise.
+ * dwfl_module_dwarf_cfi.c: Likewise.
+ * dwfl_lineinfo.c: Likewise.
+ * dwfl_nextcu.c: Likewise.
+ * dwfl_module_getdwarf.c (dwfl_module_getdwarf): Likewise.
+
+ * libdwflP.h (dwfl_adjusted_st_value): New function.
+ * relocate.c (resolve_symbol): Use it.
+ * dwfl_module_getsym.c: Likewise.
+ * dwfl_module_addrsym.c: Likewise.
+ * dwfl_module_info.c: Likewise.
+
+ * libdwflP.h (dwfl_adjusted_address): New function.
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Use it.
+ * relocate.c (__libdwfl_relocate_value): Likewise.
+ * derelocate.c (cache_sections): Likewise.
+ (dwfl_module_address_section): Likewise.
+ * dwfl_module_getelf.c: Likewise.
+ * dwfl_module_eh_cfi.c: Likewise.
+ * link_map.c (consider_executable): Likewise.
+
+2010-08-24 Roland McGrath <roland@redhat.com>
+
+ * dwfl_dwarf_line.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+
+2010-08-18 Roland McGrath <roland@redhat.com>
+
+ * link_map.c (report_r_debug): Use found name if we have no name,
+ even if we already have an Elf handle.
+
+2010-06-30 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_find_elf): Don't be
+ confused by -1 return from dwfl_build_id_find_elf after it opened
+ the Elf handle.
+ * find-debuginfo.c (dwfl_standard_find_debuginfo): Likewise for
+ dwfl_build_id_find_debuginfo.
+
+2010-06-16 Roland McGrath <roland@redhat.com>
+
+ * cu.c (cudie_offset): Use DIE_OFFSET_FROM_CU_OFFSET macro.
+
+2010-06-14 Roland McGrath <roland@redhat.com>
+
+ * find-debuginfo.c (try_open): Take new arg MAIN_STAT. Compare
+ candidate file to that st_dev/st_ino and pretend it didn't exist
+ if they match.
+ (find_debuginfo_in_path): Update caller, pass main file's info.
+
+2010-05-20 Roland McGrath <roland@redhat.com>
+
+ * linux-proc-maps.c (find_sysinfo_ehdr): Renamed to ...
+ (grovel_auxv): ... this. Take DWFL argument.
+ (dwfl_linux_proc_report): Update caller.
+
+ * dwfl_module_getdwarf.c (open_elf): Calculate alignment for bias
+ based on dwfl->segment_align or manifest alignment of MOD->low_addr.
+
+2010-05-19 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (intuit_kernel_bounds): Rewritten.
+
+2010-05-06 Roland McGrath <roland@redhat.com>
+
+ * segment.c (insert): Clear inserted elements of DWFL->lookup_module.
+
+ * libdwflP.h (DWFL_ERRORS): Add WRONG_ID_ELF.
+ * dwfl_build_id_find_elf.c: Set MOD->main.valid when there is a build
+ ID but we didn't find a file.
+ * dwfl_module_getdwarf.c (__libdwfl_getelf): When that's set, check
+ and refuse any fallback file-by-name if it lacks the matching ID.
+
+ * dwfl_error.c (dwfl_errno): Add INTDEF.
+ * libdwflP.h: Add INTDECL.
+
+ * dwfl_module_getdwarf.c (open_elf): Do elf_end and clear FILE->elf in
+ failure cases.
+
+2010-05-04 Roland McGrath <roland@redhat.com>
+
+ * dwfl_segment_report_module.c: Use "[pie]" rather than "[dso]" for an
+ ET_DYN that has a DT_DEBUG.
+
+ * dwfl_segment_report_module.c: Fix jump-start of NDX-finding loop.
+
+ * segment.c (insert): Fix moving of values following insertion.
+ (reify_segments): Fix up MOD->segment backpointer indices after
+ later insertions in the main loop invalidate them.
+
+ * link_map.c (dwfl_link_map_report): Detect bias of embedded phdrs and
+ apply it to PT_DYNAMIC p_vaddr so we handle a PIE correctly.
+
+ * core-file.c (dwfl_core_file_report): Return any nonzero count of
+ modules reported, even if link_map grovelling failed and only sniffing
+ found anything.
+
+2010-04-26 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (relocate_section): Treat R_*_NONE reloc as no reloc.
+ Works around probably-wrong ld -r behavior for case of a DWARF address
+ constant that refers to a discarded SHF_ALLOC section.
+
+2010-04-14 Roland McGrath <roland@redhat.com>
+
+ * link_map.c (report_r_debug): Limit iterations on the l_next chain to
+ an upper bound on sane possible number of elements.
+
+2010-03-11 Roland McGrath <roland@redhat.com>
+
+ * link_map.c (auxv_format_probe): Fix scanning loop, so we really scan
+ the second half for 32-bit matches.
+
+2010-03-10 Roland McGrath <roland@redhat.com>
+
+ * core-file.c (dwfl_core_file_report): Punt EHDR argument.
+ * argp-std.c (parse_opt): Update caller.
+ * libdwfl.h: Declare dwfl_core_file_report.
+ * libdwflP.h: Don't.
+
+2010-02-17 Roland McGrath <roland@redhat.com>
+
+ * dwfl_segment_report_module.c (addr_segndx): Take new flag argument.
+ If set, find the first index not below ADDR.
+ (dwfl_segment_report_module): Update callers.
+ Pass true when calculating return value.
+
+2010-02-15 Roland McGrath <roland@redhat.com>
+
+ * Makefile.am: Use config/eu.am for common stuff.
+
+ * find-debuginfo.c (find_debuginfo_in_path): Fix uninitialized
+ variable in failure path.
+
+2010-02-02 Mark Wielaard <mjw@redhat.com>
+
+ * dwfl_module_dwarf_cfi.c (dwfl_module_dwarf_cfi): Always set bias.
+ * dwfl_module_eh_cfi.c (dwfl_module_eh_cfi): Likewise
+
+2010-01-07 Roland McGrath <roland@redhat.com>
+
+ * core-file.c (dwfl_core_file_report): Use elf_getphdrnum.
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Likewise.
+ * dwfl_module_getdwarf.c (open_elf, find_dynsym): Likewise.
+ * dwfl_report_elf.c (__libdwfl_report_elf): Likewise.
+
+2010-01-06 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (relocate_getsym): For SHN_COMMON, zero st_value.
+ (relocate_section): Let unresolved SHN_COMMON symbol stay 0.
+
+2009-11-16 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (relocate_section): Skip SHT_NOBITS or empty target scn.
+
+2009-11-12 Petr Machata <pmachata@redhat.com>
+
+ * core-file.c (dwfl_elf_phdr_memory_callback): Only load ahead if
+ the chunk is both offset-contiguous and vaddr-contiguous.
+
+2009-11-05 Roland McGrath <roland@redhat.com>
+
+ * link_map.c (report_r_debug): Skip entries with l_ld==0.
+ Use dwfl_addrmodule for l_ld lookup, don't bail on lookup failure.
+
+2009-09-04 Roland McGrath <roland@redhat.com>
+
+ * image-header.c (__libdw_image_header): Fix tranposed comparison.
+
+2009-08-27 Roland McGrath <roland@redhat.com>
+
+ * image-header.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwflP.h: Declare __libdw_image_header.
+ * open.c (decompress): Don't consume ELF on failure.
+ (what_kind): New function, broken out of ...
+ (__libdw_open_file): ... here. Call it.
+ If it fails, try __libdw_image_header and then try what_kind again.
+
+ * gzip.c (unzip): Reuse *WHOLE as first INPUT_BUFFER,
+ leave it behind for next decompressor.
+ * open.c (decompress): Free BUFFER on failure.
+
+2009-08-26 Roland McGrath <roland@redhat.com>
+
+ * gzip.c (find_zImage_payload): New function, broken out of ...
+ (mapped_zImage): ... here. Call it.
+ (find_zImage_payload) [LZMA]: Match LZMA-compressed kernels with
+ stupid method of just trying the decoder.
+
+ * open.c [USE_LZMA]: Try __libdw_unlzma.
+ * libdwflP.h: Declare it.
+ (DWFL_ERRORS): Add DWFL_E_LZMA.
+ * gzip.c [LZMA]: Implement liblzma version for XZ file format.
+ * lzma.c: New file.
+ * Makefile.am [LZMA] (libdwfl_a_SOURCES): Add it.
+
+ * gzip.c (mapped_zImage): Limit scan to 32kb.
+ Make this unconditional, support bzip2 kernel images too.
+ (unzip): Use direct inflate method for non-mmap case too.
+ Only zlib uses the stream method.
+
+2009-08-09 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_build_id.c: Use new macros for versioned definitions.
+
+2009-07-08 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_dwarf_cfi.c: New file.
+ * dwfl_module_eh_cfi.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add them.
+ * libdwflP.h (struct Dwfl_Module): New members `dwarf_cfi', `eh_cfi.
+ Add INTDECL for dwfl_module_eh_cfi, dwfl_module_dwarf_cfi.
+
+2009-07-08 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (struct Dwfl_Module): Reorder members to pack better.
+
+2009-06-18 Mark Wielaard <mjw@redhat.com>
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Return NULL on overlap.
+
+2009-06-13 Ulrich Drepper <drepper@redhat.com>
+
+ * derelocate.c: Don't use deprecated libelf functions.
+ * dwfl_module_getdwarf.c: Likewise.
+ * relocate.c: Likewise.
+
+2009-04-23 Ulrich Drepper <drepper@redhat.com>
+
+ * dwfl_module_build_id.c: Define versioned symbols only if SHARED is
+ defined. Otherwise just define the latest version.
+
+2009-04-22 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (resolve_symbol): Apply correct bias to st_value found in
+ a non-ET_REL module.
+
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Fix last change to
+ adjust properly for non-ET_REL.
+
+2009-04-21 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getsym.c: Apply non-ET_REL bias only if SHF_ALLOC.
+
+ * relocate.c (__libdwfl_relocate_value): Assert that MOD is ET_REL.
+ * derelocate.c (cache_sections): Call __libdwfl_relocate_value only
+ for ET_REL.
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Likewise.
+
+2009-04-20 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (__libdwfl_getelf): Add internal_function.
+
+2009-04-19 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (find_file): Renamed to ...
+ (__libdwfl_getelf): ... this. Make it global.
+ (find_symtab, find_dw): Update callers.
+ (dwfl_module_getelf): Functions moved ...
+ * dwfl_module_getelf.c: ... here, new file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwflP.h: Declare __libdwfl_getelf.
+
+2009-04-14 Roland McGrath <roland@redhat.com>
+
+ * dwfl_segment_report_module.c: Handle DT_STRTAB value being either
+ absolute (already adjusted in place) or needing load bias adjustment.
+
+ * core-file.c (dwfl_elf_phdr_memory_callback): Fix return value for
+ gelf_getphdr failure. Fix file size limit checks.
+
+ * dwfl_segment_report_module.c: Fix underflow in DYNSTRSZ check.
+
+2009-04-08 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getsym.c: Don't adjust for bias again after
+ __libdwfl_relocate_value.
+
+ * relocate.c (__libdwfl_relocate_value): Don't adjust a value from
+ a non-SHF_ALLOC section.
+ (relocate_getsym): Test st_shndx for SHN_* values, not *SHNDX.
+ * dwfl_module_getsym.c (dwfl_module_getsym): Likewise.
+
+2009-03-09 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Move SHSTRNDX
+ variable to outer scope, so we cache it for the loop.
+
+ * relocate.c (__libdwfl_relocate_value): Add MOD->main.bias to sh_addr.
+
+2009-02-12 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Use
+ __libdwfl_relocate_value to find correct sh_addr value.
+
+2009-02-10 Roland McGrath <roland@redhat.com>
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Take new arg SANITY.
+ If false, don't fail for NO_PHDR.
+ (dwfl_report_elf): Update caller.
+ * libdwflP.h: Update decl.
+ * offline.c (process_elf): Call it with false, so we don't refuse
+ dubiously-formed objects here.
+
+ * link_map.c (consider_executable): Don't assert dwfl_addrsegment
+ finds our module. We shouldn't crash when we confuse some guesses.
+
+2009-02-10 Ulrich Drepper <drepper@redhat.com>
+
+ * open.c (decompress): Avoid crash with empty input file.
+
+2009-01-27 Roland McGrath <roland@redhat.com>
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Ignore trailing PT_LOAD
+ with zero vaddr and memsz.
+
+2009-01-22 Roland McGrath <roland@redhat.com>
+
+ * open.c (decompress): Move BUFFER, SIZE decls outside #if.
+
+ * dwfl_segment_report_module.c (addr_segndx): Remove bogus adjustments
+ after address-matching loop.
+
+ * segment.c (lookup): Fix fencepost in checking for HINT match.
+
+2009-01-14 Roland McGrath <roland@redhat.com>
+
+ * gzip.c [!BZLIB] (mapped_zImage): New function.
+ (unzip) [!BZLIB]: Grok Linux kernel zImage format.
+
+2009-01-10 Ulrich Drepper <drepper@redhat.com>
+
+ * dwfl_error.c: Always use __thread. Remove all !USE_TLS code.
+
+2009-01-08 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_offline):
+ Skip subdirectory named "source".
+ (dwfl_linux_kernel_find_elf): Likewise.
+
+2009-01-06 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (check_suffix): New function.
+ Match ".ko", ".ko.gz", and ".ko.bz2" suffixes.
+ (dwfl_linux_kernel_report_offline): Use it.
+ (dwfl_linux_kernel_find_elf): Likewise.
+
+2009-01-05 Roland McGrath <roland@redhat.com>
+
+ * argp-std.c (parse_opt): Use __libdw_open_file for core file.
+ * dwfl_build_id_find_debuginfo.c: Use it to open the file.
+ * dwfl_build_id_find_elf.c: Likewise.
+ * dwfl_module_getdwarf.c (open_elf): Likewise.
+ * dwfl_report_elf.c: Likewise.
+ * find-debuginfo.c (validate): Likewise.
+ * offline.c (__libdwfl_report_offline): Likewise.
+
+ * libdwflP.h: Declare __libdw_open_file.
+ * open.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+
+ * gzip.c: New file.
+ * Makefile.am [ZLIB] (libdwfl_a_SOURCES): Add it.
+ * bzip2.c: New file.
+ * Makefile.am [BZLIB] (libdwfl_a_SOURCES): Add it.
+ * libdwflP.h: Declare __libdw_gunzip, __libdw_bunzip2.
+
+2008-12-16 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_build_id.c (dwfl_module_build_id): Define with alias and
+ symver magic to bind to ELFUTILS_0.138.
+ (_BUG_COMPAT_dwfl_module_build_id): New function, bug compatible
+ wrapper for ELFUTILS_0.130 version set.
+
+2008-12-18 Roland McGrath <roland@redhat.com>
+
+ * derelocate.c (dwfl_module_relocate_address): Fix last fix: ET_DYN
+ addresses are taken as relative to MOD->low_addr.
+
+2008-12-15 Roland McGrath <roland@redhat.com>
+
+ * derelocate.c (dwfl_module_relocate_address): Apply main.bias, not
+ debug.bias.
+
+2008-12-11 Roland McGrath <roland@redhat.com>
+
+ * offline.c (process_archive): Don't call elf_end and close if
+ returning NULL. Check first elf_begin call and set error code
+ specially for empty archive.
+ Fixes RHBZ#465878.
+
+2008-12-02 Roland McGrath <roland@redhat.com>
+
+ * dwfl_getmodules.c (dwfl_getmodules): Typo fix in last change.
+
+2008-11-26 Roland McGrath <roland@redhat.com>
+
+ * dwfl_getmodules.c (dwfl_getmodules): Encode iteration style in
+ return value, and interpret encoded OFFSET argument.
+
+2008-10-07 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_build_id.c (check_notes): Fix typo in vaddr calculation.
+
+2008-09-29 Roland McGrath <roland@redhat.com>
+
+ * segment.c (insert): Must realloc DWFL->lookup_module here too.
+ (dwfl_report_segment): Clear DWFL->lookup_module before insert calls.
+
+2008-08-28 Roland McGrath <roland@redhat.com>
+
+ * segment.c (reify_segments): Fix last change.
+
+2008-08-27 Roland McGrath <roland@redhat.com>
+
+ * linux-proc-maps.c (read_proc_memory): Return 0 for EINVAL or EPERM
+ failure from pread64.
+
+2008-08-26 Roland McGrath <roland@redhat.com>
+
+ * segment.c (reify_segments): Insert a trailing segment for a module
+ end that is above the highest current segment.
+
+2008-08-25 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (open_elf): Extract elf_errno () for
+ coded return value, not plain DWFL_E_LIBELF. Return DWFL_E_BADELF
+ if FILE->elf is not ELF_K_ELF.
+
+ * dwfl_segment_report_module.c: Add a cast.
+
+2008-08-21 Denys Vlasenko <dvlasenk@redhat.com>
+
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Improve logic
+ which decides which symbol is "closest" to a given address.
+
+2008-08-15 Roland McGrath <roland@redhat.com>
+
+ * argp-std.c (offline_callbacks): Use dwfl_build_id_find_elf.
+ (options, parse_opt): Handle --core.
+
+ * core-file.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwflP.h (dwfl_core_file_report): Declare it.
+
+ * link_map.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwflP.h (dwfl_link_map_report): Declare it.
+
+ * libdwflP.h (MIN, MAX): New macros.
+ (Dwfl_Memory_Callback): New typedef.
+ (Dwfl_Module_Callback): New typedef.
+ (dwfl_segment_report_module): Declare it.
+ * dwfl_segment_report_module.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+
+ * derelocate.c (dwfl_module_address_section): Add INTDEF.
+ * libdwflP.h: Add INTDECL.
+
+ * segment.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_addrsegment, dwfl_report_segment.
+ * libdwflP.h (struct Dwfl): New members lookup_elts, lookup_alloc,
+ lookup_addr, lookup_module, lookup_segndx, replace removed members
+ modules, nmodules.
+ (struct Dwfl_Module): New member segment.
+ * dwfl_end.c (dwfl_end): Free the new ones. Iterate via modulelist
+ to each free module.
+ * dwfl_module.c (dwfl_report_begin_add): Do nothing.
+ (dwfl_report_begin): Don't call it. Truncate the segment table instead.
+ (dwfl_report_module): Don't touch DWFL->nmodules.
+ (dwfl_report_end): Don't touch DWFL->modules and DWFL->nmodules.
+ (compare_modules): Function removed.
+ * dwfl_getmodules.c: Rewritten.
+ Add INTDEF.
+ * libdwflP.h: Add INTDECLs.
+ * dwfl_getdwarf.c: Rewritten to call dwfl_getmodules.
+ * dwfl_addrmodule.c: Rewritten to just call dwfl_addrsegment.
+
+2008-08-03 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c: Include <fts.h> before <config.h>.
+
+2008-07-17 Roland McGrath <roland@redhat.com>
+
+ * dwfl_build_id_find_elf.c (__libdwfl_open_by_build_id): Set errno to
+ zero if the failure was only ENOENT.
+
+2008-06-03 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Exclude undefined
+ symbols.
+
+2008-05-22 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_module_getdwarf.c (open_elf): Bias of ET_EXEC files is always 0.
+
+2008-05-06 Roland McGrath <roland@frob.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_offline): Use
+ FTS_LOGICAL here too.
+ (dwfl_linux_kernel_find_elf): Likewise.
+
+2008-04-29 Roland McGrath <roland@redhat.com>
+
+ * find-debuginfo.c (dwfl_standard_find_debuginfo): Try path search
+ based on canonicalize_file_name if it differs from the supplied name.
+
+ * linux-kernel-modules.c (check_module_notes): Use FTS_LOGICAL so
+ we accept symlinks.
+
+2008-04-27 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (report_kernel): Fix crash when
+ dwfl_report_elf fails.
+
+2008-04-05 Roland McGrath <roland@redhat.com>
+
+ * linux-proc-maps.c (proc_maps_report): Don't leak LAST_FILE.
+
+ * dwfl_module_getdwarf.c (find_file): Always free build_id_bits.
+ Clear it after freeing.
+ * dwfl_module_report_build_id.c (dwfl_module_report_build_id): Likewise.
+
+2008-03-26 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (load_symtab): Don't return success for
+ SHT_DYNSYM, just set *SYMSCN like the comment says.
+
+ * dwfl_end.c (dwfl_end): Iterate on modulelist chain, not modules array.
+
+ * argp-std.c (parse_opt): On failure, call dwfl_end before argp_failure.
+
+2008-03-19 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getsrc.c: Adjust address for module bias before search.
+
+2008-03-01 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (__libdwfl_seterrno): Remove parameter name from
+ prototype to avoid older compiler's complaint about reuse of the name.
+ (__libdwfl_canon_error): Likewise.
+
+2008-02-19 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (relocate_section): Check for an unhandled relocation
+ type before resolving a reloc's symbol. Lift DWFL_E_BADRELTYPE ->
+ DWFL_E_UNKNOWN_MACHINE check out of loops.
+
+ * dwfl_module_getdwarf.c (load_dw): Skip relocation if
+ DEBUGFILE->relocated is already set.
+
+2008-01-26 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (open_elf): Open FILE->name if it's non-null.
+
+ * dwfl_build_id_find_elf.c (__libdwfl_open_by_build_id): Don't clear
+ incoming *FILE_NAME at the start.
+
+2008-01-08 Roland McGrath <roland@redhat.com>
+
+ * Makefile.am (euinclude): Variable removed.
+ (pkginclude_HEADERS): Set this instead of euinclude_HEADERS.
+
+2007-10-23 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (report_kernel_archive): Reorder the kernel
+ module to appear first.
+
+2007-10-20 Roland McGrath <roland@redhat.com>
+
+ * offline.c (process_archive_member): Take FD argument, pass it down
+ to process_file. Return Elf_Cmd, not bool.
+ Call elf_next here, always before elf_end.
+ (process_archive): Update caller. Don't close FD here unless there
+ are no member refs.
+
+ * dwfl_module.c (free_file): Close fd only when elf_end returns zero.
+
+ * libdwflP.h (struct dwfl_file): New bool member `relocated'.
+ * dwfl_module_getdwarf.c (dwfl_module_getelf): For ET_REL, apply
+ partial relocation to one or both files.
+ (dwfl_module_getdwarf): For ET_REL, make sure extra sections'
+ relocations have been applied to the debug file if dwfl_module_getelf
+ has been used before.
+
+ * relocate.c (resolve_symbol): New function.
+ (relocate_section): Call it.
+
+ * relocate.c (relocate_getsym): Handle null MOD->symfile.
+ (relocate_section): Take new bool arg, PARTIAL. If true,
+ no error for BADRELTYPE/RELUNDEF, instead just skip them
+ and leave only those skipped relocs behind the reloc section.
+ (__libdwfl_relocate_section): Take new arg, pass it down.
+ (__libdwfl_relocate): Take new bool arg, DEBUG. If false,
+ do partial relocation on all sections.
+ * dwfl_module_getdwarf.c (load_dw): Update caller.
+ * libdwflP.h: Update decls.
+ * derelocate.c (dwfl_module_address_section): Pass new argument
+ to __libdwfl_relocate_section, true.
+
+ * derelocate.c (cache_sections): Don't cache reloc sections when
+ section_address callback is null.
+
+2007-10-19 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (relocate_section): Fix fencepost error in r_offset check.
+
+ * derelocate.c (struct dwfl_relocation): Add member `relocs'.
+ (struct secref): Likewise.
+ (cache_sections): Cache the relocation section referring to each
+ section we cache, if any.
+ (dwfl_module_address_section): Use __libdwfl_relocate_section as
+ necessary.
+
+ * relocate.c (struct reloc_symtab_cache): New type.
+ (relocate_getsym): Use it instead of four arguments.
+ (__libdwfl_relocate): Update caller.
+ (relocate_section): New function, broken out of ...
+ (__libdwfl_relocate): ... here.
+ (__libdwfl_relocate_section): New function.
+ * libdwflP.h: Declare it.
+
+2007-10-17 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getsym.c (dwfl_module_getsym): Apply MOD->symfile->bias
+ to relocated st_value.
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Align initial BASE for
+ ET_REL to 0x100.
+
+2007-10-16 Roland McGrath <roland@redhat.com>
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Readjust BASE when a later
+ section has larger alignment requirements not met by the original BASE,
+ rather than padding more between sections.
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Fix bias calculation.
+
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Apply module bias
+ to sh_addr value.
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Don't be confused by BASE
+ at zero in ET_REL case. Adjust BASE to necessary alignment.
+
+ * dwfl_module_build_id.c (check_notes): Take -1, not 0, as stub value
+ for DATA_VADDR.
+ (__libdwfl_find_build_id): Update caller.
+
+ * relocate.c (__libdwfl_relocate_value): Don't use sh_offset.
+ * dwfl_report_elf.c (__libdwfl_report_elf): Likewise.
+ * offline.c (dwfl_offline_section_address): Bail early if there is
+ separate debug file.
+
+ * relocate.c (__libdwfl_relocate): Don't return DWFL_E_NO_DWARF.
+
+2007-10-09 Roland McGrath <roland@redhat.com>
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Clear SHDR->sh_offset when
+ caching SHDR->sh_addr = 0.
+ * offline.c (dwfl_offline_section_address): Never called for sh_addr
+ really at 0, don't check for it. Use MOD->debug directly, not symfile.
+
+ * dwfl_module_getdwarf.c (load_symtab): Return success properly when
+ we've found SHT_SYMTAB.
+
+ * relocate.c (relocate_getsym): New function.
+ (__libdwfl_relocate): Use it.
+ (__libdwfl_relocate_value): Take new Elf * argument. Make SYMSHSTRNDX
+ be a pointer instead of value; cache getshstrndx result there.
+ * libdwflP.h: Update decl.
+ * derelocate.c (cache_sections): Update caller.
+ Always work on the main file, not the symfile.
+ (dwfl_module_address_section): Likewise.
+ * dwfl_module_getsym.c (dwfl_module_getsym): Update caller.
+
+2007-10-07 Roland McGrath <roland@redhat.com>
+
+ * offline.c (process_archive): Initialize MOD.
+
+ * linux-kernel-modules.c (get_release): New function, broken out of ...
+ (report_kernel): ... here. Call it.
+ (try_kernel_name): Take new arg TRY_DEBUG, only try ".debug" if set.
+ (find_kernel_elf): Update caller.
+ (report_kernel_archive): New function.
+ (dwfl_linux_kernel_report_offline): Call it.
+
+ * offline.c (process_file): Take new arg PREDICATE, pass it down.
+ (process_archive): Likewise.
+ (process_archive_member): Likewise. When nonnull, let the predicate
+ decide whether to use this member.
+ (__libdwfl_report_offline): New function, broken out of ...
+ (dwfl_report_offline): ... here. Call it.
+ * libdwflP.h: Declare it.
+
+ * offline.c (process_archive, process_archive_member): New functions.
+ (process_elf, process_file): New functions, broken out of ...
+ (dwfl_report_offline): ... here. Call process_file, which recurses on
+ ELF_K_AR files.
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): New, broken out of ...
+ (dwfl_report_elf): ... here. Call it.
+ * libdwflP.h: Declare it.
+
+2007-10-06 Roland McGrath <roland@redhat.com>
+
+ * derelocate.c (dwfl_module_relocations): Don't call
+ dwfl_module_getdwarf.
+
+ * derelocate.c (find_section): Use __libdwfl_seterrno, not
+ __libdw_seterrno.
+
+ * relocate.c (__libdwfl_relocate_value): Abuse sh_offset, not
+ SHF_ALLOC, to cache sh_addr resolved to 0.
+
+ * dwfl_report_elf.c (dwfl_report_elf): When an ET_REL file has sh_addr
+ values nonzero already, just use its existing layout.
+
+ * relocate.c (__libdwfl_relocate): Clear size of reloc section in its
+ in-core shdr after applying it.
+
+2007-10-04 Ulrich Drepper <drepper@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_kernel): Fake
+ initialization of notes variable.
+
+2007-10-04 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (intuit_kernel_bounds): Take new arg NOTES,
+ fill in with vaddr of "__start_notes" symbol if found.
+ (check_notes): New function.
+ (check_kernel_notes): New function.
+ (dwfl_linux_kernel_report_kernel): Call it.
+ (check_module_notes): New function.
+ (dwfl_linux_kernel_report_modules): Call it.
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_find_elf):
+ Try dwfl_build_id_find_elf first.
+
+ * linux-kernel-modules.c (report_kernel): Don't leak FD if !REPORT.
+ Set kernel module e_type to ET_DYN.
+
+2007-10-03 Roland McGrath <roland@redhat.com>
+
+ * find-debuginfo.c (validate): New function, broken out of ...
+ (find_debuginfo_in_path): ... here. New function, broken out of ...
+ (dwfl_standard_find_debuginfo): ... here. Call it, after trying
+ dwfl_build_id_find_debuginfo first.
+
+ * dwfl_build_id_find_elf.c: New file.
+ * dwfl_build_id_find_debuginfo.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add them.
+ * libdwfl.h: Declare them.
+ * libdwflP.h: Add INTDECLs.
+
+ * dwfl_module_build_id.c: New file.
+ * dwfl_module_report_build_id.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add them.
+ * libdwfl.h: Declare them.
+ * libdwflP.h (struct Dwfl_Module): New members build_id_bits,
+ build_id_len, build_id_vaddr. Declare __libdwfl_find_build_id.
+ * dwfl_module.c (__libdwfl_module_free): Free MOD->build_id_bits.
+
+ * dwfl_module_getdwarf.c (find_offsets): New function.
+ (find_dynsym): New function, calls that.
+ (find_symtab): Call it.
+
+2007-09-11 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_addrsym.c: Prefer a later global symbol at the same
+ address if its st_size is smaller.
+
+2007-08-13 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_addrsym.c: Add dead initializer for stupid compiler.
+
+2007-08-12 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_offline): Don't use
+ FTS_LOGICAL.
+
+ * elf-from-memory.c (elf_from_remote_memory): Don't reset LOADBASE on
+ a second phdr if it happens to match EHDR_VMA exactly.
+
+2007-08-08 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_addrsym.c: Don't use STT_SECTION, STT_FILE symbols and
+ those with no names. Rewrite best symbol algorithm not to assume a
+ sorted table and to be smarter handling sizeless symbols.
+
+2007-07-16 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module.c (dwfl_report_module): Increment DWFL->nmodules when
+ reviving an existing module.
+
+2007-06-08 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h: Fix #ifndef for config.h to use PACKAGE_NAME.
+
+2007-05-17 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_offline): Look at
+ whole /lib/modules/VERSION tree, not just /lib/modules/VERSION/kernel.
+ (dwfl_linux_kernel_find_elf): Likewise.
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_modules): Use
+ getline and sscanf instead of fscanf.
+
+2007-05-08 Roland McGrath <roland@redhat.com>
+
+ * offline.c (dwfl_offline_section_address): Don't assume section
+ numbers match between stripped and debuginfo files. Instead, assume
+ only that the ordering among SHF_ALLOC sections matches.
+
+ * linux-kernel-modules.c (report_kernel): Change RELEASE argument to
+ pointer to string.
+ (dwfl_linux_kernel_report_offline): Update caller.
+ (dwfl_linux_kernel_report_kernel): Likewise.
+
+2007-04-23 Roland McGrath <roland@redhat.com>
+
+ * argp-std.c (options): Fix group title string.
+
+ * argp-std.c (parse_opt): Handle ARGP_KEY_ERROR, free the Dwfl.
+ Update via STATE->input every time we set STATE->hook, not only at
+ ARGP_KEY_SUCCESS.
+
+ * dwfl_module.c (free_file): Free FILE->name.
+
+2007-04-16 Roland McGrath <roland@redhat.com>
+
+ * derelocate.c (cache_sections): Apply bias to sh_addr.
+ (compare_secrefs): Fix address comparison to avoid signed overflow.
+ (find_section): New function, broken out of ...
+ (dwfl_module_relocate_address): ... here, call it.
+ (check_module): New function, broken out of ...
+ (dwfl_module_relocate_address): ... here, call it.
+ (dwfl_module_address_section): New function.
+ * libdwfl.h: Declare it.
+
+2007-03-26 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module.c (__libdwfl_module_free): Free MOD itself.
+
+2007-03-18 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (find_debuglink): New function, broken out of
+ (find_debuginfo): ... here. Call it.
+ Don't return error for libelf errors finding .gnu_debuglink section.
+
+2007-03-12 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module.c (dwfl_report_begin_add): New function broken out of ...
+ (dwfl_report_begin): ... here. Call it.
+ * libdwfl.h: Declare it.
+ * libdwflP.h: Add INTDECL.
+
+ * elf-from-memory.c (elf_from_remote_memory): Fix 32/64 typo.
+
+ * offline.c: Comment typo fix.
+
+2007-03-04 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (KERNEL_MODNAME): New macro for "kernel".
+ (find_kernel_elf): New function, broken out of ...
+ (report_kernel): ... here. Call it.
+ (dwfl_linux_kernel_find_elf): Use it for module named KERNEL_MODNAME.
+ (intuit_kernel_bounds): New function, grovel /proc/kallsyms to guess
+ virtual address bounds of kernel from symbols rounded to page size.
+ (dwfl_linux_kernel_report_kernel): Use that if it works, before
+ resorting to report_kernel.
+
+ * dwfl_module_getdwarf.c (open_elf): Set MOD->e_type to ET_DYN for an
+ ET_EXEC file with nonzero bias.
+
+ * dwfl_module_addrname.c (dwfl_module_addrname): Just call
+ dwfl_module_addrsym. Guts moved to ...
+ * dwfl_module_addrsym.c: ... here; new file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_module_addrsym.
+ * libdwflP.h: Add INTDECL.
+
+2007-03-03 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module.c (free_file): New function, broken out of ...
+ (__libdwfl_module_free): ... here. In it, close fd after elf_end.
+
+ * dwfl_module_getdwarf.c (open_elf): Close fd and reset to -1
+ on libelf failure.
+
+2007-03-02 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c: Fix bogus error test for asprintf call.
+
+2007-02-02 Roland McGrath <roland@redhat.com>
+
+ * dwfl_addrmodule.c (dwfl_addrmodule): Match a module's high boundary
+ address exactly if it's no other module's low boundary.
+
+ * dwfl_module_addrname.c (dwfl_module_addrname): If no symbol's value
+ and size cover the address, select the closest symbol with st_size==0
+ that lies in the same section.
+
+2007-01-29 Roland McGrath <roland@redhat.com>
+
+ * dwfl_version.c (dwfl_version): Return PACKAGE_VERSION,
+ not PACKAGE_STRING.
+
+2007-01-20 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (__libdwfl_relocate_value): Treat section_address of -1
+ as omitted, not 0.
+ * libdwfl.h (Dwfl_Callbacks): Update comment.
+ * derelocate.c (cache_sections): Don't ignore sh_addr == 0 sections.
+ * linux-kernel-modules.c (dwfl_linux_kernel_module_section_address):
+ For ignored missing section, use -1 instead of 0.
+ * offline.c (dwfl_offline_section_address): Expect a call for 0.
+
+2007-01-19 Roland McGrath <roland@redhat.com>
+
+ * argp-std.c (parse_opt): For -e, reset DWFL->offline_next_address to
+ zero so a lone -e foo.so is shown without address bias.
+
+2007-01-10 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (report_kernel): Check asprintf return value
+ directly instead of via side effect, to silence warn_unused_result.
+ (dwfl_linux_kernel_report_offline): Likewise.
+ (dwfl_linux_kernel_find_elf): Likewise.
+ (dwfl_linux_kernel_module_section_address): Likewise.
+ * find-debuginfo.c (try_open): Likewise.
+ * linux-proc-maps.c (find_sysinfo_ehdr): Likewise.
+ (dwfl_linux_proc_report): Likewise.
+
+ * libdwfl.h (dwfl_begin): Require nonnull argument.
+
+2006-12-27 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module.c (compare_modules): Fix address comparison to avoid
+ signed overflow. Patch by Frank Ch. Eigler <fche@redhat.com>.
+
+2006-10-30 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module.c (dwfl_report_module): Comment typo fix.
+
+2006-09-05 Roland McGrath <roland@redhat.com>
+
+ * derelocate.c (cache_sections): Use alloca instead of variable-sized
+ auto array, in function already using alloca.
+
+2006-08-14 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (try_kernel_name): If the call to
+ dwfl_standard_find_debuginfo produces no results, try it again
+ with NULL as DEBUGLINK_FILE to try *FNAME with .debug suffix.
+
+ * find-debuginfo.c (DEFAULT_DEBUGINFO_PATH): Macro moved ...
+ * libdwflP.h: ... to here.
+ * linux-kernel-modules.c (try_kernel_name): Skip manual open if it
+ repeats the first thing dwfl_standard_find_debuginfo will try.
+
+ * linux-kernel-modules.c (MODULE_SECT_NAME_LEN): New macro.
+ (dwfl_linux_kernel_module_section_address): If a /sys file is missing
+ and the section name is >= MODULE_SECT_NAME_LEN, try truncating the
+ section name.
+
+2006-07-12 Ulrich Drepper <drepper@redhat.com>
+
+ * cu.c: Adjust for internal_function_def removal.
+ * dwfl_error.c: Likewise.
+ * dwfl_module.c: Likewise.
+ * dwfl_module_getdwarf.c: Likewise.
+ * lines.c: Likewise.
+ * relocate.c: Likewise.
+
+2006-07-11 Ulrich Drepper <drepper@redhat.com>
+
+ * dwfl_module.c (compare_modules): Don't return GElf_Sxword value,
+ it can overflow the return value type.
+ Patch by Tim Moore <timoore@redhat.com>.
+
+2006-06-28 Roland McGrath <roland@redhat.com>
+
+ * libdwfl.h: Cosmetic changes.
+
+ * dwfl_line_comp_dir.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_line_comp_dir.
+
+ * dwfl_lineinfo.c (dwfl_lineinfo): Remove stray extern in defn.
+
+ * dwfl_linecu.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_linecu.
+
+ * libdwflP.h (dwfl_linecu_inline): Function renamed from dwfl_linecu.
+ (dwfl_linecu): Define as macro.
+
+ * relocate.c (__libdwfl_relocate): Use dwfl_module_getsym.
+
+ * dwfl_module_getdwarf.c (dwfl_module_getsymtab): New function.
+ (dwfl_module_addrname): Function moved ...
+ * dwfl_module_addrname.c: ... here, new file.
+ * dwfl_module_getsym.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add them.
+ * libdwfl.h: Declare dwfl_module_getsymtab, dwfl_module_getsym.
+ * libdwflP.h: Add INTDECLs.
+
+2006-06-27 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module.c (dwfl_report_end): Whitespace fix.
+
+2006-06-13 Roland McGrath <roland@redhat.com>
+
+ * elf-from-memory.c (elf_from_remote_memory): Fix 32/64 typo.
+ Use __libdwfl_seterrno for elf_memory failure.
+
+2006-05-22 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_return_value_location.c
+ (dwfl_module_return_value_location): Use __libdwfl_module_getebl.
+
+2006-05-27 Ulrich Drepper <drepper@redhat.com>
+
+ * libdwfl.h: Add extern "C".
+
+2006-05-22 Ulrich Drepper <drepper@redhat.com>
+
+ * cu.c (addrarange): Handle files without aranges information.
+
+2006-05-16 Ulrich Drepper <drepper@redhat.com>
+
+ * dwfl_addrmodule.c (dwfl_addrmodule): Also return NULL of
+ ->modules is NULL.
+
+2006-02-26 Roland McGrath <roland@redhat.com>
+
+ * dwfl_version.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_version.
+
+ * offline.c (dwfl_report_offline): Account for dwfl_report_elf having
+ aligned up from DWFL->offline_next_address when checking for overlap.
+
+2005-12-22 Roland McGrath <roland@redhat.com>
+
+ * argp-std.c (parse_opt): Call dwfl_end in failure cases.
+
+ * linux-proc-maps.c (proc_maps_report): New function, broken out of ...
+ (dwfl_linux_proc_report): ... here. Call it.
+ (dwfl_linux_proc_maps_report): New function.
+ * libdwfl.h: Declare it.
+ * libdwflP.h: Add INTDECL.
+ * argp-std.c (options, parse_opt): Grok -M/--linux-process-map.
+
+ * dwfl_nextcu.c (dwfl_nextcu): Don't fail when dwfl_module_getdwarf
+ failed with DWFL_E_NO_DWARF.
+
+2005-11-26 Roland McGrath <roland@redhat.com>
+
+ * dwfl_end.c (dwfl_end): Free the DWFL itself.
+
+2005-11-25 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getdwarf.c (__libdwfl_module_getebl): New function.
+ (load_dw): Use it.
+ * dwfl_module_register_names.c (dwfl_module_register_names): Likewise.
+ * libdwflP.h: Declare it.
+
+ * dwfl_module_register_names.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_module_register_names.
+
+2005-11-21 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_module_section_address):
+ Don't leak malloc'd file name.
+ If a /sys/.../sections file is missing and starts with ".init",
+ try the variant with "_init" too; catches PPC64 kernel braindamage.
+
+2005-11-15 Roland McGrath <roland@redhat.com>
+
+ * libdwfl.h: Comment fixes.
+
+ * dwfl_module_return_value_location.c: Add unlikely for error case.
+
+2005-11-13 Roland McGrath <roland@redhat.com>
+
+ * dwfl_return_value_location.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_module_return_value_location.
+ * libdwflP.h (DWFL_ERRORS): Add DWFL_E_WEIRD_TYPE.
+
+2005-10-20 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (DWFL_ERRORS): New error UNKNOWN_MACHINE.
+ * relocate.c (__libdwfl_relocate): Return DWFL_E_UNKNOWN_MACHINE
+ instead of DWFL_E_BADRELTYPE if ebl_get_elfmachine yields EM_NONE.
+
+2005-10-01 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (report_kernel): Return ENOENT if we fail
+ with errno 0.
+
+2005-09-19 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_report_modules): Use
+ PRIx64 instead of PRIi64, lest addresses with high bits set overflow
+ the signed integer reading; they will just have to be in hexadecimal.
+ (dwfl_linux_kernel_module_section_address): Likewise.
+
+2005-08-28 Ulrich Drepper <drepper@redhat.com>
+
+ * Makefile.am (%.os): Use COMPILE.os.
+ (COMPILE.os): Filter out gconv options.
+
+2005-08-25 Roland McGrath <roland@redhat.com>
+
+ * cu.c (__libdwfl_nextcu): Return success when dwarf_nextcu hits end.
+ * dwfl_nextcu.c (dwfl_nextcu): Skip modules with no dwarf info.
+
+2005-08-24 Roland McGrath <roland@redhat.com>
+
+ * dwfl_lineinfo.c (dwfl_lineinfo): Add bias, don't subtract it.
+
+ * argp-std.c [_MUDFLAP] (__libdwfl_argp_mudflap_options): New function,
+ magic initializer to set -heur-stack-bound option.
+
+2005-08-22 Roland McGrath <roland@redhat.com>
+
+ * dwfl_validate_address.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_validate_address.
+
+ * derelocate.c (dwfl_module_relocate_address): Add INTDEF.
+ * libdwflP.h: Add INTDECL.
+
+ * dwfl_module_getdwarf.c (find_symtab): Use elf_getdata instead of
+ elf_rawdata for symbol-related sections.
+
+ * offline.c (dwfl_report_offline): Move offline_next_address outside
+ module's range, in case it's an ET_EXEC using fixed segment locations.
+ * libdwfl.h: Update comment.
+
+ * dwfl_report_elf.c (dwfl_report_elf): Align BASE to first segment's
+ required alignment.
+
+2005-08-20 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (report_kernel): Take new argument PREDICATE,
+ function to choose whether to report.
+ (dwfl_linux_kernel_report_offline): Likewise.
+ * libdwfl.h: Update decl.
+ * argp-std.c (parse_opt): Update caller.
+
+ * dwfl_getsrclines.c: New file.
+ * dwfl_onesrcline.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add them.
+ * libdwfl.h: Declare dwfl_getsrclines, dwfl_onesrcline.
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_find_elf): Don't leak
+ MODULESDIR[0]. Call fts_close on failure.
+
+ * dwfl_module_getdwarf.c (load_dw): Take dwfl_file * instead of Elf *.
+ Close ET_REL file descriptors after relocation.
+ (find_dw): Update caller.
+ * offline.c (dwfl_report_offline): Get the file into memory and close
+ the file descriptor.
+
+ * dwfl_module_getdwarf.c (find_debuginfo): Do nothing when
+ MOD->debug.elf is already set.
+
+ * find-debuginfo.c (try_open): Use TEMP_FAILURE_RETRY.
+ (dwfl_standard_find_debuginfo): Fail on errors not ENOENT or ENOTDIR.
+
+ * argp-std.c (options, parse_opt): Grok -K/--offline-kernel, use
+ dwfl_linux_kernel_report_offline with offline_callbacks.
+
+ * linux-kernel-modules.c (report_kernel): New function, broken out of
+ ...
+ (dwfl_linux_kernel_report_kernel): ... here. Use it.
+ (dwfl_linux_kernel_report_offline): New function.
+ * libdwfl.h: Declare it.
+ * libdwflP.h: Add INTDECL.
+
+2005-08-19 Roland McGrath <roland@redhat.com>
+
+ Use standard debuginfo search path to look for vmlinux.
+ * find-debuginfo.c (dwfl_standard_find_debuginfo): Don't check CRC if
+ passed zero.
+ * linux-kernel-modules.c (try_kernel_name): New function, broken out
+ of ...
+ (dwfl_linux_kernel_report_kernel): ... here. Use it.
+
+ * argp-std.c (offline_callbacks): New variable.
+ (parse_opt): Use it for -e. Allow multiple -e options.
+
+ * offline.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+ * libdwfl.h: Declare dwfl_offline_section_address, dwfl_report_offline.
+ * libdwflP.h: Add INTDECLs.
+ (OFFLINE_REDZONE): New macro.
+ (struct Dwfl): New member `offline_next_address'.
+ * dwfl_begin.c (dwfl_begin): Initialize it.
+ * dwfl_module.c (dwfl_report_begin): Likewise.
+
+ * dwfl_report_elf.c (dwfl_report_elf): Accept all types. When ET_REL,
+ do a nominal absolute section layout starting at BASE.
+ * libdwfl.h: Update comment.
+
+2005-08-18 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getsrc_file.c (dwfl_module_getsrc_file): Do
+ dwfl_module_getdwarf if necessary.
+
+ * dwfl_report_elf.c (dwfl_report_elf): Permit ET_REL with BASE==0.
+ * libdwfl.h: Update comment.
+
+ * derelocate.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add it.
+
+ * libdwflP.h (struct Dwfl_Module): isrel -> e_type.
+ * dwfl_report_elf.c (dwfl_report_elf): Initialize it.
+ * dwfl_module_getdwarf.c (open_elf): Update initialization.
+ (load_dw, dwfl_module_addrname): Update uses.
+ * relocate.c (__libdwfl_relocate): Likewise.
+
+2005-08-04 Roland McGrath <roland@redhat.com>
+
+ * libdwfl.h (Dwfl_Callbacks.section_address): Take additional
+ arguments SHNDX, SHDR.
+ (dwfl_linux_kernel_module_section_address): Update prototype.
+ * relocate.c (__libdwfl_relocate_value): Update caller.
+ * linux-kernel-modules.c (dwfl_linux_kernel_module_section_address):
+ Take the new arguments.
+
+2005-08-10 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (__libdwfl_relocate): Take argument DEBUGFILE,
+ use it instead of MOD->debug.file.
+ * libdwflP.h: Update decl.
+ * dwfl_module_getdwarf.c (load_dw): Update caller.
+ Fixes bug #165598.
+
+2005-08-09 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h: Include ../libdw/libdwP.h for its INTDECLs.
+ * cu.c: Use INTUSE on dwarf_* calls.
+ * dwfl_error.c: Likewise.
+ * dwfl_module.c: Likewise.
+ * dwfl_module_getdwarf.c: Likewise.
+ * dwfl_module_getsrc_file.c: Likewise.
+ * lines.c: Likewise.
+
+2005-08-07 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (dwfl_linux_kernel_find_elf): When module
+ names contain '_' or '-', look for files named either "foo-bar.ko"
+ or "foo_bar.ko".
+
+2005-07-29 Roland McGrath <roland@redhat.com>
+
+ * loc2c.c: File removed.
+ * loc2c.h: File removed.
+ * loc2c-runtime.h: File removed.
+ * test2.c: File removed.
+ * Makefile.am (EXTRA_DIST): Variable removed.
+ (noinst_HEADERS): Remove loc2c.h from here.
+
+2005-07-28 Ulrich Drepper <drepper@redhat.com>
+
+ * libdwfl.h: Add a few missing extern for function prototypes.
+
+ * libdwfl_crc32.c: New file.
+ * libdwfl_crc32_file.c: New file.
+ * libdwflP.h: Declare the new functions.
+ * Makefile.am (libdwfl_a_SOURCES): Add libdwfl_crc32.c and
+ libdwfl_crc32_file.c.
+ * libdwfl/find-debuginfo.c (check_crc): Use __libdwfl_crc32_file
+ instead of crc32_file.
+
+2005-07-28 Roland McGrath <roland@redhat.com>
+
+ * ptest.c: Moved to ../tests/dwflmodtest.c.
+
+ * Makefile.am (noinst_PROGRAMS): Variable removed.
+ (libdwfl_so_SOURCES, libdwfl_LIBS, libdwfl_so_LDADD): Likewise.
+ (EXTRA_DIST, ptest_LDADD, test2_LDADD): Likewise.
+ (libdwfl): Don't use libdwfl.so any more.
+ (libdwfl.so, install, uninstall): Targets removed.
+ (test2_SOURCES): Define EXTRA_DIST instead of this.
+ * libdwfl.map: File removed.
+
+ * libdwfl.h: Use "" for libdw.h #include.
+
+2005-07-27 Roland McGrath <roland@redhat.com>
+
+ * libdwfl.map: Add dwfl_getmodules.
+
+2005-07-23 Ulrich Drepper <drepper@redhat.com>
+
+ * Makefile.am: Fix rules to allow building with mudflap.
+
+2005-07-21 Roland McGrath <roland@redhat.com>
+
+ * Makefile.am (noinst_HEADERS): Add loc2c.c.
+
+ * test2.c (main): Check sscanf result to quiet warning.
+
+2005-07-20 Roland McGrath <roland@redhat.com>
+
+ * libdwfl-branch merged, creating this direcotry.
diff --git a/src/libdwfl/Makefile.am b/src/libdwfl/Makefile.am
new file mode 100644
index 00000000..65b38965
--- /dev/null
+++ b/src/libdwfl/Makefile.am
@@ -0,0 +1,99 @@
+## Makefile.am for libdwfl library subdirectory in elfutils.
+##
+## Process this file with automake to create Makefile.in
+##
+## Copyright (C) 2005-2010 Red Hat, Inc.
+## This file is part of Red Hat elfutils.
+##
+## Red Hat elfutils is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by the
+## Free Software Foundation; version 2 of the License.
+##
+## Red Hat elfutils is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with Red Hat elfutils; if not, write to the Free Software Foundation,
+## Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+##
+## Red Hat elfutils is an included package of the Open Invention Network.
+## An included package of the Open Invention Network is a package for which
+## Open Invention Network licensees cross-license their patents. No patent
+## license is granted, either expressly or impliedly, by designation as an
+## included package. Should you wish to participate in the Open Invention
+## Network licensing program, please visit www.openinventionnetwork.com
+## <http://www.openinventionnetwork.com>.
+##
+include $(top_srcdir)/config/eu.am
+INCLUDES += -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
+ -I$(srcdir)/../libdw
+VERSION = 1
+
+noinst_LIBRARIES = libdwfl.a
+if !MUDFLAP
+noinst_LIBRARIES += libdwfl_pic.a
+endif
+
+pkginclude_HEADERS = libdwfl.h
+
+libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
+ dwfl_module.c dwfl_report_elf.c relocate.c \
+ dwfl_module_build_id.c dwfl_module_report_build_id.c \
+ derelocate.c offline.c segment.c \
+ dwfl_module_info.c dwfl_getmodules.c dwfl_getdwarf.c \
+ dwfl_module_getdwarf.c dwfl_module_getelf.c \
+ dwfl_validate_address.c \
+ argp-std.c find-debuginfo.c \
+ dwfl_build_id_find_elf.c \
+ dwfl_build_id_find_debuginfo.c \
+ linux-kernel-modules.c linux-proc-maps.c \
+ dwfl_addrmodule.c dwfl_addrdwarf.c \
+ cu.c dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \
+ dwfl_module_addrdie.c dwfl_addrdie.c \
+ lines.c dwfl_lineinfo.c dwfl_line_comp_dir.c \
+ dwfl_linemodule.c dwfl_linecu.c dwfl_dwarf_line.c \
+ dwfl_getsrclines.c dwfl_onesrcline.c \
+ dwfl_module_getsrc.c dwfl_getsrc.c \
+ dwfl_module_getsrc_file.c \
+ libdwfl_crc32.c libdwfl_crc32_file.c \
+ elf-from-memory.c \
+ dwfl_module_dwarf_cfi.c dwfl_module_eh_cfi.c \
+ dwfl_module_getsym.c \
+ dwfl_module_addrname.c dwfl_module_addrsym.c \
+ dwfl_module_return_value_location.c \
+ dwfl_module_register_names.c \
+ dwfl_segment_report_module.c \
+ link_map.c core-file.c open.c image-header.c
+
+if ZLIB
+libdwfl_a_SOURCES += gzip.c
+endif
+if BZLIB
+libdwfl_a_SOURCES += bzip2.c
+endif
+if LZMA
+libdwfl_a_SOURCES += lzma.c
+endif
+
+if MUDFLAP
+libdwfl = libdwfl.a $(libdw) $(libebl) $(libelf) $(libeu)
+libdw = ../libdw/libdw.a
+libelf = ../libelf/libelf.a
+else
+libdwfl = $(libdw)
+libdw = ../libdw/libdw.so
+libelf = ../libelf/libelf.so
+endif
+libebl = ../libebl/libebl.a
+libeu = ../lib/libeu.a
+
+if !MUDFLAP
+libdwfl_pic_a_SOURCES =
+am_libdwfl_pic_a_OBJECTS = $(libdwfl_a_SOURCES:.c=.os)
+endif
+
+noinst_HEADERS = libdwflP.h
+
+CLEANFILES += $(am_libdwfl_pic_a_OBJECTS)
diff --git a/src/libdwfl/Makefile.in b/src/libdwfl/Makefile.in
new file mode 100644
index 00000000..b22e1ad1
--- /dev/null
+++ b/src/libdwfl/Makefile.in
@@ -0,0 +1,680 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(noinst_HEADERS) $(pkginclude_HEADERS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/config/eu.am ChangeLog
+@MUDFLAP_TRUE@am__append_1 = -fmudflap
+@MUDFLAP_FALSE@am__append_2 = libdwfl_pic.a
+@ZLIB_TRUE@am__append_3 = gzip.c
+@BZLIB_TRUE@am__append_4 = bzip2.c
+@LZMA_TRUE@am__append_5 = lzma.c
+@MUDFLAP_TRUE@am_libdwfl_pic_a_OBJECTS =
+subdir = libdwfl
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/zip.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+AR = ar
+ARFLAGS = cru
+libdwfl_a_AR = $(AR) $(ARFLAGS)
+libdwfl_a_LIBADD =
+am__libdwfl_a_SOURCES_DIST = dwfl_begin.c dwfl_end.c dwfl_error.c \
+ dwfl_version.c dwfl_module.c dwfl_report_elf.c relocate.c \
+ dwfl_module_build_id.c dwfl_module_report_build_id.c \
+ derelocate.c offline.c segment.c dwfl_module_info.c \
+ dwfl_getmodules.c dwfl_getdwarf.c dwfl_module_getdwarf.c \
+ dwfl_module_getelf.c dwfl_validate_address.c argp-std.c \
+ find-debuginfo.c dwfl_build_id_find_elf.c \
+ dwfl_build_id_find_debuginfo.c linux-kernel-modules.c \
+ linux-proc-maps.c dwfl_addrmodule.c dwfl_addrdwarf.c cu.c \
+ dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \
+ dwfl_module_addrdie.c dwfl_addrdie.c lines.c dwfl_lineinfo.c \
+ dwfl_line_comp_dir.c dwfl_linemodule.c dwfl_linecu.c \
+ dwfl_dwarf_line.c dwfl_getsrclines.c dwfl_onesrcline.c \
+ dwfl_module_getsrc.c dwfl_getsrc.c dwfl_module_getsrc_file.c \
+ libdwfl_crc32.c libdwfl_crc32_file.c elf-from-memory.c \
+ dwfl_module_dwarf_cfi.c dwfl_module_eh_cfi.c \
+ dwfl_module_getsym.c dwfl_module_addrname.c \
+ dwfl_module_addrsym.c dwfl_module_return_value_location.c \
+ dwfl_module_register_names.c dwfl_segment_report_module.c \
+ link_map.c core-file.c open.c image-header.c gzip.c bzip2.c \
+ lzma.c
+@ZLIB_TRUE@am__objects_1 = gzip.$(OBJEXT)
+@BZLIB_TRUE@am__objects_2 = bzip2.$(OBJEXT)
+@LZMA_TRUE@am__objects_3 = lzma.$(OBJEXT)
+am_libdwfl_a_OBJECTS = dwfl_begin.$(OBJEXT) dwfl_end.$(OBJEXT) \
+ dwfl_error.$(OBJEXT) dwfl_version.$(OBJEXT) \
+ dwfl_module.$(OBJEXT) dwfl_report_elf.$(OBJEXT) \
+ relocate.$(OBJEXT) dwfl_module_build_id.$(OBJEXT) \
+ dwfl_module_report_build_id.$(OBJEXT) derelocate.$(OBJEXT) \
+ offline.$(OBJEXT) segment.$(OBJEXT) dwfl_module_info.$(OBJEXT) \
+ dwfl_getmodules.$(OBJEXT) dwfl_getdwarf.$(OBJEXT) \
+ dwfl_module_getdwarf.$(OBJEXT) dwfl_module_getelf.$(OBJEXT) \
+ dwfl_validate_address.$(OBJEXT) argp-std.$(OBJEXT) \
+ find-debuginfo.$(OBJEXT) dwfl_build_id_find_elf.$(OBJEXT) \
+ dwfl_build_id_find_debuginfo.$(OBJEXT) \
+ linux-kernel-modules.$(OBJEXT) linux-proc-maps.$(OBJEXT) \
+ dwfl_addrmodule.$(OBJEXT) dwfl_addrdwarf.$(OBJEXT) \
+ cu.$(OBJEXT) dwfl_module_nextcu.$(OBJEXT) \
+ dwfl_nextcu.$(OBJEXT) dwfl_cumodule.$(OBJEXT) \
+ dwfl_module_addrdie.$(OBJEXT) dwfl_addrdie.$(OBJEXT) \
+ lines.$(OBJEXT) dwfl_lineinfo.$(OBJEXT) \
+ dwfl_line_comp_dir.$(OBJEXT) dwfl_linemodule.$(OBJEXT) \
+ dwfl_linecu.$(OBJEXT) dwfl_dwarf_line.$(OBJEXT) \
+ dwfl_getsrclines.$(OBJEXT) dwfl_onesrcline.$(OBJEXT) \
+ dwfl_module_getsrc.$(OBJEXT) dwfl_getsrc.$(OBJEXT) \
+ dwfl_module_getsrc_file.$(OBJEXT) libdwfl_crc32.$(OBJEXT) \
+ libdwfl_crc32_file.$(OBJEXT) elf-from-memory.$(OBJEXT) \
+ dwfl_module_dwarf_cfi.$(OBJEXT) dwfl_module_eh_cfi.$(OBJEXT) \
+ dwfl_module_getsym.$(OBJEXT) dwfl_module_addrname.$(OBJEXT) \
+ dwfl_module_addrsym.$(OBJEXT) \
+ dwfl_module_return_value_location.$(OBJEXT) \
+ dwfl_module_register_names.$(OBJEXT) \
+ dwfl_segment_report_module.$(OBJEXT) link_map.$(OBJEXT) \
+ core-file.$(OBJEXT) open.$(OBJEXT) image-header.$(OBJEXT) \
+ $(am__objects_1) $(am__objects_2) $(am__objects_3)
+libdwfl_a_OBJECTS = $(am_libdwfl_a_OBJECTS)
+libdwfl_pic_a_AR = $(AR) $(ARFLAGS)
+libdwfl_pic_a_LIBADD =
+libdwfl_pic_a_OBJECTS = $(am_libdwfl_pic_a_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libdwfl_a_SOURCES) $(libdwfl_pic_a_SOURCES)
+DIST_SOURCES = $(am__libdwfl_a_SOURCES_DIST) $(libdwfl_pic_a_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkgincludedir)"
+HEADERS = $(noinst_HEADERS) $(pkginclude_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUGPRED = @DEBUGPRED@
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DLOCALEDIR='"${localedir}"'
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBEBL_SUBDIR = @LIBEBL_SUBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MODVERSION = @MODVERSION@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = 1
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+base_cpu = @base_cpu@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+eu_version = @eu_version@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+zip_LIBS = @zip_LIBS@
+INCLUDES = -I. -I$(srcdir) -I$(top_srcdir)/lib -I.. -I$(srcdir) \
+ -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
+ -I$(srcdir)/../libdw
+AM_CFLAGS = -std=gnu99 -Wall -Wshadow $(if \
+ $($(*F)_no_Werror),,-Werror) $(if \
+ $($(*F)_no_Wunused),,-Wunused -Wextra) $(if \
+ $($(*F)_no_Wformat),-Wno-format,-Wformat=2) $($(*F)_CFLAGS) \
+ $(am__append_1)
+@MUDFLAP_FALSE@libmudflap =
+@MUDFLAP_TRUE@libmudflap = -lmudflap
+COMPILE.os = $(filter-out -fprofile-arcs -ftest-coverage $(no_mudflap.os),\
+ $(COMPILE))
+
+CLEANFILES = *.gcno *.gcda $(am_libdwfl_pic_a_OBJECTS)
+textrel_check = if readelf -d $@ | fgrep -q TEXTREL; then exit 1; fi
+noinst_LIBRARIES = libdwfl.a $(am__append_2)
+pkginclude_HEADERS = libdwfl.h
+libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c \
+ dwfl_version.c dwfl_module.c dwfl_report_elf.c relocate.c \
+ dwfl_module_build_id.c dwfl_module_report_build_id.c \
+ derelocate.c offline.c segment.c dwfl_module_info.c \
+ dwfl_getmodules.c dwfl_getdwarf.c dwfl_module_getdwarf.c \
+ dwfl_module_getelf.c dwfl_validate_address.c argp-std.c \
+ find-debuginfo.c dwfl_build_id_find_elf.c \
+ dwfl_build_id_find_debuginfo.c linux-kernel-modules.c \
+ linux-proc-maps.c dwfl_addrmodule.c dwfl_addrdwarf.c cu.c \
+ dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \
+ dwfl_module_addrdie.c dwfl_addrdie.c lines.c dwfl_lineinfo.c \
+ dwfl_line_comp_dir.c dwfl_linemodule.c dwfl_linecu.c \
+ dwfl_dwarf_line.c dwfl_getsrclines.c dwfl_onesrcline.c \
+ dwfl_module_getsrc.c dwfl_getsrc.c dwfl_module_getsrc_file.c \
+ libdwfl_crc32.c libdwfl_crc32_file.c elf-from-memory.c \
+ dwfl_module_dwarf_cfi.c dwfl_module_eh_cfi.c \
+ dwfl_module_getsym.c dwfl_module_addrname.c \
+ dwfl_module_addrsym.c dwfl_module_return_value_location.c \
+ dwfl_module_register_names.c dwfl_segment_report_module.c \
+ link_map.c core-file.c open.c image-header.c $(am__append_3) \
+ $(am__append_4) $(am__append_5)
+@MUDFLAP_FALSE@libdwfl = $(libdw)
+@MUDFLAP_TRUE@libdwfl = libdwfl.a $(libdw) $(libebl) $(libelf) $(libeu)
+@MUDFLAP_FALSE@libdw = ../libdw/libdw.so
+@MUDFLAP_TRUE@libdw = ../libdw/libdw.a
+@MUDFLAP_FALSE@libelf = ../libelf/libelf.so
+@MUDFLAP_TRUE@libelf = ../libelf/libelf.a
+libebl = ../libebl/libebl.a
+libeu = ../lib/libeu.a
+@MUDFLAP_FALSE@libdwfl_pic_a_SOURCES =
+@MUDFLAP_FALSE@am_libdwfl_pic_a_OBJECTS = $(libdwfl_a_SOURCES:.c=.os)
+noinst_HEADERS = libdwflP.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/eu.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits libdwfl/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnits libdwfl/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libdwfl.a: $(libdwfl_a_OBJECTS) $(libdwfl_a_DEPENDENCIES)
+ -rm -f libdwfl.a
+ $(libdwfl_a_AR) libdwfl.a $(libdwfl_a_OBJECTS) $(libdwfl_a_LIBADD)
+ $(RANLIB) libdwfl.a
+libdwfl_pic.a: $(libdwfl_pic_a_OBJECTS) $(libdwfl_pic_a_DEPENDENCIES)
+ -rm -f libdwfl_pic.a
+ $(libdwfl_pic_a_AR) libdwfl_pic.a $(libdwfl_pic_a_OBJECTS) $(libdwfl_pic_a_LIBADD)
+ $(RANLIB) libdwfl_pic.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/argp-std.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bzip2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core-file.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/derelocate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_addrdie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_addrdwarf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_addrmodule.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_begin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_build_id_find_debuginfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_build_id_find_elf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_cumodule.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_dwarf_line.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_end.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_getdwarf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_getmodules.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_getsrc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_getsrclines.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_line_comp_dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_linecu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_lineinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_linemodule.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_addrdie.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_addrname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_addrsym.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_build_id.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_dwarf_cfi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_eh_cfi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_getdwarf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_getelf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_getsrc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_getsrc_file.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_getsym.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_info.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_nextcu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_register_names.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_report_build_id.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_module_return_value_location.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_nextcu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_onesrcline.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_report_elf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_segment_report_module.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_validate_address.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwfl_version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-from-memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/find-debuginfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gzip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/image-header.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdwfl_crc32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdwfl_crc32_file.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lines.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link_map.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux-kernel-modules.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux-proc-maps.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzma.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/offline.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/open.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/relocate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/segment.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+install-pkgincludeHEADERS: $(pkginclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgincludedir)" || $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)"
+ @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \
+ done
+
+uninstall-pkgincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pkgincludedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pkgincludedir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkgincludeHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkgincludeHEADERS install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pkgincludeHEADERS
+
+
+%.os: %.c %.o
+@AMDEP_TRUE@ if $(COMPILE.os) -c -o $@ -fpic -DPIC -DSHARED -MT $@ -MD -MP \
+@AMDEP_TRUE@ -MF "$(DEPDIR)/$*.Tpo" `test -f '$<' || echo '$(srcdir)/'`$<; \
+@AMDEP_TRUE@ then cat "$(DEPDIR)/$*.Tpo" >> "$(DEPDIR)/$*.Po"; \
+@AMDEP_TRUE@ rm -f "$(DEPDIR)/$*.Tpo"; \
+@AMDEP_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@AMDEP_TRUE@ fi
+@AMDEP_FALSE@ $(COMPILE.os) -c -o $@ -fpic -DPIC -DSHARED $<
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libdwfl/argp-std.c b/src/libdwfl/argp-std.c
new file mode 100644
index 00000000..e598c6ef
--- /dev/null
+++ b/src/libdwfl/argp-std.c
@@ -0,0 +1,334 @@
+/* Standard argp argument parsers for tools using libdwfl.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <argp.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <libintl.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* gettext helper macros. */
+#define _(Str) dgettext ("elfutils", Str)
+
+
+#define OPT_DEBUGINFO 0x100
+#define OPT_COREFILE 0x101
+
+static const struct argp_option options[] =
+{
+ { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
+ { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
+ { "core", OPT_COREFILE, "COREFILE", 0,
+ N_("Find addresses from signatures found in COREFILE"), 0 },
+ { "pid", 'p', "PID", 0,
+ N_("Find addresses in files mapped into process PID"), 0 },
+ { "linux-process-map", 'M', "FILE", 0,
+ N_("Find addresses in files mapped as read from FILE"
+ " in Linux /proc/PID/maps format"), 0 },
+ { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
+ { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
+ N_("Kernel with all modules"), 0 },
+ { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
+ N_("Search path for separate debuginfo files"), 0 },
+ { NULL, 0, NULL, 0, NULL, 0 }
+};
+
+static char *debuginfo_path;
+
+static const Dwfl_Callbacks offline_callbacks =
+ {
+ .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
+ .debuginfo_path = &debuginfo_path,
+
+ .section_address = INTUSE(dwfl_offline_section_address),
+
+ /* We use this table for core files too. */
+ .find_elf = INTUSE(dwfl_build_id_find_elf),
+ };
+
+static const Dwfl_Callbacks proc_callbacks =
+ {
+ .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
+ .debuginfo_path = &debuginfo_path,
+
+ .find_elf = INTUSE(dwfl_linux_proc_find_elf),
+ };
+
+static const Dwfl_Callbacks kernel_callbacks =
+ {
+ .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
+ .debuginfo_path = &debuginfo_path,
+
+ .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
+ .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
+ };
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ inline void failure (Dwfl *dwfl, int errnum, const char *msg)
+ {
+ if (dwfl != NULL)
+ dwfl_end (dwfl);
+ if (errnum == -1)
+ argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
+ msg, INTUSE(dwfl_errmsg) (-1));
+ else
+ argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
+ }
+ inline error_t fail (Dwfl *dwfl, int errnum, const char *msg)
+ {
+ failure (dwfl, errnum, msg);
+ return errnum == -1 ? EIO : errnum;
+ }
+
+ switch (key)
+ {
+ case OPT_DEBUGINFO:
+ debuginfo_path = arg;
+ break;
+
+ case 'e':
+ {
+ Dwfl *dwfl = state->hook;
+ if (dwfl == NULL)
+ {
+ dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ if (dwfl == NULL)
+ return fail (dwfl, -1, arg);
+ state->hook = dwfl;
+
+ /* Start at zero so if there is just one -e foo.so,
+ the DSO is shown without address bias. */
+ dwfl->offline_next_address = 0;
+ }
+ if (dwfl->callbacks == &offline_callbacks)
+ {
+ if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
+ return fail (dwfl, -1, arg);
+ state->hook = dwfl;
+ }
+ else
+ {
+ toomany:
+ argp_error (state, "%s",
+ _("only one of -e, -p, -k, -K, or --core allowed"));
+ return EINVAL;
+ }
+ }
+ break;
+
+ case 'p':
+ if (state->hook == NULL)
+ {
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
+ int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
+ if (result != 0)
+ return fail (dwfl, result, arg);
+ state->hook = dwfl;
+ }
+ else
+ goto toomany;
+ break;
+
+ case 'M':
+ if (state->hook == NULL)
+ {
+ FILE *f = fopen (arg, "r");
+ if (f == NULL)
+ nofile:
+ {
+ int code = errno;
+ argp_failure (state, EXIT_FAILURE, code,
+ "cannot open '%s'", arg);
+ return code;
+ }
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
+ int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
+ fclose (f);
+ if (result != 0)
+ return fail (dwfl, result, arg);
+ state->hook = dwfl;
+ }
+ else
+ goto toomany;
+ break;
+
+ case OPT_COREFILE:
+ {
+ Dwfl *dwfl = state->hook;
+ if (dwfl == NULL)
+ state->hook = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ /* Permit -e and --core together. */
+ else if (dwfl->callbacks != &offline_callbacks)
+ goto toomany;
+
+ int fd = open64 (arg, O_RDONLY);
+ if (fd < 0)
+ goto nofile;
+
+ Elf *core;
+ Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
+ if (error != DWFL_E_NOERROR)
+ {
+ argp_failure (state, EXIT_FAILURE, 0,
+ _("cannot read ELF core file: %s"),
+ INTUSE(dwfl_errmsg) (error));
+ return error == DWFL_E_ERRNO ? errno : EIO;
+ }
+
+ int result = INTUSE(dwfl_core_file_report) (dwfl, core);
+ if (result < 0)
+ {
+ elf_end (core);
+ close (fd);
+ return fail (dwfl, result, arg);
+ }
+
+ /* From now we leak FD and CORE. */
+
+ if (result == 0)
+ {
+ argp_failure (state, EXIT_FAILURE, 0,
+ _("No modules recognized in core file"));
+ return ENOENT;
+ }
+ }
+ break;
+
+ case 'k':
+ if (state->hook == NULL)
+ {
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
+ int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
+ if (result != 0)
+ return fail (dwfl, result, _("cannot load kernel symbols"));
+ result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
+ if (result != 0)
+ /* Non-fatal to have no modules since we do have the kernel. */
+ failure (dwfl, result, _("cannot find kernel modules"));
+ state->hook = dwfl;
+ }
+ else
+ goto toomany;
+ break;
+
+ case 'K':
+ if (state->hook == NULL)
+ {
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
+ NULL);
+ if (result != 0)
+ return fail (dwfl, result, _("cannot find kernel or modules"));
+ state->hook = dwfl;
+ }
+ else
+ goto toomany;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ {
+ Dwfl *dwfl = state->hook;
+
+ if (dwfl == NULL)
+ {
+ /* Default if no -e, -p, or -k, is "-e a.out". */
+ arg = "a.out";
+ dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
+ return fail (dwfl, -1, arg);
+ state->hook = dwfl;
+ }
+
+ /* One of the three flavors has done dwfl_begin and some reporting
+ if we got here. Tie up the Dwfl and return it to the caller of
+ argp_parse. */
+
+ int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
+ assert (result == 0);
+ }
+ break;
+
+ case ARGP_KEY_ERROR:
+ dwfl_end (state->hook);
+ state->hook = NULL;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ /* Update the input all along, so a parent parser can see it. */
+ *(Dwfl **) state->input = state->hook;
+ return 0;
+}
+
+static const struct argp libdwfl_argp =
+ { .options = options, .parser = parse_opt };
+
+const struct argp *
+dwfl_standard_argp (void)
+{
+ return &libdwfl_argp;
+}
+
+#ifdef _MUDFLAP
+/* In the absence of a mudflap wrapper for argp_parse, or a libc compiled
+ with -fmudflap, we'll see spurious errors for using the struct argp_state
+ on argp_parse's stack. */
+
+void __attribute__ ((constructor))
+__libdwfl_argp_mudflap_options (void)
+{
+ __mf_set_options ("-heur-stack-bound");
+}
+#endif
diff --git a/src/libdwfl/bzip2.c b/src/libdwfl/bzip2.c
new file mode 100644
index 00000000..8ad4ee5a
--- /dev/null
+++ b/src/libdwfl/bzip2.c
@@ -0,0 +1,4 @@
+/* bzlib is almost just like zlib. */
+
+#define BZLIB
+#include "gzip.c"
diff --git a/src/libdwfl/core-file.c b/src/libdwfl/core-file.c
new file mode 100644
index 00000000..1b556dde
--- /dev/null
+++ b/src/libdwfl/core-file.c
@@ -0,0 +1,484 @@
+/* Core file handling.
+ Copyright (C) 2008-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include "../libelf/libelfP.h" /* For NOTE_ALIGN. */
+#undef _
+#include "libdwflP.h"
+#include <gelf.h>
+
+#include <sys/param.h>
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include "system.h"
+
+
+/* This is a prototype of what a new libelf interface might be.
+ This implementation is pessimal for non-mmap cases and should
+ be replaced by more diddling inside libelf internals. */
+static Elf *
+elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next)
+{
+ if (parent == NULL)
+ return NULL;
+
+ /* On failure return, we update *NEXT to point back at OFFSET. */
+ inline Elf *fail (int error)
+ {
+ if (next != NULL)
+ *next = offset;
+ //__libelf_seterrno (error);
+ __libdwfl_seterrno (DWFL_E (LIBELF, error));
+ return NULL;
+ }
+
+ loff_t min = (parent->kind == ELF_K_ELF ?
+ (parent->class == ELFCLASS32
+ ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
+ : parent->kind == ELF_K_AR ? SARMAG
+ : 0);
+
+ if (unlikely (offset < min)
+ || unlikely (offset >= (loff_t) parent->maximum_size))
+ return fail (ELF_E_RANGE);
+
+ /* For an archive, fetch just the size field
+ from the archive header to override SIZE. */
+ if (parent->kind == ELF_K_AR)
+ {
+ struct ar_hdr h = { .ar_size = "" };
+
+ if (unlikely (parent->maximum_size - offset < sizeof h))
+ return fail (ELF_E_RANGE);
+
+ if (parent->map_address != NULL)
+ memcpy (h.ar_size, parent->map_address + parent->start_offset + offset,
+ sizeof h.ar_size);
+ else if (unlikely (pread_retry (parent->fildes,
+ h.ar_size, sizeof (h.ar_size),
+ parent->start_offset + offset
+ + offsetof (struct ar_hdr, ar_size))
+ != sizeof (h.ar_size)))
+ return fail (ELF_E_READ_ERROR);
+
+ offset += sizeof h;
+
+ char *endp;
+ size = strtoll (h.ar_size, &endp, 10);
+ if (unlikely (endp == h.ar_size)
+ || unlikely ((loff_t) parent->maximum_size - offset < size))
+ return fail (ELF_E_INVALID_ARCHIVE);
+ }
+
+ if (unlikely ((loff_t) parent->maximum_size - offset < size))
+ return fail (ELF_E_RANGE);
+
+ /* Even if we fail at this point, update *NEXT to point past the file. */
+ if (next != NULL)
+ *next = offset + size;
+
+ if (unlikely (offset == 0)
+ && unlikely (size == (loff_t) parent->maximum_size))
+ return elf_clone (parent, parent->cmd);
+
+ /* Note the image is guaranteed live only as long as PARENT
+ lives. Using elf_memory is quite suboptimal if the whole
+ file is not mmap'd. We really should have something like
+ a generalization of the archive support. */
+ Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
+ if (data == NULL)
+ return NULL;
+ assert ((loff_t) data->d_size == size);
+ return elf_memory (data->d_buf, size);
+}
+
+
+int
+dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
+{
+ if (unlikely (dwfl == NULL))
+ return -1;
+
+ int result = 0;
+
+ if (notes != NULL)
+ notes->p_type = PT_NULL;
+
+ for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
+ if (unlikely (phdr == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
+ switch (phdr->p_type)
+ {
+ case PT_LOAD:
+ result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL);
+ break;
+
+ case PT_NOTE:
+ if (notes != NULL)
+ {
+ *notes = *phdr;
+ notes = NULL;
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Never read more than this much without mmap. */
+#define MAX_EAGER_COST 8192
+
+static bool
+core_file_read_eagerly (Dwfl_Module *mod,
+ void **userdata __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ Dwarf_Addr start __attribute__ ((unused)),
+ void **buffer, size_t *buffer_available,
+ GElf_Off cost, GElf_Off worthwhile,
+ GElf_Off whole,
+ GElf_Off contiguous __attribute__ ((unused)),
+ void *arg, Elf **elfp)
+{
+ Elf *core = arg;
+
+ if (whole <= *buffer_available)
+ {
+ /* All there ever was, we already have on hand. */
+
+ if (core->map_address == NULL)
+ {
+ /* We already malloc'd the buffer. */
+ *elfp = elf_memory (*buffer, whole);
+ if (unlikely (*elfp == NULL))
+ return false;
+
+ (*elfp)->flags |= ELF_F_MALLOCED;
+ *buffer = NULL;
+ *buffer_available = 0;
+ return true;
+ }
+
+ /* We can use the image inside the core file directly. */
+ *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
+ *buffer = NULL;
+ *buffer_available = 0;
+ return *elfp != NULL;
+ }
+
+ /* We don't have the whole file.
+ Figure out if this is better than nothing. */
+
+ if (worthwhile == 0)
+ /* Caller doesn't think so. */
+ return false;
+
+ /*
+ XXX would like to fall back to partial file via memory
+ when build id find_elf fails
+ also, link_map name may give file name from disk better than partial here
+ requires find_elf hook re-doing the magic to fall back if no file found
+ */
+
+ if (mod->build_id_len > 0)
+ /* There is a build ID that could help us find the whole file,
+ which might be more useful than what we have.
+ We'll just rely on that. */
+ return false;
+
+ if (core->map_address != NULL)
+ /* It's cheap to get, so get it. */
+ return true;
+
+ /* Only use it if there isn't too much to be read. */
+ return cost <= MAX_EAGER_COST;
+}
+
+bool
+dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx,
+ void **buffer, size_t *buffer_available,
+ GElf_Addr vaddr,
+ size_t minread,
+ void *arg)
+{
+ Elf *elf = arg;
+
+ if (ndx == -1)
+ {
+ /* Called for cleanup. */
+ if (elf->map_address == NULL)
+ free (*buffer);
+ *buffer = NULL;
+ *buffer_available = 0;
+ return false;
+ }
+
+ const GElf_Off align = dwfl->segment_align ?: 1;
+ GElf_Phdr phdr;
+
+ do
+ if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
+ return false;
+ while (phdr.p_type != PT_LOAD
+ || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
+
+ GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset;
+ GElf_Off end;
+ GElf_Addr end_vaddr;
+
+ inline void update_end ()
+ {
+ end = (phdr.p_offset + phdr.p_filesz + align - 1) & -align;
+ end_vaddr = (phdr.p_vaddr + phdr.p_memsz + align - 1) & -align;
+ }
+
+ update_end ();
+
+ /* Use following contiguous segments to get towards SIZE. */
+ inline bool more (size_t size)
+ {
+ while (end <= start || end - start < size)
+ {
+ if (phdr.p_filesz < phdr.p_memsz)
+ /* This segment is truncated, so no following one helps us. */
+ return false;
+
+ if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
+ return false;
+
+ if (phdr.p_type == PT_LOAD)
+ {
+ if (phdr.p_offset > end
+ || phdr.p_vaddr > end_vaddr)
+ /* It's discontiguous! */
+ return false;
+
+ update_end ();
+ }
+ }
+ return true;
+ }
+
+ /* We need at least this much. */
+ if (! more (minread))
+ return false;
+
+ /* See how much more we can get of what the caller wants. */
+ (void) more (*buffer_available);
+
+ /* If it's already on hand anyway, use as much as there is. */
+ if (elf->map_address != NULL)
+ (void) more (elf->maximum_size - start);
+
+ /* Make sure we don't look past the end of the actual file,
+ even if the headers tell us to. */
+ if (unlikely (end > elf->maximum_size))
+ end = elf->maximum_size;
+
+ /* If the file is too small, there is nothing at all to get. */
+ if (unlikely (start >= end))
+ return false;
+
+ if (elf->map_address != NULL)
+ {
+ void *contents = elf->map_address + elf->start_offset + start;
+ size_t size = end - start;
+
+ if (minread == 0) /* String mode. */
+ {
+ const void *eos = memchr (contents, '\0', size);
+ if (unlikely (eos == NULL) || unlikely (eos == contents))
+ return false;
+ size = eos + 1 - contents;
+ }
+
+ if (*buffer == NULL)
+ {
+ *buffer = contents;
+ *buffer_available = size;
+ }
+ else
+ {
+ *buffer_available = MIN (size, *buffer_available);
+ memcpy (*buffer, contents, *buffer_available);
+ }
+ }
+ else
+ {
+ void *into = *buffer;
+ if (*buffer == NULL)
+ {
+ *buffer_available = MIN (minread ?: 512,
+ MAX (4096, MIN (end - start,
+ *buffer_available)));
+ into = malloc (*buffer_available);
+ if (unlikely (into == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return false;
+ }
+ }
+
+ ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start);
+ if (nread < (ssize_t) minread)
+ {
+ if (into != *buffer)
+ free (into);
+ if (nread < 0)
+ __libdwfl_seterrno (DWFL_E_ERRNO);
+ return false;
+ }
+
+ if (minread == 0) /* String mode. */
+ {
+ const void *eos = memchr (into, '\0', nread);
+ if (unlikely (eos == NULL) || unlikely (eos == into))
+ {
+ if (*buffer == NULL)
+ free (into);
+ return false;
+ }
+ nread = eos + 1 - into;
+ }
+
+ if (*buffer == NULL)
+ *buffer = into;
+ *buffer_available = nread;
+ }
+
+ return true;
+}
+
+int
+dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
+{
+ size_t phnum;
+ if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
+
+ /* First report each PT_LOAD segment. */
+ GElf_Phdr notes_phdr;
+ int ndx = dwfl_report_core_segments (dwfl, elf, phnum, &notes_phdr);
+ if (unlikely (ndx <= 0))
+ return ndx;
+
+ /* Now sniff segment contents for modules. */
+ int sniffed = 0;
+ ndx = 0;
+ do
+ {
+ int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
+ &dwfl_elf_phdr_memory_callback, elf,
+ core_file_read_eagerly, elf);
+ if (unlikely (seg < 0))
+ return seg;
+ if (seg > ndx)
+ {
+ ndx = seg;
+ ++sniffed;
+ }
+ else
+ ++ndx;
+ }
+ while (ndx < (int) phnum);
+
+ /* Next, we should follow the chain from DT_DEBUG. */
+
+ const void *auxv = NULL;
+ size_t auxv_size = 0;
+ if (likely (notes_phdr.p_type == PT_NOTE))
+ {
+ /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */
+
+ Elf_Data *notes = elf_getdata_rawchunk (elf,
+ notes_phdr.p_offset,
+ notes_phdr.p_filesz,
+ ELF_T_NHDR);
+ if (likely (notes != NULL))
+ {
+ size_t pos = 0;
+ GElf_Nhdr nhdr;
+ size_t name_pos;
+ size_t desc_pos;
+ while ((pos = gelf_getnote (notes, pos, &nhdr,
+ &name_pos, &desc_pos)) > 0)
+ if (nhdr.n_type == NT_AUXV
+ && nhdr.n_namesz == sizeof "CORE"
+ && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE"))
+ {
+ auxv = notes->d_buf + desc_pos;
+ auxv_size = nhdr.n_descsz;
+ break;
+ }
+ }
+ }
+
+ /* Now we have NT_AUXV contents. From here on this processing could be
+ used for a live process with auxv read from /proc. */
+
+ int listed = dwfl_link_map_report (dwfl, auxv, auxv_size,
+ dwfl_elf_phdr_memory_callback, elf);
+
+ /* We return the number of modules we found if we found any.
+ If we found none, we return -1 instead of 0 if there was an
+ error rather than just nothing found. If link_map handling
+ failed, we still have the sniffed modules. */
+ return sniffed == 0 || listed > sniffed ? listed : sniffed;
+}
+INTDEF (dwfl_core_file_report)
diff --git a/src/libdwfl/cu.c b/src/libdwfl/cu.c
new file mode 100644
index 00000000..515aff3b
--- /dev/null
+++ b/src/libdwfl/cu.c
@@ -0,0 +1,324 @@
+/* Keeping track of DWARF compilation units in libdwfl.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/libdwP.h"
+#include "../libdw/memory-access.h"
+#include <search.h>
+
+
+static inline Dwarf_Arange *
+dwar (Dwfl_Module *mod, unsigned int idx)
+{
+ return &mod->dw->aranges->info[mod->aranges[idx].arange];
+}
+
+
+static Dwfl_Error
+addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
+{
+ if (mod->aranges == NULL)
+ {
+ struct dwfl_arange *aranges = NULL;
+ Dwarf_Aranges *dwaranges = NULL;
+ size_t naranges;
+ if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
+ return DWFL_E_LIBDW;
+
+ /* If the module has no aranges (when no code is included) we
+ allocate nothing. */
+ if (naranges != 0)
+ {
+ aranges = malloc (naranges * sizeof *aranges);
+ if (unlikely (aranges == NULL))
+ return DWFL_E_NOMEM;
+
+ /* libdw has sorted its list by address, which is how we want it.
+ But the sorted list is full of not-quite-contiguous runs pointing
+ to the same CU. We don't care about the little gaps inside the
+ module, we'll consider them part of the surrounding CU anyway.
+ Collect our own array with just one record for each run of ranges
+ pointing to one CU. */
+
+ naranges = 0;
+ Dwarf_Off lastcu = 0;
+ for (size_t i = 0; i < dwaranges->naranges; ++i)
+ if (i == 0 || dwaranges->info[i].offset != lastcu)
+ {
+ aranges[naranges].arange = i;
+ aranges[naranges].cu = NULL;
+ ++naranges;
+ lastcu = dwaranges->info[i].offset;
+ }
+ }
+
+ /* Store the final array, which is probably much smaller than before. */
+ mod->naranges = naranges;
+ mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
+ ?: aranges);
+ mod->lazycu += naranges;
+ }
+
+ /* The address must be inside the module to begin with. */
+ addr = dwfl_deadjust_dwarf_addr (mod, addr);
+
+ /* The ranges are sorted by address, so we can use binary search. */
+ size_t l = 0, u = mod->naranges;
+ while (l < u)
+ {
+ size_t idx = (l + u) / 2;
+ Dwarf_Addr start = dwar (mod, idx)->addr;
+ if (addr < start)
+ {
+ u = idx;
+ continue;
+ }
+ else if (addr > start)
+ {
+ if (idx + 1 < mod->naranges)
+ {
+ if (addr >= dwar (mod, idx + 1)->addr)
+ {
+ l = idx + 1;
+ continue;
+ }
+ }
+ else
+ {
+ /* It might be in the last range. */
+ const Dwarf_Arange *last
+ = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
+ if (addr > last->addr + last->length)
+ break;
+ }
+ }
+
+ *arange = &mod->aranges[idx];
+ return DWFL_E_NOERROR;
+ }
+
+ return DWFL_E_ADDR_OUTOFRANGE;
+}
+
+
+static void
+nofree (void *arg)
+{
+ struct dwfl_cu *cu = arg;
+ if (cu == (void *) -1l)
+ return;
+
+ assert (cu->mod->lazycu == 0);
+}
+
+/* One reason fewer to keep the lazy lookup table for CUs. */
+static inline void
+less_lazy (Dwfl_Module *mod)
+{
+ if (--mod->lazycu > 0)
+ return;
+
+ /* We know about all the CUs now, we don't need this table. */
+ tdestroy (mod->lazy_cu_root, nofree);
+ mod->lazy_cu_root = NULL;
+}
+
+static inline Dwarf_Off
+cudie_offset (const struct dwfl_cu *cu)
+{
+ return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size,
+ cu->die.cu->type_sig8 != 0);
+}
+
+static int
+compare_cukey (const void *a, const void *b)
+{
+ return cudie_offset (a) - cudie_offset (b);
+}
+
+/* Intern the CU if necessary. */
+static Dwfl_Error
+intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
+{
+ struct Dwarf_CU dwkey;
+ struct dwfl_cu key;
+ key.die.cu = &dwkey;
+ dwkey.offset_size = 0;
+ dwkey.start = cuoff - (3 * 0 - 4 + 3);
+ struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
+ if (unlikely (found == NULL))
+ return DWFL_E_NOMEM;
+
+ if (*found == &key || *found == NULL)
+ {
+ if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
+ {
+ /* This is the EOF marker. Now we have interned all the CUs.
+ One increment in MOD->lazycu counts not having hit EOF yet. */
+ *found = (void *) -1l;
+ less_lazy (mod);
+ }
+ else
+ {
+ /* This is a new entry, meaning we haven't looked at this CU. */
+
+ *found = NULL;
+
+ struct dwfl_cu *cu = malloc (sizeof *cu);
+ if (unlikely (cu == NULL))
+ return DWFL_E_NOMEM;
+
+ cu->mod = mod;
+ cu->next = NULL;
+ cu->lines = NULL;
+
+ /* XXX use non-searching lookup */
+ Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die);
+ if (die == NULL)
+ return DWFL_E_LIBDW;
+ assert (die == &cu->die);
+
+ struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
+ * sizeof (mod->cu[0])));
+ if (newvec == NULL)
+ {
+ free (cu);
+ return DWFL_E_NOMEM;
+ }
+ mod->cu = newvec;
+
+ mod->cu[mod->ncu++] = cu;
+ if (cu->die.cu->start == 0)
+ mod->first_cu = cu;
+
+ *found = cu;
+ }
+ }
+
+ *result = *found;
+ return DWFL_E_NOERROR;
+}
+
+
+/* Traverse all the CUs in the module. */
+
+Dwfl_Error
+internal_function
+__libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
+ struct dwfl_cu **cu)
+{
+ Dwarf_Off cuoff;
+ struct dwfl_cu **nextp;
+
+ if (lastcu == NULL)
+ {
+ /* Start the traversal. */
+ cuoff = 0;
+ nextp = &mod->first_cu;
+ }
+ else
+ {
+ /* Continue following LASTCU. */
+ cuoff = lastcu->die.cu->end;
+ nextp = &lastcu->next;
+ }
+
+ if (*nextp == NULL)
+ {
+ size_t cuhdrsz;
+ Dwarf_Off nextoff;
+ int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
+ NULL, NULL, NULL);
+ if (end < 0)
+ return DWFL_E_LIBDW;
+ if (end > 0)
+ {
+ *cu = NULL;
+ return DWFL_E_NOERROR;
+ }
+
+ Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
+ if (result != DWFL_E_NOERROR)
+ return result;
+
+ if ((*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
+ (*nextp)->next = (void *) -1l;
+ }
+
+ *cu = *nextp == (void *) -1l ? NULL : *nextp;
+ return DWFL_E_NOERROR;
+}
+
+
+/* Intern the CU arange points to, if necessary. */
+
+static Dwfl_Error
+arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
+{
+ if (arange->cu == NULL)
+ {
+ const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
+ Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
+ if (result != DWFL_E_NOERROR)
+ return result;
+ assert (arange->cu != NULL && arange->cu != (void *) -1l);
+ less_lazy (mod); /* Each arange with null ->cu counts once. */
+ }
+
+ *cu = arange->cu;
+ return DWFL_E_NOERROR;
+}
+
+Dwfl_Error
+internal_function
+__libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
+{
+ struct dwfl_arange *arange;
+ return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
+}
diff --git a/src/libdwfl/derelocate.c b/src/libdwfl/derelocate.c
new file mode 100644
index 00000000..b8c8dd73
--- /dev/null
+++ b/src/libdwfl/derelocate.c
@@ -0,0 +1,411 @@
+/* Recover relocatibility for addresses computed from debug information.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+struct dwfl_relocation
+{
+ size_t count;
+ struct
+ {
+ Elf_Scn *scn;
+ Elf_Scn *relocs;
+ const char *name;
+ GElf_Addr start, end;
+ } refs[0];
+};
+
+
+struct secref
+{
+ struct secref *next;
+ Elf_Scn *scn;
+ Elf_Scn *relocs;
+ const char *name;
+ GElf_Addr start, end;
+};
+
+static int
+compare_secrefs (const void *a, const void *b)
+{
+ struct secref *const *p1 = a;
+ struct secref *const *p2 = b;
+
+ /* No signed difference calculation is correct here, since the
+ terms are unsigned and could be more than INT64_MAX apart. */
+ if ((*p1)->start < (*p2)->start)
+ return -1;
+ if ((*p1)->start > (*p2)->start)
+ return 1;
+
+ return 0;
+}
+
+static int
+cache_sections (Dwfl_Module *mod)
+{
+ if (likely (mod->reloc_info != NULL))
+ return mod->reloc_info->count;
+
+ struct secref *refs = NULL;
+ size_t nrefs = 0;
+
+ size_t shstrndx;
+ if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
+ {
+ elf_error:
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
+
+ bool check_reloc_sections = false;
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ goto elf_error;
+
+ if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
+ && mod->e_type == ET_REL)
+ {
+ /* This section might not yet have been looked at. */
+ if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
+ elf_ndxscn (scn),
+ &shdr->sh_addr) != DWFL_E_NOERROR)
+ continue;
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (shdr == NULL))
+ goto elf_error;
+ }
+
+ if (shdr->sh_flags & SHF_ALLOC)
+ {
+ const char *name = elf_strptr (mod->main.elf, shstrndx,
+ shdr->sh_name);
+ if (unlikely (name == NULL))
+ goto elf_error;
+
+ struct secref *newref = alloca (sizeof *newref);
+ newref->scn = scn;
+ newref->relocs = NULL;
+ newref->name = name;
+ newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
+ newref->end = newref->start + shdr->sh_size;
+ newref->next = refs;
+ refs = newref;
+ ++nrefs;
+ }
+
+ if (mod->e_type == ET_REL
+ && shdr->sh_size != 0
+ && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+ && mod->dwfl->callbacks->section_address != NULL)
+ {
+ if (shdr->sh_info < elf_ndxscn (scn))
+ {
+ /* We've already looked at the section these relocs apply to. */
+ Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
+ if (likely (tscn != NULL))
+ for (struct secref *sec = refs; sec != NULL; sec = sec->next)
+ if (sec->scn == tscn)
+ {
+ sec->relocs = scn;
+ break;
+ }
+ }
+ else
+ /* We'll have to do a second pass. */
+ check_reloc_sections = true;
+ }
+ }
+
+ mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
+ if (mod->reloc_info == NULL)
+ {
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return -1;
+ }
+
+ struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]);
+ for (size_t i = nrefs; i-- > 0; refs = refs->next)
+ sortrefs[i] = refs;
+ assert (refs == NULL);
+
+ qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
+
+ mod->reloc_info->count = nrefs;
+ for (size_t i = 0; i < nrefs; ++i)
+ {
+ mod->reloc_info->refs[i].name = sortrefs[i]->name;
+ mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
+ mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
+ mod->reloc_info->refs[i].start = sortrefs[i]->start;
+ mod->reloc_info->refs[i].end = sortrefs[i]->end;
+ }
+
+ if (unlikely (check_reloc_sections))
+ {
+ /* There was a reloc section that preceded its target section.
+ So we have to scan again now that we have cached all the
+ possible target sections we care about. */
+
+ scn = NULL;
+ while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ goto elf_error;
+
+ if (shdr->sh_size != 0
+ && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
+ {
+ Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
+ if (likely (tscn != NULL))
+ for (size_t i = 0; i < nrefs; ++i)
+ if (mod->reloc_info->refs[i].scn == tscn)
+ {
+ mod->reloc_info->refs[i].relocs = scn;
+ break;
+ }
+ }
+ }
+ }
+
+ return nrefs;
+}
+
+
+int
+dwfl_module_relocations (Dwfl_Module *mod)
+{
+ if (mod == NULL)
+ return -1;
+
+ switch (mod->e_type)
+ {
+ case ET_REL:
+ return cache_sections (mod);
+
+ case ET_DYN:
+ return 1;
+
+ case ET_EXEC:
+ assert (mod->main.vaddr == mod->low_addr);
+ break;
+ }
+
+ return 0;
+}
+
+const char *
+dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
+ Elf32_Word *shndxp)
+{
+ if (mod == NULL)
+ return NULL;
+
+ switch (mod->e_type)
+ {
+ case ET_REL:
+ break;
+
+ case ET_DYN:
+ if (idx != 0)
+ return NULL;
+ if (shndxp)
+ *shndxp = SHN_ABS;
+ return "";
+
+ default:
+ return NULL;
+ }
+
+ if (cache_sections (mod) < 0)
+ return NULL;
+
+ struct dwfl_relocation *sections = mod->reloc_info;
+
+ if (idx >= sections->count)
+ return NULL;
+
+ if (shndxp)
+ *shndxp = elf_ndxscn (sections->refs[idx].scn);
+
+ return sections->refs[idx].name;
+}
+
+/* Check that MOD is valid and make sure its relocation has been done. */
+static bool
+check_module (Dwfl_Module *mod)
+{
+ if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
+ {
+ Dwfl_Error error = dwfl_errno ();
+ if (error != DWFL_E_NO_SYMTAB)
+ {
+ __libdwfl_seterrno (error);
+ return true;
+ }
+ }
+
+ if (mod->dw == NULL)
+ {
+ Dwarf_Addr bias;
+ if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
+ {
+ Dwfl_Error error = dwfl_errno ();
+ if (error != DWFL_E_NO_DWARF)
+ {
+ __libdwfl_seterrno (error);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* Find the index in MOD->reloc_info.refs containing *ADDR. */
+static int
+find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
+{
+ if (cache_sections (mod) < 0)
+ return -1;
+
+ struct dwfl_relocation *sections = mod->reloc_info;
+
+ /* The sections are sorted by address, so we can use binary search. */
+ size_t l = 0, u = sections->count;
+ while (l < u)
+ {
+ size_t idx = (l + u) / 2;
+ if (*addr < sections->refs[idx].start)
+ u = idx;
+ else if (*addr > sections->refs[idx].end)
+ l = idx + 1;
+ else
+ {
+ /* Consider the limit of a section to be inside it, unless it's
+ inside the next one. A section limit address can appear in
+ line records. */
+ if (*addr == sections->refs[idx].end
+ && idx < sections->count
+ && *addr == sections->refs[idx + 1].start)
+ ++idx;
+
+ *addr -= sections->refs[idx].start;
+ return idx;
+ }
+ }
+
+ __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
+ return -1;
+}
+
+int
+dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
+{
+ if (unlikely (check_module (mod)))
+ return -1;
+
+ switch (mod->e_type)
+ {
+ case ET_REL:
+ return find_section (mod, addr);
+
+ case ET_DYN:
+ /* All relative to first and only relocation base: module start. */
+ *addr -= mod->low_addr;
+ break;
+
+ default:
+ /* Already absolute, dwfl_module_relocations returned zero. We
+ shouldn't really have been called, but it's a harmless no-op. */
+ break;
+ }
+
+ return 0;
+}
+INTDEF (dwfl_module_relocate_address)
+
+Elf_Scn *
+dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
+ Dwarf_Addr *bias)
+{
+ if (check_module (mod))
+ return NULL;
+
+ int idx = find_section (mod, address);
+ if (idx < 0)
+ return NULL;
+
+ if (mod->reloc_info->refs[idx].relocs != NULL)
+ {
+ assert (mod->e_type == ET_REL);
+
+ Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
+ Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
+ Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
+ relocscn, tscn, true);
+ if (likely (result == DWFL_E_NOERROR))
+ mod->reloc_info->refs[idx].relocs = NULL;
+ else
+ {
+ __libdwfl_seterrno (result);
+ return NULL;
+ }
+ }
+
+ *bias = dwfl_adjusted_address (mod, 0);
+ return mod->reloc_info->refs[idx].scn;
+}
+INTDEF (dwfl_module_address_section)
diff --git a/src/libdwfl/dwfl_addrdie.c b/src/libdwfl/dwfl_addrdie.c
new file mode 100644
index 00000000..20c15783
--- /dev/null
+++ b/src/libdwfl/dwfl_addrdie.c
@@ -0,0 +1,57 @@
+/* Fetch CU DIE from address.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwarf_Die *
+dwfl_addrdie (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias)
+{
+ return INTUSE(dwfl_module_addrdie) (INTUSE(dwfl_addrmodule) (dwfl, addr),
+ addr, bias);
+}
diff --git a/src/libdwfl/dwfl_addrdwarf.c b/src/libdwfl/dwfl_addrdwarf.c
new file mode 100644
index 00000000..365c69c5
--- /dev/null
+++ b/src/libdwfl/dwfl_addrdwarf.c
@@ -0,0 +1,58 @@
+/* Fetch libdw handle from address.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwarf *
+dwfl_addrdwarf (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Addr *bias)
+{
+ return INTUSE(dwfl_module_getdwarf) (INTUSE(dwfl_addrmodule) (dwfl, address),
+ bias);
+}
+INTDEF (dwfl_addrdwarf)
diff --git a/src/libdwfl/dwfl_addrmodule.c b/src/libdwfl/dwfl_addrmodule.c
new file mode 100644
index 00000000..64559436
--- /dev/null
+++ b/src/libdwfl/dwfl_addrmodule.c
@@ -0,0 +1,59 @@
+/* Find module containing address.
+ Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwfl_Module *
+dwfl_addrmodule (Dwfl *dwfl, Dwarf_Addr address)
+{
+ Dwfl_Module *mod;
+ (void) INTUSE(dwfl_addrsegment) (dwfl, address, &mod);
+ return mod;
+}
+INTDEF (dwfl_addrmodule)
diff --git a/src/libdwfl/dwfl_begin.c b/src/libdwfl/dwfl_begin.c
new file mode 100644
index 00000000..d388ee00
--- /dev/null
+++ b/src/libdwfl/dwfl_begin.c
@@ -0,0 +1,72 @@
+/* Set up a session using libdwfl.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwfl *
+dwfl_begin (const Dwfl_Callbacks *callbacks)
+{
+ if (elf_version (EV_CURRENT) == EV_NONE)
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return NULL;
+ }
+
+ Dwfl *dwfl = calloc (1, sizeof *dwfl);
+ if (dwfl == NULL)
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ else
+ {
+ dwfl->callbacks = callbacks;
+ dwfl->offline_next_address = OFFLINE_REDZONE;
+ }
+
+ return dwfl;
+}
+INTDEF (dwfl_begin)
diff --git a/src/libdwfl/dwfl_build_id_find_debuginfo.c b/src/libdwfl/dwfl_build_id_find_debuginfo.c
new file mode 100644
index 00000000..e51b65b1
--- /dev/null
+++ b/src/libdwfl/dwfl_build_id_find_debuginfo.c
@@ -0,0 +1,98 @@
+/* Find the debuginfo file for a module from its build ID.
+ Copyright (C) 2007, 2009 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <unistd.h>
+
+
+int
+dwfl_build_id_find_debuginfo (Dwfl_Module *mod,
+ void **userdata __attribute__ ((unused)),
+ const char *modname __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)),
+ const char *file __attribute__ ((unused)),
+ const char *debuglink __attribute__ ((unused)),
+ GElf_Word crc __attribute__ ((unused)),
+ char **debuginfo_file_name)
+{
+ int fd = -1;
+ const unsigned char *bits;
+ GElf_Addr vaddr;
+ if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
+ fd = __libdwfl_open_by_build_id (mod, true, debuginfo_file_name);
+ if (fd >= 0)
+ {
+ /* We need to open an Elf handle on the file so we can check its
+ build ID note for validation. Backdoor the handle into the
+ module data structure since we had to open it early anyway. */
+ Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, true, false);
+ if (error != DWFL_E_NOERROR)
+ __libdwfl_seterrno (error);
+ else if (likely (__libdwfl_find_build_id (mod, false,
+ mod->debug.elf) == 2))
+ {
+ /* Also backdoor the gratuitous flag. */
+ mod->debug.valid = true;
+ return fd;
+ }
+ else
+ {
+ /* A mismatch! */
+ elf_end (mod->debug.elf);
+ mod->debug.elf = NULL;
+ close (fd);
+ fd = -1;
+ }
+ free (*debuginfo_file_name);
+ *debuginfo_file_name = NULL;
+ errno = 0;
+ }
+ return fd;
+}
+INTDEF (dwfl_build_id_find_debuginfo)
diff --git a/src/libdwfl/dwfl_build_id_find_elf.c b/src/libdwfl/dwfl_build_id_find_elf.c
new file mode 100644
index 00000000..12ce1b58
--- /dev/null
+++ b/src/libdwfl/dwfl_build_id_find_elf.c
@@ -0,0 +1,180 @@
+/* Find an ELF file for a module from its build ID.
+ Copyright (C) 2007-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <inttypes.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+int
+internal_function
+__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
+{
+ /* If *FILE_NAME was primed into the module, leave it there
+ as the fallback when we have nothing to offer. */
+ errno = 0;
+ if (mod->build_id_len <= 0)
+ return -1;
+
+ const size_t id_len = mod->build_id_len;
+ const uint8_t *id = mod->build_id_bits;
+
+ /* Search debuginfo_path directories' .build-id/ subdirectories. */
+
+ char id_name[sizeof "/.build-id/" + 1 + id_len * 2 + sizeof ".debug" - 1];
+ strcpy (id_name, "/.build-id/");
+ int n = snprintf (&id_name[sizeof "/.build-id/" - 1],
+ 4, "%02" PRIx8 "/", (uint8_t) id[0]);
+ assert (n == 3);
+ for (size_t i = 1; i < id_len; ++i)
+ {
+ n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2],
+ 3, "%02" PRIx8, (uint8_t) id[i]);
+ assert (n == 2);
+ }
+ if (debug)
+ strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2],
+ ".debug");
+
+ const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
+#if defined(__BIONIC__) || defined(__APPLE__)
+ char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
+ ?: DEFAULT_DEBUGINFO_PATH);
+#else
+ char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
+ ?: DEFAULT_DEBUGINFO_PATH);
+#endif
+
+ int fd = -1;
+ char *dir;
+ while (fd < 0 && (dir = strsep (&path, ":")) != NULL)
+ {
+ if (dir[0] == '+' || dir[0] == '-')
+ ++dir;
+
+ /* Only absolute directory names are useful to us. */
+ if (dir[0] != '/')
+ continue;
+
+ size_t dirlen = strlen (dir);
+ char *name = malloc (dirlen + sizeof id_name);
+ if (unlikely (name == NULL))
+ break;
+ memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name);
+
+ fd = TEMP_FAILURE_RETRY (open64 (name, O_RDONLY));
+ if (fd >= 0)
+ {
+ if (*file_name != NULL)
+ free (*file_name);
+ *file_name = canonicalize_file_name (name);
+ if (*file_name == NULL)
+ {
+ *file_name = name;
+ name = NULL;
+ }
+ }
+ free (name);
+ }
+
+#if defined(__BIONIC__) || defined(__APPLE__)
+ free(path);
+#endif
+
+ /* If we simply found nothing, clear errno. If we had some other error
+ with the file, report that. Possibly this should treat other errors
+ like ENOENT too. But ignoring all errors could mask some that should
+ be reported. */
+ if (fd < 0 && errno == ENOENT)
+ errno = 0;
+
+ return fd;
+}
+
+int
+dwfl_build_id_find_elf (Dwfl_Module *mod,
+ void **userdata __attribute__ ((unused)),
+ const char *modname __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)),
+ char **file_name, Elf **elfp)
+{
+ *elfp = NULL;
+ int fd = __libdwfl_open_by_build_id (mod, false, file_name);
+ if (fd >= 0)
+ {
+ Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false);
+ if (error != DWFL_E_NOERROR)
+ __libdwfl_seterrno (error);
+ else if (__libdwfl_find_build_id (mod, false, *elfp) == 2)
+ {
+ /* This is a backdoor signal to short-circuit the ID refresh. */
+ mod->main.valid = true;
+ return fd;
+ }
+ else
+ {
+ /* This file does not contain the ID it should! */
+ elf_end (*elfp);
+ *elfp = NULL;
+ close (fd);
+ fd = -1;
+ }
+ free (*file_name);
+ *file_name = NULL;
+ }
+ else if (errno == 0 && mod->build_id_len > 0)
+ /* Setting this with no file yet loaded is a marker that
+ the build ID is authoritative even if we also know a
+ putative *FILE_NAME. */
+ mod->main.valid = true;
+
+ return fd;
+}
+INTDEF (dwfl_build_id_find_elf)
diff --git a/src/libdwfl/dwfl_cumodule.c b/src/libdwfl/dwfl_cumodule.c
new file mode 100644
index 00000000..787c098f
--- /dev/null
+++ b/src/libdwfl/dwfl_cumodule.c
@@ -0,0 +1,57 @@
+/* Find the module for a CU DIE previously returned by libdwfl.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwfl_Module *
+dwfl_cumodule (Dwarf_Die *cudie)
+{
+ struct dwfl_cu *cu = (struct dwfl_cu *) cudie;
+ return cu->mod;
+}
diff --git a/src/libdwfl/dwfl_dwarf_line.c b/src/libdwfl/dwfl_dwarf_line.c
new file mode 100644
index 00000000..eb085e4a
--- /dev/null
+++ b/src/libdwfl/dwfl_dwarf_line.c
@@ -0,0 +1,64 @@
+/* Get information from a source line record returned by libdwfl.
+ Copyright (C) 2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/libdwP.h"
+
+Dwarf_Line *
+dwfl_dwarf_line (Dwfl_Line *line, Dwarf_Addr *bias)
+{
+ if (line == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu = dwfl_linecu (line);
+ const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx];
+
+ *bias = dwfl_adjusted_dwarf_addr (cu->mod, 0);
+ return (Dwarf_Line *) info;
+}
diff --git a/src/libdwfl/dwfl_end.c b/src/libdwfl/dwfl_end.c
new file mode 100644
index 00000000..429abb13
--- /dev/null
+++ b/src/libdwfl/dwfl_end.c
@@ -0,0 +1,71 @@
+/* Finish a session using libdwfl.
+ Copyright (C) 2005, 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+void
+dwfl_end (Dwfl *dwfl)
+{
+ if (dwfl == NULL)
+ return;
+
+ free (dwfl->lookup_addr);
+ free (dwfl->lookup_module);
+ free (dwfl->lookup_segndx);
+
+ Dwfl_Module *next = dwfl->modulelist;
+ while (next != NULL)
+ {
+ Dwfl_Module *dead = next;
+ next = dead->next;
+ __libdwfl_module_free (dead);
+ }
+
+ free (dwfl);
+}
diff --git a/src/libdwfl/dwfl_error.c b/src/libdwfl/dwfl_error.c
new file mode 100644
index 00000000..966c9901
--- /dev/null
+++ b/src/libdwfl/dwfl_error.c
@@ -0,0 +1,189 @@
+/* Error handling in libdwfl.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <libintl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "libdwflP.h"
+
+
+/* The error number. */
+#ifdef __APPLE__
+static int global_error;
+#else
+static __thread int global_error;
+#endif
+
+
+int
+dwfl_errno (void)
+{
+ int result = global_error;
+ global_error = DWFL_E_NOERROR;
+ return result;
+}
+INTDEF (dwfl_errno)
+
+
+static const struct msgtable
+{
+#define DWFL_ERROR(name, text) char msg_##name[sizeof text];
+ DWFL_ERRORS
+#undef DWFL_ERROR
+} msgtable =
+ {
+#define DWFL_ERROR(name, text) text,
+ DWFL_ERRORS
+#undef DWFL_ERROR
+ };
+#define msgstr (&msgtable.msg_NOERROR[0])
+
+static const uint_fast16_t msgidx[] =
+{
+#define DWFL_ERROR(name, text) \
+ [DWFL_E_##name] = offsetof (struct msgtable, msg_##name),
+ DWFL_ERRORS
+#undef DWFL_ERROR
+};
+#define nmsgidx (sizeof msgidx / sizeof msgidx[0])
+
+
+static inline int
+canonicalize (Dwfl_Error error)
+{
+ unsigned int value;
+
+ switch (error)
+ {
+ default:
+ value = error;
+ if ((value &~ 0xffff) != 0)
+ break;
+ assert (value < nmsgidx);
+ break;
+ case DWFL_E_ERRNO:
+ value = DWFL_E (ERRNO, errno);
+ break;
+ case DWFL_E_LIBELF:
+ value = DWFL_E (LIBELF, elf_errno ());
+ break;
+ case DWFL_E_LIBDW:
+ value = DWFL_E (LIBDW, INTUSE(dwarf_errno) ());
+ break;
+#if 0
+ DWFL_E_LIBEBL:
+ value = DWFL_E (LIBEBL, ebl_errno ());
+ break;
+#endif
+ }
+
+ return value;
+}
+
+int
+internal_function
+__libdwfl_canon_error (Dwfl_Error error)
+{
+ return canonicalize (error);
+}
+
+void
+internal_function
+__libdwfl_seterrno (Dwfl_Error error)
+{
+ global_error = canonicalize (error);
+}
+
+
+const char *
+dwfl_errmsg (error)
+ int error;
+{
+ if (error == 0 || error == -1)
+ {
+ int last_error = global_error;
+
+ if (error == 0 && last_error == 0)
+ return NULL;
+
+ error = last_error;
+ global_error = DWFL_E_NOERROR;
+ }
+
+ switch (error &~ 0xffff)
+ {
+ case OTHER_ERROR (ERRNO):
+#ifdef __BIONIC__
+ strerror_r (error & 0xffff, "bad", 0);
+ return "bad";
+#else
+ return strerror_r (error & 0xffff, "bad", 0);
+#endif
+ case OTHER_ERROR (LIBELF):
+ return elf_errmsg (error & 0xffff);
+ case OTHER_ERROR (LIBDW):
+ return INTUSE(dwarf_errmsg) (error & 0xffff);
+#if 0
+ case OTHER_ERROR (LIBEBL):
+ return ebl_errmsg (error & 0xffff);
+#endif
+ }
+
+ return _(&msgstr[msgidx[(unsigned int) error < nmsgidx
+ ? error : DWFL_E_UNKNOWN_ERROR]]);
+}
+INTDEF (dwfl_errmsg)
diff --git a/src/libdwfl/dwfl_getdwarf.c b/src/libdwfl/dwfl_getdwarf.c
new file mode 100644
index 00000000..0a0656f7
--- /dev/null
+++ b/src/libdwfl/dwfl_getdwarf.c
@@ -0,0 +1,80 @@
+/* Iterate through modules to fetch Dwarf information.
+ Copyright (C) 2005, 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+struct module_callback_info
+{
+ int (*callback) (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ Dwarf *, Dwarf_Addr, void *);
+ void *arg;
+};
+
+static int
+module_callback (Dwfl_Module *mod, void **userdata,
+ const char *name, Dwarf_Addr start, void *arg)
+{
+ const struct module_callback_info *info = arg;
+ Dwarf_Addr bias = 0;
+ Dwarf *dw = INTUSE(dwfl_module_getdwarf) (mod, &bias);
+ return (*info->callback) (mod, userdata, name, start, dw, bias, info->arg);
+}
+
+ptrdiff_t
+dwfl_getdwarf (Dwfl *dwfl,
+ int (*callback) (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ Dwarf *, Dwarf_Addr, void *),
+ void *arg,
+ ptrdiff_t offset)
+{
+ struct module_callback_info info = { callback, arg };
+ return INTUSE(dwfl_getmodules) (dwfl, &module_callback, &info, offset);
+}
diff --git a/src/libdwfl/dwfl_getmodules.c b/src/libdwfl/dwfl_getmodules.c
new file mode 100644
index 00000000..7c6ab971
--- /dev/null
+++ b/src/libdwfl/dwfl_getmodules.c
@@ -0,0 +1,113 @@
+/* Iterate through modules.
+ Copyright (C) 2005, 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+ptrdiff_t
+dwfl_getmodules (Dwfl *dwfl,
+ int (*callback) (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr, void *),
+ void *arg,
+ ptrdiff_t offset)
+{
+ if (dwfl == NULL)
+ return -1;
+
+ /* We iterate through the linked list when it's all we have.
+ But continuing from an offset is slow that way. So when
+ DWFL->lookup_module is populated, we can instead keep our
+ place by jumping directly into the array. Since the actions
+ of a callback could cause it to get populated, we must
+ choose the style of place-holder when we return an offset,
+ and we encode the choice in the low bits of that value. */
+
+ Dwfl_Module *m = dwfl->modulelist;
+
+ if ((offset & 3) == 1)
+ {
+ offset >>= 2;
+ for (ptrdiff_t pos = 0; pos < offset; ++pos)
+ if (m == NULL)
+ return -1;
+ else
+ m = m->next;
+ }
+ else if (((offset & 3) == 2) && likely (dwfl->lookup_module != NULL))
+ {
+ offset >>= 2;
+
+ if ((size_t) offset - 1 == dwfl->lookup_elts)
+ return 0;
+
+ if (unlikely ((size_t) offset - 1 > dwfl->lookup_elts))
+ return -1;
+
+ m = dwfl->lookup_module[offset - 1];
+ if (unlikely (m == NULL))
+ return -1;
+ }
+ else if (offset != 0)
+ {
+ __libdwfl_seterrno (DWFL_E_BADSTROFF);
+ return -1;
+ }
+
+ while (m != NULL)
+ {
+ int ok = (*callback) (MODCB_ARGS (m), arg);
+ ++offset;
+ m = m->next;
+ if (ok != DWARF_CB_OK)
+ return ((dwfl->lookup_module == NULL) ? ((offset << 2) | 1)
+ : (((m == NULL ? (ptrdiff_t) dwfl->lookup_elts + 1
+ : m->segment + 1) << 2) | 2));
+ }
+ return 0;
+}
+INTDEF (dwfl_getmodules)
diff --git a/src/libdwfl/dwfl_getsrc.c b/src/libdwfl/dwfl_getsrc.c
new file mode 100644
index 00000000..1cc16953
--- /dev/null
+++ b/src/libdwfl/dwfl_getsrc.c
@@ -0,0 +1,57 @@
+/* Find source location for PC address.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwfl_Line *
+dwfl_getsrc (Dwfl *dwfl, Dwarf_Addr addr)
+{
+ return INTUSE(dwfl_module_getsrc) (INTUSE(dwfl_addrmodule) (dwfl, addr),
+ addr);
+}
diff --git a/src/libdwfl/dwfl_getsrclines.c b/src/libdwfl/dwfl_getsrclines.c
new file mode 100644
index 00000000..790481fd
--- /dev/null
+++ b/src/libdwfl/dwfl_getsrclines.c
@@ -0,0 +1,69 @@
+/* Fetch source line information for CU.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+int
+dwfl_getsrclines (Dwarf_Die *cudie, size_t *nlines)
+{
+ struct dwfl_cu *cu = (struct dwfl_cu *) cudie;
+
+ if (cu->lines == NULL)
+ {
+ Dwfl_Error error = __libdwfl_cu_getsrclines (cu);
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return -1;
+ }
+ }
+
+ *nlines = cu->die.cu->lines->nlines;
+ return -1;
+}
diff --git a/src/libdwfl/dwfl_line_comp_dir.c b/src/libdwfl/dwfl_line_comp_dir.c
new file mode 100644
index 00000000..a755524d
--- /dev/null
+++ b/src/libdwfl/dwfl_line_comp_dir.c
@@ -0,0 +1,64 @@
+/* Get information from a source line record returned by libdwfl.
+ Copyright (C) 2005, 2006 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <dwarf.h>
+
+const char *
+dwfl_line_comp_dir (Dwfl_Line *line)
+{
+ if (line == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu = dwfl_linecu (line);
+ Dwarf_Attribute attr_mem;
+ return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (&cu->die,
+ DW_AT_comp_dir,
+ &attr_mem));
+}
diff --git a/src/libdwfl/dwfl_linecu.c b/src/libdwfl/dwfl_linecu.c
new file mode 100644
index 00000000..34f5bb10
--- /dev/null
+++ b/src/libdwfl/dwfl_linecu.c
@@ -0,0 +1,62 @@
+/* Fetch the module containing a source line record returned by libdwfl.
+ Copyright (C) 2006 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+#undef dwfl_linecu
+
+Dwarf_Die *
+dwfl_linecu (Dwfl_Line *line)
+{
+ if (line == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu = dwfl_linecu_inline (line);
+ return &cu->die;
+}
diff --git a/src/libdwfl/dwfl_lineinfo.c b/src/libdwfl/dwfl_lineinfo.c
new file mode 100644
index 00000000..6049de84
--- /dev/null
+++ b/src/libdwfl/dwfl_lineinfo.c
@@ -0,0 +1,76 @@
+/* Get information from a source line record returned by libdwfl.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/libdwP.h"
+
+const char *
+dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, int *linep, int *colp,
+ Dwarf_Word *mtime, Dwarf_Word *length)
+{
+ if (line == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu = dwfl_linecu (line);
+ const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx];
+
+ if (addr != NULL)
+ *addr = dwfl_adjusted_dwarf_addr (cu->mod, info->addr);
+ if (linep != NULL)
+ *linep = info->line;
+ if (colp != NULL)
+ *colp = info->column;
+
+ struct Dwarf_Fileinfo_s *file = &info->files->info[info->file];
+ if (mtime != NULL)
+ *mtime = file->mtime;
+ if (length != NULL)
+ *length = file->length;
+ return file->name;
+}
diff --git a/src/libdwfl/dwfl_linemodule.c b/src/libdwfl/dwfl_linemodule.c
new file mode 100644
index 00000000..fb98f837
--- /dev/null
+++ b/src/libdwfl/dwfl_linemodule.c
@@ -0,0 +1,59 @@
+/* Fetch the module containing a source line record returned by libdwfl.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwfl_Module *
+dwfl_linemodule (Dwfl_Line *line)
+{
+ if (line == NULL)
+ return NULL;
+
+ return dwfl_linecu (line)->mod;
+}
diff --git a/src/libdwfl/dwfl_module.c b/src/libdwfl/dwfl_module.c
new file mode 100644
index 00000000..d7e54138
--- /dev/null
+++ b/src/libdwfl/dwfl_module.c
@@ -0,0 +1,226 @@
+/* Maintenance of module list in libdwfl.
+ Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <search.h>
+#include <unistd.h>
+
+static void
+free_cu (struct dwfl_cu *cu)
+{
+ if (cu->lines != NULL)
+ free (cu->lines);
+ free (cu);
+}
+
+static void
+nofree (void *arg __attribute__ ((unused)))
+{
+}
+
+static void
+free_file (struct dwfl_file *file)
+{
+ free (file->name);
+
+ /* Close the fd only on the last reference. */
+ if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
+ close (file->fd);
+}
+
+void
+internal_function
+__libdwfl_module_free (Dwfl_Module *mod)
+{
+ if (mod->lazy_cu_root != NULL)
+ tdestroy (mod->lazy_cu_root, nofree);
+
+ if (mod->aranges != NULL)
+ free (mod->aranges);
+
+ if (mod->cu != NULL)
+ {
+ for (size_t i = 0; i < mod->ncu; ++i)
+ free_cu (mod->cu[i]);
+ free (mod->cu);
+ }
+
+ if (mod->dw != NULL)
+ INTUSE(dwarf_end) (mod->dw);
+
+ if (mod->ebl != NULL)
+ ebl_closebackend (mod->ebl);
+
+ if (mod->debug.elf != mod->main.elf)
+ free_file (&mod->debug);
+ free_file (&mod->main);
+
+ if (mod->build_id_bits != NULL)
+ free (mod->build_id_bits);
+
+ free (mod->name);
+ free (mod);
+}
+
+void
+dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
+{
+ /* The lookup table will be cleared on demand, there is nothing we need
+ to do here. */
+}
+INTDEF (dwfl_report_begin_add)
+
+void
+dwfl_report_begin (Dwfl *dwfl)
+{
+ /* Clear the segment lookup table. */
+ dwfl->lookup_elts = 0;
+
+ for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
+ m->gc = true;
+
+ dwfl->offline_next_address = OFFLINE_REDZONE;
+}
+INTDEF (dwfl_report_begin)
+
+/* Report that a module called NAME spans addresses [START, END).
+ Returns the module handle, either existing or newly allocated,
+ or returns a null pointer for an allocation error. */
+Dwfl_Module *
+dwfl_report_module (Dwfl *dwfl, const char *name,
+ GElf_Addr start, GElf_Addr end)
+{
+ Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
+
+ inline Dwfl_Module *use (Dwfl_Module *mod)
+ {
+ mod->next = *tailp;
+ *tailp = mod;
+
+ if (unlikely (dwfl->lookup_module != NULL))
+ {
+ free (dwfl->lookup_module);
+ dwfl->lookup_module = NULL;
+ }
+
+ return mod;
+ }
+
+ for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
+ {
+ if (m->low_addr == start && m->high_addr == end
+ && !strcmp (m->name, name))
+ {
+ /* This module is still here. Move it to the place in the list
+ after the last module already reported. */
+ *prevp = m->next;
+ m->gc = false;
+ return use (m);
+ }
+
+ if (! m->gc)
+ tailp = &m->next;
+ }
+
+ Dwfl_Module *mod = calloc (1, sizeof *mod);
+ if (mod == NULL)
+ goto nomem;
+
+ mod->name = strdup (name);
+ if (mod->name == NULL)
+ {
+ free (mod);
+ nomem:
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return NULL;
+ }
+
+ mod->low_addr = start;
+ mod->high_addr = end;
+ mod->dwfl = dwfl;
+
+ return use (mod);
+}
+INTDEF (dwfl_report_module)
+
+
+/* Finish reporting the current set of modules to the library.
+ If REMOVED is not null, it's called for each module that
+ existed before but was not included in the current report.
+ Returns a nonzero return value from the callback.
+ DWFL cannot be used until this function has returned zero. */
+int
+dwfl_report_end (Dwfl *dwfl,
+ int (*removed) (Dwfl_Module *, void *,
+ const char *, Dwarf_Addr,
+ void *arg),
+ void *arg)
+{
+ Dwfl_Module **tailp = &dwfl->modulelist;
+ while (*tailp != NULL)
+ {
+ Dwfl_Module *m = *tailp;
+ if (m->gc && removed != NULL)
+ {
+ int result = (*removed) (MODCB_ARGS (m), arg);
+ if (result != 0)
+ return result;
+ }
+ if (m->gc)
+ {
+ *tailp = m->next;
+ __libdwfl_module_free (m);
+ }
+ else
+ tailp = &m->next;
+ }
+
+ return 0;
+}
+INTDEF (dwfl_report_end)
diff --git a/src/libdwfl/dwfl_module_addrdie.c b/src/libdwfl/dwfl_module_addrdie.c
new file mode 100644
index 00000000..2733196f
--- /dev/null
+++ b/src/libdwfl/dwfl_module_addrdie.c
@@ -0,0 +1,66 @@
+/* Fetch the CU DIE for a PC address in a given module.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwarf_Die *
+dwfl_module_addrdie (Dwfl_Module *mod, Dwarf_Addr addr, Dwarf_Addr *bias)
+{
+ if (INTUSE(dwfl_module_getdwarf) (mod, bias) == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu;
+ Dwfl_Error error = __libdwfl_addrcu (mod, addr, &cu);
+ if (likely (error == DWFL_E_NOERROR))
+ return &cu->die;
+
+ __libdwfl_seterrno (error);
+ return NULL;
+}
+INTDEF (dwfl_module_addrdie)
diff --git a/src/libdwfl/dwfl_module_addrname.c b/src/libdwfl/dwfl_module_addrname.c
new file mode 100644
index 00000000..7d365fe2
--- /dev/null
+++ b/src/libdwfl/dwfl_module_addrname.c
@@ -0,0 +1,57 @@
+/* Find debugging and symbol information for a module in libdwfl.
+ Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+const char *
+dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr)
+{
+ GElf_Sym sym;
+ return INTUSE(dwfl_module_addrsym) (mod, addr, &sym, NULL);
+}
diff --git a/src/libdwfl/dwfl_module_addrsym.c b/src/libdwfl/dwfl_module_addrsym.c
new file mode 100644
index 00000000..9ced0cfb
--- /dev/null
+++ b/src/libdwfl/dwfl_module_addrsym.c
@@ -0,0 +1,200 @@
+/* Find debugging and symbol information for a module in libdwfl.
+ Copyright (C) 2005-2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+/* Returns the name of the symbol "closest" to ADDR.
+ Never returns symbols at addresses above ADDR. */
+
+const char *
+dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
+ GElf_Sym *closest_sym, GElf_Word *shndxp)
+{
+ int syments = INTUSE(dwfl_module_getsymtab) (mod);
+ if (syments < 0)
+ return NULL;
+
+ /* Return true iff we consider ADDR to lie in the same section as SYM. */
+ GElf_Word addr_shndx = SHN_UNDEF;
+ inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
+ {
+ /* For absolute symbols and the like, only match exactly. */
+ if (shndx >= SHN_LORESERVE)
+ return sym->st_value == addr;
+
+ /* Figure out what section ADDR lies in. */
+ if (addr_shndx == SHN_UNDEF)
+ {
+ GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
+ Elf_Scn *scn = NULL;
+ addr_shndx = SHN_ABS;
+ while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (likely (shdr != NULL)
+ && mod_addr >= shdr->sh_addr
+ && mod_addr < shdr->sh_addr + shdr->sh_size)
+ {
+ addr_shndx = elf_ndxscn (scn);
+ break;
+ }
+ }
+ }
+
+ return shndx == addr_shndx;
+ }
+
+ /* Keep track of the closest symbol we have seen so far.
+ Here we store only symbols with nonzero st_size. */
+ const char *closest_name = NULL;
+ GElf_Word closest_shndx = SHN_UNDEF;
+
+ /* Keep track of an eligible symbol with st_size == 0 as a fallback. */
+ const char *sizeless_name = NULL;
+ GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF };
+ GElf_Word sizeless_shndx = SHN_UNDEF;
+
+ /* Keep track of the lowest address a relevant sizeless symbol could have. */
+ GElf_Addr min_label = 0;
+
+ /* Look through the symbol table for a matching symbol. */
+ inline void search_table (int start, int end)
+ {
+ for (int i = start; i < end; ++i)
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
+ if (name != NULL && name[0] != '\0'
+ && sym.st_shndx != SHN_UNDEF
+ && sym.st_value <= addr
+ && GELF_ST_TYPE (sym.st_info) != STT_SECTION
+ && GELF_ST_TYPE (sym.st_info) != STT_FILE
+ && GELF_ST_TYPE (sym.st_info) != STT_TLS)
+ {
+ /* Even if we don't choose this symbol, its existence excludes
+ any sizeless symbol (assembly label) that is below its upper
+ bound. */
+ if (sym.st_value + sym.st_size > min_label)
+ min_label = sym.st_value + sym.st_size;
+
+ if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
+ {
+ /* This symbol is a better candidate than the current one
+ if it's closer to ADDR or is global when it was local. */
+ if (closest_name == NULL
+ || closest_sym->st_value < sym.st_value
+ || (GELF_ST_BIND (closest_sym->st_info)
+ < GELF_ST_BIND (sym.st_info)))
+ {
+ if (sym.st_size != 0)
+ {
+ *closest_sym = sym;
+ closest_shndx = shndx;
+ closest_name = name;
+ }
+ else if (closest_name == NULL
+ && sym.st_value >= min_label
+ && same_section (&sym, shndx))
+ {
+ /* Handwritten assembly symbols sometimes have no
+ st_size. If no symbol with proper size includes
+ the address, we'll use the closest one that is in
+ the same section as ADDR. */
+ sizeless_sym = sym;
+ sizeless_shndx = shndx;
+ sizeless_name = name;
+ }
+ }
+ /* When the beginning of its range is no closer,
+ the end of its range might be. But do not
+ replace a global symbol with a local! */
+ else if (sym.st_size != 0
+ && closest_sym->st_value == sym.st_value
+ && closest_sym->st_size > sym.st_size
+ && (GELF_ST_BIND (closest_sym->st_info)
+ <= GELF_ST_BIND (sym.st_info)))
+ {
+ *closest_sym = sym;
+ closest_shndx = shndx;
+ closest_name = name;
+ }
+ }
+ }
+ }
+ }
+
+ /* First go through global symbols. mod->first_global is setup by
+ dwfl_module_getsymtab to the index of the first global symbol in
+ the module's symbol table, or -1 when unknown. All symbols with
+ local binding come first in the symbol table, then all globals. */
+ search_table (mod->first_global < 0 ? 1 : mod->first_global, syments);
+
+ /* If we found nothing searching the global symbols, then try the locals.
+ Unless we have a global sizeless symbol that matches exactly. */
+ if (closest_name == NULL && mod->first_global > 1
+ && (sizeless_name == NULL || sizeless_sym.st_value != addr))
+ search_table (1, mod->first_global);
+
+ /* If we found no proper sized symbol to use, fall back to the best
+ candidate sizeless symbol we found, if any. */
+ if (closest_name == NULL
+ && sizeless_name != NULL && sizeless_sym.st_value >= min_label)
+ {
+ *closest_sym = sizeless_sym;
+ closest_shndx = sizeless_shndx;
+ closest_name = sizeless_name;
+ }
+
+ if (shndxp != NULL)
+ *shndxp = closest_shndx;
+ return closest_name;
+}
+INTDEF (dwfl_module_addrsym)
diff --git a/src/libdwfl/dwfl_module_build_id.c b/src/libdwfl/dwfl_module_build_id.c
new file mode 100644
index 00000000..f9888660
--- /dev/null
+++ b/src/libdwfl/dwfl_module_build_id.c
@@ -0,0 +1,195 @@
+/* Return build ID information for a module.
+ Copyright (C) 2007-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+static int
+found_build_id (Dwfl_Module *mod, bool set,
+ const void *bits, int len, GElf_Addr vaddr)
+{
+ if (!set)
+ /* When checking bits, we do not compare VADDR because the
+ address found in a debuginfo file may not match the main
+ file as modified by prelink. */
+ return 1 + (mod->build_id_len == len
+ && !memcmp (bits, mod->build_id_bits, len));
+
+ void *copy = malloc (len);
+ if (unlikely (copy == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return -1;
+ }
+
+ mod->build_id_bits = memcpy (copy, bits, len);
+ mod->build_id_vaddr = vaddr;
+ mod->build_id_len = len;
+ return len;
+}
+
+#define NO_VADDR ((GElf_Addr) -1l)
+
+static int
+check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr)
+{
+ size_t pos = 0;
+ GElf_Nhdr nhdr;
+ size_t name_pos;
+ size_t desc_pos;
+ while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0)
+ if (nhdr.n_type == NT_GNU_BUILD_ID
+ && nhdr.n_namesz == sizeof "GNU" && !memcmp (data->d_buf + name_pos,
+ "GNU", sizeof "GNU"))
+ return found_build_id (mod, set,
+ data->d_buf + desc_pos, nhdr.n_descsz,
+ data_vaddr == NO_VADDR ? 0
+ : data_vaddr + desc_pos);
+ return 0;
+}
+
+int
+internal_function
+__libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
+{
+ size_t shstrndx = SHN_UNDEF;
+ int result = 0;
+
+ Elf_Scn *scn = elf_nextscn (elf, NULL);
+
+ if (scn == NULL)
+ {
+ /* No sections, have to look for phdrs. */
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ size_t phnum;
+ if (unlikely (ehdr == NULL)
+ || unlikely (elf_getphdrnum (elf, &phnum) != 0))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
+ for (size_t i = 0; result == 0 && i < phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
+ if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
+ result = check_notes (mod, set,
+ elf_getdata_rawchunk (elf,
+ phdr->p_offset,
+ phdr->p_filesz,
+ ELF_T_NHDR),
+ dwfl_adjusted_address (mod, phdr->p_vaddr));
+ }
+ }
+ else
+ do
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
+ {
+ /* Determine the right sh_addr in this module. */
+ GElf_Addr vaddr = 0;
+ if (!(shdr->sh_flags & SHF_ALLOC))
+ vaddr = NO_VADDR;
+ else if (mod->e_type != ET_REL)
+ vaddr = dwfl_adjusted_address (mod, shdr->sh_addr);
+ else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
+ elf_ndxscn (scn), &vaddr))
+ vaddr = NO_VADDR;
+ result = check_notes (mod, set, elf_getdata (scn, NULL), vaddr);
+ }
+ }
+ while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
+
+ return result;
+}
+
+int
+dwfl_module_build_id (Dwfl_Module *mod,
+ const unsigned char **bits, GElf_Addr *vaddr)
+{
+ if (mod == NULL)
+ return -1;
+
+ if (mod->build_id_len == 0 && mod->main.elf != NULL)
+ {
+ /* We have the file, but have not examined it yet. */
+ int result = __libdwfl_find_build_id (mod, true, mod->main.elf);
+ if (result <= 0)
+ {
+ mod->build_id_len = -1; /* Cache negative result. */
+ return result;
+ }
+ }
+
+ if (mod->build_id_len <= 0)
+ return 0;
+
+ *bits = mod->build_id_bits;
+ *vaddr = mod->build_id_vaddr;
+ return mod->build_id_len;
+}
+INTDEF (dwfl_module_build_id)
+NEW_VERSION (dwfl_module_build_id, ELFUTILS_0.138)
+
+#ifdef SHARED
+COMPAT_VERSION (dwfl_module_build_id, ELFUTILS_0.130, vaddr_at_end)
+
+int
+_compat_vaddr_at_end_dwfl_module_build_id (Dwfl_Module *mod,
+ const unsigned char **bits,
+ GElf_Addr *vaddr)
+{
+ int result = INTUSE(dwfl_module_build_id) (mod, bits, vaddr);
+ if (result > 0)
+ *vaddr += (result + 3) & -4;
+ return result;
+}
+#endif
diff --git a/src/libdwfl/dwfl_module_dwarf_cfi.c b/src/libdwfl/dwfl_module_dwarf_cfi.c
new file mode 100644
index 00000000..96e60fbf
--- /dev/null
+++ b/src/libdwfl/dwfl_module_dwarf_cfi.c
@@ -0,0 +1,92 @@
+/* Find DWARF CFI for a module in libdwfl.
+ Copyright (C) 2009-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/cfi.h"
+
+Dwarf_CFI *
+internal_function
+__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot, Dwarf_CFI *cfi)
+{
+ if (cfi != NULL && cfi->ebl == NULL)
+ {
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error == DWFL_E_NOERROR)
+ cfi->ebl = mod->ebl;
+ else
+ {
+ if (slot == &mod->eh_cfi)
+ INTUSE(dwarf_cfi_end) (cfi);
+ __libdwfl_seterrno (error);
+ return NULL;
+ }
+ }
+
+ return *slot = cfi;
+}
+
+Dwarf_CFI *
+dwfl_module_dwarf_cfi (mod, bias)
+ Dwfl_Module *mod;
+ Dwarf_Addr *bias;
+{
+ if (mod == NULL)
+ return NULL;
+
+ if (mod->dwarf_cfi != NULL)
+ {
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
+ return mod->dwarf_cfi;
+ }
+
+ return __libdwfl_set_cfi (mod, &mod->dwarf_cfi,
+ INTUSE(dwarf_getcfi)
+ (INTUSE(dwfl_module_getdwarf) (mod, bias)));
+}
+INTDEF (dwfl_module_dwarf_cfi)
diff --git a/src/libdwfl/dwfl_module_eh_cfi.c b/src/libdwfl/dwfl_module_eh_cfi.c
new file mode 100644
index 00000000..79c8279c
--- /dev/null
+++ b/src/libdwfl/dwfl_module_eh_cfi.c
@@ -0,0 +1,78 @@
+/* Find EH CFI for a module in libdwfl.
+ Copyright (C) 2009-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/cfi.h"
+
+Dwarf_CFI *
+dwfl_module_eh_cfi (mod, bias)
+ Dwfl_Module *mod;
+ Dwarf_Addr *bias;
+{
+ if (mod == NULL)
+ return NULL;
+
+ if (mod->eh_cfi != NULL)
+ {
+ *bias = dwfl_adjusted_address (mod, 0);
+ return mod->eh_cfi;
+ }
+
+ __libdwfl_getelf (mod);
+ if (mod->elferr != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (mod->elferr);
+ return NULL;
+ }
+
+ *bias = dwfl_adjusted_address (mod, 0);
+ return __libdwfl_set_cfi (mod, &mod->eh_cfi,
+ INTUSE(dwarf_getcfi_elf) (mod->main.elf));
+}
+INTDEF (dwfl_module_eh_cfi)
diff --git a/src/libdwfl/dwfl_module_getdwarf.c b/src/libdwfl/dwfl_module_getdwarf.c
new file mode 100644
index 00000000..14fcd550
--- /dev/null
+++ b/src/libdwfl/dwfl_module_getdwarf.c
@@ -0,0 +1,1093 @@
+/* Find debugging and symbol information for a module in libdwfl.
+ Copyright (C) 2005-2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
+
+
+/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
+ When we return success, FILE->elf and FILE->vaddr are set up. */
+static inline Dwfl_Error
+open_elf (Dwfl_Module *mod, struct dwfl_file *file)
+{
+ if (file->elf == NULL)
+ {
+ /* CBFAIL uses errno if it's set, so clear it first in case we don't
+ set it with an open failure below. */
+ errno = 0;
+
+ /* If there was a pre-primed file name left that the callback left
+ behind, try to open that file name. */
+ if (file->fd < 0 && file->name != NULL)
+ file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY));
+
+ if (file->fd < 0)
+ return CBFAIL;
+
+ Dwfl_Error error = __libdw_open_file (&file->fd, &file->elf, true, false);
+ if (error != DWFL_E_NOERROR)
+ return error;
+ }
+ else if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
+ {
+ elf_end (file->elf);
+ file->elf = NULL;
+ close (file->fd);
+ file->fd = -1;
+ return DWFL_E_BADELF;
+ }
+
+ GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
+ if (ehdr == NULL)
+ {
+ elf_error:
+ elf_end (file->elf);
+ file->elf = NULL;
+ close (file->fd);
+ file->fd = -1;
+ return DWFL_E (LIBELF, elf_errno ());
+ }
+
+ if (mod->e_type != ET_REL)
+ {
+ /* In any non-ET_REL file, we compute the "synchronization address".
+
+ We start with the address at the end of the first PT_LOAD
+ segment. When prelink converts REL to RELA in an ET_DYN
+ file, it expands the space between the beginning of the
+ segment and the actual code/data addresses. Since that
+ change wasn't made in the debug file, the distance from
+ p_vaddr to an address of interest (in an st_value or DWARF
+ data) now differs between the main and debug files. The
+ distance from address_sync to an address of interest remains
+ consistent.
+
+ If there are no section headers at all (full stripping), then
+ the end of the first segment is a valid synchronization address.
+ This cannot happen in a prelinked file, since prelink itself
+ relies on section headers for prelinking and for undoing it.
+ (If you do full stripping on a prelinked file, then you get what
+ you deserve--you can neither undo the prelinking, nor expect to
+ line it up with a debug file separated before prelinking.)
+
+ However, when prelink processes an ET_EXEC file, it can do
+ something different. There it juggles the "special" sections
+ (SHT_DYNSYM et al) to make space for the additional prelink
+ special sections. Sometimes it will do this by moving a special
+ section like .dynstr after the real program sections in the first
+ PT_LOAD segment--i.e. to the end. That changes the end address of
+ the segment, so it no longer lines up correctly and is not a valid
+ synchronization address to use. Because of this, we need to apply
+ a different prelink-savvy means to discover the synchronization
+ address when there is a separate debug file and a prelinked main
+ file. That is done in find_debuginfo, below. */
+
+ size_t phnum;
+ if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0))
+ goto elf_error;
+
+ file->vaddr = file->address_sync = 0;
+ for (size_t i = 0; i < phnum; ++i)
+ {
+ GElf_Phdr ph_mem;
+ GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
+ if (unlikely (ph == NULL))
+ goto elf_error;
+ if (ph->p_type == PT_LOAD)
+ {
+ file->vaddr = ph->p_vaddr & -ph->p_align;
+ file->address_sync = ph->p_vaddr + ph->p_memsz;
+ break;
+ }
+ }
+ }
+
+ mod->e_type = ehdr->e_type;
+
+ /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN. */
+ if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr)
+ mod->e_type = ET_DYN;
+
+ return DWFL_E_NOERROR;
+}
+
+/* Find the main ELF file for this module and open libelf on it.
+ When we return success, MOD->main.elf and MOD->main.bias are set up. */
+void
+internal_function
+__libdwfl_getelf (Dwfl_Module *mod)
+{
+ if (mod->main.elf != NULL /* Already done. */
+ || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */
+ return;
+
+ mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
+ &mod->main.name,
+ &mod->main.elf);
+ const bool fallback = mod->main.elf == NULL && mod->main.fd < 0;
+ mod->elferr = open_elf (mod, &mod->main);
+ if (mod->elferr != DWFL_E_NOERROR)
+ return;
+
+ if (!mod->main.valid)
+ {
+ /* Clear any explicitly reported build ID, just in case it was wrong.
+ We'll fetch it from the file when asked. */
+ free (mod->build_id_bits);
+ mod->build_id_bits = NULL;
+ mod->build_id_len = 0;
+ }
+ else if (fallback)
+ {
+ /* We have an authoritative build ID for this module, so
+ don't use a file by name that doesn't match that ID. */
+
+ assert (mod->build_id_len > 0);
+
+ switch (__builtin_expect (__libdwfl_find_build_id (mod, false,
+ mod->main.elf), 2))
+ {
+ case 2:
+ /* Build ID matches as it should. */
+ return;
+
+ case -1: /* ELF error. */
+ mod->elferr = INTUSE(dwfl_errno) ();
+ break;
+
+ case 0: /* File has no build ID note. */
+ case 1: /* FIle has a build ID that does not match. */
+ mod->elferr = DWFL_E_WRONG_ID_ELF;
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* We get here when it was the right ELF file. Clear it out. */
+ elf_end (mod->main.elf);
+ mod->main.elf = NULL;
+ if (mod->main.fd >= 0)
+ {
+ close (mod->main.fd);
+ mod->main.fd = -1;
+ }
+ }
+
+ mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr;
+}
+
+/* Search an ELF file for a ".gnu_debuglink" section. */
+static const char *
+find_debuglink (Elf *elf, GElf_Word *crc)
+{
+ size_t shstrndx;
+ if (elf_getshdrstrndx (elf, &shstrndx) < 0)
+ return NULL;
+
+ 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)
+ return NULL;
+
+ const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
+ if (name == NULL)
+ return NULL;
+
+ if (!strcmp (name, ".gnu_debuglink"))
+ break;
+ }
+
+ if (scn == NULL)
+ return NULL;
+
+ /* Found the .gnu_debuglink section. Extract its contents. */
+ Elf_Data *rawdata = elf_rawdata (scn, NULL);
+ if (rawdata == NULL)
+ return NULL;
+
+ Elf_Data crcdata =
+ {
+ .d_type = ELF_T_WORD,
+ .d_buf = crc,
+ .d_size = sizeof *crc,
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data conv =
+ {
+ .d_type = ELF_T_WORD,
+ .d_buf = rawdata->d_buf + rawdata->d_size - sizeof *crc,
+ .d_size = sizeof *crc,
+ .d_version = EV_CURRENT,
+ };
+
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return NULL;
+
+ Elf_Data *d = gelf_xlatetom (elf, &crcdata, &conv, ehdr->e_ident[EI_DATA]);
+ if (d == NULL)
+ return NULL;
+ assert (d == &crcdata);
+
+ return rawdata->d_buf;
+}
+
+/* If the main file might have been prelinked, then we need to
+ discover the correct synchronization address between the main and
+ debug files. Because of prelink's section juggling, we cannot rely
+ on the address_sync computed from PT_LOAD segments (see open_elf).
+
+ We will attempt to discover a synchronization address based on the
+ section headers instead. But finding a section address that is
+ safe to use requires identifying which sections are SHT_PROGBITS.
+ We can do that in the main file, but in the debug file all the
+ allocated sections have been transformed into SHT_NOBITS so we have
+ lost the means to match them up correctly.
+
+ The only method left to us is to decode the .gnu.prelink_undo
+ section in the prelinked main file. This shows what the sections
+ looked like before prelink juggled them--when they still had a
+ direct correspondence to the debug file. */
+static Dwfl_Error
+find_prelink_address_sync (Dwfl_Module *mod)
+{
+ /* The magic section is only identified by name. */
+ size_t shstrndx;
+ if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)
+ return DWFL_E_LIBELF;
+
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (shdr == NULL))
+ return DWFL_E_LIBELF;
+ if (shdr->sh_type == SHT_PROGBITS
+ && !(shdr->sh_flags & SHF_ALLOC)
+ && shdr->sh_name != 0)
+ {
+ const char *secname = elf_strptr (mod->main.elf, shstrndx,
+ shdr->sh_name);
+ if (unlikely (secname == NULL))
+ return DWFL_E_LIBELF;
+ if (!strcmp (secname, ".gnu.prelink_undo"))
+ break;
+ }
+ }
+
+ if (scn == NULL)
+ /* There was no .gnu.prelink_undo section. */
+ return DWFL_E_NOERROR;
+
+ Elf_Data *undodata = elf_rawdata (scn, NULL);
+ if (unlikely (undodata == NULL))
+ return DWFL_E_LIBELF;
+
+ /* Decode the section. It consists of the original ehdr, phdrs,
+ and shdrs (but omits section 0). */
+
+ union
+ {
+ Elf32_Ehdr e32;
+ Elf64_Ehdr e64;
+ } ehdr;
+ Elf_Data dst =
+ {
+ .d_buf = &ehdr,
+ .d_size = sizeof ehdr,
+ .d_type = ELF_T_EHDR,
+ .d_version = EV_CURRENT
+ };
+ Elf_Data src = *undodata;
+ src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT);
+ src.d_type = ELF_T_EHDR;
+ if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
+ elf_getident (mod->main.elf, NULL)[EI_DATA])
+ == NULL))
+ return DWFL_E_LIBELF;
+
+ size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT);
+ size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT);
+
+ uint_fast16_t phnum;
+ uint_fast16_t shnum;
+ if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ if (ehdr.e32.e_shentsize != shentsize
+ || ehdr.e32.e_phentsize != phentsize)
+ return DWFL_E_BAD_PRELINK;
+ phnum = ehdr.e32.e_phnum;
+ shnum = ehdr.e32.e_shnum;
+ }
+ else
+ {
+ if (ehdr.e64.e_shentsize != shentsize
+ || ehdr.e64.e_phentsize != phentsize)
+ return DWFL_E_BAD_PRELINK;
+ phnum = ehdr.e64.e_phnum;
+ shnum = ehdr.e64.e_shnum;
+ }
+
+ /* Since prelink does not store the zeroth section header in the undo
+ section, it cannot support SHN_XINDEX encoding. */
+ if (unlikely (shnum >= SHN_LORESERVE)
+ || unlikely (undodata->d_size != (src.d_size
+ + phnum * phentsize
+ + (shnum - 1) * shentsize)))
+ return DWFL_E_BAD_PRELINK;
+
+ /* We look at the allocated SHT_PROGBITS (or SHT_NOBITS) sections. (Most
+ every file will have some SHT_PROGBITS sections, but it's possible to
+ have one with nothing but .bss, i.e. SHT_NOBITS.) The special sections
+ that can be moved around have different sh_type values--except for
+ .interp, the section that became the PT_INTERP segment. So we exclude
+ the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr.
+ For this reason, we must examine the phdrs first to find PT_INTERP. */
+
+ GElf_Addr main_interp = 0;
+ {
+ size_t main_phnum;
+ if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum)))
+ return DWFL_E_LIBELF;
+ for (size_t i = 0; i < main_phnum; ++i)
+ {
+ GElf_Phdr phdr;
+ if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL))
+ return DWFL_E_LIBELF;
+ if (phdr.p_type == PT_INTERP)
+ {
+ main_interp = phdr.p_vaddr;
+ break;
+ }
+ }
+ }
+
+ src.d_buf += src.d_size;
+ src.d_type = ELF_T_PHDR;
+ src.d_size = phnum * phentsize;
+
+ GElf_Addr undo_interp = 0;
+ {
+ union
+ {
+ Elf32_Phdr p32[phnum];
+ Elf64_Phdr p64[phnum];
+ } phdr;
+ dst.d_buf = &phdr;
+ dst.d_size = sizeof phdr;
+ if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
+ ehdr.e32.e_ident[EI_DATA]) == NULL))
+ return DWFL_E_LIBELF;
+ if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ if (phdr.p32[i].p_type == PT_INTERP)
+ {
+ undo_interp = phdr.p32[i].p_vaddr;
+ break;
+ }
+ }
+ else
+ {
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ if (phdr.p64[i].p_type == PT_INTERP)
+ {
+ undo_interp = phdr.p64[i].p_vaddr;
+ break;
+ }
+ }
+ }
+
+ if (unlikely ((main_interp == 0) != (undo_interp == 0)))
+ return DWFL_E_BAD_PRELINK;
+
+ src.d_buf += src.d_size;
+ src.d_type = ELF_T_SHDR;
+ src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
+
+ union
+ {
+ Elf32_Shdr s32[shnum - 1];
+ Elf64_Shdr s64[shnum - 1];
+ } shdr;
+ dst.d_buf = &shdr;
+ dst.d_size = sizeof shdr;
+ if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
+ ehdr.e32.e_ident[EI_DATA]) == NULL))
+ return DWFL_E_LIBELF;
+
+ /* Now we can look at the original section headers of the main file
+ before it was prelinked. First we'll apply our method to the main
+ file sections as they are after prelinking, to calculate the
+ synchronization address of the main file. Then we'll apply that
+ same method to the saved section headers, to calculate the matching
+ synchronization address of the debug file.
+
+ The method is to consider SHF_ALLOC sections that are either
+ SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr
+ matches the PT_INTERP p_vaddr. The special sections that can be
+ moved by prelink have other types, except for .interp (which
+ becomes PT_INTERP). The "real" sections cannot move as such, but
+ .bss can be split into .dynbss and .bss, with the total memory
+ image remaining the same but being spread across the two sections.
+ So we consider the highest section end, which still matches up. */
+
+ GElf_Addr highest;
+
+ inline void consider_shdr (GElf_Addr interp,
+ GElf_Word sh_type,
+ GElf_Xword sh_flags,
+ GElf_Addr sh_addr,
+ GElf_Xword sh_size)
+ {
+ if ((sh_flags & SHF_ALLOC)
+ && ((sh_type == SHT_PROGBITS && sh_addr != interp)
+ || sh_type == SHT_NOBITS))
+ {
+ const GElf_Addr sh_end = sh_addr + sh_size;
+ if (sh_end > highest)
+ highest = sh_end;
+ }
+ }
+
+ highest = 0;
+ scn = NULL;
+ while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+ {
+ GElf_Shdr sh_mem;
+ GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem);
+ if (unlikely (sh == NULL))
+ return DWFL_E_LIBELF;
+ consider_shdr (main_interp, sh->sh_type, sh->sh_flags,
+ sh->sh_addr, sh->sh_size);
+ }
+ if (highest > mod->main.vaddr)
+ {
+ mod->main.address_sync = highest;
+
+ highest = 0;
+ if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+ for (size_t i = 0; i < shnum - 1; ++i)
+ consider_shdr (undo_interp, shdr.s32[i].sh_type, shdr.s32[i].sh_flags,
+ shdr.s32[i].sh_addr, shdr.s32[i].sh_size);
+ else
+ for (size_t i = 0; i < shnum - 1; ++i)
+ consider_shdr (undo_interp, shdr.s64[i].sh_type, shdr.s64[i].sh_flags,
+ shdr.s64[i].sh_addr, shdr.s64[i].sh_size);
+
+ if (highest > mod->debug.vaddr)
+ mod->debug.address_sync = highest;
+ else
+ return DWFL_E_BAD_PRELINK;
+ }
+
+ return DWFL_E_NOERROR;
+}
+
+/* Find the separate debuginfo file for this module and open libelf on it.
+ When we return success, MOD->debug is set up. */
+static Dwfl_Error
+find_debuginfo (Dwfl_Module *mod)
+{
+ if (mod->debug.elf != NULL)
+ return DWFL_E_NOERROR;
+
+ GElf_Word debuglink_crc = 0;
+ const char *debuglink_file = find_debuglink (mod->main.elf, &debuglink_crc);
+
+ mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
+ mod->main.name,
+ debuglink_file,
+ debuglink_crc,
+ &mod->debug.name);
+ Dwfl_Error result = open_elf (mod, &mod->debug);
+ if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0)
+ result = find_prelink_address_sync (mod);
+ return result;
+}
+
+
+/* Try to find a symbol table in FILE.
+ Returns DWFL_E_NOERROR if a proper one is found.
+ Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM. */
+static Dwfl_Error
+load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
+ Elf_Scn **symscn, Elf_Scn **xndxscn,
+ size_t *syments, int *first_global, GElf_Word *strshndx)
+{
+ bool symtab = false;
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (file->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr != NULL)
+ switch (shdr->sh_type)
+ {
+ case SHT_SYMTAB:
+ symtab = true;
+ *symscn = scn;
+ *symfile = file;
+ *strshndx = shdr->sh_link;
+ *syments = shdr->sh_size / shdr->sh_entsize;
+ *first_global = shdr->sh_info;
+ if (*xndxscn != NULL)
+ return DWFL_E_NOERROR;
+ break;
+
+ case SHT_DYNSYM:
+ if (symtab)
+ break;
+ /* Use this if need be, but keep looking for SHT_SYMTAB. */
+ *symscn = scn;
+ *symfile = file;
+ *strshndx = shdr->sh_link;
+ *syments = shdr->sh_size / shdr->sh_entsize;
+ break;
+
+ case SHT_SYMTAB_SHNDX:
+ *xndxscn = scn;
+ if (symtab)
+ return DWFL_E_NOERROR;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (symtab)
+ /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */
+ return DWFL_E_NOERROR;
+
+ /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
+ We might have found an SHT_DYNSYM and set *SYMSCN et al though. */
+ *xndxscn = NULL;
+ return DWFL_E_NO_SYMTAB;
+}
+
+
+/* Translate addresses into file offsets.
+ OFFS[*] start out zero and remain zero if unresolved. */
+static void
+find_offsets (Elf *elf, size_t phnum, size_t n,
+ GElf_Addr addrs[n], GElf_Off offs[n])
+{
+ size_t unsolved = n;
+ for (size_t i = 0; i < phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
+ if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
+ for (size_t j = 0; j < n; ++j)
+ if (offs[j] == 0
+ && addrs[j] >= phdr->p_vaddr
+ && addrs[j] - phdr->p_vaddr < phdr->p_filesz)
+ {
+ offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset;
+ if (--unsolved == 0)
+ break;
+ }
+ }
+}
+
+/* Try to find a dynamic symbol table via phdrs. */
+static void
+find_dynsym (Dwfl_Module *mod)
+{
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
+
+ size_t phnum;
+ if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0))
+ return;
+
+ for (size_t i = 0; i < phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
+ if (phdr == NULL)
+ break;
+
+ if (phdr->p_type == PT_DYNAMIC)
+ {
+ /* Examine the dynamic section for the pointers we need. */
+
+ Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
+ phdr->p_offset, phdr->p_filesz,
+ ELF_T_DYN);
+ if (data == NULL)
+ continue;
+
+ enum
+ {
+ i_symtab,
+ i_strtab,
+ i_hash,
+ i_gnu_hash,
+ i_max
+ };
+ GElf_Addr addrs[i_max] = { 0, };
+ GElf_Xword strsz = 0;
+ size_t n = data->d_size / gelf_fsize (mod->main.elf,
+ ELF_T_DYN, 1, EV_CURRENT);
+ for (size_t j = 0; j < n; ++j)
+ {
+ GElf_Dyn dyn_mem;
+ GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
+ if (dyn != NULL)
+ switch (dyn->d_tag)
+ {
+ case DT_SYMTAB:
+ addrs[i_symtab] = dyn->d_un.d_ptr;
+ continue;
+
+ case DT_HASH:
+ addrs[i_hash] = dyn->d_un.d_ptr;
+ continue;
+
+ case DT_GNU_HASH:
+ addrs[i_gnu_hash] = dyn->d_un.d_ptr;
+ continue;
+
+ case DT_STRTAB:
+ addrs[i_strtab] = dyn->d_un.d_ptr;
+ continue;
+
+ case DT_STRSZ:
+ strsz = dyn->d_un.d_val;
+ continue;
+
+ default:
+ continue;
+
+ case DT_NULL:
+ break;
+ }
+ break;
+ }
+
+ /* Translate pointers into file offsets. */
+ GElf_Off offs[i_max] = { 0, };
+ find_offsets (mod->main.elf, phnum, i_max, addrs, offs);
+
+ /* Figure out the size of the symbol table. */
+ if (offs[i_hash] != 0)
+ {
+ /* In the original format, .hash says the size of .dynsym. */
+
+ size_t entsz = SH_ENTSIZE_HASH (ehdr);
+ data = elf_getdata_rawchunk (mod->main.elf,
+ offs[i_hash] + entsz, entsz,
+ entsz == 4 ? ELF_T_WORD
+ : ELF_T_XWORD);
+ if (data != NULL)
+ mod->syments = (entsz == 4
+ ? *(const GElf_Word *) data->d_buf
+ : *(const GElf_Xword *) data->d_buf);
+ }
+ if (offs[i_gnu_hash] != 0 && mod->syments == 0)
+ {
+ /* In the new format, we can derive it with some work. */
+
+ const struct
+ {
+ Elf32_Word nbuckets;
+ Elf32_Word symndx;
+ Elf32_Word maskwords;
+ Elf32_Word shift2;
+ } *header;
+
+ data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
+ sizeof *header, ELF_T_WORD);
+ if (data != NULL)
+ {
+ header = data->d_buf;
+ Elf32_Word nbuckets = header->nbuckets;
+ Elf32_Word symndx = header->symndx;
+ GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
+ + (gelf_getclass (mod->main.elf)
+ * sizeof (Elf32_Word)
+ * header->maskwords));
+
+ data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
+ nbuckets * sizeof (Elf32_Word),
+ ELF_T_WORD);
+ if (data != NULL && symndx < nbuckets)
+ {
+ const Elf32_Word *const buckets = data->d_buf;
+ Elf32_Word maxndx = symndx;
+ for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
+ if (buckets[bucket] > maxndx)
+ maxndx = buckets[bucket];
+
+ GElf_Off hasharr_at = (buckets_at
+ + nbuckets * sizeof (Elf32_Word));
+ hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
+ do
+ {
+ data = elf_getdata_rawchunk (mod->main.elf,
+ hasharr_at,
+ sizeof (Elf32_Word),
+ ELF_T_WORD);
+ if (data != NULL
+ && (*(const Elf32_Word *) data->d_buf & 1u))
+ {
+ mod->syments = maxndx + 1;
+ break;
+ }
+ ++maxndx;
+ hasharr_at += sizeof (Elf32_Word);
+ } while (data != NULL);
+ }
+ }
+ }
+ if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
+ mod->syments = ((offs[i_strtab] - offs[i_symtab])
+ / gelf_fsize (mod->main.elf,
+ ELF_T_SYM, 1, EV_CURRENT));
+
+ if (mod->syments > 0)
+ {
+ mod->symdata = elf_getdata_rawchunk (mod->main.elf,
+ offs[i_symtab],
+ gelf_fsize (mod->main.elf,
+ ELF_T_SYM,
+ mod->syments,
+ EV_CURRENT),
+ ELF_T_SYM);
+ if (mod->symdata != NULL)
+ {
+ mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
+ offs[i_strtab],
+ strsz,
+ ELF_T_BYTE);
+ if (mod->symstrdata == NULL)
+ mod->symdata = NULL;
+ }
+ if (mod->symdata == NULL)
+ mod->symerr = DWFL_E (LIBELF, elf_errno ());
+ else
+ {
+ mod->symfile = &mod->main;
+ mod->symerr = DWFL_E_NOERROR;
+ }
+ return;
+ }
+ }
+ }
+}
+
+/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */
+static void
+find_symtab (Dwfl_Module *mod)
+{
+ if (mod->symdata != NULL /* Already done. */
+ || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */
+ return;
+
+ __libdwfl_getelf (mod);
+ mod->symerr = mod->elferr;
+ if (mod->symerr != DWFL_E_NOERROR)
+ return;
+
+ mod->first_global = -1; /* Unknown, unless explicitly set by load_symtab. */
+
+ /* First see if the main ELF file has the debugging information. */
+ Elf_Scn *symscn = NULL, *xndxscn = NULL;
+ GElf_Word strshndx;
+ mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
+ &xndxscn, &mod->syments, &mod->first_global,
+ &strshndx);
+ switch (mod->symerr)
+ {
+ default:
+ return;
+
+ case DWFL_E_NOERROR:
+ break;
+
+ case DWFL_E_NO_SYMTAB:
+ /* Now we have to look for a separate debuginfo file. */
+ mod->symerr = find_debuginfo (mod);
+ switch (mod->symerr)
+ {
+ default:
+ return;
+
+ case DWFL_E_NOERROR:
+ mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
+ &xndxscn, &mod->syments,
+ &mod->first_global, &strshndx);
+ break;
+
+ case DWFL_E_CB: /* The find_debuginfo hook failed. */
+ mod->symerr = DWFL_E_NO_SYMTAB;
+ break;
+ }
+
+ switch (mod->symerr)
+ {
+ default:
+ return;
+
+ case DWFL_E_NOERROR:
+ break;
+
+ case DWFL_E_NO_SYMTAB:
+ if (symscn != NULL)
+ {
+ /* We still have the dynamic symbol table. */
+ mod->symerr = DWFL_E_NOERROR;
+ break;
+ }
+
+ /* Last ditch, look for dynamic symbols without section headers. */
+ find_dynsym (mod);
+ return;
+ }
+ break;
+ }
+
+ /* This does some sanity checks on the string table section. */
+ if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
+ {
+ elferr:
+ mod->symerr = DWFL_E (LIBELF, elf_errno ());
+ return;
+ }
+
+ /* Cache the data; MOD->syments and MOD->first_global were set above. */
+
+ mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx),
+ NULL);
+ if (mod->symstrdata == NULL)
+ goto elferr;
+
+ if (xndxscn == NULL)
+ mod->symxndxdata = NULL;
+ else
+ {
+ mod->symxndxdata = elf_getdata (xndxscn, NULL);
+ if (mod->symxndxdata == NULL)
+ goto elferr;
+ }
+
+ mod->symdata = elf_getdata (symscn, NULL);
+ if (mod->symdata == NULL)
+ goto elferr;
+}
+
+
+/* Try to open a libebl backend for MOD. */
+Dwfl_Error
+internal_function
+__libdwfl_module_getebl (Dwfl_Module *mod)
+{
+ if (mod->ebl == NULL)
+ {
+ __libdwfl_getelf (mod);
+ if (mod->elferr != DWFL_E_NOERROR)
+ return mod->elferr;
+
+ mod->ebl = ebl_openbackend (mod->main.elf);
+ if (mod->ebl == NULL)
+ return DWFL_E_LIBEBL;
+ }
+ return DWFL_E_NOERROR;
+}
+
+/* Try to start up libdw on DEBUGFILE. */
+static Dwfl_Error
+load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
+{
+ if (mod->e_type == ET_REL && !debugfile->relocated)
+ {
+ const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
+
+ /* The debugging sections have to be relocated. */
+ if (cb->section_address == NULL)
+ return DWFL_E_NOREL;
+
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error != DWFL_E_NOERROR)
+ return error;
+
+ find_symtab (mod);
+ Dwfl_Error result = mod->symerr;
+ if (result == DWFL_E_NOERROR)
+ result = __libdwfl_relocate (mod, debugfile->elf, true);
+ if (result != DWFL_E_NOERROR)
+ return result;
+
+ /* Don't keep the file descriptors around. */
+ if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
+ {
+ close (mod->main.fd);
+ mod->main.fd = -1;
+ }
+ if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
+ {
+ close (debugfile->fd);
+ debugfile->fd = -1;
+ }
+ }
+
+ mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
+ if (mod->dw == NULL)
+ {
+ int err = INTUSE(dwarf_errno) ();
+ return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
+ }
+
+ /* Until we have iterated through all CU's, we might do lazy lookups. */
+ mod->lazycu = 1;
+
+ return DWFL_E_NOERROR;
+}
+
+/* Try to start up libdw on either the main file or the debuginfo file. */
+static void
+find_dw (Dwfl_Module *mod)
+{
+ if (mod->dw != NULL /* Already done. */
+ || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */
+ return;
+
+ __libdwfl_getelf (mod);
+ mod->dwerr = mod->elferr;
+ if (mod->dwerr != DWFL_E_NOERROR)
+ return;
+
+ /* First see if the main ELF file has the debugging information. */
+ mod->dwerr = load_dw (mod, &mod->main);
+ switch (mod->dwerr)
+ {
+ case DWFL_E_NOERROR:
+ mod->debug.elf = mod->main.elf;
+ mod->debug.address_sync = mod->main.address_sync;
+ return;
+
+ case DWFL_E_NO_DWARF:
+ break;
+
+ default:
+ goto canonicalize;
+ }
+
+ /* Now we have to look for a separate debuginfo file. */
+ mod->dwerr = find_debuginfo (mod);
+ switch (mod->dwerr)
+ {
+ case DWFL_E_NOERROR:
+ mod->dwerr = load_dw (mod, &mod->debug);
+ break;
+
+ case DWFL_E_CB: /* The find_debuginfo hook failed. */
+ mod->dwerr = DWFL_E_NO_DWARF;
+ return;
+
+ default:
+ break;
+ }
+
+ canonicalize:
+ mod->dwerr = __libdwfl_canon_error (mod->dwerr);
+}
+
+Dwarf *
+dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
+{
+ if (mod == NULL)
+ return NULL;
+
+ find_dw (mod);
+ if (mod->dwerr == DWFL_E_NOERROR)
+ {
+ /* If dwfl_module_getelf was used previously, then partial apply
+ relocation to miscellaneous sections in the debug file too. */
+ if (mod->e_type == ET_REL
+ && mod->main.relocated && ! mod->debug.relocated)
+ {
+ mod->debug.relocated = true;
+ if (mod->debug.elf != mod->main.elf)
+ (void) __libdwfl_relocate (mod, mod->debug.elf, false);
+ }
+
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
+ return mod->dw;
+ }
+
+ __libdwfl_seterrno (mod->dwerr);
+ return NULL;
+}
+INTDEF (dwfl_module_getdwarf)
+
+int
+dwfl_module_getsymtab (Dwfl_Module *mod)
+{
+ if (mod == NULL)
+ return -1;
+
+ find_symtab (mod);
+ if (mod->symerr == DWFL_E_NOERROR)
+ return mod->syments;
+
+ __libdwfl_seterrno (mod->symerr);
+ return -1;
+}
+INTDEF (dwfl_module_getsymtab)
diff --git a/src/libdwfl/dwfl_module_getelf.c b/src/libdwfl/dwfl_module_getelf.c
new file mode 100644
index 00000000..b4e4a2b7
--- /dev/null
+++ b/src/libdwfl/dwfl_module_getelf.c
@@ -0,0 +1,88 @@
+/* Find debugging and symbol information for a module in libdwfl.
+ Copyright (C) 2009-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Elf *
+dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase)
+{
+ if (mod == NULL)
+ return NULL;
+
+ __libdwfl_getelf (mod);
+ if (mod->elferr == DWFL_E_NOERROR)
+ {
+ if (mod->e_type == ET_REL && ! mod->main.relocated)
+ {
+ /* Before letting them get at the Elf handle,
+ apply all the relocations we know how to. */
+
+ mod->main.relocated = true;
+ if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
+ {
+ (void) __libdwfl_relocate (mod, mod->main.elf, false);
+
+ if (mod->debug.elf == mod->main.elf)
+ mod->debug.relocated = true;
+ else if (mod->debug.elf != NULL && ! mod->debug.relocated)
+ {
+ mod->debug.relocated = true;
+ (void) __libdwfl_relocate (mod, mod->debug.elf, false);
+ }
+ }
+ }
+
+ *loadbase = dwfl_adjusted_address (mod, 0);
+ return mod->main.elf;
+ }
+
+ __libdwfl_seterrno (mod->elferr);
+ return NULL;
+}
+INTDEF (dwfl_module_getelf)
diff --git a/src/libdwfl/dwfl_module_getsrc.c b/src/libdwfl/dwfl_module_getsrc.c
new file mode 100644
index 00000000..be03055e
--- /dev/null
+++ b/src/libdwfl/dwfl_module_getsrc.c
@@ -0,0 +1,99 @@
+/* Find source location for PC address in module.
+ Copyright (C) 2005, 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/libdwP.h"
+
+Dwfl_Line *
+dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr)
+{
+ Dwarf_Addr bias;
+ if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu;
+ Dwfl_Error error = __libdwfl_addrcu (mod, addr, &cu);
+ if (likely (error == DWFL_E_NOERROR))
+ error = __libdwfl_cu_getsrclines (cu);
+ if (likely (error == DWFL_E_NOERROR))
+ {
+ /* Now we look at the module-relative address. */
+ addr -= bias;
+
+ /* The lines are sorted by address, so we can use binary search. */
+ size_t l = 0, u = cu->die.cu->lines->nlines;
+ while (l < u)
+ {
+ size_t idx = (l + u) / 2;
+ if (addr < cu->die.cu->lines->info[idx].addr)
+ u = idx;
+ else if (addr > cu->die.cu->lines->info[idx].addr)
+ l = idx + 1;
+ else
+ return &cu->lines->idx[idx];
+ }
+
+ if (cu->die.cu->lines->nlines > 0)
+ assert (cu->die.cu->lines->info
+ [cu->die.cu->lines->nlines - 1].end_sequence);
+
+ /* If none were equal, the closest one below is what we want.
+ We never want the last one, because it's the end-sequence
+ marker with an address at the high bound of the CU's code. */
+ if (u > 0 && u < cu->die.cu->lines->nlines
+ && addr > cu->die.cu->lines->info[u - 1].addr)
+ return &cu->lines->idx[u - 1];
+
+ error = DWFL_E_ADDR_OUTOFRANGE;
+ }
+
+ __libdwfl_seterrno (error);
+ return NULL;
+}
+INTDEF (dwfl_module_getsrc)
diff --git a/src/libdwfl/dwfl_module_getsrc_file.c b/src/libdwfl/dwfl_module_getsrc_file.c
new file mode 100644
index 00000000..9d0c786b
--- /dev/null
+++ b/src/libdwfl/dwfl_module_getsrc_file.c
@@ -0,0 +1,188 @@
+/* Find matching source locations in a module.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/libdwP.h"
+
+
+int
+dwfl_module_getsrc_file (Dwfl_Module *mod,
+ const char *fname, int lineno, int column,
+ Dwfl_Line ***srcsp, size_t *nsrcs)
+{
+ if (mod == NULL)
+ return -1;
+
+ if (mod->dw == NULL)
+ {
+ Dwarf_Addr bias;
+ if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == 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;
+ Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp;
+
+ struct dwfl_cu *cu = NULL;
+ Dwfl_Error error;
+ while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR
+ && cu != NULL
+ && (error = __libdwfl_cu_getsrclines (cu)) == DWFL_E_NOERROR)
+ {
+ inline const char *INTUSE(dwarf_line_file) (const Dwarf_Line *line)
+ {
+ return line->files->info[line->file].name;
+ }
+ inline Dwarf_Line *dwfl_line (const Dwfl_Line *line)
+ {
+ return &dwfl_linecu (line)->die.cu->lines->info[line->idx];
+ }
+ inline const char *dwfl_line_file (const Dwfl_Line *line)
+ {
+ return INTUSE(dwarf_line_file) (dwfl_line (line));
+ }
+
+ /* 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. */
+ const char *lastfile = NULL;
+ bool lastmatch = false;
+ for (size_t cnt = 0; cnt < cu->die.cu->lines->nlines; ++cnt)
+ {
+ Dwarf_Line *line = &cu->die.cu->lines->info[cnt];
+
+ if (unlikely (line->file >= line->files->nfiles))
+ {
+ __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
+ return -1;
+ }
+ else
+ {
+ const char *file = INTUSE(dwarf_line_file) (line);
+ if (file != lastfile)
+ {
+ /* Match the name with the name the user provided. */
+ lastfile = file;
+ lastmatch = !strcmp (is_basename ? basename (file) : file,
+ fname);
+ }
+ }
+ 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 (dwfl_line_file (match[inner])
+ == INTUSE(dwarf_line_file) (line))
+ break;
+ if (inner < cur_match
+ && (dwfl_line (match[inner])->line != line->line
+ || dwfl_line (match[inner])->line != lineno
+ || (column != 0
+ && (dwfl_line (match[inner])->column != line->column
+ || dwfl_line (match[inner])->column != column))))
+ {
+ /* We know about this file already. If this is a better
+ match for the line number, use it. */
+ if (dwfl_line (match[inner])->line >= line->line
+ && (dwfl_line (match[inner])->line != line->line
+ || dwfl_line (match[inner])->column >= line->column))
+ /* Use the new line. Otherwise the old one. */
+ match[inner] = &cu->lines->idx[cnt];
+ continue;
+ }
+
+ if (cur_match < max_match)
+ {
+ if (cur_match == act_match)
+ {
+ /* Enlarge the array for the results. */
+ act_match += 10;
+ Dwfl_Line **newp = realloc (match,
+ act_match
+ * sizeof (Dwfl_Line *));
+ if (newp == NULL)
+ {
+ free (match);
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return -1;
+ }
+ match = newp;
+ }
+
+ match[cur_match++] = &cu->lines->idx[cnt];
+ }
+ }
+ }
+
+ if (cur_match > 0)
+ {
+ assert (*nsrcs == 0 || *srcsp == match);
+
+ *nsrcs = cur_match;
+ *srcsp = match;
+
+ return 0;
+ }
+
+ __libdwfl_seterrno (DWFL_E_NO_MATCH);
+ return -1;
+}
diff --git a/src/libdwfl/dwfl_module_getsym.c b/src/libdwfl/dwfl_module_getsym.c
new file mode 100644
index 00000000..6bc063bb
--- /dev/null
+++ b/src/libdwfl/dwfl_module_getsym.c
@@ -0,0 +1,128 @@
+/* Find debugging and symbol information for a module in libdwfl.
+ Copyright (C) 2006-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+const char *
+dwfl_module_getsym (Dwfl_Module *mod, int ndx,
+ GElf_Sym *sym, GElf_Word *shndxp)
+{
+ if (unlikely (mod == NULL))
+ return NULL;
+
+ if (unlikely (mod->symdata == NULL))
+ {
+ int result = INTUSE(dwfl_module_getsymtab) (mod);
+ if (result < 0)
+ return NULL;
+ }
+
+ GElf_Word shndx;
+ sym = gelf_getsymshndx (mod->symdata, mod->symxndxdata, ndx, sym, &shndx);
+ if (unlikely (sym == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return NULL;
+ }
+
+ if (sym->st_shndx != SHN_XINDEX)
+ shndx = sym->st_shndx;
+
+ /* Figure out whether this symbol points into an SHF_ALLOC section. */
+ bool alloc = true;
+ if ((shndxp != NULL || mod->e_type != ET_REL)
+ && (sym->st_shndx == SHN_XINDEX
+ || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF)))
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (elf_getscn (mod->symfile->elf, shndx),
+ &shdr_mem);
+ alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
+ }
+
+ if (shndxp != NULL)
+ /* Yield -1 in case of a non-SHF_ALLOC section. */
+ *shndxp = alloc ? shndx : (GElf_Word) -1;
+
+ switch (sym->st_shndx)
+ {
+ case SHN_ABS: /* XXX sometimes should use bias?? */
+ case SHN_UNDEF:
+ case SHN_COMMON:
+ break;
+
+ default:
+ if (mod->e_type == ET_REL)
+ {
+ /* In an ET_REL file, the symbol table values are relative
+ to the section, not to the module's load base. */
+ size_t symshstrndx = SHN_UNDEF;
+ Dwfl_Error result = __libdwfl_relocate_value (mod, mod->symfile->elf,
+ &symshstrndx,
+ shndx, &sym->st_value);
+ if (unlikely (result != DWFL_E_NOERROR))
+ {
+ __libdwfl_seterrno (result);
+ return NULL;
+ }
+ }
+ else if (alloc)
+ /* Apply the bias to the symbol value. */
+ sym->st_value = dwfl_adjusted_st_value (mod, sym->st_value);
+ break;
+ }
+
+ if (unlikely (sym->st_name >= mod->symstrdata->d_size))
+ {
+ __libdwfl_seterrno (DWFL_E_BADSTROFF);
+ return NULL;
+ }
+ return (const char *) mod->symstrdata->d_buf + sym->st_name;
+}
+INTDEF (dwfl_module_getsym)
diff --git a/src/libdwfl/dwfl_module_info.c b/src/libdwfl/dwfl_module_info.c
new file mode 100644
index 00000000..bfde6fc1
--- /dev/null
+++ b/src/libdwfl/dwfl_module_info.c
@@ -0,0 +1,82 @@
+/* Return information about a module.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+const char *
+dwfl_module_info (Dwfl_Module *mod, void ***userdata,
+ Dwarf_Addr *start, Dwarf_Addr *end,
+ Dwarf_Addr *dwbias, Dwarf_Addr *symbias,
+ const char **mainfile, const char **debugfile)
+{
+ if (mod == NULL)
+ return NULL;
+
+ if (userdata)
+ *userdata = &mod->userdata;
+ if (start)
+ *start = mod->low_addr;
+ if (end)
+ *end = mod->high_addr;
+
+ if (dwbias)
+ *dwbias = (mod->debug.elf == NULL ? (Dwarf_Addr) -1
+ : dwfl_adjusted_dwarf_addr (mod, 0));
+ if (symbias)
+ *symbias = (mod->symfile == NULL ? (Dwarf_Addr) -1
+ : dwfl_adjusted_st_value (mod, 0));
+
+ if (mainfile)
+ *mainfile = mod->main.name;
+
+ if (debugfile)
+ *debugfile = mod->debug.name;
+
+ return mod->name;
+}
diff --git a/src/libdwfl/dwfl_module_nextcu.c b/src/libdwfl/dwfl_module_nextcu.c
new file mode 100644
index 00000000..1b37d299
--- /dev/null
+++ b/src/libdwfl/dwfl_module_nextcu.c
@@ -0,0 +1,65 @@
+/* Iterate through DWARF compilation units in a module.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwarf_Die *
+dwfl_module_nextcu (Dwfl_Module *mod, Dwarf_Die *lastcu, Dwarf_Addr *bias)
+{
+ if (INTUSE(dwfl_module_getdwarf) (mod, bias) == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu;
+ Dwfl_Error error = __libdwfl_nextcu (mod, (struct dwfl_cu *) lastcu, &cu);
+ if (likely (error == DWFL_E_NOERROR))
+ return &cu->die; /* Same as a cast, so ok for null too. */
+
+ __libdwfl_seterrno (error);
+ return NULL;
+}
diff --git a/src/libdwfl/dwfl_module_register_names.c b/src/libdwfl/dwfl_module_register_names.c
new file mode 100644
index 00000000..79a874a8
--- /dev/null
+++ b/src/libdwfl/dwfl_module_register_names.c
@@ -0,0 +1,100 @@
+/* Enumerate DWARF register numbers and their names.
+ Copyright (C) 2005, 2006 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+
+int
+dwfl_module_register_names (mod, func, arg)
+ Dwfl_Module *mod;
+ int (*func) (void *, int regno, const char *setname,
+ const char *prefix, const char *regname,
+ int bits, int type);
+ void *arg;
+{
+ if (unlikely (mod == NULL))
+ return -1;
+
+ if (unlikely (mod->ebl == NULL))
+ {
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return -1;
+ }
+ }
+
+ int nregs = ebl_register_info (mod->ebl, -1, NULL, 0,
+ NULL, NULL, NULL, NULL);
+ int result = 0;
+ for (int regno = 0; regno < nregs && likely (result == 0); ++regno)
+ {
+ char name[32];
+ const char *setname = NULL;
+ const char *prefix = NULL;
+ int bits = -1;
+ int type = -1;
+ ssize_t len = ebl_register_info (mod->ebl, regno, name, sizeof name,
+ &prefix, &setname, &bits, &type);
+ if (unlikely (len < 0))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBEBL);
+ result = -1;
+ break;
+ }
+ if (likely (len > 0))
+ {
+ assert (len > 1); /* Backend should never yield "". */
+ result = (*func) (arg, regno, setname, prefix, name, bits, type);
+ }
+ }
+
+ return result;
+}
diff --git a/src/libdwfl/dwfl_module_report_build_id.c b/src/libdwfl/dwfl_module_report_build_id.c
new file mode 100644
index 00000000..9a1b14f7
--- /dev/null
+++ b/src/libdwfl/dwfl_module_report_build_id.c
@@ -0,0 +1,101 @@
+/* Report build ID information for a module.
+ Copyright (C) 2007, 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+// XXX vs report changed module: punting old file
+int
+dwfl_module_report_build_id (Dwfl_Module *mod,
+ const unsigned char *bits, size_t len,
+ GElf_Addr vaddr)
+{
+ if (mod == NULL)
+ return -1;
+
+ if (mod->main.elf != NULL)
+ {
+ /* Once we know about a file, we won't take any lies about
+ its contents. The only permissible call is a no-op. */
+
+ if ((size_t) mod->build_id_len == len
+ && (mod->build_id_vaddr == vaddr || vaddr == 0)
+ && !memcmp (bits, mod->build_id_bits, len))
+ return 0;
+
+ __libdwfl_seterrno (DWFL_E_ALREADY_ELF);
+ return -1;
+ }
+
+ if (vaddr != 0 && (vaddr < mod->low_addr || vaddr + len > mod->high_addr))
+ {
+ __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE);
+ return -1;
+ }
+
+ void *copy = NULL;
+ if (len > 0)
+ {
+ copy = malloc (len);
+ if (unlikely (copy == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return -1;
+ }
+ memcpy (copy, bits, len);
+ }
+
+ free (mod->build_id_bits);
+
+ mod->build_id_bits = copy;
+ mod->build_id_len = len;
+ mod->build_id_vaddr = vaddr;
+
+ return 0;
+}
+INTDEF (dwfl_module_report_build_id)
diff --git a/src/libdwfl/dwfl_module_return_value_location.c b/src/libdwfl/dwfl_module_return_value_location.c
new file mode 100644
index 00000000..3d5154e2
--- /dev/null
+++ b/src/libdwfl/dwfl_module_return_value_location.c
@@ -0,0 +1,85 @@
+/* Return location expression to find return value given a function type DIE.
+ Copyright (C) 2005, 2006 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+
+int
+dwfl_module_return_value_location (mod, functypedie, locops)
+ Dwfl_Module *mod;
+ Dwarf_Die *functypedie;
+ const Dwarf_Op **locops;
+{
+ if (mod == NULL)
+ return -1;
+
+ if (mod->ebl == NULL)
+ {
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return -1;
+ }
+ }
+
+ int nops = ebl_return_value_location (mod->ebl, functypedie, locops);
+ if (unlikely (nops < 0))
+ {
+ if (nops == -1)
+ __libdwfl_seterrno (DWFL_E_LIBDW);
+ else if (nops == -2)
+ __libdwfl_seterrno (DWFL_E_WEIRD_TYPE);
+ else
+ __libdwfl_seterrno (DWFL_E_LIBEBL);
+ nops = -1;
+ }
+
+ return nops;
+}
diff --git a/src/libdwfl/dwfl_nextcu.c b/src/libdwfl/dwfl_nextcu.c
new file mode 100644
index 00000000..90862d20
--- /dev/null
+++ b/src/libdwfl/dwfl_nextcu.c
@@ -0,0 +1,103 @@
+/* Iterate through DWARF compilation units across all modules.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwarf_Die *
+dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias)
+{
+ if (dwfl == NULL)
+ return NULL;
+
+ struct dwfl_cu *cu = (struct dwfl_cu *) lastcu;
+ Dwfl_Module *mod;
+
+ if (cu == NULL)
+ {
+ mod = dwfl->modulelist;
+ goto nextmod;
+ }
+ else
+ mod = cu->mod;
+
+ Dwfl_Error error;
+ do
+ {
+ error = __libdwfl_nextcu (mod, cu, &cu);
+ if (error != DWFL_E_NOERROR)
+ break;
+
+ if (cu != NULL)
+ {
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
+ return &cu->die;
+ }
+
+ do
+ {
+ mod = mod->next;
+
+ nextmod:
+ if (mod == NULL)
+ return NULL;
+
+ if (mod->dwerr == DWFL_E_NOERROR
+ && (mod->dw != NULL
+ || INTUSE(dwfl_module_getdwarf) (mod, bias) != NULL))
+ break;
+ }
+ while (mod->dwerr == DWFL_E_NO_DWARF);
+ error = mod->dwerr;
+ }
+ while (error == DWFL_E_NOERROR);
+
+ __libdwfl_seterrno (error);
+ return NULL;
+}
+INTDEF (dwfl_nextcu)
diff --git a/src/libdwfl/dwfl_onesrcline.c b/src/libdwfl/dwfl_onesrcline.c
new file mode 100644
index 00000000..558d2408
--- /dev/null
+++ b/src/libdwfl/dwfl_onesrcline.c
@@ -0,0 +1,77 @@
+/* Return one of the sources lines of a CU.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+Dwfl_Line *
+dwfl_onesrcline (Dwarf_Die *cudie, size_t idx)
+{
+ struct dwfl_cu *cu = (struct dwfl_cu *) cudie;
+
+ if (cudie == NULL)
+ return NULL;
+
+ if (cu->lines == NULL)
+ {
+ Dwfl_Error error = __libdwfl_cu_getsrclines (cu);
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return NULL;
+ }
+ }
+
+ if (idx >= cu->die.cu->lines->nlines)
+ {
+ __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_LINE_IDX));
+ return NULL;
+ }
+
+ return &cu->lines->idx[idx];
+}
diff --git a/src/libdwfl/dwfl_report_elf.c b/src/libdwfl/dwfl_report_elf.c
new file mode 100644
index 00000000..4c4132b1
--- /dev/null
+++ b/src/libdwfl/dwfl_report_elf.c
@@ -0,0 +1,306 @@
+/* Report a module to libdwfl based on ELF program headers.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/* We start every ET_REL module at a moderately aligned boundary.
+ This keeps the low addresses easy to read compared to a layout
+ starting at 0 (as when using -e). It also makes it unlikely
+ that a middle section will have a larger alignment and require
+ rejiggering (see below). */
+#define REL_MIN_ALIGN ((GElf_Xword) 0x100)
+
+Dwfl_Module *
+internal_function
+__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
+ int fd, Elf *elf, GElf_Addr base, bool sanity)
+{
+ GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ {
+ elf_error:
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return NULL;
+ }
+
+ GElf_Addr vaddr = 0;
+ GElf_Addr address_sync = 0;
+ GElf_Addr start = 0, end = 0, bias = 0;
+ switch (ehdr->e_type)
+ {
+ case ET_REL:
+ /* For a relocatable object, we do an arbitrary section layout.
+ By updating the section header in place, we leave the layout
+ information to be found by relocation. */
+
+ start = end = base = (base + REL_MIN_ALIGN - 1) & -REL_MIN_ALIGN;
+
+ bool first = true;
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (shdr == NULL))
+ goto elf_error;
+
+ if (shdr->sh_flags & SHF_ALLOC)
+ {
+ const GElf_Xword align = shdr->sh_addralign ?: 1;
+ const GElf_Addr next = (end + align - 1) & -align;
+ if (shdr->sh_addr == 0
+ /* Once we've started doing layout we have to do it all,
+ unless we just layed out the first section at 0 when
+ it already was at 0. */
+ || (bias == 0 && end > start && end != next))
+ {
+ shdr->sh_addr = next;
+ if (end == base)
+ /* This is the first section assigned a location.
+ Use its aligned address as the module's base. */
+ start = base = shdr->sh_addr;
+ else if (unlikely (base & (align - 1)))
+ {
+ /* If BASE has less than the maximum alignment of
+ any section, we eat more than the optimal amount
+ of padding and so make the module's apparent
+ size come out larger than it would when placed
+ at zero. So reset the layout with a better base. */
+
+ start = end = base = (base + align - 1) & -align;
+ Elf_Scn *prev_scn = NULL;
+ do
+ {
+ prev_scn = elf_nextscn (elf, prev_scn);
+ GElf_Shdr prev_shdr_mem;
+ GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn,
+ &prev_shdr_mem);
+ if (unlikely (prev_shdr == NULL))
+ goto elf_error;
+ if (prev_shdr->sh_flags & SHF_ALLOC)
+ {
+ const GElf_Xword prev_align
+ = prev_shdr->sh_addralign ?: 1;
+
+ prev_shdr->sh_addr
+ = (end + prev_align - 1) & -prev_align;
+ end = prev_shdr->sh_addr + prev_shdr->sh_size;
+
+ if (unlikely (! gelf_update_shdr (prev_scn,
+ prev_shdr)))
+ goto elf_error;
+ }
+ }
+ while (prev_scn != scn);
+ continue;
+ }
+
+ end = shdr->sh_addr + shdr->sh_size;
+ if (likely (shdr->sh_addr != 0)
+ && unlikely (! gelf_update_shdr (scn, shdr)))
+ goto elf_error;
+ }
+ else
+ {
+ /* The address is already assigned. Just track it. */
+ if (first || end < shdr->sh_addr + shdr->sh_size)
+ end = shdr->sh_addr + shdr->sh_size;
+ if (first || bias > shdr->sh_addr)
+ /* This is the lowest address in the module. */
+ bias = shdr->sh_addr;
+
+ if ((shdr->sh_addr - bias + base) & (align - 1))
+ /* This section winds up misaligned using BASE.
+ Adjust BASE upwards to make it congruent to
+ the lowest section address in the file modulo ALIGN. */
+ base = (((base + align - 1) & -align)
+ + (bias & (align - 1)));
+ }
+
+ first = false;
+ }
+ }
+
+ if (bias != 0)
+ {
+ /* The section headers had nonzero sh_addr values. The layout
+ was already done. We've just collected the total span.
+ Now just compute the bias from the requested base. */
+ start = base;
+ end = end - bias + start;
+ bias = start - bias;
+ }
+ break;
+
+ /* Everything else has to have program headers. */
+
+ case ET_EXEC:
+ case ET_CORE:
+ /* An assigned base address is meaningless for these. */
+ base = 0;
+
+ case ET_DYN:
+ default:;
+ size_t phnum;
+ if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
+ goto elf_error;
+ for (size_t i = 0; i < phnum; ++i)
+ {
+ GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
+ if (unlikely (ph == NULL))
+ goto elf_error;
+ if (ph->p_type == PT_LOAD)
+ {
+ vaddr = ph->p_vaddr & -ph->p_align;
+ address_sync = ph->p_vaddr + ph->p_memsz;
+ if ((base & (ph->p_align - 1)) != 0)
+ base = (base + ph->p_align - 1) & -ph->p_align;
+ start = base + (ph->p_vaddr & -ph->p_align);
+ break;
+ }
+ }
+ bias = start - vaddr;
+
+ for (size_t i = phnum; i-- > 0;)
+ {
+ GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
+ if (unlikely (ph == NULL))
+ goto elf_error;
+ if (ph->p_type == PT_LOAD
+ && ph->p_vaddr + ph->p_memsz > 0)
+ {
+ end = base + (ph->p_vaddr + ph->p_memsz);
+ break;
+ }
+ }
+
+ if (end == 0 && sanity)
+ {
+ __libdwfl_seterrno (DWFL_E_NO_PHDR);
+ return NULL;
+ }
+ break;
+ }
+
+ Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end);
+ if (m != NULL)
+ {
+ if (m->main.name == NULL)
+ {
+ m->main.name = strdup (file_name);
+ m->main.fd = fd;
+ }
+ else if ((fd >= 0 && m->main.fd != fd)
+ || strcmp (m->main.name, file_name))
+ {
+ overlap:
+ m->gc = true;
+ __libdwfl_seterrno (DWFL_E_OVERLAP);
+ return NULL;
+ }
+
+ /* Preinstall the open ELF handle for the module. */
+ if (m->main.elf == NULL)
+ {
+ m->main.elf = elf;
+ m->main.vaddr = vaddr;
+ m->main.address_sync = address_sync;
+ m->main_bias = bias;
+ m->e_type = ehdr->e_type;
+ }
+ else
+ {
+ elf_end (elf);
+ if (m->main_bias != bias
+ || m->main.vaddr != vaddr || m->main.address_sync != address_sync)
+ goto overlap;
+ }
+ }
+ return m;
+}
+
+Dwfl_Module *
+dwfl_report_elf (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd, GElf_Addr base)
+{
+ bool closefd = false;
+ if (fd < 0)
+ {
+ closefd = true;
+ fd = open64 (file_name, O_RDONLY);
+ if (fd < 0)
+ {
+ __libdwfl_seterrno (DWFL_E_ERRNO);
+ return NULL;
+ }
+ }
+
+ Elf *elf;
+ Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, false);
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return NULL;
+ }
+
+ Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name,
+ fd, elf, base, true);
+ if (mod == NULL)
+ {
+ elf_end (elf);
+ if (closefd)
+ close (fd);
+ }
+
+ return mod;
+}
+INTDEF (dwfl_report_elf)
diff --git a/src/libdwfl/dwfl_segment_report_module.c b/src/libdwfl/dwfl_segment_report_module.c
new file mode 100644
index 00000000..012a0fde
--- /dev/null
+++ b/src/libdwfl/dwfl_segment_report_module.c
@@ -0,0 +1,673 @@
+/* Sniff out modules from ELF headers visible in memory segments.
+ Copyright (C) 2008-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include "../libelf/libelfP.h" /* For NOTE_ALIGN. */
+#undef _
+#include "libdwflP.h"
+
+#include <elf.h>
+#include <gelf.h>
+#include <inttypes.h>
+#include <sys/param.h>
+#include <alloca.h>
+#include <endian.h>
+
+
+/* A good size for the initial read from memory, if it's not too costly.
+ This more than covers the phdrs and note segment in the average 64-bit
+ binary. */
+
+#define INITIAL_READ 1024
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define MY_ELFDATA ELFDATA2LSB
+#else
+# define MY_ELFDATA ELFDATA2MSB
+#endif
+
+
+/* Return user segment index closest to ADDR but not above it.
+ If NEXT, return the closest to ADDR but not below it. */
+static int
+addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
+{
+ int ndx = -1;
+ do
+ {
+ if (dwfl->lookup_segndx[segment] >= 0)
+ ndx = dwfl->lookup_segndx[segment];
+ if (++segment >= dwfl->lookup_elts - 1)
+ return next ? ndx + 1 : ndx;
+ }
+ while (dwfl->lookup_addr[segment] < addr);
+
+ if (next)
+ {
+ while (dwfl->lookup_segndx[segment] < 0)
+ if (++segment >= dwfl->lookup_elts - 1)
+ return ndx + 1;
+ ndx = dwfl->lookup_segndx[segment];
+ }
+
+ return ndx;
+}
+
+int
+dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
+ Dwfl_Memory_Callback *memory_callback,
+ void *memory_callback_arg,
+ Dwfl_Module_Callback *read_eagerly,
+ void *read_eagerly_arg)
+{
+ size_t segment = ndx;
+
+ if (segment >= dwfl->lookup_elts)
+ segment = dwfl->lookup_elts - 1;
+
+ while (segment > 0
+ && (dwfl->lookup_segndx[segment] > ndx
+ || dwfl->lookup_segndx[segment] == -1))
+ --segment;
+
+ while (dwfl->lookup_segndx[segment] < ndx)
+ if (++segment == dwfl->lookup_elts)
+ return 0;
+
+ GElf_Addr start = dwfl->lookup_addr[segment];
+
+ inline bool segment_read (int segndx,
+ void **buffer, size_t *buffer_available,
+ GElf_Addr addr, size_t minread)
+ {
+ return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
+ addr, minread, memory_callback_arg);
+ }
+
+ inline void release_buffer (void **buffer, size_t *buffer_available)
+ {
+ if (*buffer != NULL)
+ (void) segment_read (-1, buffer, buffer_available, 0, 0);
+ }
+
+ /* First read in the file header and check its sanity. */
+
+ void *buffer = NULL;
+ size_t buffer_available = INITIAL_READ;
+
+ inline int finish (void)
+ {
+ release_buffer (&buffer, &buffer_available);
+ return ndx;
+ }
+
+ if (segment_read (ndx, &buffer, &buffer_available,
+ start, sizeof (Elf64_Ehdr))
+ || memcmp (buffer, ELFMAG, SELFMAG) != 0)
+ return finish ();
+
+ inline bool read_portion (void **data, size_t *data_size,
+ GElf_Addr vaddr, size_t filesz)
+ {
+ if (vaddr - start + filesz > buffer_available)
+ {
+ *data = NULL;
+ *data_size = filesz;
+ return segment_read (addr_segndx (dwfl, segment, vaddr, false),
+ data, data_size, vaddr, filesz);
+ }
+
+ /* We already have this whole note segment from our initial read. */
+ *data = vaddr - start + buffer;
+ *data_size = 0;
+ return false;
+ }
+
+ inline void finish_portion (void **data, size_t *data_size)
+ {
+ if (*data_size != 0)
+ release_buffer (data, data_size);
+ }
+
+ /* Extract the information we need from the file header. */
+ union
+ {
+ Elf32_Ehdr e32;
+ Elf64_Ehdr e64;
+ } ehdr;
+ GElf_Off phoff;
+ uint_fast16_t phnum;
+ uint_fast16_t phentsize;
+ GElf_Off shdrs_end;
+ Elf_Data xlatefrom =
+ {
+ .d_type = ELF_T_EHDR,
+ .d_buf = (void *) buffer,
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data xlateto =
+ {
+ .d_type = ELF_T_EHDR,
+ .d_buf = &ehdr,
+ .d_size = sizeof ehdr,
+ .d_version = EV_CURRENT,
+ };
+ switch (((const unsigned char *) buffer)[EI_CLASS])
+ {
+ case ELFCLASS32:
+ xlatefrom.d_size = sizeof (Elf32_Ehdr);
+ if (elf32_xlatetom (&xlateto, &xlatefrom,
+ ((const unsigned char *) buffer)[EI_DATA]) == NULL)
+ return finish ();
+ phoff = ehdr.e32.e_phoff;
+ phnum = ehdr.e32.e_phnum;
+ phentsize = ehdr.e32.e_phentsize;
+ if (phentsize != sizeof (Elf32_Phdr))
+ return finish ();
+ shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
+ break;
+
+ case ELFCLASS64:
+ xlatefrom.d_size = sizeof (Elf64_Ehdr);
+ if (elf64_xlatetom (&xlateto, &xlatefrom,
+ ((const unsigned char *) buffer)[EI_DATA]) == NULL)
+ return finish ();
+ phoff = ehdr.e64.e_phoff;
+ phnum = ehdr.e64.e_phnum;
+ phentsize = ehdr.e64.e_phentsize;
+ if (phentsize != sizeof (Elf64_Phdr))
+ return finish ();
+ shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
+ break;
+
+ default:
+ return finish ();
+ }
+
+ /* The file header tells where to find the program headers.
+ These are what we need to find the boundaries of the module.
+ Without them, we don't have a module to report. */
+
+ if (phnum == 0)
+ return finish ();
+
+ xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
+ xlatefrom.d_size = phnum * phentsize;
+
+ void *ph_buffer = NULL;
+ size_t ph_buffer_size = 0;
+ if (read_portion (&ph_buffer, &ph_buffer_size,
+ start + phoff, xlatefrom.d_size))
+ return finish ();
+
+ xlatefrom.d_buf = ph_buffer;
+
+ union
+ {
+ Elf32_Phdr p32[phnum];
+ Elf64_Phdr p64[phnum];
+ } phdrs;
+
+ xlateto.d_buf = &phdrs;
+ xlateto.d_size = sizeof phdrs;
+
+ /* Track the bounds of the file visible in memory. */
+ GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */
+ GElf_Off file_end = 0; /* Rounded up to effective page size. */
+ GElf_Off contiguous = 0; /* Visible as contiguous file from START. */
+ GElf_Off total_filesz = 0; /* Total size of data to read. */
+
+ /* Collect the bias between START and the containing PT_LOAD's p_vaddr. */
+ GElf_Addr bias = 0;
+ bool found_bias = false;
+
+ /* Collect the unbiased bounds of the module here. */
+ GElf_Addr module_start = -1l;
+ GElf_Addr module_end = 0;
+ GElf_Addr module_address_sync = 0;
+
+ /* If we see PT_DYNAMIC, record it here. */
+ GElf_Addr dyn_vaddr = 0;
+ GElf_Xword dyn_filesz = 0;
+
+ /* Collect the build ID bits here. */
+ void *build_id = NULL;
+ size_t build_id_len = 0;
+ GElf_Addr build_id_vaddr = 0;
+
+ /* Consider a PT_NOTE we've found in the image. */
+ inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
+ {
+ /* If we have already seen a build ID, we don't care any more. */
+ if (build_id != NULL || filesz == 0)
+ return;
+
+ void *data;
+ size_t data_size;
+ if (read_portion (&data, &data_size, vaddr, filesz))
+ return;
+
+ assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
+
+ void *notes;
+ if (ehdr.e32.e_ident[EI_DATA] == MY_ELFDATA)
+ notes = data;
+ else
+ {
+ notes = malloc (filesz);
+ if (unlikely (notes == NULL))
+ return;
+ xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
+ xlatefrom.d_buf = (void *) data;
+ xlatefrom.d_size = filesz;
+ xlateto.d_buf = notes;
+ xlateto.d_size = filesz;
+ if (elf32_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) == NULL)
+ goto done;
+ }
+
+ const GElf_Nhdr *nh = notes;
+ while ((const void *) nh < (const void *) notes + filesz)
+ {
+ const void *note_name = nh + 1;
+ const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
+ if (unlikely ((size_t) ((const void *) notes + filesz
+ - note_desc) < nh->n_descsz))
+ break;
+
+ if (nh->n_type == NT_GNU_BUILD_ID
+ && nh->n_descsz > 0
+ && nh->n_namesz == sizeof "GNU"
+ && !memcmp (note_name, "GNU", sizeof "GNU"))
+ {
+ build_id_vaddr = note_desc - (const void *) notes + vaddr;
+ build_id_len = nh->n_descsz;
+ build_id = malloc (nh->n_descsz);
+ if (likely (build_id != NULL))
+ memcpy (build_id, note_desc, build_id_len);
+ break;
+ }
+
+ nh = note_desc + NOTE_ALIGN (nh->n_descsz);
+ }
+
+ done:
+ if (notes != data)
+ free (notes);
+ finish_portion (&data, &data_size);
+ }
+
+ /* Consider each of the program headers we've read from the image. */
+ inline void consider_phdr (GElf_Word type,
+ GElf_Addr vaddr, GElf_Xword memsz,
+ GElf_Off offset, GElf_Xword filesz,
+ GElf_Xword align)
+ {
+ switch (type)
+ {
+ case PT_DYNAMIC:
+ dyn_vaddr = vaddr;
+ dyn_filesz = filesz;
+ break;
+
+ case PT_NOTE:
+ /* We calculate from the p_offset of the note segment,
+ because we don't yet know the bias for its p_vaddr. */
+ consider_notes (start + offset, filesz);
+ break;
+
+ case PT_LOAD:
+ align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
+
+ GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
+ GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
+ GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
+
+ if (file_trimmed_end < offset + filesz)
+ {
+ file_trimmed_end = offset + filesz;
+
+ /* Trim the last segment so we don't bother with zeros
+ in the last page that are off the end of the file.
+ However, if the extra bit in that page includes the
+ section headers, keep them. */
+ if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
+ {
+ filesz += shdrs_end - file_trimmed_end;
+ file_trimmed_end = shdrs_end;
+ }
+ }
+
+ total_filesz += filesz;
+
+ if (file_end < filesz_offset)
+ {
+ file_end = filesz_offset;
+ if (filesz_vaddr - start == filesz_offset)
+ contiguous = file_end;
+ }
+
+ if (!found_bias && (offset & -align) == 0
+ && likely (filesz_offset >= phoff + phnum * phentsize))
+ {
+ bias = start - vaddr;
+ found_bias = true;
+ }
+
+ if ((vaddr & -align) < module_start)
+ {
+ module_start = vaddr & -align;
+ module_address_sync = vaddr + memsz;
+ }
+
+ if (module_end < vaddr_end)
+ module_end = vaddr_end;
+ break;
+ }
+ }
+ if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ if (elf32_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) == NULL)
+ found_bias = false; /* Trigger error check. */
+ else
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ consider_phdr (phdrs.p32[i].p_type,
+ phdrs.p32[i].p_vaddr, phdrs.p32[i].p_memsz,
+ phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz,
+ phdrs.p32[i].p_align);
+ }
+ else
+ {
+ if (elf64_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) == NULL)
+ found_bias = false; /* Trigger error check. */
+ else
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ consider_phdr (phdrs.p64[i].p_type,
+ phdrs.p64[i].p_vaddr, phdrs.p64[i].p_memsz,
+ phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz,
+ phdrs.p64[i].p_align);
+ }
+
+ finish_portion (&ph_buffer, &ph_buffer_size);
+
+ /* We must have seen the segment covering offset 0, or else the ELF
+ header we read at START was not produced by these program headers. */
+ if (unlikely (!found_bias))
+ return finish ();
+
+ /* Now we know enough to report a module for sure: its bounds. */
+ module_start += bias;
+ module_end += bias;
+
+ dyn_vaddr += bias;
+
+ /* Our return value now says to skip the segments contained
+ within the module. */
+ ndx = addr_segndx (dwfl, segment, module_end, true);
+
+ /* Examine its .dynamic section to get more interesting details.
+ If it has DT_SONAME, we'll use that as the module name.
+ If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
+ We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
+ and they also tell us the essential portion of the file
+ for fetching symbols. */
+ GElf_Addr soname_stroff = 0;
+ GElf_Addr dynstr_vaddr = 0;
+ GElf_Xword dynstrsz = 0;
+ bool execlike = false;
+ inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
+ {
+ switch (tag)
+ {
+ default:
+ return false;
+
+ case DT_DEBUG:
+ execlike = true;
+ break;
+
+ case DT_SONAME:
+ soname_stroff = val;
+ break;
+
+ case DT_STRTAB:
+ dynstr_vaddr = val;
+ break;
+
+ case DT_STRSZ:
+ dynstrsz = val;
+ break;
+ }
+
+ return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
+ }
+
+ const size_t dyn_entsize = (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32
+ ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
+ void *dyn_data = NULL;
+ size_t dyn_data_size = 0;
+ if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
+ && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
+ {
+ union
+ {
+ Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
+ Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
+ } dyn;
+
+ xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
+ xlatefrom.d_buf = (void *) dyn_data;
+ xlatefrom.d_size = dyn_filesz;
+ xlateto.d_buf = &dyn;
+ xlateto.d_size = sizeof dyn;
+
+ if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ if (elf32_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) != NULL)
+ for (size_t i = 0; i < dyn_filesz / sizeof dyn.d32[0]; ++i)
+ if (consider_dyn (dyn.d32[i].d_tag, dyn.d32[i].d_un.d_val))
+ break;
+ }
+ else
+ {
+ if (elf64_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) != NULL)
+ for (size_t i = 0; i < dyn_filesz / sizeof dyn.d64[0]; ++i)
+ if (consider_dyn (dyn.d64[i].d_tag, dyn.d64[i].d_un.d_val))
+ break;
+ }
+ }
+ finish_portion (&dyn_data, &dyn_data_size);
+
+ /* We'll use the name passed in or a stupid default if not DT_SONAME. */
+ if (name == NULL)
+ name = ehdr.e32.e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
+
+ void *soname = NULL;
+ size_t soname_size = 0;
+ if (dynstrsz != 0 && dynstr_vaddr != 0)
+ {
+ /* We know the bounds of the .dynstr section.
+
+ The DYNSTR_VADDR pointer comes from the .dynamic section
+ (DT_STRTAB, detected above). Ordinarily the dynamic linker
+ will have adjusted this pointer in place so it's now an
+ absolute address. But sometimes .dynamic is read-only (in
+ vDSOs and odd architectures), and sometimes the adjustment
+ just hasn't happened yet in the memory image we looked at.
+ So treat DYNSTR_VADDR as an absolute address if it falls
+ within the module bounds, or try applying the phdr bias
+ when that adjusts it to fall within the module bounds. */
+
+ if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
+ && dynstr_vaddr + bias >= module_start
+ && dynstr_vaddr + bias < module_end)
+ dynstr_vaddr += bias;
+
+ if (unlikely (dynstr_vaddr + dynstrsz > module_end))
+ dynstrsz = 0;
+
+ /* Try to get the DT_SONAME string. */
+ if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
+ && ! read_portion (&soname, &soname_size,
+ dynstr_vaddr + soname_stroff, 0))
+ name = soname;
+ }
+
+ /* Now that we have chosen the module's name and bounds, report it.
+ If we found a build ID, report that too. */
+
+ Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
+ module_start, module_end);
+ if (likely (mod != NULL) && build_id != NULL
+ && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
+ build_id,
+ build_id_len,
+ build_id_vaddr)))
+ {
+ mod->gc = true;
+ mod = NULL;
+ }
+
+ /* At this point we do not need BUILD_ID or NAME any more.
+ They have been copied. */
+ free (build_id);
+ finish_portion (&soname, &soname_size);
+
+ if (unlikely (mod == NULL))
+ {
+ ndx = -1;
+ return finish ();
+ }
+
+ /* We have reported the module. Now let the caller decide whether we
+ should read the whole thing in right now. */
+
+ const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
+ : buffer_available >= contiguous ? 0
+ : contiguous - buffer_available);
+ const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
+ : dynstr_vaddr + dynstrsz - start);
+ const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
+
+ Elf *elf = NULL;
+ if ((*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
+ cost, worthwhile, whole, contiguous,
+ read_eagerly_arg, &elf)
+ && elf == NULL)
+ {
+ /* The caller wants to read the whole file in right now, but hasn't
+ done it for us. Fill in a local image of the virtual file. */
+
+ void *contents = calloc (1, file_trimmed_end);
+ if (unlikely (contents == NULL))
+ return finish ();
+
+ inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
+ {
+ void *into = contents + offset;
+ size_t read_size = size;
+ (void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
+ &into, &read_size, vaddr, size);
+ }
+
+ if (contiguous < file_trimmed_end)
+ {
+ /* We can't use the memory image verbatim as the file image.
+ So we'll be reading into a local image of the virtual file. */
+
+ inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
+ GElf_Off offset, GElf_Xword filesz)
+ {
+ if (type == PT_LOAD)
+ final_read (offset, vaddr + bias, filesz);
+ }
+
+ if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ read_phdr (phdrs.p32[i].p_type, phdrs.p32[i].p_vaddr,
+ phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz);
+ else
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ read_phdr (phdrs.p64[i].p_type, phdrs.p64[i].p_vaddr,
+ phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz);
+ }
+ else
+ {
+ /* The whole file sits contiguous in memory,
+ but the caller didn't want to just do it. */
+
+ const size_t have = MIN (buffer_available, file_trimmed_end);
+ memcpy (contents, buffer, have);
+
+ if (have < file_trimmed_end)
+ final_read (have, start + have, file_trimmed_end - have);
+ }
+
+ elf = elf_memory (contents, file_trimmed_end);
+ if (unlikely (elf == NULL))
+ free (contents);
+ else
+ elf->flags |= ELF_F_MALLOCED;
+ }
+
+ if (elf != NULL)
+ {
+ /* Install the file in the module. */
+ mod->main.elf = elf;
+ mod->main.vaddr = module_start - bias;
+ mod->main.address_sync = module_address_sync;
+ }
+
+ return finish ();
+}
diff --git a/src/libdwfl/dwfl_validate_address.c b/src/libdwfl/dwfl_validate_address.c
new file mode 100644
index 00000000..81073762
--- /dev/null
+++ b/src/libdwfl/dwfl_validate_address.c
@@ -0,0 +1,82 @@
+/* Validate an address and the relocatability of an offset from it.
+ Copyright (C) 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+int
+dwfl_validate_address (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Sword offset)
+{
+ Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, address);
+ if (mod == NULL)
+ return -1;
+
+ Dwarf_Addr relative = address;
+ int idx = INTUSE(dwfl_module_relocate_address) (mod, &relative);
+ if (idx < 0)
+ return -1;
+
+ if (offset != 0)
+ {
+ int offset_idx = -1;
+ relative = address + offset;
+ if (relative >= mod->low_addr && relative <= mod->high_addr)
+ {
+ offset_idx = INTUSE(dwfl_module_relocate_address) (mod, &relative);
+ if (offset_idx < 0)
+ return -1;
+ }
+ if (offset_idx != idx)
+ {
+ __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/libdwfl/dwfl_version.c b/src/libdwfl/dwfl_version.c
new file mode 100644
index 00000000..9c7074c5
--- /dev/null
+++ b/src/libdwfl/dwfl_version.c
@@ -0,0 +1,57 @@
+/* Return implementation's version string suitable for printing.
+ Copyright (C) 2006, 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+const char *
+dwfl_version (dwfl)
+ Dwfl *dwfl __attribute__ ((unused));
+{
+ return PACKAGE_VERSION;
+}
diff --git a/src/libdwfl/elf-from-memory.c b/src/libdwfl/elf-from-memory.c
new file mode 100644
index 00000000..0fb5f8a3
--- /dev/null
+++ b/src/libdwfl/elf-from-memory.c
@@ -0,0 +1,368 @@
+/* Reconstruct an ELF file by reading the segments out of remote memory.
+ Copyright (C) 2005-2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include "../libelf/libelfP.h"
+#undef _
+
+#include "libdwflP.h"
+
+#include <gelf.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Reconstruct an ELF file by reading the segments out of remote memory
+ based on the ELF file header at EHDR_VMA and the ELF program headers it
+ points to. If not null, *LOADBASEP is filled in with the difference
+ between the addresses from which the segments were read, and the
+ addresses the file headers put them at.
+
+ The function READ_MEMORY is called to copy at least MINREAD and at most
+ MAXREAD bytes from the remote memory at target address ADDRESS into the
+ local buffer at DATA; it should return -1 for errors (with code in
+ `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or
+ the number of bytes read if >= MINREAD. ARG is passed through. */
+
+Elf *
+elf_from_remote_memory (GElf_Addr ehdr_vma,
+ GElf_Addr *loadbasep,
+ ssize_t (*read_memory) (void *arg, void *data,
+ GElf_Addr address,
+ size_t minread,
+ size_t maxread),
+ void *arg)
+{
+ /* First read in the file header and check its sanity. */
+
+ const size_t initial_bufsize = 256;
+ unsigned char *buffer = malloc (initial_bufsize);
+ if (buffer == NULL)
+ {
+ no_memory:
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return NULL;
+ }
+
+ ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
+ sizeof (Elf32_Ehdr), initial_bufsize);
+ if (nread <= 0)
+ {
+ read_error:
+ free (buffer);
+ __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
+ return NULL;
+ }
+
+ if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
+ {
+ bad_elf:
+ __libdwfl_seterrno (DWFL_E_BADELF);
+ return NULL;
+ }
+
+ /* Extract the information we need from the file header. */
+
+ union
+ {
+ Elf32_Ehdr e32;
+ Elf64_Ehdr e64;
+ } ehdr;
+ Elf_Data xlatefrom =
+ {
+ .d_type = ELF_T_EHDR,
+ .d_buf = buffer,
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data xlateto =
+ {
+ .d_type = ELF_T_EHDR,
+ .d_buf = &ehdr,
+ .d_size = sizeof ehdr,
+ .d_version = EV_CURRENT,
+ };
+
+ GElf_Off phoff;
+ uint_fast16_t phnum;
+ uint_fast16_t phentsize;
+ GElf_Off shdrs_end;
+
+ switch (buffer[EI_CLASS])
+ {
+ case ELFCLASS32:
+ xlatefrom.d_size = sizeof (Elf32_Ehdr);
+ if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
+ {
+ libelf_error:
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return NULL;
+ }
+ phoff = ehdr.e32.e_phoff;
+ phnum = ehdr.e32.e_phnum;
+ phentsize = ehdr.e32.e_phentsize;
+ if (phentsize != sizeof (Elf32_Phdr) || phnum == 0)
+ goto bad_elf;
+ shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
+ break;
+
+ case ELFCLASS64:
+ xlatefrom.d_size = sizeof (Elf64_Ehdr);
+ if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
+ goto libelf_error;
+ phoff = ehdr.e64.e_phoff;
+ phnum = ehdr.e64.e_phnum;
+ phentsize = ehdr.e64.e_phentsize;
+ if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
+ goto bad_elf;
+ shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
+ break;
+
+ default:
+ goto bad_elf;
+ }
+
+
+ /* The file header tells where to find the program headers.
+ These are what we use to actually choose what to read. */
+
+ xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
+ xlatefrom.d_size = phnum * phentsize;
+
+ if ((size_t) nread >= phoff + phnum * phentsize)
+ /* We already have all the phdrs from the initial read. */
+ xlatefrom.d_buf = buffer + phoff;
+ else
+ {
+ /* Read in the program headers. */
+
+ if (initial_bufsize < phnum * phentsize)
+ {
+ unsigned char *newbuf = realloc (buffer, phnum * phentsize);
+ if (newbuf == NULL)
+ {
+ free (buffer);
+ goto no_memory;
+ }
+ buffer = newbuf;
+ }
+ nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
+ phnum * phentsize, phnum * phentsize);
+ if (nread <= 0)
+ goto read_error;
+
+ xlatefrom.d_buf = buffer;
+ }
+
+ union
+ {
+ Elf32_Phdr p32[phnum];
+ Elf64_Phdr p64[phnum];
+ } phdrs;
+
+ xlateto.d_buf = &phdrs;
+ xlateto.d_size = sizeof phdrs;
+
+ /* Scan for PT_LOAD segments to find the total size of the file image. */
+ size_t contents_size = 0;
+ GElf_Off segments_end = 0;
+ GElf_Addr loadbase = ehdr_vma;
+ bool found_base = false;
+ switch (ehdr.e32.e_ident[EI_CLASS])
+ {
+ inline void handle_segment (GElf_Addr vaddr, GElf_Off offset,
+ GElf_Xword filesz, GElf_Xword align)
+ {
+ GElf_Off segment_end = ((offset + filesz + align - 1) & -align);
+
+ if (segment_end > (GElf_Off) contents_size)
+ contents_size = segment_end;
+
+ if (!found_base && (offset & -align) == 0)
+ {
+ loadbase = ehdr_vma - (vaddr & -align);
+ found_base = true;
+ }
+
+ segments_end = offset + filesz;
+ }
+
+ case ELFCLASS32:
+ if (elf32_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) == NULL)
+ goto libelf_error;
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ if (phdrs.p32[i].p_type == PT_LOAD)
+ handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
+ phdrs.p32[i].p_filesz, phdrs.p32[i].p_align);
+ break;
+
+ case ELFCLASS64:
+ if (elf64_xlatetom (&xlateto, &xlatefrom,
+ ehdr.e64.e_ident[EI_DATA]) == NULL)
+ goto libelf_error;
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ if (phdrs.p64[i].p_type == PT_LOAD)
+ handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
+ phdrs.p64[i].p_filesz, phdrs.p64[i].p_align);
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ /* Trim the last segment so we don't bother with zeros in the last page
+ that are off the end of the file. However, if the extra bit in that
+ page includes the section headers, keep them. */
+ if ((GElf_Off) contents_size > segments_end
+ && (GElf_Off) contents_size >= shdrs_end)
+ {
+ contents_size = segments_end;
+ if ((GElf_Off) contents_size < shdrs_end)
+ contents_size = shdrs_end;
+ }
+ else
+ contents_size = segments_end;
+
+ free (buffer);
+
+ /* Now we know the size of the whole image we want read in. */
+ buffer = calloc (1, contents_size);
+ if (buffer == NULL)
+ goto no_memory;
+
+ switch (ehdr.e32.e_ident[EI_CLASS])
+ {
+ inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
+ GElf_Xword filesz, GElf_Xword align)
+ {
+ GElf_Off start = offset & -align;
+ GElf_Off end = (offset + filesz + align - 1) & -align;
+ if (end > (GElf_Off) contents_size)
+ end = contents_size;
+ nread = (*read_memory) (arg, buffer + start,
+ (loadbase + vaddr) & -align,
+ end - start, end - start);
+ return nread <= 0;
+ }
+
+ case ELFCLASS32:
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ if (phdrs.p32[i].p_type == PT_LOAD)
+ if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
+ phdrs.p32[i].p_filesz, phdrs.p32[i].p_align))
+ goto read_error;
+
+ /* If the segments visible in memory didn't include the section
+ headers, then clear them from the file header. */
+ if (contents_size < shdrs_end)
+ {
+ ehdr.e32.e_shoff = 0;
+ ehdr.e32.e_shnum = 0;
+ ehdr.e32.e_shstrndx = 0;
+ }
+
+ /* This will normally have been in the first PT_LOAD segment. But it
+ conceivably could be missing, and we might have just changed it. */
+ xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
+ xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
+ xlatefrom.d_buf = &ehdr.e32;
+ xlateto.d_buf = buffer;
+ if (elf32_xlatetof (&xlateto, &xlatefrom,
+ ehdr.e32.e_ident[EI_DATA]) == NULL)
+ goto libelf_error;
+ break;
+
+ case ELFCLASS64:
+ for (uint_fast16_t i = 0; i < phnum; ++i)
+ if (phdrs.p32[i].p_type == PT_LOAD)
+ if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
+ phdrs.p64[i].p_filesz, phdrs.p64[i].p_align))
+ goto read_error;
+
+ /* If the segments visible in memory didn't include the section
+ headers, then clear them from the file header. */
+ if (contents_size < shdrs_end)
+ {
+ ehdr.e64.e_shoff = 0;
+ ehdr.e64.e_shnum = 0;
+ ehdr.e64.e_shstrndx = 0;
+ }
+
+ /* This will normally have been in the first PT_LOAD segment. But it
+ conceivably could be missing, and we might have just changed it. */
+ xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
+ xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
+ xlatefrom.d_buf = &ehdr.e64;
+ xlateto.d_buf = buffer;
+ if (elf64_xlatetof (&xlateto, &xlatefrom,
+ ehdr.e64.e_ident[EI_DATA]) == NULL)
+ goto libelf_error;
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ /* Now we have the image. Open libelf on it. */
+
+ Elf *elf = elf_memory ((char *) buffer, contents_size);
+ if (elf == NULL)
+ {
+ free (buffer);
+ goto libelf_error;
+ }
+
+ elf->flags |= ELF_F_MALLOCED;
+ if (loadbasep != NULL)
+ *loadbasep = loadbase;
+ return elf;
+}
diff --git a/src/libdwfl/find-debuginfo.c b/src/libdwfl/find-debuginfo.c
new file mode 100644
index 00000000..12cfe636
--- /dev/null
+++ b/src/libdwfl/find-debuginfo.c
@@ -0,0 +1,315 @@
+/* Standard find_debuginfo callback for libdwfl.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "system.h"
+
+
+/* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1.
+ On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */
+static int
+try_open (const struct stat64 *main_stat,
+ const char *dir, const char *subdir, const char *debuglink,
+ char **debuginfo_file_name)
+{
+ char *fname;
+ if (dir == NULL && subdir == NULL)
+ {
+ fname = strdup (debuglink);
+ if (fname == NULL)
+ return -1;
+ }
+ else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink)
+ : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink)
+ : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0)
+ return -1;
+
+ struct stat64 st;
+ int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
+ if (fd < 0)
+ free (fname);
+ else if (fstat64 (fd, &st) == 0
+ && st.st_ino == main_stat->st_ino
+ && st.st_dev == main_stat->st_dev)
+ {
+ /* This is the main file by another name. Don't look at it again. */
+ close (fd);
+ errno = ENOENT;
+ fd = -1;
+ }
+ else
+ *debuginfo_file_name = fname;
+
+ return fd;
+}
+
+/* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */
+static inline bool
+check_crc (int fd, GElf_Word debuglink_crc)
+{
+ uint32_t file_crc;
+ return (__libdwfl_crc32_file (fd, &file_crc) == 0
+ && file_crc == debuglink_crc);
+}
+
+static bool
+validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
+{
+ /* If we have a build ID, check only that. */
+ if (mod->build_id_len > 0)
+ {
+ /* We need to open an Elf handle on the file so we can check its
+ build ID note for validation. Backdoor the handle into the
+ module data structure since we had to open it early anyway. */
+
+ mod->debug.valid = false;
+ Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
+ if (error != DWFL_E_NOERROR)
+ __libdwfl_seterrno (error);
+ else if (likely (__libdwfl_find_build_id (mod, false,
+ mod->debug.elf) == 2))
+ /* Also backdoor the gratuitous flag. */
+ mod->debug.valid = true;
+ else
+ {
+ /* A mismatch! */
+ elf_end (mod->debug.elf);
+ mod->debug.elf = NULL;
+ close (fd);
+ fd = -1;
+ }
+
+ return mod->debug.valid;
+ }
+
+ return !check || check_crc (fd, debuglink_crc);
+}
+
+static int
+find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
+ const char *debuglink_file, GElf_Word debuglink_crc,
+ char **debuginfo_file_name)
+{
+ bool cancheck = debuglink_crc != (GElf_Word) 0;
+
+ const char *file_basename = file_name == NULL ? NULL : basename (file_name);
+ if (debuglink_file == NULL)
+ {
+ if (file_basename == NULL)
+ {
+ errno = 0;
+ return -1;
+ }
+
+ size_t len = strlen (file_basename);
+ char *localname = alloca (len + sizeof ".debug");
+ memcpy (localname, file_basename, len);
+ memcpy (&localname[len], ".debug", sizeof ".debug");
+ debuglink_file = localname;
+ cancheck = false;
+ }
+
+ /* Look for a file named DEBUGLINK_FILE in the directories
+ indicated by the debug directory path setting. */
+
+ const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
+#if defined(__BIONIC__) || defined(__APPLE__)
+ char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
+ ?: DEFAULT_DEBUGINFO_PATH);
+#else
+ char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
+ ?: DEFAULT_DEBUGINFO_PATH);
+#endif
+
+ /* A leading - or + in the whole path sets whether to check file CRCs. */
+ bool defcheck = true;
+ if (path[0] == '-' || path[0] == '+')
+ {
+ defcheck = path[0] == '+';
+ ++path;
+ }
+
+ /* XXX dev/ino should be cached in struct dwfl_file. */
+ struct stat64 main_stat;
+ if (unlikely ((mod->main.fd != -1 ? fstat64 (mod->main.fd, &main_stat)
+ : file_name != NULL ? stat64 (file_name, &main_stat)
+ : -1) < 0))
+ {
+ main_stat.st_dev = 0;
+ main_stat.st_ino = 0;
+ }
+
+#if defined(__BIONIC__) || defined(__APPLE__)
+ char *file_dirname = (file_basename == file_name ? NULL
+ : strndup (file_name, file_basename - 1 - file_name));
+#else
+ char *file_dirname = (file_basename == file_name ? NULL
+ : strndupa (file_name, file_basename - 1 - file_name));
+#endif
+
+ char *p;
+ while ((p = strsep (&path, ":")) != NULL)
+ {
+ /* A leading - or + says whether to check file CRCs for this element. */
+ bool check = defcheck;
+ if (*p == '+' || *p == '-')
+ check = *p++ == '+';
+ check = check && cancheck;
+
+ const char *dir, *subdir;
+ switch (p[0])
+ {
+ case '\0':
+ /* An empty entry says to try the main file's directory. */
+ dir = file_dirname;
+ subdir = NULL;
+ break;
+ case '/':
+ /* An absolute path says to look there for a subdirectory
+ named by the main file's absolute directory.
+ This cannot be applied to a relative file name. */
+ if (file_dirname == NULL || file_dirname[0] != '/')
+ continue;
+ dir = p;
+ subdir = file_dirname + 1;
+ break;
+ default:
+ /* A relative path says to try a subdirectory of that name
+ in the main file's directory. */
+ dir = file_dirname;
+ subdir = p;
+ break;
+ }
+
+ char *fname = NULL;
+ int fd = try_open (&main_stat, dir, subdir, debuglink_file, &fname);
+ if (fd < 0)
+ switch (errno)
+ {
+ case ENOENT:
+ case ENOTDIR:
+ continue;
+ default:
+#if defined(__BIONIC__) || defined(__APPLE__)
+ free(path);
+ free(file_dirname);
+#endif
+ return -1;
+ }
+ if (validate (mod, fd, check, debuglink_crc))
+ {
+ *debuginfo_file_name = fname;
+#if defined(__BIONIC__) || defined(__APPLE__)
+ free(path);
+ free(file_dirname);
+#endif
+ return fd;
+ }
+ free (fname);
+ close (fd);
+ }
+
+ /* No dice. */
+ errno = 0;
+#if defined(__BIONIC__) || defined(__APPLE__)
+ free(path);
+ free(file_dirname);
+#endif
+ return -1;
+}
+
+int
+dwfl_standard_find_debuginfo (Dwfl_Module *mod,
+ void **userdata __attribute__ ((unused)),
+ const char *modname __attribute__ ((unused)),
+ GElf_Addr base __attribute__ ((unused)),
+ const char *file_name,
+ const char *debuglink_file,
+ GElf_Word debuglink_crc,
+ char **debuginfo_file_name)
+{
+ /* First try by build ID if we have one. If that succeeds or fails
+ other than just by finding nothing, that's all we do. */
+ const unsigned char *bits;
+ GElf_Addr vaddr;
+ if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
+ {
+ int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
+ NULL, NULL, 0,
+ NULL, NULL, 0,
+ debuginfo_file_name);
+ if (fd >= 0 || mod->debug.elf != NULL || errno != 0)
+ return fd;
+ }
+
+ /* Failing that, search the path by name. */
+ int fd = find_debuginfo_in_path (mod, file_name,
+ debuglink_file, debuglink_crc,
+ debuginfo_file_name);
+
+ if (fd < 0 && errno == 0)
+ {
+ /* If FILE_NAME is a symlink, the debug file might be associated
+ with the symlink target name instead. */
+
+ char *canon = canonicalize_file_name (file_name);
+ if (canon != NULL && strcmp (file_name, canon))
+ fd = find_debuginfo_in_path (mod, canon,
+ debuglink_file, debuglink_crc,
+ debuginfo_file_name);
+ free (canon);
+ }
+
+ return fd;
+}
+INTDEF (dwfl_standard_find_debuginfo)
diff --git a/src/libdwfl/gzip.c b/src/libdwfl/gzip.c
new file mode 100644
index 00000000..5604d490
--- /dev/null
+++ b/src/libdwfl/gzip.c
@@ -0,0 +1,316 @@
+/* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
+ Copyright (C) 2009 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "system.h"
+
+#include <unistd.h>
+
+#ifdef LZMA
+# define USE_INFLATE 1
+# include <lzma.h>
+# define unzip __libdw_unlzma
+# define DWFL_E_ZLIB DWFL_E_LZMA
+# define MAGIC "\xFD" "7zXZ\0" /* XZ file format. */
+# define MAGIC2 "\x5d\0" /* Raw LZMA format. */
+# define Z(what) LZMA_##what
+# define LZMA_ERRNO LZMA_PROG_ERROR
+# define z_stream lzma_stream
+# define inflateInit(z) lzma_auto_decoder (z, 1 << 30, 0)
+# define do_inflate(z) lzma_code (z, LZMA_RUN)
+# define inflateEnd(z) lzma_end (z)
+#elif defined BZLIB
+# define USE_INFLATE 1
+# include <bzlib.h>
+# define unzip __libdw_bunzip2
+# define DWFL_E_ZLIB DWFL_E_BZLIB
+# define MAGIC "BZh"
+# define Z(what) BZ_##what
+# define BZ_ERRNO BZ_IO_ERROR
+# define z_stream bz_stream
+# define inflateInit(z) BZ2_bzDecompressInit (z, 0, 0)
+# define do_inflate(z) BZ2_bzDecompress (z)
+# define inflateEnd(z) BZ2_bzDecompressEnd (z)
+#else
+# define USE_INFLATE 0
+# define crc32 loser_crc32
+# include <zlib.h>
+# define unzip __libdw_gunzip
+# define MAGIC "\037\213"
+# define Z(what) Z_##what
+#endif
+
+#define READ_SIZE (1 << 20)
+
+/* If this is not a compressed image, return DWFL_E_BADELF.
+ If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
+ Otherwise return an error for bad compressed data or I/O failure.
+ If we return an error after reading the first part of the file,
+ leave that portion malloc'd in *WHOLE, *WHOLE_SIZE. If *WHOLE
+ is not null on entry, we'll use it in lieu of repeating a read. */
+
+Dwfl_Error internal_function
+unzip (int fd, off64_t start_offset,
+ void *mapped, size_t mapped_size,
+ void **whole, size_t *whole_size)
+{
+ void *buffer = NULL;
+ size_t size = 0;
+ inline bool bigger_buffer (size_t start)
+ {
+ size_t more = size ? size * 2 : start;
+ char *b = realloc (buffer, more);
+ while (unlikely (b == NULL) && more >= size + 1024)
+ b = realloc (buffer, more -= 1024);
+ if (unlikely (b == NULL))
+ return false;
+ buffer = b;
+ size = more;
+ return true;
+ }
+ inline void smaller_buffer (size_t end)
+ {
+ buffer = realloc (buffer, end) ?: end == 0 ? NULL : buffer;
+ size = end;
+ }
+
+ void *input_buffer = NULL;
+ off_t input_pos = 0;
+
+ inline Dwfl_Error fail (Dwfl_Error failure)
+ {
+ if (input_pos == (off_t) mapped_size)
+ *whole = input_buffer;
+ else
+ {
+ free (input_buffer);
+ *whole = NULL;
+ }
+ free (buffer);
+ return failure;
+ }
+
+ inline Dwfl_Error zlib_fail (int result)
+ {
+ switch (result)
+ {
+ case Z (MEM_ERROR):
+ return fail (DWFL_E_NOMEM);
+ case Z (ERRNO):
+ return fail (DWFL_E_ERRNO);
+ default:
+ return fail (DWFL_E_ZLIB);
+ }
+ }
+
+ if (mapped == NULL)
+ {
+ if (*whole == NULL)
+ {
+ input_buffer = malloc (READ_SIZE);
+ if (unlikely (input_buffer == NULL))
+ return DWFL_E_NOMEM;
+
+ ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, start_offset);
+ if (unlikely (n < 0))
+ return zlib_fail (Z (ERRNO));
+
+ input_pos = n;
+ mapped = input_buffer;
+ mapped_size = n;
+ }
+ else
+ {
+ input_buffer = *whole;
+ input_pos = mapped_size = *whole_size;
+ }
+ }
+
+#define NOMAGIC(magic) \
+ (mapped_size <= sizeof magic || memcmp (mapped, magic, sizeof magic - 1))
+
+ /* First, look at the header. */
+ if (NOMAGIC (MAGIC)
+#ifdef MAGIC2
+ && NOMAGIC (MAGIC2)
+#endif
+ )
+ /* Not a compressed file. */
+ return DWFL_E_BADELF;
+
+#if USE_INFLATE
+
+ /* This style actually only works with bzlib and liblzma.
+ The stupid zlib interface has nothing to grok the
+ gzip file headers except the slow gzFile interface. */
+
+ z_stream z = { .next_in = mapped, .avail_in = mapped_size };
+ int result = inflateInit (&z);
+ if (result != Z (OK))
+ {
+ inflateEnd (&z);
+ return zlib_fail (result);
+ }
+
+ do
+ {
+ if (z.avail_in == 0 && input_buffer != NULL)
+ {
+ ssize_t n = pread_retry (fd, input_buffer, READ_SIZE,
+ start_offset + input_pos);
+ if (unlikely (n < 0))
+ {
+ inflateEnd (&z);
+ return zlib_fail (Z (ERRNO));
+ }
+ z.next_in = input_buffer;
+ z.avail_in = n;
+ input_pos += n;
+ }
+ if (z.avail_out == 0)
+ {
+ ptrdiff_t pos = (void *) z.next_out - buffer;
+ if (!bigger_buffer (z.avail_in))
+ {
+ result = Z (MEM_ERROR);
+ break;
+ }
+ z.next_out = buffer + pos;
+ z.avail_out = size - pos;
+ }
+ }
+ while ((result = do_inflate (&z)) == Z (OK));
+
+#ifdef BZLIB
+ uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
+ | z.total_out_lo32);
+ smaller_buffer (total_out);
+#else
+ smaller_buffer (z.total_out);
+#endif
+
+ inflateEnd (&z);
+
+ if (result != Z (STREAM_END))
+ return zlib_fail (result);
+
+#else /* gzip only. */
+
+ /* Let the decompression library read the file directly. */
+
+ gzFile zf;
+ Dwfl_Error open_stream (void)
+ {
+ int d = dup (fd);
+ if (unlikely (d < 0))
+ return DWFL_E_BADELF;
+ if (start_offset != 0)
+ {
+ off64_t off = lseek (d, start_offset, SEEK_SET);
+ if (off != start_offset)
+ {
+ close (d);
+ return DWFL_E_BADELF;
+ }
+ }
+ zf = gzdopen (d, "r");
+ if (unlikely (zf == NULL))
+ {
+ close (d);
+ return zlib_fail (Z (MEM_ERROR));
+ }
+
+ /* From here on, zlib will close D. */
+
+ return DWFL_E_NOERROR;
+ }
+
+ Dwfl_Error result = open_stream ();
+
+ if (result == DWFL_E_NOERROR && gzdirect (zf))
+ {
+ gzclose (zf);
+ return fail (DWFL_E_BADELF);
+ }
+
+ if (result != DWFL_E_NOERROR)
+ return fail (result);
+
+ ptrdiff_t pos = 0;
+ while (1)
+ {
+ if (!bigger_buffer (1024))
+ {
+ gzclose (zf);
+ return zlib_fail (Z (MEM_ERROR));
+ }
+ int n = gzread (zf, buffer + pos, size - pos);
+ if (n < 0)
+ {
+ int code;
+ gzerror (zf, &code);
+ gzclose (zf);
+ return zlib_fail (code);
+ }
+ if (n == 0)
+ break;
+ pos += n;
+ }
+
+ gzclose (zf);
+ smaller_buffer (pos);
+#endif
+
+ free (input_buffer);
+
+ *whole = buffer;
+ *whole_size = size;
+
+ return DWFL_E_NOERROR;
+}
diff --git a/src/libdwfl/image-header.c b/src/libdwfl/image-header.c
new file mode 100644
index 00000000..c36d10c1
--- /dev/null
+++ b/src/libdwfl/image-header.c
@@ -0,0 +1,122 @@
+/* Linux kernel image support for libdwfl.
+ Copyright (C) 2009-2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "system.h"
+
+#include <unistd.h>
+#include <endian.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define LE16(x) (x)
+#else
+# define LE16(x) bswap_16 (x)
+#endif
+
+/* See Documentation/x86/boot.txt in Linux kernel sources
+ for an explanation of these format details. */
+
+#define MAGIC1 0xaa55
+#define MAGIC2 0x53726448 /* "HdrS" little-endian */
+#define MIN_VERSION 0x0208
+
+#define H_START (H_SETUP_SECTS & -4)
+#define H_SETUP_SECTS 0x1f1
+#define H_MAGIC1 0x1fe
+#define H_MAGIC2 0x202
+#define H_VERSION 0x206
+#define H_PAYLOAD_OFFSET 0x248
+#define H_PAYLOAD_LENGTH 0x24c
+#define H_END 0x250
+#define H_READ_SIZE (H_END - H_START)
+
+Dwfl_Error
+internal_function
+__libdw_image_header (int fd, off64_t *start_offset,
+ void *mapped, size_t mapped_size)
+{
+ if (likely (mapped_size > H_END))
+ {
+ const void *header = mapped;
+ char header_buffer[H_READ_SIZE];
+ if (header == NULL)
+ {
+ ssize_t n = pread_retry (fd, header_buffer, H_READ_SIZE,
+ *start_offset + H_START);
+ if (n < 0)
+ return DWFL_E_ERRNO;
+ if (n < H_READ_SIZE)
+ return DWFL_E_BADELF;
+
+ header = header_buffer - H_START;
+ }
+
+ if (*(uint16_t *) (header + H_MAGIC1) == LE16 (MAGIC1)
+ && *(uint32_t *) (header + H_MAGIC2) == LE32 (MAGIC2)
+ && LE16 (*(uint16_t *) (header + H_VERSION)) >= MIN_VERSION)
+ {
+ /* The magic numbers match and the version field is sufficient.
+ Extract the payload bounds. */
+
+ uint32_t offset = LE32 (*(uint32_t *) (header + H_PAYLOAD_OFFSET));
+ uint32_t length = LE32 (*(uint32_t *) (header + H_PAYLOAD_LENGTH));
+
+ offset += ((*(uint8_t *) (header + H_SETUP_SECTS) ?: 4) + 1) * 512;
+
+ if (offset > H_END && offset < mapped_size
+ && mapped_size - offset >= length)
+ {
+ /* It looks kosher. Use it! */
+ *start_offset += offset;
+ return DWFL_E_NOERROR;
+ }
+ }
+ }
+ return DWFL_E_BADELF;
+}
diff --git a/src/libdwfl/libdwfl.h b/src/libdwfl/libdwfl.h
new file mode 100644
index 00000000..4ea2796c
--- /dev/null
+++ b/src/libdwfl/libdwfl.h
@@ -0,0 +1,585 @@
+/* Interfaces for libdwfl.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifndef _LIBDWFL_H
+#define _LIBDWFL_H 1
+
+#include "libdw.h"
+#include <stdio.h>
+
+/* Handle for a session using the library. */
+typedef struct Dwfl Dwfl;
+
+/* Handle for a module. */
+typedef struct Dwfl_Module Dwfl_Module;
+
+/* Handle describing a line record. */
+typedef struct Dwfl_Line Dwfl_Line;
+
+/* Callbacks. */
+typedef struct
+{
+ int (*find_elf) (Dwfl_Module *mod, void **userdata,
+ const char *modname, Dwarf_Addr base,
+ char **file_name, Elf **elfp);
+
+ int (*find_debuginfo) (Dwfl_Module *mod, void **userdata,
+ const char *modname, Dwarf_Addr base,
+ const char *file_name,
+ const char *debuglink_file, GElf_Word debuglink_crc,
+ char **debuginfo_file_name);
+
+ /* Fill *ADDR with the loaded address of the section called SECNAME in
+ the given module. Use (Dwarf_Addr) -1 if this section is omitted from
+ accessible memory. This is called exactly once for each SHF_ALLOC
+ section that relocations affecting DWARF data refer to, so it can
+ easily be used to collect state about the sections referenced. */
+ int (*section_address) (Dwfl_Module *mod, void **userdata,
+ const char *modname, Dwarf_Addr base,
+ const char *secname,
+ GElf_Word shndx, const GElf_Shdr *shdr,
+ Dwarf_Addr *addr);
+
+ char **debuginfo_path; /* See dwfl_standard_find_debuginfo. */
+} Dwfl_Callbacks;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Start a new session with the library. */
+extern Dwfl *dwfl_begin (const Dwfl_Callbacks *callbacks)
+ __nonnull_attribute__ (1);
+
+
+/* End a session. */
+extern void dwfl_end (Dwfl *);
+
+/* Return implementation's version string suitable for printing. */
+extern const char *dwfl_version (Dwfl *);
+
+/* Return error code of last failing function call. This value is kept
+ separately for each thread. */
+extern int dwfl_errno (void);
+
+/* Return error string for ERROR. If ERROR is zero, return error string
+ for most recent error or NULL if 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 *dwfl_errmsg (int err);
+
+
+/* Start reporting the current set of segments and modules to the library.
+ All existing segments are wiped. Existing modules are marked to be
+ deleted, and will not be found via dwfl_addrmodule et al if they are not
+ re-reported before dwfl_report_end is called. */
+extern void dwfl_report_begin (Dwfl *dwfl);
+
+/* Report that segment NDX begins at PHDR->p_vaddr + BIAS.
+ If NDX is < 0, the value succeeding the last call's NDX
+ is used instead (zero on the first call).
+
+ If nonzero, the smallest PHDR->p_align value seen sets the
+ effective page size for the address space DWFL describes.
+ This is the granularity at which reported module boundary
+ addresses will be considered to fall in or out of a segment.
+
+ Returns -1 for errors, or NDX (or its assigned replacement) on success.
+
+ When NDX is the value succeeding the last call's NDX (or is implicitly
+ so as above), IDENT is nonnull and matches the value in the last call,
+ and the PHDR and BIAS values reflect a segment that would be contiguous,
+ in both memory and file, with the last segment reported, then this
+ segment may be coalesced internally with preceding segments. When given
+ an address inside this segment, dwfl_addrsegment may return the NDX of a
+ preceding contiguous segment. To prevent coalesced segments, always
+ pass a null pointer for IDENT.
+
+ The values passed are not stored (except to track coalescence).
+ The only information that can be extracted from DWFL later is the
+ mapping of an address to a segment index that starts at or below
+ it. Reporting segments at all is optional. Its only benefit to
+ the caller is to offer this quick lookup via dwfl_addrsegment,
+ or use other segment-based calls. */
+extern int dwfl_report_segment (Dwfl *dwfl, int ndx,
+ const GElf_Phdr *phdr, GElf_Addr bias,
+ const void *ident);
+
+/* Report that a module called NAME spans addresses [START, END).
+ Returns the module handle, either existing or newly allocated,
+ or returns a null pointer for an allocation error. */
+extern Dwfl_Module *dwfl_report_module (Dwfl *dwfl, const char *name,
+ Dwarf_Addr start, Dwarf_Addr end);
+
+/* Report a module with start and end addresses computed from the ELF
+ program headers in the given file, plus BASE. For an ET_REL file,
+ does a simple absolute section layout starting at BASE.
+ FD may be -1 to open FILE_NAME. On success, FD is consumed by the
+ library, and the `find_elf' callback will not be used for this module. */
+extern Dwfl_Module *dwfl_report_elf (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd,
+ GElf_Addr base);
+
+/* Similar, but report the module for offline use. All ET_EXEC files
+ being reported must be reported before any relocatable objects.
+ If this is used, dwfl_report_module and dwfl_report_elf may not be
+ used in the same reporting session. */
+extern Dwfl_Module *dwfl_report_offline (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd);
+
+
+/* Finish reporting the current set of modules to the library.
+ If REMOVED is not null, it's called for each module that
+ existed before but was not included in the current report.
+ Returns a nonzero return value from the callback.
+ The callback may call dwfl_report_module; doing so with the
+ details of the module being removed prevents its removal.
+ DWFL cannot be used until this function has returned zero. */
+extern int dwfl_report_end (Dwfl *dwfl,
+ int (*removed) (Dwfl_Module *, void *,
+ const char *, Dwarf_Addr,
+ void *arg),
+ void *arg);
+
+/* Start reporting additional modules to the library. No calls but
+ dwfl_report_* can be made on DWFL until dwfl_report_end is called.
+ This is like dwfl_report_begin, but all the old modules are kept on.
+ More dwfl_report_* calls can follow to add more modules.
+ When dwfl_report_end is called, no old modules will be removed. */
+extern void dwfl_report_begin_add (Dwfl *dwfl);
+
+
+/* Return the name of the module, and for each non-null argument store
+ interesting details: *USERDATA is a location for storing your own
+ pointer, **USERDATA is initially null; *START and *END give the address
+ range covered by the module; *DWBIAS is the address bias for debugging
+ information, and *SYMBIAS for symbol table entries (either is -1 if not
+ yet accessed); *MAINFILE is the name of the ELF file, and *DEBUGFILE the
+ name of the debuginfo file (might be equal to *MAINFILE; either is null
+ if not yet accessed). */
+extern const char *dwfl_module_info (Dwfl_Module *mod, void ***userdata,
+ Dwarf_Addr *start, Dwarf_Addr *end,
+ Dwarf_Addr *dwbias, Dwarf_Addr *symbias,
+ const char **mainfile,
+ const char **debugfile);
+
+/* Iterate through the modules, starting the walk with OFFSET == 0.
+ Calls *CALLBACK for each module as long as it returns DWARF_CB_OK.
+ When *CALLBACK returns another value, the walk stops and the
+ return value can be passed as OFFSET to resume it. Returns 0 when
+ there are no more modules, or -1 for errors. */
+extern ptrdiff_t dwfl_getmodules (Dwfl *dwfl,
+ int (*callback) (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ void *arg),
+ void *arg,
+ ptrdiff_t offset);
+
+/* Find the module containing the given address. */
+extern Dwfl_Module *dwfl_addrmodule (Dwfl *dwfl, Dwarf_Addr address);
+
+/* Find the segment, if any, and module, if any, containing ADDRESS.
+ Returns a segment index returned by dwfl_report_segment, or -1
+ if no segment matches the address. Regardless of the return value,
+ *MOD is always set to the module containing ADDRESS, or to null. */
+extern int dwfl_addrsegment (Dwfl *dwfl, Dwarf_Addr address, Dwfl_Module **mod);
+
+
+
+/* Report the known build ID bits associated with a module.
+ If VADDR is nonzero, it gives the absolute address where those
+ bits are found within the module. This can be called at any
+ time, but is usually used immediately after dwfl_report_module.
+ Once the module's main ELF file is opened, the ID note found
+ there takes precedence and cannot be changed. */
+extern int dwfl_module_report_build_id (Dwfl_Module *mod,
+ const unsigned char *bits, size_t len,
+ GElf_Addr vaddr)
+ __nonnull_attribute__ (2);
+
+/* Extract the build ID bits associated with a module.
+ Returns -1 for errors, 0 if no ID is known, or the number of ID bytes.
+ When an ID is found, *BITS points to it; *VADDR is the absolute address
+ at which the ID bits are found within the module, or 0 if unknown.
+
+ This returns 0 when the module's main ELF file has not yet been loaded
+ and its build ID bits were not reported. To ensure the ID is always
+ returned when determinable, call dwfl_module_getelf first. */
+extern int dwfl_module_build_id (Dwfl_Module *mod,
+ const unsigned char **bits, GElf_Addr *vaddr)
+ __nonnull_attribute__ (2, 3);
+
+
+/*** Standard callbacks ***/
+
+/* These standard find_elf and find_debuginfo callbacks are
+ controlled by a string specifying directories to look in.
+ If `debuginfo_path' is set in the Dwfl_Callbacks structure
+ and the char * it points to is not null, that supplies the
+ string. Otherwise a default path is used.
+
+ If the first character of the string is + or - that enables or
+ disables CRC32 checksum validation when it's necessary. The
+ remainder of the string is composed of elements separated by
+ colons. Each element can start with + or - to override the
+ global checksum behavior. This flag is never relevant when
+ working with build IDs, but it's always parsed in the path
+ string. The remainder of the element indicates a directory.
+
+ Searches by build ID consult only the elements naming absolute
+ directory paths. They look under those directories for a link
+ named ".build-id/xx/yy" or ".build-id/xx/yy.debug", where "xxyy"
+ is the lower-case hexadecimal representation of the ID bytes.
+
+ In searches for debuginfo by name, if the remainder of the
+ element is empty, the directory containing the main file is
+ tried; if it's an absolute path name, the absolute directory path
+ containing the main file is taken as a subdirectory of this path;
+ a relative path name is taken as a subdirectory of the directory
+ containing the main file. Hence for /bin/ls, the default string
+ ":.debug:/usr/lib/debug" says to look in /bin, then /bin/.debug,
+ then /usr/lib/debug/bin, for the file name in the .gnu_debuglink
+ section (or "ls.debug" if none was found). */
+
+/* Standard find_elf callback function working solely on build ID.
+ This can be tried first by any find_elf callback, to use the
+ bits passed to dwfl_module_report_build_id, if any. */
+extern int dwfl_build_id_find_elf (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ char **, Elf **);
+
+/* Standard find_debuginfo callback function working solely on build ID.
+ This can be tried first by any find_debuginfo callback,
+ to use the build ID bits from the main file when present. */
+extern int dwfl_build_id_find_debuginfo (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ const char *, const char *,
+ GElf_Word, char **);
+
+/* Standard find_debuginfo callback function.
+ If a build ID is available, this tries first to use that.
+ If there is no build ID or no valid debuginfo found by ID,
+ it searches the debuginfo path by name, as described above.
+ Any file found in the path is validated by build ID if possible,
+ or else by CRC32 checksum if enabled, and skipped if it does not match. */
+extern int dwfl_standard_find_debuginfo (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ const char *, const char *,
+ GElf_Word, char **);
+
+
+/* This callback must be used when using dwfl_offline_* to report modules,
+ if ET_REL is to be supported. */
+extern int dwfl_offline_section_address (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ const char *, GElf_Word,
+ const GElf_Shdr *,
+ Dwarf_Addr *addr);
+
+
+/* Callbacks for working with kernel modules in the running Linux kernel. */
+extern int dwfl_linux_kernel_find_elf (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ char **, Elf **);
+extern int dwfl_linux_kernel_module_section_address (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ const char *, GElf_Word,
+ const GElf_Shdr *,
+ Dwarf_Addr *addr);
+
+/* Call dwfl_report_elf for the running Linux kernel.
+ Returns zero on success, -1 if dwfl_report_module failed,
+ or an errno code if opening the kernel binary failed. */
+extern int dwfl_linux_kernel_report_kernel (Dwfl *dwfl);
+
+/* Call dwfl_report_module for each kernel module in the running Linux kernel.
+ Returns zero on success, -1 if dwfl_report_module failed,
+ or an errno code if reading the list of modules failed. */
+extern int dwfl_linux_kernel_report_modules (Dwfl *dwfl);
+
+/* Report a kernel and its modules found on disk, for offline use.
+ If RELEASE starts with '/', it names a directory to look in;
+ if not, it names a directory to find under /lib/modules/;
+ if null, /lib/modules/`uname -r` is used.
+ Returns zero on success, -1 if dwfl_report_module failed,
+ or an errno code if finding the files on disk failed.
+
+ If PREDICATE is not null, it is called with each module to be reported;
+ its arguments are the module name, and the ELF file name or null if unknown,
+ and its return value should be zero to skip the module, one to report it,
+ or -1 to cause the call to fail and return errno. */
+extern int dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
+ int (*predicate) (const char *,
+ const char *));
+
+/* Examine an ET_CORE file and report modules based on its contents.
+ This can follow a dwfl_report_offline call to bootstrap the
+ DT_DEBUG method of following the dynamic linker link_map chain, in
+ case the core file does not contain enough of the executable's text
+ segment to locate its PT_DYNAMIC in the dump. This might call
+ dwfl_report_elf on file names found in the dump if reading some
+ link_map files is the only way to ascertain those modules' addresses.
+ Returns the number of modules reported, or -1 for errors. */
+extern int dwfl_core_file_report (Dwfl *dwfl, Elf *elf);
+
+/* Call dwfl_report_module for each file mapped into the address space of PID.
+ Returns zero on success, -1 if dwfl_report_module failed,
+ or an errno code if opening the kernel binary failed. */
+extern int dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid);
+
+/* Similar, but reads an input stream in the format of Linux /proc/PID/maps
+ files giving module layout, not the file for a live process. */
+extern int dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *);
+
+/* Trivial find_elf callback for use with dwfl_linux_proc_report.
+ This uses the module name as a file name directly and tries to open it
+ if it begin with a slash, or handles the magic string "[vdso]". */
+extern int dwfl_linux_proc_find_elf (Dwfl_Module *mod, void **userdata,
+ const char *module_name, Dwarf_Addr base,
+ char **file_name, Elf **);
+
+/* Standard argument parsing for using a standard callback set. */
+struct argp;
+extern const struct argp *dwfl_standard_argp (void) __attribute__ ((const));
+
+
+/*** Relocation of addresses from Dwfl ***/
+
+/* Return the number of relocatable bases associated with the module,
+ which is zero for ET_EXEC and one for ET_DYN. Returns -1 for errors. */
+extern int dwfl_module_relocations (Dwfl_Module *mod);
+
+/* Return the relocation base index associated with the *ADDRESS location,
+ and adjust *ADDRESS to be an offset relative to that base.
+ Returns -1 for errors. */
+extern int dwfl_module_relocate_address (Dwfl_Module *mod,
+ Dwarf_Addr *address);
+
+/* Return the ELF section name for the given relocation base index;
+ if SHNDXP is not null, set *SHNDXP to the ELF section index.
+ For ET_DYN, returns "" and sets *SHNDXP to SHN_ABS; the relocation
+ base is the runtime start address reported for the module.
+ Returns null for errors. */
+extern const char *dwfl_module_relocation_info (Dwfl_Module *mod,
+ unsigned int idx,
+ GElf_Word *shndxp);
+
+/* Validate that ADDRESS and ADDRESS+OFFSET lie in a known module
+ and both within the same contiguous region for relocation purposes.
+ Returns zero for success and -1 for errors. */
+extern int dwfl_validate_address (Dwfl *dwfl,
+ Dwarf_Addr address, Dwarf_Sword offset);
+
+
+/*** ELF access functions ***/
+
+/* Fetch the module main ELF file (where the allocated sections
+ are found) for use with libelf. If successful, fills in *BIAS
+ with the difference between addresses within the loaded module
+ and those in symbol tables or Dwarf information referring to it. */
+extern Elf *dwfl_module_getelf (Dwfl_Module *, GElf_Addr *bias);
+
+/* Return the number of symbols in the module's symbol table,
+ or -1 for errors. */
+extern int dwfl_module_getsymtab (Dwfl_Module *mod);
+
+/* Fetch one entry from the module's symbol table. On errors, returns
+ NULL. If successful, fills in *SYM and returns the string for st_name.
+ This works like gelf_getsym except that st_value is always adjusted to
+ an absolute value based on the module's location, when the symbol is in
+ an SHF_ALLOC section. If SHNDXP is non-null, it's set with the section
+ index (whether from st_shndx or extended index table); in case of a
+ symbol in a non-allocated section, *SHNDXP is instead set to -1. */
+extern const char *dwfl_module_getsym (Dwfl_Module *mod, int ndx,
+ GElf_Sym *sym, GElf_Word *shndxp)
+ __nonnull_attribute__ (3);
+
+/* Find the symbol that ADDRESS lies inside, and return its name. */
+extern const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address);
+
+/* Find the symbol that ADDRESS lies inside, and return detailed
+ information as for dwfl_module_getsym (above). */
+extern const char *dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr address,
+ GElf_Sym *sym, GElf_Word *shndxp)
+ __nonnull_attribute__ (3);
+
+/* Find the ELF section that *ADDRESS lies inside and return it.
+ On success, adjusts *ADDRESS to be relative to the section,
+ and sets *BIAS to the difference between addresses used in
+ the returned section's headers and run-time addresses. */
+extern Elf_Scn *dwfl_module_address_section (Dwfl_Module *mod,
+ Dwarf_Addr *address,
+ Dwarf_Addr *bias)
+ __nonnull_attribute__ (2, 3);
+
+
+/*** Dwarf access functions ***/
+
+/* Fetch the module's debug information for use with libdw.
+ If successful, fills in *BIAS with the difference between
+ addresses within the loaded module and those to use with libdw. */
+extern Dwarf *dwfl_module_getdwarf (Dwfl_Module *, Dwarf_Addr *bias)
+ __nonnull_attribute__ (2);
+
+/* Get the libdw handle for each module. */
+extern ptrdiff_t dwfl_getdwarf (Dwfl *,
+ int (*callback) (Dwfl_Module *, void **,
+ const char *, Dwarf_Addr,
+ Dwarf *, Dwarf_Addr, void *),
+ void *arg, ptrdiff_t offset);
+
+/* Look up the module containing ADDR and return its debugging information,
+ loading it if necessary. */
+extern Dwarf *dwfl_addrdwarf (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias)
+ __nonnull_attribute__ (3);
+
+
+/* Find the CU containing ADDR and return its DIE. */
+extern Dwarf_Die *dwfl_addrdie (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias)
+ __nonnull_attribute__ (3);
+extern Dwarf_Die *dwfl_module_addrdie (Dwfl_Module *mod,
+ Dwarf_Addr addr, Dwarf_Addr *bias)
+ __nonnull_attribute__ (3);
+
+/* Iterate through the CUs, start with null for LASTCU. */
+extern Dwarf_Die *dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias)
+ __nonnull_attribute__ (3);
+extern Dwarf_Die *dwfl_module_nextcu (Dwfl_Module *mod,
+ Dwarf_Die *lastcu, Dwarf_Addr *bias)
+ __nonnull_attribute__ (3);
+
+/* Return the module containing the CU DIE. */
+extern Dwfl_Module *dwfl_cumodule (Dwarf_Die *cudie);
+
+
+/* Cache the source line information fo the CU and return the
+ number of Dwfl_Line entries it has. */
+extern int dwfl_getsrclines (Dwarf_Die *cudie, size_t *nlines);
+
+/* Access one line number entry within the CU. */
+extern Dwfl_Line *dwfl_onesrcline (Dwarf_Die *cudie, size_t idx);
+
+/* Get source for address. */
+extern Dwfl_Line *dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr);
+extern Dwfl_Line *dwfl_getsrc (Dwfl *dwfl, Dwarf_Addr addr);
+
+/* Get address for source. */
+extern int dwfl_module_getsrc_file (Dwfl_Module *mod,
+ const char *fname, int lineno, int column,
+ Dwfl_Line ***srcsp, size_t *nsrcs);
+
+/* Return the module containing this line record. */
+extern Dwfl_Module *dwfl_linemodule (Dwfl_Line *line);
+
+/* Return the CU containing this line record. */
+extern Dwarf_Die *dwfl_linecu (Dwfl_Line *line);
+
+/* Return the source file name and fill in other information.
+ Arguments may be null for unneeded fields. */
+extern const char *dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr,
+ int *linep, int *colp,
+ Dwarf_Word *mtime, Dwarf_Word *length);
+
+ /* Return the equivalent Dwarf_Line and the bias to apply to its address. */
+extern Dwarf_Line *dwfl_dwarf_line (Dwfl_Line *line, Dwarf_Addr *bias);
+
+/* Return the compilation directory (AT_comp_dir) from this line's CU. */
+extern const char *dwfl_line_comp_dir (Dwfl_Line *line);
+
+
+/*** Machine backend access functions ***/
+
+/* Return location expression to find return value given a
+ DW_TAG_subprogram, DW_TAG_subroutine_type, or similar DIE describing
+ function itself (whose DW_AT_type attribute describes its return type).
+ The given DIE must come from the given module. Returns -1 for errors.
+ Returns zero if the function has no return value (e.g. "void" in C).
+ Otherwise, *LOCOPS gets a location expression to find the return value,
+ and returns the number of operations in the expression. The pointer is
+ permanently allocated at least as long as the module is live. */
+extern int dwfl_module_return_value_location (Dwfl_Module *mod,
+ Dwarf_Die *functypedie,
+ const Dwarf_Op **locops);
+
+/* Enumerate the DWARF register numbers and their names.
+ For each register, CALLBACK gets its DWARF number, a string describing
+ the register set (such as "integer" or "FPU"), a prefix used in
+ assembler syntax (such as "%" or "$", may be ""), and the name for the
+ register (contains identifier characters only, possibly all digits).
+ The REGNAME string is valid only during the callback. */
+extern int dwfl_module_register_names (Dwfl_Module *mod,
+ int (*callback) (void *arg,
+ int regno,
+ const char *setname,
+ const char *prefix,
+ const char *regname,
+ int bits, int type),
+ void *arg);
+
+
+/* Find the CFI for this module. Returns NULL if there is no CFI.
+ On success, fills in *BIAS with the difference between addresses
+ within the loaded module and those in the CFI referring to it.
+ The pointer returned can be used until the module is cleaned up.
+ Calling these more than once returns the same pointers.
+
+ dwfl_module_dwarf_cfi gets the '.debug_frame' information found with the
+ rest of the DWARF information. dwfl_module_eh_cfi gets the '.eh_frame'
+ information found linked into the text. A module might have either or
+ both. */
+extern Dwarf_CFI *dwfl_module_dwarf_cfi (Dwfl_Module *mod, Dwarf_Addr *bias);
+extern Dwarf_CFI *dwfl_module_eh_cfi (Dwfl_Module *mod, Dwarf_Addr *bias);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* libdwfl.h */
diff --git a/src/libdwfl/libdwflP.h b/src/libdwfl/libdwflP.h
new file mode 100644
index 00000000..bca82d2e
--- /dev/null
+++ b/src/libdwfl/libdwflP.h
@@ -0,0 +1,512 @@
+/* Internal definitions for libdwfl.
+ Copyright (C) 2005-2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifndef _LIBDWFLP_H
+#define _LIBDWFLP_H 1
+
+#ifndef PACKAGE_NAME
+# include <config.h>
+#endif
+#include <libdwfl.h>
+#include <libebl.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../libdw/libdwP.h" /* We need its INTDECLs. */
+
+/* gettext helper macros. */
+#define _(Str) dgettext ("elfutils", Str)
+
+#define DWFL_ERRORS \
+ DWFL_ERROR (NOERROR, N_("no error")) \
+ DWFL_ERROR (UNKNOWN_ERROR, N_("unknown error")) \
+ DWFL_ERROR (NOMEM, N_("out of memory")) \
+ DWFL_ERROR (ERRNO, N_("See errno")) \
+ DWFL_ERROR (LIBELF, N_("See elf_errno")) \
+ DWFL_ERROR (LIBDW, N_("See dwarf_errno")) \
+ DWFL_ERROR (LIBEBL, N_("See ebl_errno (XXX missing)")) \
+ DWFL_ERROR (ZLIB, N_("gzip decompression failed")) \
+ DWFL_ERROR (BZLIB, N_("bzip2 decompression failed")) \
+ DWFL_ERROR (LZMA, N_("LZMA decompression failed")) \
+ DWFL_ERROR (UNKNOWN_MACHINE, N_("no support library found for machine")) \
+ DWFL_ERROR (NOREL, N_("Callbacks missing for ET_REL file")) \
+ DWFL_ERROR (BADRELTYPE, N_("Unsupported relocation type")) \
+ DWFL_ERROR (BADRELOFF, N_("r_offset is bogus")) \
+ DWFL_ERROR (BADSTROFF, N_("offset out of range")) \
+ DWFL_ERROR (RELUNDEF, N_("relocation refers to undefined symbol")) \
+ DWFL_ERROR (CB, N_("Callback returned failure")) \
+ DWFL_ERROR (NO_DWARF, N_("No DWARF information found")) \
+ DWFL_ERROR (NO_SYMTAB, N_("No symbol table found")) \
+ DWFL_ERROR (NO_PHDR, N_("No ELF program headers")) \
+ DWFL_ERROR (OVERLAP, N_("address range overlaps an existing module")) \
+ DWFL_ERROR (ADDR_OUTOFRANGE, N_("address out of range")) \
+ DWFL_ERROR (NO_MATCH, N_("no matching address range")) \
+ DWFL_ERROR (TRUNCATED, N_("image truncated")) \
+ DWFL_ERROR (ALREADY_ELF, N_("ELF file opened")) \
+ DWFL_ERROR (BADELF, N_("not a valid ELF file")) \
+ DWFL_ERROR (WEIRD_TYPE, N_("cannot handle DWARF type description")) \
+ DWFL_ERROR (WRONG_ID_ELF, N_("ELF file does not match build ID")) \
+ DWFL_ERROR (BAD_PRELINK, N_("corrupt .gnu.prelink_undo section data"))
+
+#define DWFL_ERROR(name, text) DWFL_E_##name,
+typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error;
+#undef DWFL_ERROR
+
+#define OTHER_ERROR(name) ((unsigned int) DWFL_E_##name << 16)
+#define DWFL_E(name, errno) (OTHER_ERROR (name) | (errno))
+
+extern int __libdwfl_canon_error (Dwfl_Error) internal_function;
+extern void __libdwfl_seterrno (Dwfl_Error) internal_function;
+
+struct Dwfl
+{
+ const Dwfl_Callbacks *callbacks;
+
+ Dwfl_Module *modulelist; /* List in order used by full traversals. */
+
+ GElf_Addr offline_next_address;
+
+ GElf_Addr segment_align; /* Smallest granularity of segments. */
+
+ /* Binary search table in three parallel malloc'd arrays. */
+ size_t lookup_elts; /* Elements in use. */
+ size_t lookup_alloc; /* Elements allococated. */
+ GElf_Addr *lookup_addr; /* Start address of segment. */
+ Dwfl_Module **lookup_module; /* Module associated with segment, or null. */
+ int *lookup_segndx; /* User segment index, or -1. */
+
+ /* Cache from last dwfl_report_segment call. */
+ const void *lookup_tail_ident;
+ GElf_Off lookup_tail_vaddr;
+ GElf_Off lookup_tail_offset;
+ int lookup_tail_ndx;
+};
+
+#define OFFLINE_REDZONE 0x10000
+
+struct dwfl_file
+{
+ char *name;
+ int fd;
+ bool valid; /* The build ID note has been matched. */
+ bool relocated; /* Partial relocation of all sections done. */
+
+ Elf *elf;
+
+ /* This is the lowest p_vaddr in this ELF file, aligned to p_align.
+ For a file without phdrs, this is zero. */
+ GElf_Addr vaddr;
+
+ /* This is an address chosen for synchronization between the main file
+ and the debug file. See dwfl_module_getdwarf.c for how it's chosen. */
+ GElf_Addr address_sync;
+};
+
+struct Dwfl_Module
+{
+ Dwfl *dwfl;
+ struct Dwfl_Module *next; /* Link on Dwfl.modulelist. */
+
+ void *userdata;
+
+ char *name; /* Iterator name for this module. */
+ GElf_Addr low_addr, high_addr;
+
+ struct dwfl_file main, debug;
+ GElf_Addr main_bias;
+ Ebl *ebl;
+ GElf_Half e_type; /* GElf_Ehdr.e_type cache. */
+ Dwfl_Error elferr; /* Previous failure to open main file. */
+
+ struct dwfl_relocation *reloc_info; /* Relocatable sections. */
+
+ struct dwfl_file *symfile; /* Either main or debug. */
+ Elf_Data *symdata; /* Data in the ELF symbol table section. */
+ size_t syments; /* sh_size / sh_entsize of that section. */
+ int first_global; /* Index of first global symbol of table. */
+ Elf_Data *symstrdata; /* Data for its string table. */
+ Elf_Data *symxndxdata; /* Data in the extended section index table. */
+
+ Dwarf *dw; /* libdw handle for its debugging info. */
+
+ Dwfl_Error symerr; /* Previous failure to load symbols. */
+ Dwfl_Error dwerr; /* Previous failure to load DWARF. */
+
+ /* Known CU's in this module. */
+ struct dwfl_cu *first_cu, **cu;
+
+ void *lazy_cu_root; /* Table indexed by Dwarf_Off of CU. */
+
+ struct dwfl_arange *aranges; /* Mapping of addresses in module to CUs. */
+
+ void *build_id_bits; /* malloc'd copy of build ID bits. */
+ GElf_Addr build_id_vaddr; /* Address where they reside, 0 if unknown. */
+ int build_id_len; /* -1 for prior failure, 0 if unset. */
+
+ unsigned int ncu;
+ unsigned int lazycu; /* Possible users, deleted when none left. */
+ unsigned int naranges;
+
+ Dwarf_CFI *dwarf_cfi; /* Cached DWARF CFI for this module. */
+ Dwarf_CFI *eh_cfi; /* Cached EH CFI for this module. */
+
+ int segment; /* Index of first segment table entry. */
+ bool gc; /* Mark/sweep flag. */
+};
+
+
+
+/* Information cached about each CU in Dwfl_Module.dw. */
+struct dwfl_cu
+{
+ /* This caches libdw information about the CU. It's also the
+ address passed back to users, so we take advantage of the
+ fact that it's placed first to cast back. */
+ Dwarf_Die die;
+
+ Dwfl_Module *mod; /* Pointer back to containing module. */
+
+ struct dwfl_cu *next; /* CU immediately following in the file. */
+
+ struct Dwfl_Lines *lines;
+};
+
+struct Dwfl_Lines
+{
+ struct dwfl_cu *cu;
+
+ /* This is what the opaque Dwfl_Line * pointers we pass to users are.
+ We need to recover pointers to our struct dwfl_cu and a record in
+ libdw's Dwarf_Line table. To minimize the memory used in addition
+ to libdw's Dwarf_Lines buffer, we just point to our own index in
+ this table, and have one pointer back to the CU. The indices here
+ match those in libdw's Dwarf_CU.lines->info table. */
+ struct Dwfl_Line
+ {
+ unsigned int idx; /* My index in the dwfl_cu.lines table. */
+ } idx[0];
+};
+
+static inline struct dwfl_cu *
+dwfl_linecu_inline (const Dwfl_Line *line)
+{
+ const struct Dwfl_Lines *lines = ((const void *) line
+ - offsetof (struct Dwfl_Lines,
+ idx[line->idx]));
+ return lines->cu;
+}
+#define dwfl_linecu dwfl_linecu_inline
+
+static inline GElf_Addr
+dwfl_adjusted_address (Dwfl_Module *mod, GElf_Addr addr)
+{
+ return addr + mod->main_bias;
+}
+
+static inline GElf_Addr
+dwfl_deadjust_address (Dwfl_Module *mod, GElf_Addr addr)
+{
+ return addr - mod->main_bias;
+}
+
+static inline Dwarf_Addr
+dwfl_adjusted_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr)
+{
+ return dwfl_adjusted_address (mod, (addr
+ - mod->debug.address_sync
+ + mod->main.address_sync));
+}
+
+static inline Dwarf_Addr
+dwfl_deadjust_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr)
+{
+ return (dwfl_deadjust_address (mod, addr)
+ - mod->main.address_sync
+ + mod->debug.address_sync);
+}
+
+static inline GElf_Addr
+dwfl_adjusted_st_value (Dwfl_Module *mod, GElf_Addr addr)
+{
+ if (mod->symfile == &mod->main)
+ return dwfl_adjusted_address (mod, addr);
+ return dwfl_adjusted_dwarf_addr (mod, addr);
+}
+
+static inline GElf_Addr
+dwfl_deadjust_st_value (Dwfl_Module *mod, GElf_Addr addr)
+{
+ if (mod->symfile == &mod->main)
+ return dwfl_deadjust_address (mod, addr);
+ return dwfl_deadjust_dwarf_addr (mod, addr);
+}
+
+/* This describes a contiguous address range that lies in a single CU.
+ We condense runs of Dwarf_Arange entries for the same CU into this. */
+struct dwfl_arange
+{
+ struct dwfl_cu *cu;
+ size_t arange; /* Index in Dwarf_Aranges. */
+};
+
+
+
+extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function;
+
+/* Find the main ELF file, update MOD->elferr and/or MOD->main.elf. */
+extern void __libdwfl_getelf (Dwfl_Module *mod) internal_function;
+
+/* Process relocations in debugging sections in an ET_REL file.
+ FILE must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ,
+ to make it possible to relocate the data in place (or ELF_C_RDWR or
+ ELF_C_RDWR_MMAP if you intend to modify the Elf file on disk). After
+ this, dwarf_begin_elf on FILE will read the relocated data.
+
+ When DEBUG is false, apply partial relocation to all sections. */
+extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug)
+ internal_function;
+
+/* Process (simple) relocations in arbitrary section TSCN of an ET_REL file.
+ RELOCSCN is SHT_REL or SHT_RELA and TSCN is its sh_info target section. */
+extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
+ Elf_Scn *relocscn, Elf_Scn *tscn,
+ bool partial)
+ internal_function;
+
+/* Adjust *VALUE from section-relative to absolute.
+ MOD->dwfl->callbacks->section_address is called to determine the actual
+ address of a loaded section. */
+extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf,
+ size_t *shstrndx_cache,
+ Elf32_Word shndx,
+ GElf_Addr *value)
+ internal_function;
+
+
+/* Ensure that MOD->ebl is set up. */
+extern Dwfl_Error __libdwfl_module_getebl (Dwfl_Module *mod) internal_function;
+
+/* Install a new Dwarf_CFI in *SLOT (MOD->eh_cfi or MOD->dwarf_cfi). */
+extern Dwarf_CFI *__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot,
+ Dwarf_CFI *cfi)
+ internal_function;
+
+/* Iterate through all the CU's in the module. Start by passing a null
+ LASTCU, and then pass the last *CU returned. Success return with null
+ *CU no more CUs. */
+extern Dwfl_Error __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
+ struct dwfl_cu **cu) internal_function;
+
+/* Find the CU by address. */
+extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr,
+ struct dwfl_cu **cu) internal_function;
+
+/* Ensure that CU->lines (and CU->cu->lines) is set up. */
+extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu)
+ internal_function;
+
+/* Look in ELF for an NT_GNU_BUILD_ID note. If SET is true, store it
+ in MOD and return its length. If SET is false, instead compare it
+ to that stored in MOD and return 2 if they match, 1 if they do not.
+ Returns -1 for errors, 0 if no note is found. */
+extern int __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
+ internal_function;
+
+/* Open a main or debuginfo file by its build ID, returns the fd. */
+extern int __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug,
+ char **file_name) internal_function;
+
+extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len)
+ attribute_hidden;
+extern int __libdwfl_crc32_file (int fd, uint32_t *resp) attribute_hidden;
+
+
+/* Meat of dwfl_report_elf, given elf_begin just called.
+ Consumes ELF on success, not on failure. */
+extern Dwfl_Module *__libdwfl_report_elf (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd,
+ Elf *elf, GElf_Addr base, bool sanity)
+ internal_function;
+
+/* Meat of dwfl_report_offline. */
+extern Dwfl_Module *__libdwfl_report_offline (Dwfl *dwfl, const char *name,
+ const char *file_name,
+ int fd, bool closefd,
+ int (*predicate) (const char *,
+ const char *))
+ internal_function;
+
+/* Decompression wrappers: decompress whole file into memory. */
+extern Dwfl_Error __libdw_gunzip (int fd, off64_t start_offset,
+ void *mapped, size_t mapped_size,
+ void **whole, size_t *whole_size)
+ internal_function;
+extern Dwfl_Error __libdw_bunzip2 (int fd, off64_t start_offset,
+ void *mapped, size_t mapped_size,
+ void **whole, size_t *whole_size)
+ internal_function;
+extern Dwfl_Error __libdw_unlzma (int fd, off64_t start_offset,
+ void *mapped, size_t mapped_size,
+ void **whole, size_t *whole_size)
+ internal_function;
+
+/* Skip the image header before a file image: updates *START_OFFSET. */
+extern Dwfl_Error __libdw_image_header (int fd, off64_t *start_offset,
+ void *mapped, size_t mapped_size)
+ internal_function;
+
+/* Open Elf handle on *FDP. This handles decompression and checks
+ elf_kind. Succeed only for ELF_K_ELF, or also ELF_K_AR if ARCHIVE_OK.
+ Returns DWFL_E_NOERROR and sets *ELFP on success, resets *FDP to -1 if
+ it's no longer used. Resets *FDP on failure too iff CLOSE_ON_FAIL. */
+extern Dwfl_Error __libdw_open_file (int *fdp, Elf **elfp,
+ bool close_on_fail, bool archive_ok)
+ internal_function;
+
+/* These are working nicely for --core, but are not ready to be
+ exported interfaces quite yet. */
+
+/* Type of callback function ...
+ */
+typedef bool Dwfl_Memory_Callback (Dwfl *dwfl, int segndx,
+ void **buffer, size_t *buffer_available,
+ GElf_Addr vaddr, size_t minread, void *arg);
+
+/* Type of callback function ...
+ */
+typedef bool Dwfl_Module_Callback (Dwfl_Module *mod, void **userdata,
+ const char *name, Dwarf_Addr base,
+ void **buffer, size_t *buffer_available,
+ GElf_Off cost, GElf_Off worthwhile,
+ GElf_Off whole, GElf_Off contiguous,
+ void *arg, Elf **elfp);
+
+/* ...
+ */
+extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
+ Dwfl_Memory_Callback *memory_callback,
+ void *memory_callback_arg,
+ Dwfl_Module_Callback *read_eagerly,
+ void *read_eagerly_arg);
+
+/* Report a module for entry in the dynamic linker's struct link_map list.
+ For each link_map entry, if an existing module resides at its address,
+ this just modifies that module's name and suggested file name. If
+ no such module exists, this calls dwfl_report_elf on the l_name string.
+
+ If AUXV is not null, it points to AUXV_SIZE bytes of auxiliary vector
+ data as contained in an NT_AUXV note or read from a /proc/pid/auxv
+ file. When this is available, it guides the search. If AUXV is null
+ or the memory it points to is not accessible, then this search can
+ only find where to begin if the correct executable file was
+ previously reported and preloaded as with dwfl_report_elf.
+
+ Returns the number of modules found, or -1 for errors. */
+extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
+ Dwfl_Memory_Callback *memory_callback,
+ void *memory_callback_arg);
+
+
+/* Avoid PLT entries. */
+INTDECL (dwfl_begin)
+INTDECL (dwfl_errmsg)
+INTDECL (dwfl_errno)
+INTDECL (dwfl_addrmodule)
+INTDECL (dwfl_addrsegment)
+INTDECL (dwfl_addrdwarf)
+INTDECL (dwfl_addrdie)
+INTDECL (dwfl_core_file_report)
+INTDECL (dwfl_getmodules)
+INTDECL (dwfl_module_addrdie)
+INTDECL (dwfl_module_address_section)
+INTDECL (dwfl_module_addrsym)
+INTDECL (dwfl_module_build_id)
+INTDECL (dwfl_module_getdwarf)
+INTDECL (dwfl_module_getelf)
+INTDECL (dwfl_module_getsym)
+INTDECL (dwfl_module_getsymtab)
+INTDECL (dwfl_module_getsrc)
+INTDECL (dwfl_module_report_build_id)
+INTDECL (dwfl_report_elf)
+INTDECL (dwfl_report_begin)
+INTDECL (dwfl_report_begin_add)
+INTDECL (dwfl_report_module)
+INTDECL (dwfl_report_segment)
+INTDECL (dwfl_report_offline)
+INTDECL (dwfl_report_end)
+INTDECL (dwfl_build_id_find_elf)
+INTDECL (dwfl_build_id_find_debuginfo)
+INTDECL (dwfl_standard_find_debuginfo)
+INTDECL (dwfl_link_map_report)
+INTDECL (dwfl_linux_kernel_find_elf)
+INTDECL (dwfl_linux_kernel_module_section_address)
+INTDECL (dwfl_linux_proc_report)
+INTDECL (dwfl_linux_proc_maps_report)
+INTDECL (dwfl_linux_proc_find_elf)
+INTDECL (dwfl_linux_kernel_report_kernel)
+INTDECL (dwfl_linux_kernel_report_modules)
+INTDECL (dwfl_linux_kernel_report_offline)
+INTDECL (dwfl_offline_section_address)
+INTDECL (dwfl_module_relocate_address)
+INTDECL (dwfl_module_dwarf_cfi)
+INTDECL (dwfl_module_eh_cfi)
+
+/* Leading arguments standard to callbacks passed a Dwfl_Module. */
+#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
+#define CBFAIL (errno ? DWFL_E (ERRNO, errno) : DWFL_E_CB);
+
+
+/* The default used by dwfl_standard_find_debuginfo. */
+#define DEFAULT_DEBUGINFO_PATH ":.debug:/usr/lib/debug"
+
+
+#endif /* libdwflP.h */
diff --git a/src/libdwfl/libdwfl_crc32.c b/src/libdwfl/libdwfl_crc32.c
new file mode 100644
index 00000000..0fa23789
--- /dev/null
+++ b/src/libdwfl/libdwfl_crc32.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002, 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define crc32 attribute_hidden __libdwfl_crc32
+#define LIB_SYSTEM_H 1
+#include <libdwflP.h>
+#include "../lib/crc32.c"
diff --git a/src/libdwfl/libdwfl_crc32_file.c b/src/libdwfl/libdwfl_crc32_file.c
new file mode 100644
index 00000000..ca154be3
--- /dev/null
+++ b/src/libdwfl/libdwfl_crc32_file.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002, 2005 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define crc32_file attribute_hidden __libdwfl_crc32_file
+#define crc32 __libdwfl_crc32
+#define LIB_SYSTEM_H 1
+#include <libdwflP.h>
+#include "../lib/crc32_file.c"
diff --git a/src/libdwfl/lines.c b/src/libdwfl/lines.c
new file mode 100644
index 00000000..ed4267fc
--- /dev/null
+++ b/src/libdwfl/lines.c
@@ -0,0 +1,73 @@
+/* Fetch source line info for CU.
+ Copyright (C) 2005, 2006 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/libdwP.h"
+
+Dwfl_Error
+internal_function
+__libdwfl_cu_getsrclines (struct dwfl_cu *cu)
+{
+ if (cu->lines == NULL)
+ {
+ Dwarf_Lines *lines;
+ size_t nlines;
+ if (INTUSE(dwarf_getsrclines) (&cu->die, &lines, &nlines) != 0)
+ return DWFL_E_LIBDW;
+
+ cu->lines = malloc (offsetof (struct Dwfl_Lines, idx[nlines]));
+ if (cu->lines == NULL)
+ return DWFL_E_NOMEM;
+ cu->lines->cu = cu;
+ for (unsigned int i = 0; i < nlines; ++i)
+ cu->lines->idx[i].idx = i;
+ }
+
+ return DWFL_E_NOERROR;
+}
diff --git a/src/libdwfl/link_map.c b/src/libdwfl/link_map.c
new file mode 100644
index 00000000..05839b3a
--- /dev/null
+++ b/src/libdwfl/link_map.c
@@ -0,0 +1,888 @@
+/* Report modules by examining dynamic linker data structures.
+ Copyright (C) 2008-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include <config.h>
+#include "libdwflP.h"
+
+#include <byteswap.h>
+#include <endian.h>
+
+/* This element is always provided and always has a constant value.
+ This makes it an easy thing to scan for to discern the format. */
+#define PROBE_TYPE AT_PHENT
+#define PROBE_VAL32 sizeof (Elf32_Phdr)
+#define PROBE_VAL64 sizeof (Elf64_Phdr)
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define BE32(x) (x)
+# define BE64(x) (x)
+# define LE32(x) bswap_32 (x)
+# define LE64(x) bswap_64 (x)
+#else
+# define LE32(x) (x)
+# define LE64(x) (x)
+# define BE32(x) bswap_32 (x)
+# define BE64(x) bswap_64 (x)
+#endif
+
+
+/* Examine an auxv data block and determine its format.
+ Return true iff we figured it out. */
+static bool
+auxv_format_probe (const void *auxv, size_t size,
+ uint_fast8_t *elfclass, uint_fast8_t *elfdata)
+{
+ const union
+ {
+ char buf[size];
+ Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
+ Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
+ } *u = auxv;
+
+ inline bool check64 (size_t i)
+ {
+ if (u->a64[i].a_type == BE64 (PROBE_TYPE)
+ && u->a64[i].a_un.a_val == BE64 (PROBE_VAL64))
+ {
+ *elfdata = ELFDATA2MSB;
+ return true;
+ }
+
+ if (u->a64[i].a_type == LE64 (PROBE_TYPE)
+ && u->a64[i].a_un.a_val == LE64 (PROBE_VAL64))
+ {
+ *elfdata = ELFDATA2LSB;
+ return true;
+ }
+
+ return false;
+ }
+
+ inline bool check32 (size_t i)
+ {
+ if (u->a32[i].a_type == BE32 (PROBE_TYPE)
+ && u->a32[i].a_un.a_val == BE32 (PROBE_VAL32))
+ {
+ *elfdata = ELFDATA2MSB;
+ return true;
+ }
+
+ if (u->a32[i].a_type == LE32 (PROBE_TYPE)
+ && u->a32[i].a_un.a_val == LE32 (PROBE_VAL32))
+ {
+ *elfdata = ELFDATA2LSB;
+ return true;
+ }
+
+ return false;
+ }
+
+ for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
+ {
+ if (check64 (i))
+ {
+ *elfclass = ELFCLASS64;
+ return true;
+ }
+
+ if (check32 (i * 2) || check32 (i * 2 + 1))
+ {
+ *elfclass = ELFCLASS32;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* This is a Dwfl_Memory_Callback that wraps another memory callback.
+ If the underlying callback cannot fill the data, then this will
+ fall back to fetching data from module files. */
+
+struct integrated_memory_callback
+{
+ Dwfl_Memory_Callback *memory_callback;
+ void *memory_callback_arg;
+ void *buffer;
+};
+
+static bool
+integrated_memory_callback (Dwfl *dwfl, int ndx,
+ void **buffer, size_t *buffer_available,
+ GElf_Addr vaddr,
+ size_t minread,
+ void *arg)
+{
+ struct integrated_memory_callback *info = arg;
+
+ if (ndx == -1)
+ {
+ /* Called for cleanup. */
+ if (info->buffer != NULL)
+ {
+ /* The last probe buffer came from the underlying callback.
+ Let it do its cleanup. */
+ assert (*buffer == info->buffer); /* XXX */
+ *buffer = info->buffer;
+ info->buffer = NULL;
+ return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
+ vaddr, minread,
+ info->memory_callback_arg);
+ }
+ *buffer = NULL;
+ *buffer_available = 0;
+ return false;
+ }
+
+ if (*buffer != NULL)
+ /* For a final-read request, we only use the underlying callback. */
+ return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
+ vaddr, minread, info->memory_callback_arg);
+
+ /* Let the underlying callback try to fill this request. */
+ if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
+ vaddr, minread, info->memory_callback_arg))
+ {
+ *buffer = info->buffer;
+ return true;
+ }
+
+ /* Now look for module text covering this address. */
+
+ Dwfl_Module *mod;
+ (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
+ if (mod == NULL)
+ return false;
+
+ Dwarf_Addr bias;
+ Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
+ if (unlikely (scn == NULL))
+ {
+#if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
+ /* If we have no sections we can try to fill it from the module file
+ based on its phdr mappings. */
+ if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
+ return INTUSE(dwfl_elf_phdr_memory_callback)
+ (dwfl, 0, buffer, buffer_available,
+ vaddr - mod->main.bias, minread, mod->main.elf);
+#endif
+ return false;
+ }
+
+ Elf_Data *data = elf_rawdata (scn, NULL);
+ if (unlikely (data == NULL))
+ // XXX throw error?
+ return false;
+
+ if (unlikely (data->d_size < vaddr))
+ return false;
+
+ /* Provide as much data as we have. */
+ void *contents = data->d_buf + vaddr;
+ size_t avail = data->d_size - vaddr;
+ if (unlikely (avail < minread))
+ return false;
+
+ /* If probing for a string, make sure it's terminated. */
+ if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
+ return false;
+
+ /* We have it! */
+ *buffer = contents;
+ *buffer_available = avail;
+ return true;
+}
+
+static size_t
+addrsize (uint_fast8_t elfclass)
+{
+ return elfclass * 4;
+}
+
+/* Report a module for each struct link_map in the linked list at r_map
+ in the struct r_debug at R_DEBUG_VADDR.
+
+ For each link_map entry, if an existing module resides at its address,
+ this just modifies that module's name and suggested file name. If
+ no such module exists, this calls dwfl_report_elf on the l_name string.
+
+ Returns the number of modules found, or -1 for errors. */
+
+static int
+report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
+ Dwfl *dwfl, GElf_Addr r_debug_vaddr,
+ Dwfl_Memory_Callback *memory_callback,
+ void *memory_callback_arg)
+{
+ /* Skip r_version, to aligned r_map field. */
+ GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
+
+ void *buffer = NULL;
+ size_t buffer_available = 0;
+ inline int release_buffer (int result)
+ {
+ if (buffer != NULL)
+ (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
+ memory_callback_arg);
+ return result;
+ }
+
+ GElf_Addr addrs[4];
+ inline bool read_addrs (GElf_Addr vaddr, size_t n)
+ {
+ size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */
+
+ /* Read a new buffer if the old one doesn't cover these words. */
+ if (buffer == NULL
+ || vaddr < read_vaddr
+ || vaddr - read_vaddr + nb > buffer_available)
+ {
+ release_buffer (0);
+
+ read_vaddr = vaddr;
+ int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
+ if (unlikely (segndx < 0)
+ || unlikely (! (*memory_callback) (dwfl, segndx,
+ &buffer, &buffer_available,
+ vaddr, nb, memory_callback_arg)))
+ return true;
+ }
+
+ const union
+ {
+ Elf32_Addr a32[n];
+ Elf64_Addr a64[n];
+ } *in = vaddr - read_vaddr + buffer;
+
+ if (elfclass == ELFCLASS32)
+ {
+ if (elfdata == ELFDATA2MSB)
+ for (size_t i = 0; i < n; ++i)
+ addrs[i] = BE32 (in->a32[i]);
+ else
+ for (size_t i = 0; i < n; ++i)
+ addrs[i] = LE32 (in->a32[i]);
+ }
+ else
+ {
+ if (elfdata == ELFDATA2MSB)
+ for (size_t i = 0; i < n; ++i)
+ addrs[i] = BE64 (in->a64[i]);
+ else
+ for (size_t i = 0; i < n; ++i)
+ addrs[i] = LE64 (in->a64[i]);
+ }
+
+ return false;
+ }
+
+ if (unlikely (read_addrs (read_vaddr, 1)))
+ return release_buffer (-1);
+
+ GElf_Addr next = addrs[0];
+
+ Dwfl_Module **lastmodp = &dwfl->modulelist;
+ int result = 0;
+
+ /* There can't be more elements in the link_map list than there are
+ segments. DWFL->lookup_elts is probably twice that number, so it
+ is certainly above the upper bound. If we iterate too many times,
+ there must be a loop in the pointers due to link_map clobberation. */
+ size_t iterations = 0;
+ while (next != 0 && ++iterations < dwfl->lookup_elts)
+ {
+ if (read_addrs (next, 4))
+ return release_buffer (-1);
+
+ GElf_Addr l_addr = addrs[0];
+ GElf_Addr l_name = addrs[1];
+ GElf_Addr l_ld = addrs[2];
+ next = addrs[3];
+
+ /* If a clobbered or truncated memory image has no useful pointer,
+ just skip this element. */
+ if (l_ld == 0)
+ continue;
+
+ /* Fetch the string at the l_name address. */
+ const char *name = NULL;
+ if (buffer != NULL
+ && read_vaddr <= l_name
+ && l_name + 1 - read_vaddr < buffer_available
+ && memchr (l_name - read_vaddr + buffer, '\0',
+ buffer_available - (l_name - read_vaddr)) != NULL)
+ name = l_name - read_vaddr + buffer;
+ else
+ {
+ release_buffer (0);
+ read_vaddr = l_name;
+ int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
+ if (likely (segndx >= 0)
+ && (*memory_callback) (dwfl, segndx,
+ &buffer, &buffer_available,
+ l_name, 0, memory_callback_arg))
+ name = buffer;
+ }
+
+ if (name != NULL && name[0] == '\0')
+ name = NULL;
+
+ /* If content-sniffing already reported a module covering
+ the same area, find that existing module to adjust.
+ The l_ld address is the only one we know for sure
+ to be within the module's own segments (its .dynamic). */
+ Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, l_ld);
+ if (mod != NULL)
+ {
+ /* We have a module. We can give it a better name from l_name. */
+ if (name != NULL && mod->name[0] == '[')
+ {
+ char *newname = strdup (basename (name));
+ if (newname != NULL)
+ {
+ free (mod->name);
+ mod->name = newname;
+ }
+ }
+
+ if (name == NULL && mod->name[0] == '/')
+ name = mod->name;
+
+ /* If we don't have a file for it already, we can pre-install
+ the full file name from l_name. Opening the file by this
+ name will be the fallback when no build ID match is found.
+ XXX hook for sysroot */
+ if (name != NULL && mod->main.name == NULL)
+ mod->main.name = strdup (name);
+ }
+ else if (name != NULL)
+ {
+ /* We have to find the file's phdrs to compute along with l_addr
+ what its runtime address boundaries are. */
+
+ // XXX hook for sysroot
+ mod = INTUSE(dwfl_report_elf) (dwfl, basename (name),
+ name, -1, l_addr);
+ }
+
+ if (mod != NULL)
+ {
+ ++result;
+
+ /* Move this module to the end of the list, so that we end
+ up with a list in the same order as the link_map chain. */
+ if (mod->next != NULL)
+ {
+ if (*lastmodp != mod)
+ {
+ lastmodp = &dwfl->modulelist;
+ while (*lastmodp != mod)
+ lastmodp = &(*lastmodp)->next;
+ }
+ *lastmodp = mod->next;
+ mod->next = NULL;
+ while (*lastmodp != NULL)
+ lastmodp = &(*lastmodp)->next;
+ *lastmodp = mod;
+ }
+
+ lastmodp = &mod->next;
+ }
+ }
+
+ return release_buffer (result);
+}
+
+static GElf_Addr
+consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
+ uint_fast8_t *elfclass, uint_fast8_t *elfdata,
+ Dwfl_Memory_Callback *memory_callback,
+ void *memory_callback_arg)
+{
+ GElf_Ehdr ehdr;
+ if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
+ return 0;
+
+ if (at_entry != 0)
+ {
+ /* If we have an AT_ENTRY value, reject this executable if
+ its entry point address could not have supplied that. */
+
+ if (ehdr.e_entry == 0)
+ return 0;
+
+ if (mod->e_type == ET_EXEC)
+ {
+ if (ehdr.e_entry != at_entry)
+ return 0;
+ }
+ else
+ {
+ /* It could be a PIE. */
+ }
+ }
+
+ // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
+ /* Find the vaddr of the DT_DEBUG's d_ptr. This is the memory
+ address where &r_debug was written at runtime. */
+ GElf_Xword align = mod->dwfl->segment_align;
+ GElf_Addr d_val_vaddr = 0;
+ for (uint_fast16_t i = 0; i < ehdr.e_phnum; ++i)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
+ if (phdr == NULL)
+ break;
+
+ if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
+ align = phdr->p_align;
+
+ if (at_phdr != 0
+ && phdr->p_type == PT_LOAD
+ && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
+ {
+ /* This is the segment that would map the phdrs.
+ If we have an AT_PHDR value, reject this executable
+ if its phdr mapping could not have supplied that. */
+ if (mod->e_type == ET_EXEC)
+ {
+ if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
+ return 0;
+ }
+ else
+ {
+ /* It could be a PIE. If the AT_PHDR value and our
+ phdr address don't match modulo ALIGN, then this
+ could not have been the right PIE. */
+ if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
+ != (at_phdr & -align))
+ return 0;
+
+ /* Calculate the bias applied to the PIE's p_vaddr values. */
+ GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
+ + phdr->p_vaddr));
+
+ /* Final sanity check: if we have an AT_ENTRY value,
+ reject this PIE unless its biased e_entry matches. */
+ if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
+ return 0;
+
+ /* If we're changing the module's address range,
+ we've just invalidated the module lookup table. */
+ GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
+ if (bias != mod_bias)
+ {
+ mod->low_addr -= mod_bias;
+ mod->high_addr -= mod_bias;
+ mod->low_addr += bias;
+ mod->high_addr += bias;
+
+ free (mod->dwfl->lookup_module);
+ mod->dwfl->lookup_module = NULL;
+ }
+ }
+ }
+
+ if (phdr->p_type == PT_DYNAMIC)
+ {
+ Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
+ phdr->p_filesz, ELF_T_DYN);
+ if (data == NULL)
+ continue;
+ const size_t entsize = gelf_fsize (mod->main.elf,
+ ELF_T_DYN, 1, EV_CURRENT);
+ const size_t n = data->d_size / entsize;
+ for (size_t j = 0; j < n; ++j)
+ {
+ GElf_Dyn dyn_mem;
+ GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
+ if (dyn != NULL && dyn->d_tag == DT_DEBUG)
+ {
+ d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
+ break;
+ }
+ }
+ }
+ }
+
+ if (d_val_vaddr != 0)
+ {
+ /* Now we have the final address from which to read &r_debug. */
+ d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
+
+ void *buffer = NULL;
+ size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
+
+ int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
+
+ if ((*memory_callback) (mod->dwfl, segndx,
+ &buffer, &buffer_available,
+ d_val_vaddr, buffer_available,
+ memory_callback_arg))
+ {
+ const union
+ {
+ Elf32_Addr a32;
+ Elf64_Addr a64;
+ } *u = buffer;
+
+ GElf_Addr vaddr;
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
+ vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
+ ? BE32 (u->a32) : LE32 (u->a32));
+ else
+ vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
+ ? BE64 (u->a64) : LE64 (u->a64));
+
+ (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
+ memory_callback_arg);
+
+ if (*elfclass == ELFCLASSNONE)
+ *elfclass = ehdr.e_ident[EI_CLASS];
+ else if (*elfclass != ehdr.e_ident[EI_CLASS])
+ return 0;
+
+ if (*elfdata == ELFDATANONE)
+ *elfdata = ehdr.e_ident[EI_DATA];
+ else if (*elfdata != ehdr.e_ident[EI_DATA])
+ return 0;
+
+ return vaddr;
+ }
+ }
+
+ return 0;
+}
+
+/* Try to find an existing executable module with a DT_DEBUG. */
+static GElf_Addr
+find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
+ uint_fast8_t *elfclass, uint_fast8_t *elfdata,
+ Dwfl_Memory_Callback *memory_callback,
+ void *memory_callback_arg)
+{
+ for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
+ if (mod->main.elf != NULL)
+ {
+ GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
+ elfclass, elfdata,
+ memory_callback,
+ memory_callback_arg);
+ if (r_debug_vaddr != 0)
+ return r_debug_vaddr;
+ }
+
+ return 0;
+}
+
+
+int
+dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
+ Dwfl_Memory_Callback *memory_callback,
+ void *memory_callback_arg)
+{
+ GElf_Addr r_debug_vaddr = 0;
+
+ uint_fast8_t elfclass = ELFCLASSNONE;
+ uint_fast8_t elfdata = ELFDATANONE;
+ if (likely (auxv != NULL)
+ && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
+ {
+ GElf_Addr entry = 0;
+ GElf_Addr phdr = 0;
+ GElf_Xword phent = 0;
+ GElf_Xword phnum = 0;
+
+#define AUXV_SCAN(NN, BL) do \
+ { \
+ const Elf##NN##_auxv_t *av = auxv; \
+ for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i) \
+ { \
+ Elf##NN##_Addr val = BL##NN (av[i].a_un.a_val); \
+ if (av[i].a_type == BL##NN (AT_ENTRY)) \
+ entry = val; \
+ else if (av[i].a_type == BL##NN (AT_PHDR)) \
+ phdr = val; \
+ else if (av[i].a_type == BL##NN (AT_PHNUM)) \
+ phnum = val; \
+ else if (av[i].a_type == BL##NN (AT_PHENT)) \
+ phent = val; \
+ else if (av[i].a_type == BL##NN (AT_PAGESZ)) \
+ { \
+ if (val > 1 \
+ && (dwfl->segment_align == 0 \
+ || val < dwfl->segment_align)) \
+ dwfl->segment_align = val; \
+ } \
+ } \
+ } \
+ while (0)
+
+ if (elfclass == ELFCLASS32)
+ {
+ if (elfdata == ELFDATA2MSB)
+ AUXV_SCAN (32, BE);
+ else
+ AUXV_SCAN (32, LE);
+ }
+ else
+ {
+ if (elfdata == ELFDATA2MSB)
+ AUXV_SCAN (64, BE);
+ else
+ AUXV_SCAN (64, LE);
+ }
+
+ /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC. */
+ GElf_Addr dyn_vaddr = 0;
+ GElf_Xword dyn_filesz = 0;
+ GElf_Addr dyn_bias = (GElf_Addr) -1;
+
+ inline bool consider_phdr (GElf_Word type,
+ GElf_Addr vaddr, GElf_Xword filesz)
+ {
+ switch (type)
+ {
+ case PT_PHDR:
+ if (dyn_bias == (GElf_Addr) -1
+ /* Do a sanity check on the putative address. */
+ && ((vaddr & (dwfl->segment_align - 1))
+ == (phdr & (dwfl->segment_align - 1))))
+ {
+ dyn_bias = phdr - vaddr;
+ return dyn_vaddr != 0;
+ }
+ break;
+
+ case PT_DYNAMIC:
+ dyn_vaddr = vaddr;
+ dyn_filesz = filesz;
+ return dyn_bias != (GElf_Addr) -1;
+ }
+
+ return false;
+ }
+
+ if (phdr != 0 && phnum != 0)
+ {
+ Dwfl_Module *phdr_mod;
+ int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
+ Elf_Data in =
+ {
+ .d_type = ELF_T_PHDR,
+ .d_version = EV_CURRENT,
+ .d_size = phnum * phent,
+ .d_buf = NULL
+ };
+ if ((*memory_callback) (dwfl, phdr_segndx, &in.d_buf, &in.d_size,
+ phdr, phnum * phent, memory_callback_arg))
+ {
+ union
+ {
+ Elf32_Phdr p32;
+ Elf64_Phdr p64;
+ char data[phnum * phent];
+ } buf;
+ Elf_Data out =
+ {
+ .d_type = ELF_T_PHDR,
+ .d_version = EV_CURRENT,
+ .d_size = phnum * phent,
+ .d_buf = &buf
+ };
+ in.d_size = out.d_size;
+ if (likely ((elfclass == ELFCLASS32
+ ? elf32_xlatetom : elf64_xlatetom)
+ (&out, &in, elfdata) != NULL))
+ {
+ /* We are looking for PT_DYNAMIC. */
+ const union
+ {
+ Elf32_Phdr p32[phnum];
+ Elf64_Phdr p64[phnum];
+ } *u = (void *) &buf;
+ if (elfclass == ELFCLASS32)
+ {
+ for (size_t i = 0; i < phnum; ++i)
+ if (consider_phdr (u->p32[i].p_type,
+ u->p32[i].p_vaddr,
+ u->p32[i].p_filesz))
+ break;
+ }
+ else
+ {
+ for (size_t i = 0; i < phnum; ++i)
+ if (consider_phdr (u->p64[i].p_type,
+ u->p64[i].p_vaddr,
+ u->p64[i].p_filesz))
+ break;
+ }
+ }
+
+ (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
+ memory_callback_arg);
+ }
+ else
+ /* We could not read the executable's phdrs from the
+ memory image. If we have a presupplied executable,
+ we can still use the AT_PHDR and AT_ENTRY values to
+ verify it, and to adjust its bias if it's a PIE.
+
+ If there was an ET_EXEC module presupplied that contains
+ the AT_PHDR address, then we only consider that one.
+ We'll either accept it if its phdr location and e_entry
+ make sense or reject it if they don't. If there is no
+ presupplied ET_EXEC, then look for a presupplied module,
+ which might be a PIE (ET_DYN) that needs its bias adjusted. */
+ r_debug_vaddr = ((phdr_mod == NULL
+ || phdr_mod->main.elf == NULL
+ || phdr_mod->e_type != ET_EXEC)
+ ? find_executable (dwfl, phdr, entry,
+ &elfclass, &elfdata,
+ memory_callback,
+ memory_callback_arg)
+ : consider_executable (phdr_mod, phdr, entry,
+ &elfclass, &elfdata,
+ memory_callback,
+ memory_callback_arg));
+ }
+
+ /* If we found PT_DYNAMIC, search it for DT_DEBUG. */
+ if (dyn_filesz != 0)
+ {
+ if (dyn_bias != (GElf_Addr) -1)
+ dyn_vaddr += dyn_bias;
+
+ Elf_Data in =
+ {
+ .d_type = ELF_T_DYN,
+ .d_version = EV_CURRENT,
+ .d_size = dyn_filesz,
+ .d_buf = NULL
+ };
+ int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
+ if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
+ dyn_vaddr, dyn_filesz, memory_callback_arg))
+ {
+ union
+ {
+ Elf32_Dyn d32;
+ Elf64_Dyn d64;
+ char data[dyn_filesz];
+ } buf;
+ Elf_Data out =
+ {
+ .d_type = ELF_T_DYN,
+ .d_version = EV_CURRENT,
+ .d_size = dyn_filesz,
+ .d_buf = &buf
+ };
+ in.d_size = out.d_size;
+ if (likely ((elfclass == ELFCLASS32
+ ? elf32_xlatetom : elf64_xlatetom)
+ (&out, &in, elfdata) != NULL))
+ {
+ /* We are looking for DT_DEBUG. */
+ const union
+ {
+ Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
+ Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
+ } *u = (void *) &buf;
+ if (elfclass == ELFCLASS32)
+ {
+ size_t n = dyn_filesz / sizeof (Elf32_Dyn);
+ for (size_t i = 0; i < n; ++i)
+ if (u->d32[i].d_tag == DT_DEBUG)
+ {
+ r_debug_vaddr = u->d32[i].d_un.d_val;
+ break;
+ }
+ }
+ else
+ {
+ size_t n = dyn_filesz / sizeof (Elf64_Dyn);
+ for (size_t i = 0; i < n; ++i)
+ if (u->d64[i].d_tag == DT_DEBUG)
+ {
+ r_debug_vaddr = u->d64[i].d_un.d_val;
+ break;
+ }
+ }
+ }
+
+ (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
+ memory_callback_arg);
+ }
+ }
+ }
+ else
+ /* We have to look for a presupplied executable file to determine
+ the vaddr of its dynamic section and DT_DEBUG therein. */
+ r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
+ memory_callback, memory_callback_arg);
+
+ if (r_debug_vaddr == 0)
+ return 0;
+
+ /* For following pointers from struct link_map, we will use an
+ integrated memory access callback that can consult module text
+ elided from the core file. This is necessary when the l_name
+ pointer for the dynamic linker's own entry is a pointer into the
+ executable's .interp section. */
+ struct integrated_memory_callback mcb =
+ {
+ .memory_callback = memory_callback,
+ .memory_callback_arg = memory_callback_arg
+ };
+
+ /* Now we can follow the dynamic linker's library list. */
+ return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
+ &integrated_memory_callback, &mcb);
+}
+INTDEF (dwfl_link_map_report)
diff --git a/src/libdwfl/linux-kernel-modules.c b/src/libdwfl/linux-kernel-modules.c
new file mode 100644
index 00000000..e2392722
--- /dev/null
+++ b/src/libdwfl/linux-kernel-modules.c
@@ -0,0 +1,943 @@
+/* Standard libdwfl callbacks for debugging the running Linux kernel.
+ Copyright (C) 2005-2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+/* We include this before config.h because it can't handle _FILE_OFFSET_BITS.
+ Everything we need here is fine if its declarations just come first. */
+
+/* TODO ANDROID - defined in AndroidConfig.h. */
+#undef _FILE_OFFSET_BITS
+
+#include <fts.h>
+
+#include <config.h>
+
+#include "libdwflP.h"
+#include <inttypes.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#define KERNEL_MODNAME "kernel"
+
+#define MODULEDIRFMT "/lib/modules/%s"
+
+#define KNOTESFILE "/sys/kernel/notes"
+#define MODNOTESFMT "/sys/module/%s/notes"
+#define KSYMSFILE "/proc/kallsyms"
+#define MODULELIST "/proc/modules"
+#define SECADDRDIRFMT "/sys/module/%s/sections/"
+#define MODULE_SECT_NAME_LEN 32 /* Minimum any linux/module.h has had. */
+
+
+#if defined (USE_ZLIB) || defined (USE_BZLIB) || defined (USE_LZMA)
+static const char *vmlinux_suffixes[] =
+ {
+#ifdef USE_ZLIB
+ ".gz",
+#endif
+#ifdef USE_BZLIB
+ ".bz2",
+#endif
+#ifdef USE_LZMA
+ ".xz",
+#endif
+ };
+#endif
+
+/* Try to open the given file as it is or under the debuginfo directory. */
+static int
+try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug)
+{
+ if (*fname == NULL)
+ return -1;
+
+ /* Don't bother trying *FNAME itself here if the path will cause it to be
+ tried because we give its own basename as DEBUGLINK_FILE. */
+ int fd = ((((dwfl->callbacks->debuginfo_path
+ ? *dwfl->callbacks->debuginfo_path : NULL)
+ ?: DEFAULT_DEBUGINFO_PATH)[0] == ':') ? -1
+ : TEMP_FAILURE_RETRY (open64 (*fname, O_RDONLY)));
+
+ if (fd < 0)
+ {
+ char *debugfname = NULL;
+ Dwfl_Module fakemod = { .dwfl = dwfl };
+ /* First try the file's unadorned basename as DEBUGLINK_FILE,
+ to look for "vmlinux" files. */
+ fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
+ *fname, basename (*fname), 0,
+ &debugfname);
+ if (fd < 0 && try_debug)
+ /* Next, let the call use the default of basename + ".debug",
+ to look for "vmlinux.debug" files. */
+ fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
+ *fname, NULL, 0,
+ &debugfname);
+ if (debugfname != NULL)
+ {
+ free (*fname);
+ *fname = debugfname;
+ }
+ }
+
+#if defined (USE_ZLIB) || defined (USE_BZLIB) || defined (USE_LZMA)
+ if (fd < 0)
+ for (size_t i = 0;
+ i < sizeof vmlinux_suffixes / sizeof vmlinux_suffixes[0];
+ ++i)
+ {
+ char *zname;
+ if (asprintf (&zname, "%s%s", *fname, vmlinux_suffixes[i]) > 0)
+ {
+ fd = TEMP_FAILURE_RETRY (open64 (zname, O_RDONLY));
+ if (fd < 0)
+ free (zname);
+ else
+ {
+ free (*fname);
+ *fname = zname;
+ }
+ }
+ }
+#endif
+
+ if (fd < 0)
+ {
+ free (*fname);
+ *fname = NULL;
+ }
+
+ return fd;
+}
+
+static inline const char *
+kernel_release (void)
+{
+ /* Cache the `uname -r` string we'll use. */
+ static struct utsname utsname;
+ if (utsname.release[0] == '\0' && uname (&utsname) != 0)
+ return NULL;
+ return utsname.release;
+}
+
+static int
+find_kernel_elf (Dwfl *dwfl, const char *release, char **fname)
+{
+ if ((release[0] == '/'
+ ? asprintf (fname, "%s/vmlinux", release)
+ : asprintf (fname, "/boot/vmlinux-%s", release)) < 0)
+ return -1;
+
+ int fd = try_kernel_name (dwfl, fname, true);
+ if (fd < 0 && release[0] != '/')
+ {
+ free (*fname);
+ if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0)
+ return -1;
+ fd = try_kernel_name (dwfl, fname, true);
+ }
+
+ return fd;
+}
+
+static int
+get_release (Dwfl *dwfl, const char **release)
+{
+ if (dwfl == NULL)
+ return -1;
+
+ const char *release_string = release == NULL ? NULL : *release;
+ if (release_string == NULL)
+ {
+ release_string = kernel_release ();
+ if (release_string == NULL)
+ return errno;
+ if (release != NULL)
+ *release = release_string;
+ }
+
+ return 0;
+}
+
+static int
+report_kernel (Dwfl *dwfl, const char **release,
+ int (*predicate) (const char *module, const char *file))
+{
+ int result = get_release (dwfl, release);
+ if (unlikely (result != 0))
+ return result;
+
+ char *fname;
+ int fd = find_kernel_elf (dwfl, *release, &fname);
+
+ if (fd < 0)
+ result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL))
+ ? 0 : errno ?: ENOENT);
+ else
+ {
+ bool report = true;
+
+ if (predicate != NULL)
+ {
+ /* Let the predicate decide whether to use this one. */
+ int want = (*predicate) (KERNEL_MODNAME, fname);
+ if (want < 0)
+ result = errno;
+ report = want > 0;
+ }
+
+ if (report)
+ {
+ Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME,
+ fname, fd, 0);
+ if (mod == NULL)
+ result = -1;
+ else
+ /* The kernel is ET_EXEC, but always treat it as relocatable. */
+ mod->e_type = ET_DYN;
+ }
+
+ if (!report || result < 0)
+ close (fd);
+ }
+
+ free (fname);
+
+ return result;
+}
+
+/* Look for a kernel debug archive. If we find one, report all its modules.
+ If not, return ENOENT. */
+static int
+report_kernel_archive (Dwfl *dwfl, const char **release,
+ int (*predicate) (const char *module, const char *file))
+{
+ int result = get_release (dwfl, release);
+ if (unlikely (result != 0))
+ return result;
+
+ char *archive;
+ if (unlikely ((*release)[0] == '/'
+ ? asprintf (&archive, "%s/debug.a", *release)
+ : asprintf (&archive, MODULEDIRFMT "/debug.a", *release)) < 0)
+ return ENOMEM;
+
+ int fd = try_kernel_name (dwfl, &archive, false);
+ if (fd < 0)
+ result = errno ?: ENOENT;
+ else
+ {
+ /* We have the archive file open! */
+ Dwfl_Module *last = __libdwfl_report_offline (dwfl, NULL, archive, fd,
+ true, predicate);
+ if (unlikely (last == NULL))
+ result = -1;
+ else
+ {
+ /* Find the kernel and move it to the head of the list. */
+ Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
+ for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
+ if (!m->gc && m->e_type != ET_REL && !strcmp (m->name, "kernel"))
+ {
+ *prevp = m->next;
+ m->next = *tailp;
+ *tailp = m;
+ break;
+ }
+ }
+ }
+
+ free (archive);
+ return result;
+}
+
+static size_t
+check_suffix (const FTSENT *f, size_t namelen)
+{
+#define TRY(sfx) \
+ if ((namelen ? f->fts_namelen == namelen + sizeof sfx - 1 \
+ : f->fts_namelen >= sizeof sfx) \
+ && !memcmp (f->fts_name + f->fts_namelen - (sizeof sfx - 1), \
+ sfx, sizeof sfx)) \
+ return sizeof sfx - 1
+
+ TRY (".ko");
+#if USE_ZLIB
+ TRY (".ko.gz");
+#endif
+#if USE_BZLIB
+ TRY (".ko.bz2");
+#endif
+
+ return 0;
+
+#undef TRY
+}
+
+/* Report a kernel and all its modules found on disk, for offline use.
+ If RELEASE starts with '/', it names a directory to look in;
+ if not, it names a directory to find under /lib/modules/;
+ if null, /lib/modules/`uname -r` is used.
+ Returns zero on success, -1 if dwfl_report_module failed,
+ or an errno code if finding the files on disk failed. */
+int
+dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
+ int (*predicate) (const char *module,
+ const char *file))
+{
+ int result = report_kernel_archive (dwfl, &release, predicate);
+ if (result != ENOENT)
+ return result;
+
+ /* First report the kernel. */
+ result = report_kernel (dwfl, &release, predicate);
+ if (result == 0)
+ {
+ /* Do "find /lib/modules/RELEASE -name *.ko". */
+
+ char *modulesdir[] = { NULL, NULL };
+ if (release[0] == '/')
+ modulesdir[0] = (char *) release;
+ else
+ {
+ if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
+ return errno;
+ }
+
+ FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
+ if (modulesdir[0] == (char *) release)
+ modulesdir[0] = NULL;
+ if (fts == NULL)
+ {
+ free (modulesdir[0]);
+ return errno;
+ }
+
+ FTSENT *f;
+ while ((f = fts_read (fts)) != NULL)
+ {
+ /* Skip a "source" subtree, which tends to be large.
+ This insane hard-coding of names is what depmod does too. */
+ if (f->fts_namelen == sizeof "source" - 1
+ && !strcmp (f->fts_name, "source"))
+ {
+ fts_set (fts, f, FTS_SKIP);
+ continue;
+ }
+
+ switch (f->fts_info)
+ {
+ case FTS_F:
+ case FTS_SL:
+ case FTS_NSOK:;
+ /* See if this file name matches "*.ko". */
+ const size_t suffix = check_suffix (f, 0);
+ if (suffix)
+ {
+ /* We have a .ko file to report. Following the algorithm
+ by which the kernel makefiles set KBUILD_MODNAME, we
+ replace all ',' or '-' with '_' in the file name and
+ call that the module name. Modules could well be
+ built using different embedded names than their file
+ names. To handle that, we would have to look at the
+ __this_module.name contents in the module's text. */
+
+ char name[f->fts_namelen - suffix + 1];
+ for (size_t i = 0; i < f->fts_namelen - 3U; ++i)
+ if (f->fts_name[i] == '-' || f->fts_name[i] == ',')
+ name[i] = '_';
+ else
+ name[i] = f->fts_name[i];
+ name[f->fts_namelen - suffix] = '\0';
+
+ if (predicate != NULL)
+ {
+ /* Let the predicate decide whether to use this one. */
+ int want = (*predicate) (name, f->fts_path);
+ if (want < 0)
+ {
+ result = -1;
+ break;
+ }
+ if (!want)
+ continue;
+ }
+
+ if (dwfl_report_offline (dwfl, name, f->fts_path, -1) == NULL)
+ {
+ result = -1;
+ break;
+ }
+ }
+ continue;
+
+ case FTS_ERR:
+ case FTS_DNR:
+ case FTS_NS:
+ result = f->fts_errno;
+ break;
+
+ case FTS_SLNONE:
+ default:
+ continue;
+ }
+
+ /* We only get here in error cases. */
+ break;
+ }
+ fts_close (fts);
+ free (modulesdir[0]);
+ }
+
+ return result;
+}
+INTDEF (dwfl_linux_kernel_report_offline)
+
+
+/* Grovel around to guess the bounds of the runtime kernel image. */
+static int
+intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes)
+{
+ FILE *f = fopen (KSYMSFILE, "r");
+ if (f == NULL)
+ return errno;
+
+ (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
+
+ *notes = 0;
+
+ char *line = NULL;
+ size_t linesz = 0;
+ size_t n;
+ char *p = NULL;
+ const char *type;
+
+ inline bool read_address (Dwarf_Addr *addr)
+ {
+ if ((n = getline (&line, &linesz, f)) < 1 || line[n - 2] == ']')
+ return false;
+ *addr = strtoull (line, &p, 16);
+ p += strspn (p, " \t");
+ type = strsep (&p, " \t\n");
+ if (type == NULL)
+ return false;
+ return p != NULL && p != line;
+ }
+
+ int result;
+ do
+ result = read_address (start) ? 0 : -1;
+ while (result == 0 && strchr ("TtRr", *type) == NULL);
+
+ if (result == 0)
+ {
+ *end = *start;
+ while (read_address (end))
+ if (*notes == 0 && !strcmp (p, "__start_notes\n"))
+ *notes = *end;
+
+ Dwarf_Addr round_kernel = sysconf (_SC_PAGE_SIZE);
+ *start &= -(Dwarf_Addr) round_kernel;
+ *end += round_kernel - 1;
+ *end &= -(Dwarf_Addr) round_kernel;
+ if (*start >= *end || *end - *start < round_kernel)
+ result = -1;
+ }
+ free (line);
+
+ if (result == -1)
+ result = ferror_unlocked (f) ? errno : ENOEXEC;
+
+ fclose (f);
+
+ return result;
+}
+
+
+/* Look for a build ID note in NOTESFILE and associate the ID with MOD. */
+static int
+check_notes (Dwfl_Module *mod, const char *notesfile,
+ Dwarf_Addr vaddr, const char *secname)
+{
+ int fd = open64 (notesfile, O_RDONLY);
+ if (fd < 0)
+ return 1;
+
+ assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr));
+ assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr));
+ union
+ {
+ GElf_Nhdr nhdr;
+ unsigned char data[8192];
+ } buf;
+
+ ssize_t n = read (fd, buf.data, sizeof buf);
+ close (fd);
+
+ if (n <= 0)
+ return 1;
+
+ unsigned char *p = buf.data;
+ while (p < &buf.data[n])
+ {
+ /* No translation required since we are reading the native kernel. */
+ GElf_Nhdr *nhdr = (void *) p;
+ p += sizeof *nhdr;
+ unsigned char *name = p;
+ p += (nhdr->n_namesz + 3) & -4U;
+ unsigned char *bits = p;
+ p += (nhdr->n_descsz + 3) & -4U;
+
+ if (p <= &buf.data[n]
+ && nhdr->n_type == NT_GNU_BUILD_ID
+ && nhdr->n_namesz == sizeof "GNU"
+ && !memcmp (name, "GNU", sizeof "GNU"))
+ {
+ /* Found it. For a module we must figure out its VADDR now. */
+
+ if (secname != NULL
+ && (INTUSE(dwfl_linux_kernel_module_section_address)
+ (mod, NULL, mod->name, 0, secname, 0, NULL, &vaddr) != 0
+ || vaddr == (GElf_Addr) -1l))
+ vaddr = 0;
+
+ if (vaddr != 0)
+ vaddr += bits - buf.data;
+ return INTUSE(dwfl_module_report_build_id) (mod, bits,
+ nhdr->n_descsz, vaddr);
+ }
+ }
+
+ return 0;
+}
+
+/* Look for a build ID for the kernel. */
+static int
+check_kernel_notes (Dwfl_Module *kernelmod, GElf_Addr vaddr)
+{
+ return check_notes (kernelmod, KNOTESFILE, vaddr, NULL) < 0 ? -1 : 0;
+}
+
+/* Look for a build ID for a loaded kernel module. */
+static int
+check_module_notes (Dwfl_Module *mod)
+{
+ char *dirs[2] = { NULL, NULL };
+ if (asprintf (&dirs[0], MODNOTESFMT, mod->name) < 0)
+ return ENOMEM;
+
+ FTS *fts = fts_open (dirs, FTS_NOSTAT | FTS_LOGICAL, NULL);
+ if (fts == NULL)
+ {
+ free (dirs[0]);
+ return 0;
+ }
+
+ int result = 0;
+ FTSENT *f;
+ while ((f = fts_read (fts)) != NULL)
+ {
+ switch (f->fts_info)
+ {
+ case FTS_F:
+ case FTS_SL:
+ case FTS_NSOK:
+ result = check_notes (mod, f->fts_accpath, 0, f->fts_name);
+ if (result > 0) /* Nothing found. */
+ {
+ result = 0;
+ continue;
+ }
+ break;
+
+ case FTS_ERR:
+ case FTS_DNR:
+ result = f->fts_errno;
+ break;
+
+ case FTS_NS:
+ case FTS_SLNONE:
+ default:
+ continue;
+ }
+
+ /* We only get here when finished or in error cases. */
+ break;
+ }
+ fts_close (fts);
+ free (dirs[0]);
+
+ return result;
+}
+
+int
+dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
+{
+ Dwarf_Addr start;
+ Dwarf_Addr end;
+ inline Dwfl_Module *report (void)
+ {
+ return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end);
+ }
+
+ /* This is a bit of a kludge. If we already reported the kernel,
+ don't bother figuring it out again--it never changes. */
+ for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
+ if (!strcmp (m->name, KERNEL_MODNAME))
+ {
+ start = m->low_addr;
+ end = m->high_addr;
+ return report () == NULL ? -1 : 0;
+ }
+
+ /* Try to figure out the bounds of the kernel image without
+ looking for any vmlinux file. */
+ Dwarf_Addr notes;
+ /* The compiler cannot deduce that if intuit_kernel_bounds returns
+ zero NOTES will be initialized. Fake the initialization. */
+ asm ("" : "=m" (notes));
+ int result = intuit_kernel_bounds (&start, &end, &notes);
+ if (result == 0)
+ {
+ Dwfl_Module *mod = report ();
+ return unlikely (mod == NULL) ? -1 : check_kernel_notes (mod, notes);
+ }
+ if (result != ENOENT)
+ return result;
+
+ /* Find the ELF file for the running kernel and dwfl_report_elf it. */
+ return report_kernel (dwfl, NULL, NULL);
+}
+INTDEF (dwfl_linux_kernel_report_kernel)
+
+
+/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules. */
+
+int
+dwfl_linux_kernel_find_elf (Dwfl_Module *mod,
+ void **userdata __attribute__ ((unused)),
+ const char *module_name,
+ Dwarf_Addr base __attribute__ ((unused)),
+ char **file_name, Elf **elfp)
+{
+ if (mod->build_id_len > 0)
+ {
+ int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0,
+ file_name, elfp);
+ if (fd >= 0 || mod->main.elf != NULL || errno != 0)
+ return fd;
+ }
+
+ const char *release = kernel_release ();
+ if (release == NULL)
+ return errno;
+
+ if (!strcmp (module_name, KERNEL_MODNAME))
+ return find_kernel_elf (mod->dwfl, release, file_name);
+
+ /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */
+
+ char *modulesdir[] = { NULL, NULL };
+ if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
+ return -1;
+
+ FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
+ if (fts == NULL)
+ {
+ free (modulesdir[0]);
+ return -1;
+ }
+
+ size_t namelen = strlen (module_name);
+
+ /* This is a kludge. There is no actual necessary relationship between
+ the name of the .ko file installed and the module name the kernel
+ knows it by when it's loaded. The kernel's only idea of the module
+ name comes from the name embedded in the object's magic
+ .gnu.linkonce.this_module section.
+
+ In practice, these module names match the .ko file names except for
+ some using '_' and some using '-'. So our cheap kludge is to look for
+ two files when either a '_' or '-' appears in a module name, one using
+ only '_' and one only using '-'. */
+
+ char alternate_name[namelen + 1];
+ inline bool subst_name (char from, char to)
+ {
+ const char *n = memchr (module_name, from, namelen);
+ if (n == NULL)
+ return false;
+ char *a = mempcpy (alternate_name, module_name, n - module_name);
+ *a++ = to;
+ ++n;
+ const char *p;
+ while ((p = memchr (n, from, namelen - (n - module_name))) != NULL)
+ {
+ a = mempcpy (a, n, p - n);
+ *a++ = to;
+ n = p + 1;
+ }
+ memcpy (a, n, namelen - (n - module_name) + 1);
+ return true;
+ }
+ if (!subst_name ('-', '_') && !subst_name ('_', '-'))
+ alternate_name[0] = '\0';
+
+ FTSENT *f;
+ int error = ENOENT;
+ while ((f = fts_read (fts)) != NULL)
+ {
+ /* Skip a "source" subtree, which tends to be large.
+ This insane hard-coding of names is what depmod does too. */
+ if (f->fts_namelen == sizeof "source" - 1
+ && !strcmp (f->fts_name, "source"))
+ {
+ fts_set (fts, f, FTS_SKIP);
+ continue;
+ }
+
+ error = ENOENT;
+ switch (f->fts_info)
+ {
+ case FTS_F:
+ case FTS_SL:
+ case FTS_NSOK:
+ /* See if this file name is "MODULE_NAME.ko". */
+ if (check_suffix (f, namelen)
+ && (!memcmp (f->fts_name, module_name, namelen)
+ || !memcmp (f->fts_name, alternate_name, namelen)))
+ {
+ int fd = open64 (f->fts_accpath, O_RDONLY);
+ *file_name = strdup (f->fts_path);
+ fts_close (fts);
+ free (modulesdir[0]);
+ if (fd < 0)
+ free (*file_name);
+ else if (*file_name == NULL)
+ {
+ close (fd);
+ fd = -1;
+ }
+ return fd;
+ }
+ break;
+
+ case FTS_ERR:
+ case FTS_DNR:
+ case FTS_NS:
+ error = f->fts_errno;
+ break;
+
+ case FTS_SLNONE:
+ default:
+ break;
+ }
+ }
+
+ fts_close (fts);
+ free (modulesdir[0]);
+ errno = error;
+ return -1;
+}
+INTDEF (dwfl_linux_kernel_find_elf)
+
+
+/* Dwfl_Callbacks.section_address for kernel modules in the running Linux.
+ We read the information from /sys/module directly. */
+
+int
+dwfl_linux_kernel_module_section_address
+(Dwfl_Module *mod __attribute__ ((unused)),
+ void **userdata __attribute__ ((unused)),
+ const char *modname, Dwarf_Addr base __attribute__ ((unused)),
+ const char *secname, Elf32_Word shndx __attribute__ ((unused)),
+ const GElf_Shdr *shdr __attribute__ ((unused)),
+ Dwarf_Addr *addr)
+{
+ char *sysfile;
+ if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0)
+ return DWARF_CB_ABORT;
+
+ FILE *f = fopen (sysfile, "r");
+ free (sysfile);
+
+ if (f == NULL)
+ {
+ if (errno == ENOENT)
+ {
+ /* The .modinfo and .data.percpu sections are never kept
+ loaded in the kernel. If the kernel was compiled without
+ CONFIG_MODULE_UNLOAD, the .exit.* sections are not
+ actually loaded at all.
+
+ Setting *ADDR to -1 tells the caller this section is
+ actually absent from memory. */
+
+ if (!strcmp (secname, ".modinfo")
+ || !strcmp (secname, ".data.percpu")
+ || !strncmp (secname, ".exit", 5))
+ {
+ *addr = (Dwarf_Addr) -1l;
+ return DWARF_CB_OK;
+ }
+
+ /* The goofy PPC64 module_frob_arch_sections function tweaks
+ the section names as a way to control other kernel code's
+ behavior, and this cruft leaks out into the /sys information.
+ The file name for ".init*" may actually look like "_init*". */
+
+ const bool is_init = !strncmp (secname, ".init", 5);
+ if (is_init)
+ {
+ if (asprintf (&sysfile, SECADDRDIRFMT "_%s",
+ modname, &secname[1]) < 0)
+ return ENOMEM;
+ f = fopen (sysfile, "r");
+ free (sysfile);
+ if (f != NULL)
+ goto ok;
+ }
+
+ /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1.
+ In case that size increases in the future, look for longer
+ truncated names first. */
+ size_t namelen = strlen (secname);
+ if (namelen >= MODULE_SECT_NAME_LEN)
+ {
+ int len = asprintf (&sysfile, SECADDRDIRFMT "%s",
+ modname, secname);
+ if (len < 0)
+ return DWARF_CB_ABORT;
+ char *end = sysfile + len;
+ do
+ {
+ *--end = '\0';
+ f = fopen (sysfile, "r");
+ if (is_init && f == NULL && errno == ENOENT)
+ {
+ sysfile[len - namelen] = '_';
+ f = fopen (sysfile, "r");
+ sysfile[len - namelen] = '.';
+ }
+ }
+ while (f == NULL && errno == ENOENT
+ && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN);
+ free (sysfile);
+
+ if (f != NULL)
+ goto ok;
+ }
+ }
+
+ return DWARF_CB_ABORT;
+ }
+
+ ok:
+ (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
+
+ int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0
+ : ferror_unlocked (f) ? errno : ENOEXEC);
+ fclose (f);
+
+ if (result == 0)
+ return DWARF_CB_OK;
+
+ errno = result;
+ return DWARF_CB_ABORT;
+}
+INTDEF (dwfl_linux_kernel_module_section_address)
+
+int
+dwfl_linux_kernel_report_modules (Dwfl *dwfl)
+{
+ FILE *f = fopen (MODULELIST, "r");
+ if (f == NULL)
+ return errno;
+
+ (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
+
+ int result = 0;
+ Dwarf_Addr modaddr;
+ unsigned long int modsz;
+ char modname[128];
+ char *line = NULL;
+ size_t linesz = 0;
+ /* We can't just use fscanf here because it's not easy to distinguish \n
+ from other whitespace so as to take the optional word following the
+ address but always stop at the end of the line. */
+ while (getline (&line, &linesz, f) > 0
+ && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n",
+ modname, &modsz, &modaddr) == 3)
+ {
+ Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, modname,
+ modaddr, modaddr + modsz);
+ if (mod == NULL)
+ {
+ result = -1;
+ break;
+ }
+
+ result = check_module_notes (mod);
+ }
+ free (line);
+
+ if (result == 0)
+ result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
+
+ fclose (f);
+
+ return result;
+}
+INTDEF (dwfl_linux_kernel_report_modules)
diff --git a/src/libdwfl/linux-proc-maps.c b/src/libdwfl/linux-proc-maps.c
new file mode 100644
index 00000000..8504a5f3
--- /dev/null
+++ b/src/libdwfl/linux-proc-maps.c
@@ -0,0 +1,348 @@
+/* Standard libdwfl callbacks for debugging a live Linux process.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <inttypes.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <endian.h>
+
+
+#define PROCMAPSFMT "/proc/%d/maps"
+#define PROCMEMFMT "/proc/%d/mem"
+#define PROCAUXVFMT "/proc/%d/auxv"
+
+
+/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag. */
+
+static int
+grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
+{
+ char *fname;
+ if (asprintf (&fname, PROCAUXVFMT, pid) < 0)
+ return ENOMEM;
+
+ int fd = open64 (fname, O_RDONLY);
+ free (fname);
+ if (fd < 0)
+ return errno == ENOENT ? 0 : errno;
+
+ ssize_t nread;
+ do
+ {
+ union
+ {
+ char buffer[sizeof (long int) * 2 * 64];
+ Elf64_auxv_t a64[sizeof (long int) * 2 * 64 / sizeof (Elf64_auxv_t)];
+ Elf32_auxv_t a32[sizeof (long int) * 2 * 32 / sizeof (Elf32_auxv_t)];
+ } d;
+ nread = read (fd, &d, sizeof d);
+ if (nread > 0)
+ {
+ switch (sizeof (long int))
+ {
+ case 4:
+ for (size_t i = 0; (char *) &d.a32[i] < &d.buffer[nread]; ++i)
+ if (d.a32[i].a_type == AT_SYSINFO_EHDR)
+ {
+ *sysinfo_ehdr = d.a32[i].a_un.a_val;
+ if (dwfl->segment_align > 1)
+ {
+ nread = 0;
+ break;
+ }
+ }
+ else if (d.a32[i].a_type == AT_PAGESZ
+ && dwfl->segment_align <= 1)
+ dwfl->segment_align = d.a32[i].a_un.a_val;
+ break;
+ case 8:
+ for (size_t i = 0; (char *) &d.a64[i] < &d.buffer[nread]; ++i)
+ if (d.a64[i].a_type == AT_SYSINFO_EHDR)
+ {
+ *sysinfo_ehdr = d.a64[i].a_un.a_val;
+ if (dwfl->segment_align > 1)
+ {
+ nread = 0;
+ break;
+ }
+ }
+ else if (d.a64[i].a_type == AT_PAGESZ
+ && dwfl->segment_align <= 1)
+ dwfl->segment_align = d.a64[i].a_un.a_val;
+ break;
+ default:
+ abort ();
+ break;
+ }
+ }
+ }
+ while (nread > 0);
+
+ close (fd);
+
+ return nread < 0 ? errno : 0;
+}
+
+static int
+proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
+{
+ unsigned int last_dmajor = -1, last_dminor = -1;
+ uint64_t last_ino = -1;
+ char *last_file = NULL;
+ Dwarf_Addr low = 0, high = 0;
+
+ inline bool report (void)
+ {
+ if (last_file != NULL)
+ {
+ Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file,
+ low, high);
+ free (last_file);
+ last_file = NULL;
+ if (unlikely (mod == NULL))
+ return true;
+ }
+ return false;
+ }
+
+ char *line = NULL;
+ size_t linesz;
+ ssize_t len;
+ while ((len = getline (&line, &linesz, f)) > 0)
+ {
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+
+ Dwarf_Addr start, end, offset;
+ unsigned int dmajor, dminor;
+ uint64_t ino;
+ int nread = -1;
+ if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64
+ " %x:%x %" PRIi64 " %n",
+ &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6
+ || nread <= 0)
+ {
+ free (line);
+ return ENOEXEC;
+ }
+
+ /* If this is the special mapping AT_SYSINFO_EHDR pointed us at,
+ report the last one and then this special one. */
+ if (start == sysinfo_ehdr && start != 0)
+ {
+ if (report ())
+ {
+ bad_report:
+ free (line);
+ fclose (f);
+ return -1;
+ }
+
+ low = start;
+ high = end;
+ if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
+ || report ())
+ goto bad_report;
+ }
+
+ char *file = line + nread + strspn (line + nread, " \t");
+ if (file[0] == '\0' || (ino == 0 && dmajor == 0 && dminor == 0))
+ /* This line doesn't indicate a file mapping. */
+ continue;
+
+ if (last_file != NULL
+ && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor)
+ {
+ /* This is another portion of the same file's mapping. */
+ assert (!strcmp (last_file, file));
+ high = end;
+ }
+ else
+ {
+ /* This is a different file mapping. Report the last one. */
+ if (report ())
+ goto bad_report;
+ low = start;
+ high = end;
+ last_file = strdup (file);
+ last_ino = ino;
+ last_dmajor = dmajor;
+ last_dminor = dminor;
+ }
+ }
+ free (line);
+
+ int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
+
+ /* Report the final one. */
+ bool lose = report ();
+
+ return result != 0 ? result : lose ? -1 : 0;
+}
+
+int
+dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f)
+{
+ return proc_maps_report (dwfl, f, 0, 0);
+}
+INTDEF (dwfl_linux_proc_maps_report)
+
+int
+dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
+{
+ if (dwfl == NULL)
+ return -1;
+
+ /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it. */
+ GElf_Addr sysinfo_ehdr = 0;
+ int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr);
+ if (result != 0)
+ return result;
+
+ char *fname;
+ if (asprintf (&fname, PROCMAPSFMT, pid) < 0)
+ return ENOMEM;
+
+ FILE *f = fopen (fname, "r");
+ free (fname);
+ if (f == NULL)
+ return errno;
+
+ (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
+
+ result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid);
+
+ fclose (f);
+
+ return result;
+}
+INTDEF (dwfl_linux_proc_report)
+
+static ssize_t
+read_proc_memory (void *arg, void *data, GElf_Addr address,
+ size_t minread, size_t maxread)
+{
+ const int fd = *(const int *) arg;
+ ssize_t nread = pread64 (fd, data, maxread, (off64_t) address);
+ /* Some kernels don't actually let us do this read, ignore those errors. */
+ if (nread < 0 && (errno == EINVAL || errno == EPERM))
+ return 0;
+ if (nread > 0 && (size_t) nread < minread)
+ nread = 0;
+ return nread;
+}
+
+extern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma,
+ GElf_Addr *loadbasep,
+ ssize_t (*read_memory) (void *arg,
+ void *data,
+ GElf_Addr address,
+ size_t minread,
+ size_t maxread),
+ void *arg);
+
+
+/* Dwfl_Callbacks.find_elf */
+
+int
+dwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
+ void **userdata __attribute__ ((unused)),
+ const char *module_name, Dwarf_Addr base,
+ char **file_name, Elf **elfp)
+{
+ if (module_name[0] == '/')
+ {
+ int fd = open64 (module_name, O_RDONLY);
+ if (fd >= 0)
+ {
+ *file_name = strdup (module_name);
+ if (*file_name == NULL)
+ {
+ close (fd);
+ return ENOMEM;
+ }
+ }
+ return fd;
+ }
+
+ int pid;
+ if (sscanf (module_name, "[vdso: %d]", &pid) == 1)
+ {
+ /* Special case for in-memory ELF image. */
+
+ char *fname;
+ if (asprintf (&fname, PROCMEMFMT, pid) < 0)
+ return -1;
+
+ int fd = open64 (fname, O_RDONLY);
+ free (fname);
+ if (fd < 0)
+ return -1;
+
+ *elfp = elf_from_remote_memory (base, NULL, &read_proc_memory, &fd);
+
+ close (fd);
+
+ *file_name = NULL;
+ return -1;
+ }
+
+ abort ();
+ return -1;
+}
+INTDEF (dwfl_linux_proc_find_elf)
diff --git a/src/libdwfl/lzma.c b/src/libdwfl/lzma.c
new file mode 100644
index 00000000..3edfdc22
--- /dev/null
+++ b/src/libdwfl/lzma.c
@@ -0,0 +1,4 @@
+/* liblzma is pretty close to zlib and bzlib. */
+
+#define LZMA
+#include "gzip.c"
diff --git a/src/libdwfl/offline.c b/src/libdwfl/offline.c
new file mode 100644
index 00000000..34aa9f84
--- /dev/null
+++ b/src/libdwfl/offline.c
@@ -0,0 +1,329 @@
+/* Recover relocatibility for addresses computed from debug information.
+ Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include <fcntl.h>
+#include <unistd.h>
+
+/* Since dwfl_report_elf lays out the sections already, this will only be
+ called when the section headers of the debuginfo file are being
+ consulted instead, or for the section placed at 0. With binutils
+ strip-to-debug, the symbol table is in the debuginfo file and relocation
+ looks there. */
+int
+dwfl_offline_section_address (Dwfl_Module *mod,
+ void **userdata __attribute__ ((unused)),
+ const char *modname __attribute__ ((unused)),
+ Dwarf_Addr base __attribute__ ((unused)),
+ const char *secname __attribute__ ((unused)),
+ Elf32_Word shndx,
+ const GElf_Shdr *shdr __attribute__ ((unused)),
+ Dwarf_Addr *addr)
+{
+ assert (mod->e_type == ET_REL);
+ assert (shdr->sh_addr == 0);
+ assert (shdr->sh_flags & SHF_ALLOC);
+
+ if (mod->debug.elf == NULL)
+ /* We are only here because sh_addr is zero even though layout is complete.
+ The first section in the first file under -e is placed at 0. */
+ return 0;
+
+ /* The section numbers might not match between the two files.
+ The best we can rely on is the order of SHF_ALLOC sections. */
+
+ Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
+ Elf_Scn *scn = NULL;
+ uint_fast32_t skip_alloc = 0;
+ while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
+ {
+ assert (scn != NULL);
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (sh == NULL))
+ return -1;
+ if (sh->sh_flags & SHF_ALLOC)
+ ++skip_alloc;
+ }
+
+ scn = NULL;
+ while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (main_shdr == NULL))
+ return -1;
+ if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
+ {
+ assert (main_shdr->sh_flags == shdr->sh_flags);
+ *addr = main_shdr->sh_addr;
+ return 0;
+ }
+ }
+
+ /* This should never happen. */
+ return -1;
+}
+INTDEF (dwfl_offline_section_address)
+
+/* Forward declarations. */
+static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd, Elf *elf);
+static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd, Elf *elf,
+ int (*predicate) (const char *module,
+ const char *file));
+
+/* Report one module for an ELF file, or many for an archive.
+ Always consumes ELF and FD. */
+static Dwfl_Module *
+process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
+ Elf *elf, int (*predicate) (const char *module,
+ const char *file))
+{
+ switch (elf_kind (elf))
+ {
+ default:
+ case ELF_K_NONE:
+ __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
+ return NULL;
+
+ case ELF_K_ELF:
+ return process_elf (dwfl, name, file_name, fd, elf);
+
+ case ELF_K_AR:
+ return process_archive (dwfl, name, file_name, fd, elf, predicate);
+ }
+}
+
+/* Report the open ELF file as a module. Always consumes ELF and FD. */
+static Dwfl_Module *
+process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
+ Elf *elf)
+{
+ Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
+ dwfl->offline_next_address, false);
+ if (mod != NULL)
+ {
+ /* If this is an ET_EXEC file with fixed addresses, the address range
+ it consumed may or may not intersect with the arbitrary range we
+ will use for relocatable modules. Make sure we always use a free
+ range for the offline allocations. If this module did use
+ offline_next_address, it may have rounded it up for the module's
+ alignment requirements. */
+ if ((dwfl->offline_next_address >= mod->low_addr
+ || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
+ && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
+ dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
+
+ /* Don't keep the file descriptor around. */
+ if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
+ {
+ close (mod->main.fd);
+ mod->main.fd = -1;
+ }
+ }
+
+ return mod;
+}
+
+/* Always consumes MEMBER. Returns elf_next result on success.
+ For errors returns ELF_C_NULL with *MOD set to null. */
+static Elf_Cmd
+process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
+ int (*predicate) (const char *module, const char *file),
+ int fd, Elf *member, Dwfl_Module **mod)
+{
+ const Elf_Arhdr *h = elf_getarhdr (member);
+ if (unlikely (h == NULL))
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ fail:
+ elf_end (member);
+ *mod = NULL;
+ return ELF_C_NULL;
+ }
+
+ if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//"))
+ {
+ skip:;
+ /* Skip this and go to the next. */
+ Elf_Cmd result = elf_next (member);
+ elf_end (member);
+ return result;
+ }
+
+ char *member_name;
+ if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
+ {
+ nomem:
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ elf_end (member);
+ *mod = NULL;
+ return ELF_C_NULL;
+ }
+
+ char *module_name = NULL;
+ if (name == NULL || name[0] == '\0')
+ name = h->ar_name;
+ else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
+ {
+ free (member_name);
+ goto nomem;
+ }
+ else
+ name = module_name;
+
+ if (predicate != NULL)
+ {
+ /* Let the predicate decide whether to use this one. */
+ int want = (*predicate) (name, member_name);
+ if (want <= 0)
+ {
+ free (member_name);
+ free (module_name);
+ if (unlikely (want < 0))
+ {
+ __libdwfl_seterrno (DWFL_E_CB);
+ goto fail;
+ }
+ goto skip;
+ }
+ }
+
+ /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
+ though it's the same fd for all the members.
+ On module teardown we will close it only on the last Elf reference. */
+ *mod = process_file (dwfl, name, member_name, fd, member, predicate);
+ free (member_name);
+ free (module_name);
+
+ if (*mod == NULL) /* process_file called elf_end. */
+ return ELF_C_NULL;
+
+ /* Advance the archive-reading offset for the next iteration. */
+ return elf_next (member);
+}
+
+/* Report each member of the archive as its own module. */
+static Dwfl_Module *
+process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
+ Elf *archive,
+ int (*predicate) (const char *module, const char *file))
+
+{
+ Dwfl_Module *mod = NULL;
+ Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
+ if (unlikely (member == NULL)) /* Empty archive. */
+ {
+ __libdwfl_seterrno (DWFL_E_BADELF);
+ return NULL;
+ }
+
+ while (process_archive_member (dwfl, name, file_name, predicate,
+ fd, member, &mod) != ELF_C_NULL)
+ member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
+
+ /* We can drop the archive Elf handle even if we're still using members
+ in live modules. When the last module's elf_end on a member returns
+ zero, that module will close FD. If no modules survived the predicate,
+ we are all done with the file right here. */
+ if (mod != NULL /* If no modules, caller will clean up. */
+ && elf_end (archive) == 0)
+ close (fd);
+
+ return mod;
+}
+
+Dwfl_Module *
+internal_function
+__libdwfl_report_offline (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd, bool closefd,
+ int (*predicate) (const char *module,
+ const char *file))
+{
+ Elf *elf;
+ Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
+ if (error != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (error);
+ return NULL;
+ }
+ Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
+ if (mod == NULL)
+ {
+ elf_end (elf);
+ if (closefd)
+ close (fd);
+ }
+ return mod;
+}
+
+Dwfl_Module *
+dwfl_report_offline (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd)
+{
+ if (dwfl == NULL)
+ return NULL;
+
+ bool closefd = false;
+ if (fd < 0)
+ {
+ closefd = true;
+ fd = open64 (file_name, O_RDONLY);
+ if (fd < 0)
+ {
+ __libdwfl_seterrno (DWFL_E_ERRNO);
+ return NULL;
+ }
+ }
+
+ return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
+}
+INTDEF (dwfl_report_offline)
diff --git a/src/libdwfl/open.c b/src/libdwfl/open.c
new file mode 100644
index 00000000..397af358
--- /dev/null
+++ b/src/libdwfl/open.c
@@ -0,0 +1,203 @@
+/* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
+ Copyright (C) 2009 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "../libelf/libelfP.h"
+#undef _
+#include "libdwflP.h"
+
+#include <unistd.h>
+
+#if !USE_ZLIB
+# define __libdw_gunzip(...) false
+#endif
+
+#if !USE_BZLIB
+# define __libdw_bunzip2(...) false
+#endif
+
+#if !USE_LZMA
+# define __libdw_unlzma(...) false
+#endif
+
+/* Consumes and replaces *ELF only on success. */
+static Dwfl_Error
+decompress (int fd __attribute__ ((unused)), Elf **elf)
+{
+ Dwfl_Error error = DWFL_E_BADELF;
+ void *buffer = NULL;
+ size_t size = 0;
+
+#if USE_ZLIB || USE_BZLIB || USE_LZMA
+ const off64_t offset = (*elf)->start_offset;
+ void *const mapped = ((*elf)->map_address == NULL ? NULL
+ : (*elf)->map_address + offset);
+ const size_t mapped_size = (*elf)->maximum_size;
+ if (mapped_size == 0)
+ return error;
+
+ error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
+ if (error == DWFL_E_BADELF)
+ error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
+ if (error == DWFL_E_BADELF)
+ error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
+#endif
+
+ if (error == DWFL_E_NOERROR)
+ {
+ if (unlikely (size == 0))
+ {
+ error = DWFL_E_BADELF;
+ free (buffer);
+ }
+ else
+ {
+ Elf *memelf = elf_memory (buffer, size);
+ if (memelf == NULL)
+ {
+ error = DWFL_E_LIBELF;
+ free (buffer);
+ }
+ else
+ {
+ memelf->flags |= ELF_F_MALLOCED;
+ elf_end (*elf);
+ *elf = memelf;
+ }
+ }
+ }
+ else
+ free (buffer);
+
+ return error;
+}
+
+static Dwfl_Error
+what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd)
+{
+ Dwfl_Error error = DWFL_E_NOERROR;
+ *kind = elf_kind (*elfp);
+ if (unlikely (*kind == ELF_K_NONE))
+ {
+ if (unlikely (*elfp == NULL))
+ error = DWFL_E_LIBELF;
+ else
+ {
+ error = decompress (fd, elfp);
+ if (error == DWFL_E_NOERROR)
+ {
+ *close_fd = true;
+ *kind = elf_kind (*elfp);
+ }
+ }
+ }
+ return error;
+}
+
+Dwfl_Error internal_function
+__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
+{
+ bool close_fd = false;
+
+ Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
+
+ Elf_Kind kind;
+ Dwfl_Error error = what_kind (*fdp, &elf, &kind, &close_fd);
+ if (error == DWFL_E_BADELF)
+ {
+ /* It's not an ELF file or a compressed file.
+ See if it's an image with a header preceding the real file. */
+
+ off64_t offset = elf->start_offset;
+ error = __libdw_image_header (*fdp, &offset,
+ (elf->map_address == NULL ? NULL
+ : elf->map_address + offset),
+ elf->maximum_size);
+ if (error == DWFL_E_NOERROR)
+ {
+ /* Pure evil. libelf needs some better interfaces. */
+ elf->kind = ELF_K_AR;
+ elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
+ elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
+ elf->state.ar.offset = offset - sizeof (struct ar_hdr);
+ Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
+ elf->kind = ELF_K_NONE;
+ if (unlikely (subelf == NULL))
+ error = DWFL_E_LIBELF;
+ else
+ {
+ subelf->parent = NULL;
+ subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
+ elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
+ elf_end (elf);
+ elf = subelf;
+ error = what_kind (*fdp, &elf, &kind, &close_fd);
+ }
+ }
+ }
+
+ if (error == DWFL_E_NOERROR
+ && kind != ELF_K_ELF
+ && !(archive_ok && kind == ELF_K_AR))
+ error = DWFL_E_BADELF;
+
+ if (error != DWFL_E_NOERROR)
+ {
+ elf_end (elf);
+ elf = NULL;
+ }
+
+ if (error == DWFL_E_NOERROR ? close_fd : close_on_fail)
+ {
+ close (*fdp);
+ *fdp = -1;
+ }
+
+ *elfp = elf;
+ return error;
+}
diff --git a/src/libdwfl/relocate.c b/src/libdwfl/relocate.c
new file mode 100644
index 00000000..95206f47
--- /dev/null
+++ b/src/libdwfl/relocate.c
@@ -0,0 +1,655 @@
+/* Relocate debug information.
+ Copyright (C) 2005-2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+typedef uint8_t GElf_Byte;
+
+/* Adjust *VALUE to add the load address of the SHNDX section.
+ We update the section header in place to cache the result. */
+
+Dwfl_Error
+internal_function
+__libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
+ Elf32_Word shndx, GElf_Addr *value)
+{
+ assert (mod->e_type == ET_REL);
+
+ Elf_Scn *refscn = elf_getscn (elf, shndx);
+ GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
+ if (refshdr == NULL)
+ return DWFL_E_LIBELF;
+
+ if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
+ {
+ /* This is a loaded section. Find its actual
+ address and update the section header. */
+
+ if (*shstrndx == SHN_UNDEF
+ && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0))
+ return DWFL_E_LIBELF;
+
+ const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
+ if (unlikely (name == NULL))
+ return DWFL_E_LIBELF;
+
+ if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
+ name, shndx, refshdr,
+ &refshdr->sh_addr))
+ return CBFAIL;
+
+ if (refshdr->sh_addr == (Dwarf_Addr) -1l)
+ /* The callback indicated this section wasn't really loaded but we
+ don't really care. */
+ refshdr->sh_addr = 0; /* Make no adjustment below. */
+
+ /* Update the in-core file's section header to show the final
+ load address (or unloadedness). This serves as a cache,
+ so we won't get here again for the same section. */
+ if (likely (refshdr->sh_addr != 0)
+ && unlikely (! gelf_update_shdr (refscn, refshdr)))
+ return DWFL_E_LIBELF;
+ }
+
+ if (refshdr->sh_flags & SHF_ALLOC)
+ /* Apply the adjustment. */
+ *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
+
+ return DWFL_E_NOERROR;
+}
+
+
+/* Cache used by relocate_getsym. */
+struct reloc_symtab_cache
+{
+ Elf *symelf;
+ Elf_Data *symdata;
+ Elf_Data *symxndxdata;
+ Elf_Data *symstrdata;
+ size_t symshstrndx;
+ size_t strtabndx;
+};
+#define RELOC_SYMTAB_CACHE(cache) \
+ struct reloc_symtab_cache cache = \
+ { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
+
+/* This is just doing dwfl_module_getsym, except that we must always use
+ the symbol table in RELOCATED itself when it has one, not MOD->symfile. */
+static Dwfl_Error
+relocate_getsym (Dwfl_Module *mod,
+ Elf *relocated, struct reloc_symtab_cache *cache,
+ int symndx, GElf_Sym *sym, GElf_Word *shndx)
+{
+ if (cache->symdata == NULL)
+ {
+ if (mod->symfile == NULL || mod->symfile->elf != relocated)
+ {
+ /* We have to look up the symbol table in the file we are
+ relocating, if it has its own. These reloc sections refer to
+ the symbol table in this file, and a symbol table in the main
+ file might not match. However, some tools did produce ET_REL
+ .debug files with relocs but no symtab of their own. */
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (relocated, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr != NULL)
+ switch (shdr->sh_type)
+ {
+ default:
+ continue;
+ case SHT_SYMTAB:
+ cache->symelf = relocated;
+ cache->symdata = elf_getdata (scn, NULL);
+ cache->strtabndx = shdr->sh_link;
+ if (unlikely (cache->symdata == NULL))
+ return DWFL_E_LIBELF;
+ break;
+ case SHT_SYMTAB_SHNDX:
+ cache->symxndxdata = elf_getdata (scn, NULL);
+ if (unlikely (cache->symxndxdata == NULL))
+ return DWFL_E_LIBELF;
+ break;
+ }
+ if (cache->symdata != NULL && cache->symxndxdata != NULL)
+ break;
+ }
+ }
+ if (cache->symdata == NULL)
+ {
+ /* We might not have looked for a symbol table file yet,
+ when coming from __libdwfl_relocate_section. */
+ if (unlikely (mod->symfile == NULL)
+ && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
+ return dwfl_errno ();
+
+ /* The symbol table we have already cached is the one from
+ the file being relocated, so it's what we need. Or else
+ this is an ET_REL .debug file with no .symtab of its own;
+ the symbols refer to the section indices in the main file. */
+ cache->symelf = mod->symfile->elf;
+ cache->symdata = mod->symdata;
+ cache->symxndxdata = mod->symxndxdata;
+ cache->symstrdata = mod->symstrdata;
+ }
+ }
+
+ if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
+ symndx, sym, shndx) == NULL))
+ return DWFL_E_LIBELF;
+
+ if (sym->st_shndx != SHN_XINDEX)
+ *shndx = sym->st_shndx;
+
+ switch (sym->st_shndx)
+ {
+ case SHN_ABS:
+ case SHN_UNDEF:
+ return DWFL_E_NOERROR;
+
+ case SHN_COMMON:
+ sym->st_value = 0; /* Value is size, not helpful. */
+ return DWFL_E_NOERROR;
+ }
+
+ return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
+ *shndx, &sym->st_value);
+}
+
+/* Handle an undefined symbol. We really only support ET_REL for Linux
+ kernel modules, and offline archives. The behavior of the Linux module
+ loader is very simple and easy to mimic. It only matches magically
+ exported symbols, and we match any defined symbols. But we get the same
+ answer except when the module's symbols are undefined and would prevent
+ it from being loaded. */
+static Dwfl_Error
+resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
+ GElf_Sym *sym, GElf_Word shndx)
+{
+ /* First we need its name. */
+ if (sym->st_name != 0)
+ {
+ if (symtab->symstrdata == NULL)
+ {
+ /* Cache the strtab for this symtab. */
+ assert (referer->symfile == NULL
+ || referer->symfile->elf != symtab->symelf);
+ symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
+ symtab->strtabndx),
+ NULL);
+ if (unlikely (symtab->symstrdata == NULL))
+ return DWFL_E_LIBELF;
+ }
+ if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
+ return DWFL_E_BADSTROFF;
+
+ const char *name = symtab->symstrdata->d_buf;
+ name += sym->st_name;
+
+ for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
+ if (m != referer)
+ {
+ /* Get this module's symtab.
+ If we got a fresh error reading the table, report it.
+ If we just have no symbols in this module, no harm done. */
+ if (m->symdata == NULL
+ && m->symerr == DWFL_E_NOERROR
+ && INTUSE(dwfl_module_getsymtab) (m) < 0
+ && m->symerr != DWFL_E_NO_SYMTAB)
+ return m->symerr;
+
+ for (size_t ndx = 1; ndx < m->syments; ++ndx)
+ {
+ sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
+ ndx, sym, &shndx);
+ if (unlikely (sym == NULL))
+ return DWFL_E_LIBELF;
+ if (sym->st_shndx != SHN_XINDEX)
+ shndx = sym->st_shndx;
+
+ /* We are looking for a defined global symbol with a name. */
+ if (shndx == SHN_UNDEF || shndx == SHN_COMMON
+ || GELF_ST_BIND (sym->st_info) == STB_LOCAL
+ || sym->st_name == 0)
+ continue;
+
+ /* Get this candidate symbol's name. */
+ if (unlikely (sym->st_name >= m->symstrdata->d_size))
+ return DWFL_E_BADSTROFF;
+ const char *n = m->symstrdata->d_buf;
+ n += sym->st_name;
+
+ /* Does the name match? */
+ if (strcmp (name, n))
+ continue;
+
+ /* We found it! */
+ if (shndx == SHN_ABS) /* XXX maybe should apply bias? */
+ return DWFL_E_NOERROR;
+
+ if (m->e_type != ET_REL)
+ {
+ sym->st_value = dwfl_adjusted_st_value (m, sym->st_value);
+ return DWFL_E_NOERROR;
+ }
+
+ /* In an ET_REL file, the symbol table values are relative
+ to the section, not to the module's load base. */
+ size_t symshstrndx = SHN_UNDEF;
+ return __libdwfl_relocate_value (m, m->symfile->elf,
+ &symshstrndx,
+ shndx, &sym->st_value);
+ }
+ }
+ }
+
+ return DWFL_E_RELUNDEF;
+}
+
+static Dwfl_Error
+relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
+ size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
+ Elf_Scn *scn, GElf_Shdr *shdr,
+ Elf_Scn *tscn, bool debugscn, bool partial)
+{
+ /* First, fetch the name of the section these relocations apply to. */
+ GElf_Shdr tshdr_mem;
+ GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
+ const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
+ if (tname == NULL)
+ return DWFL_E_LIBELF;
+
+ if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0))
+ /* No contents to relocate. */
+ return DWFL_E_NOERROR;
+
+ if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
+ /* This relocation section is not for a debugging section.
+ Nothing to do here. */
+ return DWFL_E_NOERROR;
+
+ /* Fetch the section data that needs the relocations applied. */
+ Elf_Data *tdata = elf_rawdata (tscn, NULL);
+ if (tdata == NULL)
+ return DWFL_E_LIBELF;
+
+ /* Apply one relocation. Returns true for any invalid data. */
+ Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
+ int rtype, int symndx)
+ {
+ /* First see if this is a reloc we can handle.
+ If we are skipping it, don't bother resolving the symbol. */
+
+ if (unlikely (rtype == 0))
+ /* In some odd situations, the linker can leave R_*_NONE relocs
+ behind. This is probably bogus ld -r behavior, but the only
+ cases it's known to appear in are harmless: DWARF data
+ referring to addresses in a section that has been discarded.
+ So we just pretend it's OK without further relocation. */
+ return DWFL_E_NOERROR;
+
+ Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
+ if (unlikely (type == ELF_T_NUM))
+ return DWFL_E_BADRELTYPE;
+
+ /* First, resolve the symbol to an absolute value. */
+ GElf_Addr value;
+
+ if (symndx == STN_UNDEF)
+ /* When strip removes a section symbol referring to a
+ section moved into the debuginfo file, it replaces
+ that symbol index in relocs with STN_UNDEF. We
+ don't actually need the symbol, because those relocs
+ are always references relative to the nonallocated
+ debugging sections, which start at zero. */
+ value = 0;
+ else
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
+ symndx, &sym, &shndx);
+ if (unlikely (error != DWFL_E_NOERROR))
+ return error;
+
+ if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
+ {
+ /* Maybe we can figure it out anyway. */
+ error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
+ if (error != DWFL_E_NOERROR
+ && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON))
+ return error;
+ }
+
+ value = sym.st_value;
+ }
+
+ /* These are the types we can relocate. */
+#define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
+ DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
+ DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
+ size_t size;
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ size = sizeof (GElf_##Name); \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ return DWFL_E_BADRELTYPE;
+ }
+
+ if (offset + size > tdata->d_size)
+ return DWFL_E_BADRELOFF;
+
+#define DO_TYPE(NAME, Name) GElf_##Name Name;
+ union { TYPES; } tmpbuf;
+#undef DO_TYPE
+ Elf_Data tmpdata =
+ {
+ .d_type = type,
+ .d_buf = &tmpbuf,
+ .d_size = size,
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data rdata =
+ {
+ .d_type = type,
+ .d_buf = tdata->d_buf + offset,
+ .d_size = size,
+ .d_version = EV_CURRENT,
+ };
+
+ /* XXX check for overflow? */
+ if (addend)
+ {
+ /* For the addend form, we have the value already. */
+ value += *addend;
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ tmpbuf.Name = value; \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ /* Extract the original value and apply the reloc. */
+ Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
+ ehdr->e_ident[EI_DATA]);
+ if (d == NULL)
+ return DWFL_E_LIBELF;
+ assert (d == &tmpdata);
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ tmpbuf.Name += (GElf_##Name) value; \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ }
+
+ /* Now convert the relocated datum back to the target
+ format. This will write into rdata.d_buf, which
+ points into the raw section data being relocated. */
+ Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
+ ehdr->e_ident[EI_DATA]);
+ if (s == NULL)
+ return DWFL_E_LIBELF;
+ assert (s == &rdata);
+
+ /* We have applied this relocation! */
+ return DWFL_E_NOERROR;
+ }
+
+ /* Fetch the relocation section and apply each reloc in it. */
+ Elf_Data *reldata = elf_getdata (scn, NULL);
+ if (reldata == NULL)
+ return DWFL_E_LIBELF;
+
+ Dwfl_Error result = DWFL_E_NOERROR;
+ bool first_badreltype = true;
+ inline void check_badreltype (void)
+ {
+ if (first_badreltype)
+ {
+ first_badreltype = false;
+ if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
+ /* This might be because ebl_openbackend failed to find
+ any libebl_CPU.so library. Diagnose that clearly. */
+ result = DWFL_E_UNKNOWN_MACHINE;
+ }
+ }
+
+ size_t nrels = shdr->sh_size / shdr->sh_entsize;
+ size_t complete = 0;
+ if (shdr->sh_type == SHT_REL)
+ for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
+ {
+ GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
+ if (r == NULL)
+ return DWFL_E_LIBELF;
+ result = relocate (r->r_offset, NULL,
+ GELF_R_TYPE (r->r_info),
+ GELF_R_SYM (r->r_info));
+ check_badreltype ();
+ if (partial)
+ switch (result)
+ {
+ case DWFL_E_NOERROR:
+ /* We applied the relocation. Elide it. */
+ memset (&rel_mem, 0, sizeof rel_mem);
+ gelf_update_rel (reldata, relidx, &rel_mem);
+ ++complete;
+ break;
+ case DWFL_E_BADRELTYPE:
+ case DWFL_E_RELUNDEF:
+ /* We couldn't handle this relocation. Skip it. */
+ result = DWFL_E_NOERROR;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
+ {
+ GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
+ &rela_mem);
+ if (r == NULL)
+ return DWFL_E_LIBELF;
+ result = relocate (r->r_offset, &r->r_addend,
+ GELF_R_TYPE (r->r_info),
+ GELF_R_SYM (r->r_info));
+ check_badreltype ();
+ if (partial)
+ switch (result)
+ {
+ case DWFL_E_NOERROR:
+ /* We applied the relocation. Elide it. */
+ memset (&rela_mem, 0, sizeof rela_mem);
+ gelf_update_rela (reldata, relidx, &rela_mem);
+ ++complete;
+ break;
+ case DWFL_E_BADRELTYPE:
+ case DWFL_E_RELUNDEF:
+ /* We couldn't handle this relocation. Skip it. */
+ result = DWFL_E_NOERROR;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (likely (result == DWFL_E_NOERROR))
+ {
+ if (!partial || complete == nrels)
+ /* Mark this relocation section as being empty now that we have
+ done its work. This affects unstrip -R, so e.g. it emits an
+ empty .rela.debug_info along with a .debug_info that has
+ already been fully relocated. */
+ nrels = 0;
+ else if (complete != 0)
+ {
+ /* We handled some of the relocations but not all.
+ We've zeroed out the ones we processed.
+ Now remove them from the section. */
+
+ size_t next = 0;
+ if (shdr->sh_type == SHT_REL)
+ for (size_t relidx = 0; relidx < nrels; ++relidx)
+ {
+ GElf_Rel rel_mem;
+ GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
+ if (r->r_info != 0 || r->r_offset != 0)
+ {
+ if (next != relidx)
+ gelf_update_rel (reldata, next, r);
+ ++next;
+ }
+ }
+ else
+ for (size_t relidx = 0; relidx < nrels; ++relidx)
+ {
+ GElf_Rela rela_mem;
+ GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
+ if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
+ {
+ if (next != relidx)
+ gelf_update_rela (reldata, next, r);
+ ++next;
+ }
+ }
+ nrels = next;
+ }
+
+ shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
+ gelf_update_shdr (scn, shdr);
+ }
+
+ return result;
+}
+
+Dwfl_Error
+internal_function
+__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
+{
+ assert (mod->e_type == ET_REL);
+
+ GElf_Ehdr ehdr_mem;
+ const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
+ if (ehdr == NULL)
+ return DWFL_E_LIBELF;
+
+ size_t d_shstrndx;
+ if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0)
+ return DWFL_E_LIBELF;
+
+ RELOC_SYMTAB_CACHE (reloc_symtab);
+
+ /* Look at each section in the debuginfo file, and process the
+ relocation sections for debugging sections. */
+ Dwfl_Error result = DWFL_E_NOERROR;
+ Elf_Scn *scn = NULL;
+ while (result == DWFL_E_NOERROR
+ && (scn = elf_nextscn (debugfile, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+ if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+ && shdr->sh_size != 0)
+ {
+ /* It's a relocation section. */
+
+ Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
+ if (unlikely (tscn == NULL))
+ result = DWFL_E_LIBELF;
+ else
+ result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
+ &reloc_symtab, scn, shdr, tscn,
+ debug, !debug);
+ }
+ }
+
+ return result;
+}
+
+Dwfl_Error
+internal_function
+__libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
+ Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
+{
+ GElf_Ehdr ehdr_mem;
+ GElf_Shdr shdr_mem;
+
+ RELOC_SYMTAB_CACHE (reloc_symtab);
+
+ size_t shstrndx;
+ if (elf_getshdrstrndx (relocated, &shstrndx) < 0)
+ return DWFL_E_LIBELF;
+
+ return (__libdwfl_module_getebl (mod)
+ ?: relocate_section (mod, relocated,
+ gelf_getehdr (relocated, &ehdr_mem), shstrndx,
+ &reloc_symtab,
+ relocscn, gelf_getshdr (relocscn, &shdr_mem),
+ tscn, false, partial));
+}
diff --git a/src/libdwfl/segment.c b/src/libdwfl/segment.c
new file mode 100644
index 00000000..9d78c87f
--- /dev/null
+++ b/src/libdwfl/segment.c
@@ -0,0 +1,350 @@
+/* Manage address space lookup table for libdwfl.
+ Copyright (C) 2008, 2009, 2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+
+static GElf_Addr
+segment_start (Dwfl *dwfl, GElf_Addr start)
+{
+ if (dwfl->segment_align > 1)
+ start &= -dwfl->segment_align;
+ return start;
+}
+
+static GElf_Addr
+segment_end (Dwfl *dwfl, GElf_Addr end)
+{
+ if (dwfl->segment_align > 1)
+ end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
+ return end;
+}
+
+static bool
+insert (Dwfl *dwfl, size_t i, GElf_Addr start, GElf_Addr end, int segndx)
+{
+ bool need_start = (i == 0 || dwfl->lookup_addr[i - 1] != start);
+ bool need_end = (i >= dwfl->lookup_elts || dwfl->lookup_addr[i + 1] != end);
+ size_t need = need_start + need_end;
+ if (need == 0)
+ return false;
+
+ if (dwfl->lookup_alloc - dwfl->lookup_elts < need)
+ {
+ size_t n = dwfl->lookup_alloc == 0 ? 16 : dwfl->lookup_alloc * 2;
+ GElf_Addr *naddr = realloc (dwfl->lookup_addr, sizeof naddr[0] * n);
+ if (unlikely (naddr == NULL))
+ return true;
+ int *nsegndx = realloc (dwfl->lookup_segndx, sizeof nsegndx[0] * n);
+ if (unlikely (nsegndx == NULL))
+ {
+ if (naddr != dwfl->lookup_addr)
+ free (naddr);
+ return true;
+ }
+ dwfl->lookup_alloc = n;
+ dwfl->lookup_addr = naddr;
+ dwfl->lookup_segndx = nsegndx;
+
+ if (dwfl->lookup_module != NULL)
+ {
+ /* Make sure this array is big enough too. */
+ Dwfl_Module **old = dwfl->lookup_module;
+ dwfl->lookup_module = realloc (dwfl->lookup_module,
+ sizeof dwfl->lookup_module[0] * n);
+ if (unlikely (dwfl->lookup_module == NULL))
+ {
+ free (old);
+ return true;
+ }
+ }
+ }
+
+ if (unlikely (i < dwfl->lookup_elts))
+ {
+ const size_t move = dwfl->lookup_elts - i;
+ memmove (&dwfl->lookup_addr[i + need], &dwfl->lookup_addr[i],
+ move * sizeof dwfl->lookup_addr[0]);
+ memmove (&dwfl->lookup_segndx[i + need], &dwfl->lookup_segndx[i],
+ move * sizeof dwfl->lookup_segndx[0]);
+ if (dwfl->lookup_module != NULL)
+ memmove (&dwfl->lookup_module[i + need], &dwfl->lookup_module[i],
+ move * sizeof dwfl->lookup_module[0]);
+ }
+
+ if (need_start)
+ {
+ dwfl->lookup_addr[i] = start;
+ dwfl->lookup_segndx[i] = segndx;
+ if (dwfl->lookup_module != NULL)
+ dwfl->lookup_module[i] = NULL;
+ ++i;
+ }
+ else
+ dwfl->lookup_segndx[i - 1] = segndx;
+
+ if (need_end)
+ {
+ dwfl->lookup_addr[i] = end;
+ dwfl->lookup_segndx[i] = -1;
+ if (dwfl->lookup_module != NULL)
+ dwfl->lookup_module[i] = NULL;
+ }
+
+ dwfl->lookup_elts += need;
+
+ return false;
+}
+
+static int
+lookup (Dwfl *dwfl, GElf_Addr address, int hint)
+{
+ if (hint >= 0
+ && address >= dwfl->lookup_addr[hint]
+ && ((size_t) hint + 1 == dwfl->lookup_elts
+ || address < dwfl->lookup_addr[hint + 1]))
+ return hint;
+
+ /* Do binary search on the array indexed by module load address. */
+ size_t l = 0, u = dwfl->lookup_elts;
+ while (l < u)
+ {
+ size_t idx = (l + u) / 2;
+ if (address < dwfl->lookup_addr[idx])
+ u = idx;
+ else
+ {
+ l = idx + 1;
+ if (l == dwfl->lookup_elts || address < dwfl->lookup_addr[l])
+ return idx;
+ }
+ }
+
+ return -1;
+}
+
+static bool
+reify_segments (Dwfl *dwfl)
+{
+ int hint = -1;
+ int highest = -1;
+ bool fixup = false;
+ for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
+ if (! mod->gc)
+ {
+ const GElf_Addr start = segment_start (dwfl, mod->low_addr);
+ const GElf_Addr end = segment_end (dwfl, mod->high_addr);
+ bool resized = false;
+
+ int idx = lookup (dwfl, start, hint);
+ if (unlikely (idx < 0))
+ {
+ /* Module starts below any segment. Insert a low one. */
+ if (unlikely (insert (dwfl, 0, start, end, -1)))
+ return true;
+ idx = 0;
+ resized = true;
+ }
+ else if (dwfl->lookup_addr[idx] > start)
+ {
+ /* The module starts in the middle of this segment. Split it. */
+ if (unlikely (insert (dwfl, idx + 1, start, end,
+ dwfl->lookup_segndx[idx])))
+ return true;
+ ++idx;
+ resized = true;
+ }
+ else if (dwfl->lookup_addr[idx] < start)
+ {
+ /* The module starts past the end of this segment.
+ Add a new one. */
+ if (unlikely (insert (dwfl, idx + 1, start, end, -1)))
+ return true;
+ ++idx;
+ resized = true;
+ }
+
+ if ((size_t) idx + 1 < dwfl->lookup_elts
+ && end < dwfl->lookup_addr[idx + 1])
+ {
+ /* The module ends in the middle of this segment. Split it. */
+ if (unlikely (insert (dwfl, idx + 1,
+ end, dwfl->lookup_addr[idx + 1], -1)))
+ return true;
+ resized = true;
+ }
+
+ if (dwfl->lookup_module == NULL)
+ {
+ dwfl->lookup_module = calloc (dwfl->lookup_alloc,
+ sizeof dwfl->lookup_module[0]);
+ if (unlikely (dwfl->lookup_module == NULL))
+ return true;
+ }
+
+ /* Cache a backpointer in the module. */
+ mod->segment = idx;
+
+ /* Put MOD in the table for each segment that's inside it. */
+ do
+ dwfl->lookup_module[idx++] = mod;
+ while ((size_t) idx < dwfl->lookup_elts
+ && dwfl->lookup_addr[idx] < end);
+ assert (dwfl->lookup_module[mod->segment] == mod);
+
+ if (resized && idx - 1 >= highest)
+ /* Expanding the lookup tables invalidated backpointers
+ we've already stored. Reset those ones. */
+ fixup = true;
+
+ highest = idx - 1;
+ hint = (size_t) idx < dwfl->lookup_elts ? idx : -1;
+ }
+
+ if (fixup)
+ /* Reset backpointer indices invalidated by table insertions. */
+ for (size_t idx = 0; idx < dwfl->lookup_elts; ++idx)
+ if (dwfl->lookup_module[idx] != NULL)
+ dwfl->lookup_module[idx]->segment = idx;
+
+ return false;
+}
+
+int
+dwfl_addrsegment (Dwfl *dwfl, Dwarf_Addr address, Dwfl_Module **mod)
+{
+ if (unlikely (dwfl == NULL))
+ return -1;
+
+ if (unlikely (dwfl->lookup_module == NULL)
+ && mod != NULL
+ && unlikely (reify_segments (dwfl)))
+ {
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return -1;
+ }
+
+ int idx = lookup (dwfl, address, -1);
+ if (likely (mod != NULL))
+ {
+ if (unlikely (idx < 0) || unlikely (dwfl->lookup_module == NULL))
+ *mod = NULL;
+ else
+ {
+ *mod = dwfl->lookup_module[idx];
+
+ /* If this segment does not have a module, but the address is
+ the upper boundary of the previous segment's module, use that. */
+ if (*mod == NULL && idx > 0 && dwfl->lookup_addr[idx] == address)
+ {
+ *mod = dwfl->lookup_module[idx - 1];
+ if (*mod != NULL && (*mod)->high_addr != address)
+ *mod = NULL;
+ }
+ }
+ }
+
+ if (likely (idx >= 0))
+ /* Translate internal segment table index to user segment index. */
+ idx = dwfl->lookup_segndx[idx];
+
+ return idx;
+}
+INTDEF (dwfl_addrsegment)
+
+int
+dwfl_report_segment (Dwfl *dwfl, int ndx, const GElf_Phdr *phdr, GElf_Addr bias,
+ const void *ident)
+{
+ if (dwfl == NULL)
+ return -1;
+
+ if (ndx < 0)
+ ndx = dwfl->lookup_tail_ndx;
+
+ if (phdr->p_align > 1 && (dwfl->segment_align <= 1 ||
+ phdr->p_align < dwfl->segment_align))
+ dwfl->segment_align = phdr->p_align;
+
+ if (unlikely (dwfl->lookup_module != NULL))
+ {
+ free (dwfl->lookup_module);
+ dwfl->lookup_module = NULL;
+ }
+
+ GElf_Addr start = segment_start (dwfl, bias + phdr->p_vaddr);
+ GElf_Addr end = segment_end (dwfl, bias + phdr->p_vaddr + phdr->p_memsz);
+
+ /* Coalesce into the last one if contiguous and matching. */
+ if (ndx != dwfl->lookup_tail_ndx
+ || ident == NULL
+ || ident != dwfl->lookup_tail_ident
+ || start != dwfl->lookup_tail_vaddr
+ || phdr->p_offset != dwfl->lookup_tail_offset)
+ {
+ /* Normally just appending keeps us sorted. */
+
+ size_t i = dwfl->lookup_elts;
+ while (i > 0 && unlikely (start < dwfl->lookup_addr[i - 1]))
+ --i;
+
+ if (unlikely (insert (dwfl, i, start, end, ndx)))
+ {
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return -1;
+ }
+ }
+
+ dwfl->lookup_tail_ident = ident;
+ dwfl->lookup_tail_vaddr = end;
+ dwfl->lookup_tail_offset = end - bias - phdr->p_vaddr + phdr->p_offset;
+ dwfl->lookup_tail_ndx = ndx + 1;
+
+ return ndx;
+}
+INTDEF (dwfl_report_segment)