summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2005-08-23 08:20:21 +0000
committerRoland McGrath <roland@redhat.com>2005-08-23 08:20:21 +0000
commitd17fac7e89666b47811581b10b5ca0d253a3a82d (patch)
tree31a39f5bbf15cdaa7740ba91302651ad40c3fc1d
parent3712b288d1407cf6551d359cdaacb31bbf2b2a75 (diff)
downloadandroid_external_elfutils-d17fac7e89666b47811581b10b5ca0d253a3a82d.tar.gz
android_external_elfutils-d17fac7e89666b47811581b10b5ca0d253a3a82d.tar.bz2
android_external_elfutils-d17fac7e89666b47811581b10b5ca0d253a3a82d.zip
2005-08-23 Roland McGrath <roland@redhat.com>
* dwarf_attr_integrate.c (dwarf_attr_integrate): Treat DW_AT_specification the same as DW_AT_abstract_origin.
-rw-r--r--libdw/ChangeLog17
-rw-r--r--libdw/dwarf_attr_integrate.c4
-rw-r--r--libdw/libdw.map10
-rw-r--r--libdwfl/=ideas16
-rw-r--r--libdwfl/=oops30
-rw-r--r--libdwfl/ChangeLog103
-rw-r--r--libdwfl/Makefile.am3
-rw-r--r--libdwfl/argp-std.c64
-rw-r--r--libdwfl/derelocate.c231
-rw-r--r--libdwfl/dwfl_begin.c5
-rw-r--r--libdwfl/dwfl_getsrclines.c33
-rw-r--r--libdwfl/dwfl_module.c2
-rw-r--r--libdwfl/dwfl_module_getdwarf.c32
-rw-r--r--libdwfl/dwfl_module_getsrc_file.c7
-rw-r--r--libdwfl/dwfl_onesrcline.c41
-rw-r--r--libdwfl/dwfl_report_elf.c108
-rw-r--r--libdwfl/dwfl_validate_address.c46
-rw-r--r--libdwfl/find-debuginfo.c15
-rw-r--r--libdwfl/libdwfl.h89
-rw-r--r--libdwfl/libdwflP.h14
-rw-r--r--libdwfl/linux-kernel-modules.c210
-rw-r--r--libdwfl/offline.c78
-rw-r--r--libdwfl/relocate.c5
-rw-r--r--src/nm.c7
-rw-r--r--tests/ChangeLog14
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/line2addr.c143
-rwxr-xr-xtests/run-line2addr.sh32
-rw-r--r--tests/testfile23.bz2bin0 -> 956 bytes
29 files changed, 1210 insertions, 153 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index de716d43..3b84ab9e 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,20 @@
+2005-08-23 Roland McGrath <roland@redhat.com>
+
+ * dwarf_attr_integrate.c (dwarf_attr_integrate): Treat
+ DW_AT_specification the same as DW_AT_abstract_origin.
+
+2005-08-20 Roland McGrath <roland@redhat.com>
+
+ * libdw.map: Add dwfl_cumodule, remove dwfl_linecu.
+ Add dwfl_linux_kernel_report_offline, dwfl_offline_section_address,
+ and dwfl_report_offline.
+
+2005-08-19 Roland McGrath <roland@redhat.com>
+
+ * libdw.map: Bump version to ELFUTILS_0.114 for libdwfl changes.
+ Add dwfl_module_relocate_address, dwfl_module_relocations,
+ dwfl_module_relocation_info.
+
2005-08-18 Roland McGrath <roland@redhat.com>
* dwarf_getscopes.c (dwarf_getscopes): Include the CU itself as
diff --git a/libdw/dwarf_attr_integrate.c b/libdw/dwarf_attr_integrate.c
index 4b27296a..4f95937e 100644
--- a/libdw/dwarf_attr_integrate.c
+++ b/libdw/dwarf_attr_integrate.c
@@ -1,4 +1,4 @@
-/* Return specific DWARF attribute of a DIE, integrating DW_AT_abstract_origin.
+/* Return specific DWARF attribute of a DIE, integrating indirections.
Copyright (C) 2005 Red Hat, Inc.
This program is Open Source software; you can redistribute it and/or
@@ -32,6 +32,8 @@ dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name,
attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, result);
if (attr == NULL)
+ attr = INTUSE(dwarf_attr) (die, DW_AT_specification, result);
+ if (attr == NULL)
break;
die = INTUSE(dwarf_formref_die) (attr, &die_mem);
diff --git a/libdw/libdw.map b/libdw/libdw.map
index b54dea3e..01ee5f60 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -96,19 +96,21 @@ ELFUTILS_0.114 {
dwfl_addrdwarf;
dwfl_addrmodule;
dwfl_begin;
+ dwfl_cumodule;
dwfl_end;
dwfl_errmsg;
dwfl_errno;
dwfl_getdwarf;
dwfl_getmodules;
dwfl_getsrc;
- dwfl_linecu;
+ dwfl_getsrclines;
dwfl_lineinfo;
dwfl_linemodule;
dwfl_linux_kernel_find_elf;
dwfl_linux_kernel_module_section_address;
dwfl_linux_kernel_report_kernel;
dwfl_linux_kernel_report_modules;
+ dwfl_linux_kernel_report_offline;
dwfl_linux_proc_find_elf;
dwfl_linux_proc_report;
dwfl_module_addrdie;
@@ -119,11 +121,17 @@ ELFUTILS_0.114 {
dwfl_module_getsrc_file;
dwfl_module_info;
dwfl_module_nextcu;
+ dwfl_module_relocate_address;
+ dwfl_module_relocation_info;
+ dwfl_module_relocations;
dwfl_nextcu;
+ dwfl_offline_section_address;
+ dwfl_onesrcline;
dwfl_report_begin;
dwfl_report_elf;
dwfl_report_end;
dwfl_report_module;
+ dwfl_report_offline;
dwfl_standard_argp;
dwfl_standard_find_debuginfo;
diff --git a/libdwfl/=ideas b/libdwfl/=ideas
new file mode 100644
index 00000000..bdce3253
--- /dev/null
+++ b/libdwfl/=ideas
@@ -0,0 +1,16 @@
+* dev+ino+mtime hash table, global
+** share fd; if !isrel, share Elf*,Ebl*,Dwarf*
+
+* find_debuginfo
+ When local search fails, try "yum install-debugfor elf-file".
+ i.e., yum install `rpm -qf elffile --qf '%{SOURCERPM} %{V}-%{R} %{ARCH}\n' | awk '{ print substr($1, 1, length($1)-length("-" $2 ".src.rpm")) "-debuginfo-" $2 "." $3 }' `
+ done in rpm-python inside yum(?)
+** all yum ops should have a -qf mode, means `rpm -qf --qf %{name}.%{arch}`
+ plus debug-of modifier to name.arch or -qf *
+
+* libdw_findcu reads all cu hdrs from beginning
+** good for dwarf_offdie: find cu containing that offset
+** bad for dwarf_addrdie: reads in whole debuginfo file
+** when from aranges (dwarf_addrdie), could read cuhdr offset directly w/o scan
+*** aranges really store cu header offset, but libdw adds in header size to
+ get cu die offset; but libdw_findcu interning should start with header
diff --git a/libdwfl/=oops b/libdwfl/=oops
new file mode 100644
index 00000000..a8bb38bd
--- /dev/null
+++ b/libdwfl/=oops
@@ -0,0 +1,30 @@
+* regexp on multiple formats to yield records (pc, mod, sym, offset, size?)
+
+glibc backtrace_symbols_fd:
+
+foo.so(sym+0x123)[0x345]
+foo.so(sym-0x123)[0x345]
+foobar[0x12345678]
+
+i386 kernel oops:
+
+ st_size
+[<%x>] sym+0x123/0x32
+[<%x>] sym-0x123/0x32
+[<%x>] sym+0x123/0x32 [mod]
+
+x86-64 oops:
+
+[<%x>]
+<%x>{sym+%d}
+<%x>{sym-%d}
+<%x>{:mod:sym+%d}
+<%x>{:mod:sym-%d}
+
+kernel `uname -r`:
+
+... Not tainted (%s)
+... Tainted: [A-Z]* (%s)
+
+
+* guess mod loadbase from sym+ofs==pc -> pc-(symval+ofs)==bias
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 3d4320c6..2edaf6f9 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,8 +1,111 @@
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,
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 243f67f5..a0735ff0 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -35,14 +35,17 @@ euinclude_HEADERS = libdwfl.h
libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c \
dwfl_module.c dwfl_report_elf.c relocate.c \
+ derelocate.c offline.c \
dwfl_module_info.c dwfl_getmodules.c \
dwfl_module_getdwarf.c dwfl_getdwarf.c \
+ dwfl_validate_address.c \
argp-std.c 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_linemodule.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 \
diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c
index ebddcfb1..75f8b99f 100644
--- a/libdwfl/argp-std.c
+++ b/libdwfl/argp-std.c
@@ -30,6 +30,8 @@ static const struct argp_option options[] =
{ "pid", 'p', "PID", 0,
N_("Find addresses in files mapped into process PID"), 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 }
@@ -37,6 +39,14 @@ static const struct argp_option options[] =
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),
+ };
+
static const Dwfl_Callbacks proc_callbacks =
{
.find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
@@ -78,19 +88,29 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'e':
- if (state->hook == NULL)
- {
- Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
- if (INTUSE(dwfl_report_elf) (dwfl, "", arg, -1, 0) == NULL)
- return fail (-1, arg);
- state->hook = dwfl;
- }
- else
- {
- toomany:
- argp_error (state, "%s", _("only one -e, -p, or -k option allowed"));
- return EINVAL;
- }
+ {
+ Dwfl *dwfl = state->hook;
+ if (dwfl == NULL)
+ {
+ dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ if (dwfl == NULL)
+ return fail (-1, arg);
+ state->hook = dwfl;
+ }
+ if (dwfl->callbacks == &offline_callbacks)
+ {
+ if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
+ return fail (-1, arg);
+ state->hook = dwfl;
+ }
+ else
+ {
+ toomany:
+ argp_error (state,
+ "%s", _("only one of -e, -p, -k, or -K allowed"));
+ return EINVAL;
+ }
+ }
break;
case 'p':
@@ -123,6 +143,20 @@ parse_opt (int key, char *arg, struct argp_state *state)
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 (result, _("cannot find kernel or modules"));
+ state->hook = dwfl;
+ }
+ else
+ goto toomany;
+ break;
+
case ARGP_KEY_SUCCESS:
{
Dwfl *dwfl = state->hook;
@@ -131,8 +165,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
{
/* Default if no -e, -p, or -k, is "-e a.out". */
arg = "a.out";
- dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
- if (INTUSE(dwfl_report_elf) (dwfl, "", arg, -1, 0) == NULL)
+ dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
return fail (-1, arg);
state->hook = dwfl;
}
diff --git a/libdwfl/derelocate.c b/libdwfl/derelocate.c
new file mode 100644
index 00000000..b2b16f49
--- /dev/null
+++ b/libdwfl/derelocate.c
@@ -0,0 +1,231 @@
+/* Recover relocatibility for addresses computed from debug information.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#include "libdwflP.h"
+
+struct dwfl_relocation
+{
+ size_t count;
+ struct
+ {
+ Elf_Scn *scn;
+ const char *name;
+ GElf_Addr start, end;
+ } refs[0];
+};
+
+
+struct secref
+{
+ struct secref *next;
+ Elf_Scn *scn;
+ 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;
+
+ return (*p1)->start - (*p2)->start;
+}
+
+static int
+cache_sections (Dwfl_Module *mod)
+{
+ size_t symshstrndx;
+ if (elf_getshstrndx (mod->symfile->elf, &symshstrndx) < 0)
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
+
+ struct secref *refs = NULL;
+ size_t nrefs = 0;
+
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ return -1;
+
+ if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr != 0)
+ {
+ const char *name = elf_strptr (mod->symfile->elf, symshstrndx,
+ shdr->sh_name);
+ if (name == NULL)
+ return -1;
+
+ struct secref *newref = alloca (sizeof *newref);
+ newref->scn = scn;
+ newref->name = name;
+ newref->start = shdr->sh_addr;
+ newref->end = shdr->sh_addr + shdr->sh_size;
+ newref->next = refs;
+ refs = newref;
+ ++nrefs;
+ }
+ }
+
+ 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[nrefs];
+ 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].start = sortrefs[i]->start;
+ mod->reloc_info->refs[i].end = sortrefs[i]->end;
+ }
+
+ return nrefs;
+}
+
+
+int
+dwfl_module_relocations (Dwfl_Module *mod)
+{
+ if (mod == NULL)
+ return -1;
+
+ if (mod->reloc_info != NULL)
+ return mod->reloc_info->count;
+
+ if (mod->dw == NULL)
+ {
+ Dwarf_Addr bias;
+ if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
+ return -1;
+ }
+
+ switch (mod->e_type)
+ {
+ case ET_REL:
+ return cache_sections (mod);
+
+ case ET_DYN:
+ return 1;
+
+ case ET_EXEC:
+ assert (mod->debug.bias == 0);
+ 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 (unlikely (mod->reloc_info == NULL) && 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;
+}
+
+int
+dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
+{
+ if (mod == NULL)
+ return -1;
+
+ if (mod->dw == NULL)
+ {
+ Dwarf_Addr bias;
+ if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
+ return -1;
+ }
+
+ if (mod->e_type != ET_REL)
+ {
+ *addr -= mod->debug.bias;
+ return 0;
+ }
+
+ if (unlikely (mod->reloc_info == NULL) && 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;
+ }
+ }
+
+ __libdw_seterrno (DWARF_E_NO_MATCH);
+ return -1;
+}
+INTDEF (dwfl_module_relocate_address)
diff --git a/libdwfl/dwfl_begin.c b/libdwfl/dwfl_begin.c
index e7130a4a..f90d4b60 100644
--- a/libdwfl/dwfl_begin.c
+++ b/libdwfl/dwfl_begin.c
@@ -26,7 +26,10 @@ dwfl_begin (const Dwfl_Callbacks *callbacks)
if (dwfl == NULL)
__libdwfl_seterrno (DWFL_E_NOMEM);
else
- dwfl->callbacks = callbacks;
+ {
+ dwfl->callbacks = callbacks;
+ dwfl->offline_next_address = OFFLINE_REDZONE;
+ }
return dwfl;
}
diff --git a/libdwfl/dwfl_getsrclines.c b/libdwfl/dwfl_getsrclines.c
new file mode 100644
index 00000000..0d1482ad
--- /dev/null
+++ b/libdwfl/dwfl_getsrclines.c
@@ -0,0 +1,33 @@
+/* Fetch source line information for CU.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#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/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index eecdb524..613c48de 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -68,6 +68,8 @@ dwfl_report_begin (Dwfl *dwfl)
free (dwfl->modules);
dwfl->modules = NULL;
dwfl->nmodules = 0;
+
+ dwfl->offline_next_address = OFFLINE_REDZONE;
}
INTDEF (dwfl_report_begin)
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 329ecde1..50245750 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -14,6 +14,7 @@
#include "libdwflP.h"
#include <fcntl.h>
#include <string.h>
+#include <unistd.h>
#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
@@ -34,7 +35,7 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
if (ehdr == NULL)
return DWFL_E (LIBELF, elf_errno ());
- mod->isrel = ehdr->e_type == ET_REL;
+ mod->e_type = ehdr->e_type;
file->bias = 0;
for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
@@ -74,6 +75,9 @@ find_file (Dwfl_Module *mod)
static Dwfl_Error
find_debuginfo (Dwfl_Module *mod)
{
+ if (mod->debug.elf != NULL)
+ return DWFL_E_NOERROR;
+
size_t shstrndx;
if (elf_getshstrndx (mod->main.elf, &shstrndx) < 0)
return DWFL_E_LIBELF;
@@ -279,9 +283,9 @@ find_symtab (Dwfl_Module *mod)
/* Try to start up libdw on DEBUGFILE. */
static Dwfl_Error
-load_dw (Dwfl_Module *mod, Elf *debugfile)
+load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
{
- if (mod->isrel)
+ if (mod->e_type == ET_REL)
{
const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
@@ -299,12 +303,24 @@ load_dw (Dwfl_Module *mod, Elf *debugfile)
find_symtab (mod);
Dwfl_Error result = mod->symerr;
if (result == DWFL_E_NOERROR)
- result = __libdwfl_relocate (mod, debugfile);
+ result = __libdwfl_relocate (mod, debugfile->elf);
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, DWARF_C_READ, NULL);
+ mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
if (mod->dw == NULL)
{
int err = INTUSE(dwarf_errno) ();
@@ -331,7 +347,7 @@ find_dw (Dwfl_Module *mod)
return;
/* First see if the main ELF file has the debugging information. */
- mod->dwerr = load_dw (mod, mod->main.elf);
+ mod->dwerr = load_dw (mod, &mod->main);
switch (mod->dwerr)
{
case DWFL_E_NOERROR:
@@ -351,7 +367,7 @@ find_dw (Dwfl_Module *mod)
switch (mod->dwerr)
{
case DWFL_E_NOERROR:
- mod->dwerr = load_dw (mod, mod->debug.elf);
+ mod->dwerr = load_dw (mod, &mod->debug);
break;
case DWFL_E_CB: /* The find_debuginfo hook failed. */
@@ -435,7 +451,7 @@ dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr)
if (sym->st_shndx != SHN_XINDEX)
shndx = sym->st_shndx;
- if (mod->isrel)
+ 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. */
switch (shndx)
diff --git a/libdwfl/dwfl_module_getsrc_file.c b/libdwfl/dwfl_module_getsrc_file.c
index 7c617dd8..640899d0 100644
--- a/libdwfl/dwfl_module_getsrc_file.c
+++ b/libdwfl/dwfl_module_getsrc_file.c
@@ -23,6 +23,13 @@ dwfl_module_getsrc_file (Dwfl_Module *mod,
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;
diff --git a/libdwfl/dwfl_onesrcline.c b/libdwfl/dwfl_onesrcline.c
new file mode 100644
index 00000000..3b09de02
--- /dev/null
+++ b/libdwfl/dwfl_onesrcline.c
@@ -0,0 +1,41 @@
+/* Return one of the sources lines of a CU.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#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/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c
index 21c9e846..82545631 100644
--- a/libdwfl/dwfl_report_elf.c
+++ b/libdwfl/dwfl_report_elf.c
@@ -45,41 +45,94 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
return NULL;
}
- GElf_Addr start = 0, end = 0;
- for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+ GElf_Addr start = 0, end = 0, bias = 0;
+ switch (ehdr->e_type)
{
- GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
- if (ph == NULL)
- goto elf_error;
- if (ph->p_type == PT_LOAD)
+ 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;
+
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
{
- start = base + (ph->p_vaddr & -ph->p_align);
- break;
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ goto elf_error;
+
+ if (shdr->sh_flags & SHF_ALLOC)
+ {
+ const GElf_Xword align = shdr->sh_addralign ?: 1;
+ shdr->sh_addr = (end + align - 1) & -align;
+ if (end == base)
+ /* This is the first section assigned a location.
+ Use its aligned address as the module's base. */
+ start = shdr->sh_addr;
+ end = shdr->sh_addr + shdr->sh_size;
+ if (! gelf_update_shdr (scn, shdr))
+ goto elf_error;
+ }
}
- }
- for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;)
- {
- GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
- if (ph == NULL)
- goto elf_error;
- if (ph->p_type == PT_LOAD)
+ if (end == start)
{
- end = base + (ph->p_vaddr + ph->p_memsz);
- break;
+ __libdwfl_seterrno (DWFL_E_BADELF);
+ if (closefd)
+ close (fd);
+ return NULL;
}
- }
+ break;
- if (end == 0)
- {
- __libdwfl_seterrno (DWFL_E_NO_PHDR);
- if (closefd)
- close (fd);
- return NULL;
+ /* 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:
+ for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+ {
+ GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
+ if (ph == NULL)
+ goto elf_error;
+ if (ph->p_type == PT_LOAD)
+ {
+ 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 = base;
+
+ for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;)
+ {
+ GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
+ if (ph == NULL)
+ goto elf_error;
+ if (ph->p_type == PT_LOAD)
+ {
+ end = base + (ph->p_vaddr + ph->p_memsz);
+ break;
+ }
+ }
+
+ if (end == 0)
+ {
+ __libdwfl_seterrno (DWFL_E_NO_PHDR);
+ if (closefd)
+ close (fd);
+ return NULL;
+ }
+ break;
}
- Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name,
- base + start, base + end);
+ Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end);
if (m != NULL)
{
if (m->main.name == NULL)
@@ -103,7 +156,8 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
if (m->main.elf == NULL)
{
m->main.elf = elf;
- m->main.bias = base;
+ m->main.bias = bias;
+ m->e_type = ehdr->e_type;
}
else
{
diff --git a/libdwfl/dwfl_validate_address.c b/libdwfl/dwfl_validate_address.c
new file mode 100644
index 00000000..b828f17e
--- /dev/null
+++ b/libdwfl/dwfl_validate_address.c
@@ -0,0 +1,46 @@
+/* Validate an address and the relocatability of an offset from it.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#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/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c
index 372ece9e..03171914 100644
--- a/libdwfl/find-debuginfo.c
+++ b/libdwfl/find-debuginfo.c
@@ -40,7 +40,7 @@ try_open (const char *dir, const char *subdir, const char *debuglink,
if (fname == NULL)
return -1;
- int fd = open64 (fname, O_RDONLY);
+ int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
if (fd < 0)
free (fname);
else
@@ -59,7 +59,7 @@ check_crc (int fd, GElf_Word debuglink_crc)
}
int
-dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
+dwfl_standard_find_debuginfo (Dwfl_Module *mod,
void **userdata __attribute__ ((unused)),
const char *modname __attribute__ ((unused)),
GElf_Addr base __attribute__ ((unused)),
@@ -68,7 +68,7 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
GElf_Word debuglink_crc,
char **debuginfo_file_name)
{
- bool cancheck = true;
+ bool cancheck = debuglink_crc != (GElf_Word) 0;
const char *file_basename = file_name == NULL ? NULL : basename (file_name);
if (debuglink_file == NULL)
@@ -141,7 +141,14 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
char *fname;
int fd = try_open (dir, subdir, debuglink_file, &fname);
if (fd < 0)
- continue;
+ switch (errno)
+ {
+ case ENOENT:
+ case ENOTDIR:
+ continue;
+ default:
+ return -1;
+ }
if (!check || check_crc (fd, debuglink_crc))
{
*debuginfo_file_name = fname;
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index c319d19e..64e38d59 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -38,11 +38,15 @@ typedef struct
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. */
+ /* Fill *ADDR with the loaded address of the section called SECNAME in
+ the given module. 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, Dwarf_Addr *addr);
+ const char *secname,
+ Elf32_Word shndx, const GElf_Shdr *shdr,
+ Dwarf_Addr *addr);
char **debuginfo_path; /* See dwfl_standard_find_debuginfo. */
} Dwfl_Callbacks;
@@ -66,7 +70,7 @@ extern const char *dwfl_errmsg (int err);
/* Start reporting the current set of modules to the library. No calls but
- dwfl_report_module can be made on DWFL until dwfl_report_end is called. */
+ dwfl_report_* can be made on DWFL until dwfl_report_end is called. */
extern void dwfl_report_begin (Dwfl *dwfl);
/* Report that a module called NAME spans addresses [START, END).
@@ -76,13 +80,22 @@ 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. 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. */
+ 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.
@@ -150,13 +163,23 @@ extern int dwfl_standard_find_debuginfo (Dwfl_Module *, void **,
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 *, Elf32_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 *,
+ const char *, Elf32_Word,
+ const GElf_Shdr *,
Dwarf_Addr *addr);
/* Call dwfl_report_elf for the running Linux kernel.
@@ -169,6 +192,21 @@ extern int dwfl_linux_kernel_report_kernel (Dwfl *dwfl);
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 *));
+
/* Call dwfl_report_module for each file mapped into the address space of PID.
Returns zero on success, -1 if dwfl_report_module failed,
@@ -187,6 +225,34 @@ 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,
+ Elf32_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);
+
+
/*** Dwarf access functions ***/
/* Find the module containing the given address. */
@@ -235,6 +301,13 @@ extern Dwarf_Die *dwfl_module_nextcu (Dwfl_Module *mod,
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);
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 4f99386f..ae8985db 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -71,8 +71,12 @@ struct Dwfl
Dwfl_Module **modules;
size_t nmodules;
+
+ GElf_Addr offline_next_address;
};
+#define OFFLINE_REDZONE 0x10000
+
struct dwfl_file
{
char *name;
@@ -85,7 +89,7 @@ struct dwfl_file
struct Dwfl_Module
{
Dwfl *dwfl;
- struct Dwfl_Module *next; /* Link on Dwfl.moduelist. */
+ struct Dwfl_Module *next; /* Link on Dwfl.modulelist. */
void *userdata;
@@ -94,9 +98,11 @@ struct Dwfl_Module
struct dwfl_file main, debug;
Ebl *ebl;
- bool isrel; /* True iff this is an ET_REL file. */
+ 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. */
@@ -227,6 +233,7 @@ INTDECL (dwfl_module_getsrc)
INTDECL (dwfl_report_elf)
INTDECL (dwfl_report_begin)
INTDECL (dwfl_report_module)
+INTDECL (dwfl_report_offline)
INTDECL (dwfl_report_end)
INTDECL (dwfl_standard_find_debuginfo)
INTDECL (dwfl_linux_kernel_find_elf)
@@ -235,6 +242,9 @@ INTDECL (dwfl_linux_proc_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)
/* Leading arguments standard to callbacks passed a Dwfl_Module. */
#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
index 5b75e418..ba65c599 100644
--- a/libdwfl/linux-kernel-modules.c
+++ b/libdwfl/linux-kernel-modules.c
@@ -33,6 +33,28 @@
#define SECADDRFMT "/sys/module/%s/sections/%s"
+/* Try to open the given file as it is or under the debuginfo directory. */
+static int
+try_kernel_name (Dwfl *dwfl, char **fname)
+{
+ if (*fname == NULL)
+ return -1;
+
+ int fd = TEMP_FAILURE_RETRY (open64 (*fname, O_RDONLY));
+ if (fd < 0)
+ {
+ char *debugfname = NULL;
+ Dwfl_Module fakemod = { .dwfl = dwfl };
+ fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
+ *fname, basename (*fname), 0,
+ &debugfname);
+ free (*fname);
+ *fname = debugfname;
+ }
+
+ return fd;
+}
+
static inline const char *
kernel_release (void)
{
@@ -43,47 +65,183 @@ kernel_release (void)
return utsname.release;
}
-/* Find the ELF file for the running kernel and dwfl_report_elf it. */
-int
-dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
+static int
+report_kernel (Dwfl *dwfl, const char *release,
+ int (*predicate) (const char *module, const char *file))
{
if (dwfl == NULL)
return -1;
- const char *release = kernel_release ();
- if (release == NULL)
- return errno;
-
char *fname = NULL;
- asprintf (&fname, "/boot/vmlinux-%s", release);
- if (fname == NULL)
- return -1;
- int fd = open64 (fname, O_RDONLY);
- if (fd < 0)
+ if (release[0] == '/')
+ asprintf (&fname, "%s/vmlinux", release);
+ else
+ asprintf (&fname, "/boot/vmlinux-%s", release);
+ int fd = try_kernel_name (dwfl, &fname);
+ if (fd < 0 && release[0] != '/')
{
free (fname);
fname = NULL;
- asprintf (&fname, "/usr/lib/debug" MODULEDIRFMT "/vmlinux", release);
- if (fname == NULL)
- return -1;
- fd = open64 (fname, O_RDONLY);
+ asprintf (&fname, MODULEDIRFMT "/vmlinux", release);
+ fd = try_kernel_name (dwfl, &fname);
}
int result = 0;
if (fd < 0)
- result = errno;
- else if (INTUSE(dwfl_report_elf) (dwfl, "kernel", fname, fd, 0) == NULL)
+ result = (predicate != NULL && !(*predicate) ("kernel", NULL)) ? 0 : errno;
+ else
{
- close (fd);
- result = -1;
+ bool report = true;
+
+ if (predicate != NULL)
+ {
+ /* Let the predicate decide whether to use this one. */
+ int want = (*predicate) ("kernel", fname);
+ if (want < 0)
+ result = errno;
+ report = want > 0;
+ }
+
+ if (report
+ && INTUSE(dwfl_report_elf) (dwfl, "kernel", fname, fd, 0) == NULL)
+ {
+ close (fd);
+ result = -1;
+ }
}
free (fname);
return result;
}
+
+/* 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))
+{
+ if (release == NULL)
+ {
+ release = kernel_release ();
+ if (release == NULL)
+ return errno;
+ }
+
+ /* First report the kernel. */
+ int result = report_kernel (dwfl, release, predicate);
+ if (result == 0)
+ {
+ /* Do "find /lib/modules/RELEASE/kernel -name *.ko". */
+
+ char *modulesdir[] = { NULL, NULL };
+ if (release[0] == '/')
+ modulesdir[0] = (char *) release;
+ else
+ {
+ asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release);
+ if (modulesdir[0] == NULL)
+ return errno;
+ }
+
+ FTS *fts = fts_open (modulesdir, FTS_LOGICAL | FTS_NOSTAT, 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)
+ {
+ switch (f->fts_info)
+ {
+ case FTS_F:
+ case FTS_NSOK:
+ /* See if this file name matches "*.ko". */
+ if (f->fts_namelen > 3
+ && !memcmp (f->fts_name + f->fts_namelen - 3, ".ko", 4))
+ {
+ /* 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 - 3 + 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 - 3] = '\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;
+
+ default:
+ continue;
+ }
+
+ /* We only get here in error cases. */
+ break;
+ }
+ fts_close (fts);
+ free (modulesdir[0]);
+ }
+
+ return result;
+}
+INTDEF (dwfl_linux_kernel_report_offline)
+
+
+/* Find the ELF file for the running kernel and dwfl_report_elf it. */
+int
+dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
+{
+ const char *release = kernel_release ();
+ if (release == NULL)
+ return errno;
+
+ return report_kernel (dwfl, release, NULL);
+}
INTDEF (dwfl_linux_kernel_report_kernel)
+
/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules. */
int
@@ -96,9 +254,9 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
{
const char *release = kernel_release ();
if (release == NULL)
- return -1;
+ return errno;
- /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */
+ /* Do "find /lib/modules/`uname -r`/kernel -name MODULE_NAME.ko". */
char *modulesdir[] = { NULL, NULL };
asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release);
@@ -165,6 +323,7 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
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)
@@ -187,11 +346,14 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
}
}
+ 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. */
@@ -200,7 +362,9 @@ 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, Dwarf_Addr *addr)
+ const char *secname, Elf32_Word shndx __attribute__ ((unused)),
+ const GElf_Shdr *shdr __attribute__ ((unused)),
+ Dwarf_Addr *addr)
{
char *sysfile = NULL;
asprintf (&sysfile, SECADDRFMT, modname, secname);
diff --git a/libdwfl/offline.c b/libdwfl/offline.c
new file mode 100644
index 00000000..05496399
--- /dev/null
+++ b/libdwfl/offline.c
@@ -0,0 +1,78 @@
+/* Recover relocatibility for addresses computed from debug information.
+ Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#include "libdwflP.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. 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->symfile != &mod->main);
+
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *main_shdr = gelf_getshdr (elf_getscn (mod->main.elf, shndx),
+ &shdr_mem);
+ if (unlikely (main_shdr == NULL))
+ return -1;
+
+ assert (shdr->sh_addr == 0);
+ assert (shdr->sh_flags & SHF_ALLOC);
+ assert (main_shdr->sh_addr != 0);
+ assert (main_shdr->sh_flags == shdr->sh_flags);
+
+ *addr = main_shdr->sh_addr;
+ return 0;
+}
+INTDEF (dwfl_offline_section_address)
+
+Dwfl_Module *
+dwfl_report_offline (Dwfl *dwfl, const char *name,
+ const char *file_name, int fd)
+{
+ if (dwfl == NULL)
+ return NULL;
+
+ Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, name, file_name, fd,
+ dwfl->offline_next_address);
+ 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 (dwfl->offline_next_address >= mod->low_addr
+ && 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;
+}
+INTDEF (dwfl_report_offline)
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 48cb1ad2..fe03d397 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -37,7 +37,8 @@ __libdwfl_relocate_value (Dwfl_Module *mod, size_t symshstrndx,
if (name == NULL)
return DWFL_E_LIBELF;
- if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), name,
+ if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
+ name, shndx, refshdr,
&refshdr->sh_addr))
return CBFAIL;
@@ -63,7 +64,7 @@ Dwfl_Error
internal_function_def
__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
{
- assert (mod->isrel);
+ assert (mod->e_type == ET_REL);
GElf_Ehdr ehdr_mem;
const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
diff --git a/src/nm.c b/src/nm.c
index b1e71a33..2e3d1615 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -507,13 +507,6 @@ static const int length_map[2][3] =
};
-struct global_name
-{
- Dwarf_Global global;
- const char *name;
-};
-
-
static int
global_compare (const void *p1, const void *p2)
{
diff --git a/tests/ChangeLog b/tests/ChangeLog
index b5b6e18f..17bef797 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2005-08-22 Roland McGrath <roland@redhat.com>
+
+ * run-line2addr.sh: Add a case.
+ * testfile23.bz2: New data file.
+ * Makefile.am (EXTRA_DIST): Add it.
+
2005-08-18 Roland McGrath <roland@redhat.com>
* run-addrscopes.sh: New file.
@@ -51,6 +57,14 @@
* Makefile.am (dwflmodtest_LDADD): Add $(libebl).
+2005-06-01 Roland McGrath <roland@redhat.com>
+
+ * line2addr.c: Rewritten using libdwfl.
+ * run-line2addr.sh: Update test for changed arguments.
+ * Makefile.am (INCLUDES): Add libdwfl source directory to path.
+ (libdwfl): New variable.
+ (line2addr_LDADD): Use it.
+
2005-07-28 Roland McGrath <roland@redhat.com>
* dwflmodtest.c: New file, moved from ../libdwfl/ptest.c to here.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a8ae760b..99c769ca 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -69,7 +69,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
testfile18.bz2 testfile19.bz2 testfile19.index.bz2 \
testfile20.bz2 testfile20.index.bz2 \
testfile21.bz2 testfile21.index.bz2 \
- testfile22.bz2
+ testfile22.bz2 testfile23.bz2
if MUDFLAP
static_build=yes
@@ -111,7 +111,7 @@ get_files_LDADD = $(libdw) $(libelf) $(libmudflap)
get_aranges_LDADD = $(libdw) $(libelf) $(libmudflap)
allfcts_LDADD = $(libdw) $(libelf) $(libmudflap)
line2addr_no_Wformat = yes
-line2addr_LDADD = $(libdw) $(libelf) $(libmudflap)
+line2addr_LDADD = $(libdw) $(libmudflap)
addrscopes_LDADD = $(libdw) $(libmudflap)
#show_ciefde_LDADD = ../libdwarf/libdwarf.so $(libelf) $(libmudflap)
asm_tst1_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) -ldl
diff --git a/tests/line2addr.c b/tests/line2addr.c
index d2017fba..73c57f49 100644
--- a/tests/line2addr.c
+++ b/tests/line2addr.c
@@ -1,64 +1,125 @@
-#include <fcntl.h>
#include <inttypes.h>
-#include <libdw.h>
+#include <assert.h>
+#include <libdwfl.h>
+#include <argp.h>
#include <stdio.h>
+#include <locale.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
+#include <error.h>
+static void
+print_address (Dwfl_Module *mod, Dwarf_Addr address)
+{
+ int n = dwfl_module_relocations (mod);
+ if (n < 0)
+ error (0, 0, "dwfl_module_relocations: %s", dwfl_errmsg (-1));
+ else if (n > 0)
+ {
+ int i = dwfl_module_relocate_address (mod, &address);
+ if (i < 0)
+ error (0, 0, "dwfl_module_relocate_address: %s", dwfl_errmsg (-1));
+ else
+ {
+ const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ const char *secname = dwfl_module_relocation_info (mod, i, NULL);
+ if (n > 1 || secname[0] != '\0')
+ printf ("%s(%s)+%#" PRIx64, modname, secname, address);
+ else
+ printf ("%s(%s)+%#" PRIx64, modname, secname, address);
+ return;
+ }
+ }
+
+ printf ("%#" PRIx64, address);
+}
+
+
+struct args
+{
+ const char *arg;
+ char *file;
+ int line;
+};
+
+static int
+handle_module (Dwfl_Module *mod __attribute__ ((unused)),
+ void **udata __attribute__ ((unused)),
+ const char *modname, Dwarf_Addr base __attribute__ ((unused)),
+ Dwarf *dbg __attribute__ ((unused)),
+ Dwarf_Addr bias __attribute__ ((unused)), void *arg)
+{
+ const struct args *const a = arg;
+
+ Dwfl_Line **lines = NULL;
+ size_t nlines = 0;
+
+ if (dwfl_module_getsrc_file (mod, a->file, a->line, 0, &lines, &nlines) == 0)
+ {
+ for (size_t inner = 0; inner < nlines; ++inner)
+ {
+ Dwarf_Addr addr;
+ int line = a->line, col = 0;
+ const char *file = dwfl_lineinfo (lines[inner], &addr, &line, &col,
+ NULL, NULL);
+ if (file != NULL)
+ {
+ printf ("%s -> ", a->arg);
+ print_address (mod, addr);
+ if (modname[0] != '\0')
+ printf (" (%s:", modname);
+ if (strcmp (file, a->file) || line != a->line || col != 0)
+ printf (" %s%s:%d", modname[0] != '\0' ? "" : "(",
+ file, line);
+ if (col != 0)
+ printf (":%d");
+ if (modname[0] != '\0'
+ || strcmp (file, a->file) || line != a->line || col != 0)
+ puts (")");
+ else
+ puts ("");
+ }
+ }
+ free (lines);
+ }
+
+ return DWARF_CB_OK;
+}
+
int
main (int argc, char *argv[])
{
- for (int cnt = 1; cnt < argc; ++cnt)
+ int cnt;
+
+ /* Set locale. */
+ (void) setlocale (LC_ALL, "");
+
+ Dwfl *dwfl = NULL;
+ (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &cnt, &dwfl);
+ assert (dwfl != NULL);
+
+ for (; cnt < argc; ++cnt)
{
- char *fname;
- char *file;
- int line;
+ struct args a = { .arg = argv[cnt] };
- switch (sscanf (argv[cnt], "%a[^:]:%a[^:]:%d",
- &fname, &file, &line))
+ switch (sscanf (a.arg, "%a[^:]:%d", &a.file, &a.line))
{
default:
case 0:
- case 1:
printf ("ignored %s\n", argv[cnt]);
continue;
- case 2:
- line = 0;
+ case 1:
+ a.line = 0;
break;
- case 3:
+ case 2:
break;
}
- int fd = open (fname, O_RDONLY);
- if (fd == -1)
- continue;
-
- Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
- if (dbg != NULL)
- {
- Dwarf_Line **lines = NULL;
- size_t nlines = 0;
-
- if (dwarf_getsrc_file (dbg, file, line, 0, &lines, &nlines) == 0)
- {
- for (size_t inner = 0; inner < nlines; ++inner)
- {
- Dwarf_Addr addr;
- if (dwarf_lineaddr (lines[inner], &addr) == 0)
- printf ("%s -> %#" PRIxMAX "\n",
- argv[cnt], (uintmax_t) addr);
- }
-
- free (lines);
- }
-
- dwarf_end (dbg);
- }
+ (void) dwfl_getdwarf (dwfl, &handle_module, &a, 0);
- close (fd);
- free (fname);
- free (file);
+ free (a.file);
}
return 0;
diff --git a/tests/run-line2addr.sh b/tests/run-line2addr.sh
index c46c8fda..e1459cd1 100755
--- a/tests/run-line2addr.sh
+++ b/tests/run-line2addr.sh
@@ -25,20 +25,30 @@ bunzip2 -c $srcdir/testfile8.bz2 > testfile8 2>/dev/null || exit 0
# Don't fail if we cannot decompress the file.
bunzip2 -c $srcdir/testfile14.bz2 > testfile14 2>/dev/null || exit 0
-./line2addr testfile:f.c:4 testfile:f.c:8 testfile2:m.c:6 testfile2:b.c:1 testfile8:strip.c:953 testfile8:strip.c:365 testfile14:v.c:6 > line2addr.out
+# Don't fail if we cannot decompress the file.
+bunzip2 -c $srcdir/testfile23.bz2 > testfile23 2>/dev/null || exit 0
+
+(./line2addr -e testfile f.c:4 testfile f.c:8
+ ./line2addr -e testfile2 m.c:6 b.c:1
+ ./line2addr -e testfile8 strip.c:953 strip.c:365
+ ./line2addr -e testfile14 v.c:6
+ ./line2addr -e testfile23 foo.c:2 foo.c:6
+) > line2addr.out
diff -u line2addr.out - <<"EOF"
-testfile:f.c:4 -> 0x804846b
-testfile2:m.c:6 -> 0x100004cc
-testfile2:b.c:1 -> 0x10000470
-testfile8:strip.c:953 -> 0x169f
-testfile8:strip.c:953 -> 0x16aa
-testfile8:strip.c:365 -> 0x278b
-testfile8:strip.c:365 -> 0x2797
-testfile14:v.c:6 -> 0x400468
-testfile14:v.c:6 -> 0x400487
+f.c:4 -> 0x804846b (/home/drepper/gnu/new-bu/build/ttt/f.c:4)
+m.c:6 -> 0x100004cc (/shoggoth/drepper/m.c:6)
+b.c:1 -> 0x10000470 (/shoggoth/drepper/b.c:4)
+strip.c:953 -> (.text)+0x169f (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:953)
+strip.c:953 -> (.text)+0x16aa (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:953)
+strip.c:365 -> (.text)+0x278b (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:365)
+strip.c:365 -> (.text)+0x2797 (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:365)
+v.c:6 -> 0x400468 (/home/drepper/local/elfutils-build/20050425/v.c:6)
+v.c:6 -> 0x400487 (/home/drepper/local/elfutils-build/20050425/v.c:6)
+foo.c:2 -> (.init.text)+0xc (/home/roland/stock-elfutils-build/foo.c:2)
+foo.c:6 -> (.text)+0xc (/home/roland/stock-elfutils-build/foo.c:6)
EOF
-rm -f testfile testfile2 testfile8 testfile14 line2addr.out
+rm -f testfile testfile2 testfile8 testfile14 testfile22 line2addr.out
exit 0
diff --git a/tests/testfile23.bz2 b/tests/testfile23.bz2
new file mode 100644
index 00000000..cf0ce559
--- /dev/null
+++ b/tests/testfile23.bz2
Binary files differ