summaryrefslogtreecommitdiffstats
path: root/src/libdwfl
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2015-02-15 12:34:33 -0800
committerElliott Hughes <enh@google.com>2015-02-15 16:11:56 -0800
commit41f677100e15f315f638774fbd055e497fc90069 (patch)
tree961dfef28571e02a7d969fbba9bb51991086476b /src/libdwfl
parentdb42bd18ad7a482e080e506f47121383e19274ef (diff)
downloadandroid_external_elfutils-41f677100e15f315f638774fbd055e497fc90069.tar.gz
android_external_elfutils-41f677100e15f315f638774fbd055e497fc90069.tar.bz2
android_external_elfutils-41f677100e15f315f638774fbd055e497fc90069.zip
Export elfutils headers and lose the version number from the path.
Having the version number in the path just means that diffs for updates are completely unusable. perf refers to libdw.h, libdwfl.h, and version.h as <elfutils/libdw.h> and so on, so we do still need to do some manual work there, but let's use symlinks rather than duplicating the header files. Change-Id: I9fd3c5f5024bde12747fdb1c06d21cdcb3418f03
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)