]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
2005-08-23 Roland McGrath <roland@redhat.com>
authorRoland McGrath <roland@redhat.com>
Tue, 23 Aug 2005 08:20:21 +0000 (08:20 +0000)
committerRoland McGrath <roland@redhat.com>
Tue, 23 Aug 2005 08:20:21 +0000 (08:20 +0000)
* dwarf_attr_integrate.c (dwarf_attr_integrate): Treat
DW_AT_specification the same as DW_AT_abstract_origin.

29 files changed:
libdw/ChangeLog
libdw/dwarf_attr_integrate.c
libdw/libdw.map
libdwfl/=ideas [new file with mode: 0644]
libdwfl/=oops [new file with mode: 0644]
libdwfl/ChangeLog
libdwfl/Makefile.am
libdwfl/argp-std.c
libdwfl/derelocate.c [new file with mode: 0644]
libdwfl/dwfl_begin.c
libdwfl/dwfl_getsrclines.c [new file with mode: 0644]
libdwfl/dwfl_module.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/dwfl_module_getsrc_file.c
libdwfl/dwfl_onesrcline.c [new file with mode: 0644]
libdwfl/dwfl_report_elf.c
libdwfl/dwfl_validate_address.c [new file with mode: 0644]
libdwfl/find-debuginfo.c
libdwfl/libdwfl.h
libdwfl/libdwflP.h
libdwfl/linux-kernel-modules.c
libdwfl/offline.c [new file with mode: 0644]
libdwfl/relocate.c
src/nm.c
tests/ChangeLog
tests/Makefile.am
tests/line2addr.c
tests/run-line2addr.sh
tests/testfile23.bz2 [new file with mode: 0644]

index de716d43f5087bc7d4a385c50ce830e35ebe7170..3b84ab9e6150d4bcb25bd1d11eb3ad0b7fc8be59 100644 (file)
@@ -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
index 4b27296aa0f0314b5ea5f3fe21658bdd84b9252a..4f95937eb31e11e5bf864920a4fd60163af06ac6 100644 (file)
@@ -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
@@ -31,6 +31,8 @@ dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name,
        return attr;
 
       attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, result);
+      if (attr == NULL)
+       attr = INTUSE(dwarf_attr) (die, DW_AT_specification, result);
       if (attr == NULL)
        break;
 
index b54dea3e3261ee286a0537d94acf8f8d57169c5c..01ee5f60676a373d623cee8cd33cd9f477a7820c 100644 (file)
@@ -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 (file)
index 0000000..bdce325
--- /dev/null
@@ -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 (file)
index 0000000..a8bb38b
--- /dev/null
@@ -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
index 3d4320c62c329b90a12159982281dcaf606291c1..2edaf6f91be81fca3173ce5c0c096fd7dd09ea00 100644 (file)
@@ -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,
index 243f67f571736433e3f08c158b8a3ecee290ebb6..a0735ff0b385d7e2fba6efc8d519c8192b756916 100644 (file)
@@ -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 \
index ebddcfb1fe7d133687700cda84be6003a0eeed2a..75f8b99f04dc96a68c8428f899f05400db4009b8 100644 (file)
@@ -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 (file)
index 0000000..b2b16f4
--- /dev/null
@@ -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)
index e7130a4ab1c2dce62df00ace369b027299dc925c..f90d4b60e1975a2f6413af3c988e298dfa8a4cfb 100644 (file)
@@ -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 (file)
index 0000000..0d1482a
--- /dev/null
@@ -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;
+}
index eecdb5247ca934943678e6aa40cf951765cabbb2..613c48de9f41f9aa916bcd75e335e611dc2c0611 100644 (file)
@@ -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)
 
index 329ecde199e5a148f30e3589d0c1a6cb61a8c430..5024575067c0100939a311bd26865ca2086b86c0 100644 (file)
@@ -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)
index 7c617dd8582103f89428bc616a159b181e4a86a8..640899d0f7453fe7a5635d03305f726046a19356 100644 (file)
@@ -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 (file)
index 0000000..3b09de0
--- /dev/null
@@ -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];
+}
index 21c9e84685d8776e34408d0996075e11cd297fb7..82545631f1692a6afdcfa2c9f050eb6ec8b8623d 100644 (file)
@@ -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 (file)
index 0000000..b828f17
--- /dev/null
@@ -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;
+}
index 372ece9e85bb6ef8cc91c902e5a6f857349c63ec..03171914a9dbc345a073ec4a013ef01c9af6cb77 100644 (file)
@@ -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;
index c319d19e5d70c848553786bdfafbf2ed54f629da..64e38d5938fc945d526073c9c38b6ff39b0f28fe 100644 (file)
@@ -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);
index 4f99386f61baeaf9ebc120b966de75c8b4644949..ae8985db53643592ccf9f46706db1fb944417cde 100644 (file)
@@ -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
index 5b75e4180830f5473f42508a315caba88c9db4ff..ba65c5998ae3f86c62b1704749c05bd7e73f54d7 100644 (file)
 #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 (file)
index 0000000..0549639
--- /dev/null
@@ -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)
index 48cb1ad26b2109dee0f3283fdc045128499f0f70..fe03d397fbee05beb96c77f31440bd53b959b363 100644 (file)
@@ -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);
index b1e71a33d9595f2fed81c37050ac833d38b75657..2e3d16150dc36a82603b15bcfc0d446721285708 100644 (file)
--- 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)
 {
index b5b6e18f625d637c3890e2e7aa08a67fd5aa8220..17bef79724e7bb6b7caf418a5bcdcb3d9aa4bee6 100644 (file)
@@ -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.
 
        * 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.
index a8ae760b54af801936459b4a343eae7383fdc1c9..99c769ca5ed0704ae14e53b4fd74076cd1d35ae8 100644 (file)
@@ -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
index d2017fbabe7e21d39f22caedb5e41db2b44b5f18..73c57f4962f1f8ea5e64890a309d7e679fe987e1 100644 (file)
-#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;
index c46c8fdafe5665c5488cd9622a77f56c70e2c766..e1459cd1a327ced44bc45006d6ddb49021f01ee2 100755 (executable)
@@ -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 (file)
index 0000000..cf0ce55
Binary files /dev/null and b/tests/testfile23.bz2 differ